accounting wip
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
DROP TABLE IF EXISTS `acc_gl_journal_entry`;
|
||||||
|
|
||||||
|
CREATE TABLE `acc_gl_journal_entry` (
|
||||||
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`account_id` BIGINT(20) NOT NULL,
|
||||||
|
`office_id` BIGINT(20) NOT NULL,
|
||||||
|
`reversal_id` BIGINT(20) NULL DEFAULT NULL,
|
||||||
|
`transaction_id` VARCHAR(50) NOT NULL,
|
||||||
|
`reversed` TINYINT(1) NOT NULL DEFAULT '0',
|
||||||
|
`portfolio_generated` TINYINT(1) NOT NULL DEFAULT '0',
|
||||||
|
`entry_date` DATE NOT NULL,
|
||||||
|
`type` VARCHAR(50) NOT NULL,
|
||||||
|
`amount` DECIMAL(19,6) NOT NULL,
|
||||||
|
`description` VARCHAR(500) NULL DEFAULT NULL,
|
||||||
|
`entity_type` VARCHAR(50) NULL DEFAULT NULL,
|
||||||
|
`entity_id` BIGINT(20) NULL DEFAULT NULL,
|
||||||
|
`createdby_id` BIGINT(20) NOT NULL,
|
||||||
|
`lastmodifiedby_id` BIGINT(20) NOT NULL,
|
||||||
|
`created_date` DATETIME NOT NULL,
|
||||||
|
`lastmodified_date` DATETIME NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
INDEX `FK_acc_gl_journal_entry_m_office` (`office_id`),
|
||||||
|
INDEX `FK_acc_gl_journal_entry_m_appuser` (`createdby_id`),
|
||||||
|
INDEX `FK_acc_gl_journal_entry_m_appuser_2` (`lastmodifiedby_id`),
|
||||||
|
INDEX `FK_acc_gl_journal_entry_acc_gl_journal_entry` (`reversal_id`),
|
||||||
|
INDEX `FK_acc_gl_journal_entry_acc_gl_account` (`account_id`),
|
||||||
|
CONSTRAINT `FK_acc_gl_journal_entry_acc_gl_account` FOREIGN KEY (`account_id`) REFERENCES `acc_gl_account` (`id`),
|
||||||
|
CONSTRAINT `FK_acc_gl_journal_entry_acc_gl_journal_entry` FOREIGN KEY (`reversal_id`) REFERENCES `acc_gl_journal_entry` (`id`),
|
||||||
|
CONSTRAINT `FK_acc_gl_journal_entry_m_appuser` FOREIGN KEY (`createdby_id`) REFERENCES `m_appuser` (`id`),
|
||||||
|
CONSTRAINT `FK_acc_gl_journal_entry_m_appuser_2` FOREIGN KEY (`lastmodifiedby_id`) REFERENCES `m_appuser` (`id`),
|
||||||
|
CONSTRAINT `FK_acc_gl_journal_entry_m_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`)
|
||||||
|
)
|
||||||
|
COLLATE='utf8_general_ci'
|
||||||
|
ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
ALTER TABLE `acc_gl_account`
|
||||||
|
ALTER `description` DROP DEFAULT;
|
||||||
|
ALTER TABLE `acc_gl_account`
|
||||||
|
CHANGE COLUMN `description` `description` VARCHAR(500) NULL AFTER `classification`;
|
||||||
|
|
||||||
Executable
+411
@@ -0,0 +1,411 @@
|
|||||||
|
package org.mifosplatform.infrastructure.dataqueries.service;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.sql.Date;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.sql.rowset.CachedRowSet;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.StreamingOutput;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
|
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||||
|
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
||||||
|
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
||||||
|
import org.mifosplatform.infrastructure.dataqueries.exception.ReportNotFoundException;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.MasterReport;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.PdfReportUtil;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.modules.output.table.csv.CSVReportUtil;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlReportUtil;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.modules.output.table.xls.ExcelReportUtil;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.parameters.ParameterDefinitionEntry;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.parameters.ReportParameterDefinition;
|
||||||
|
import org.pentaho.reporting.engine.classic.core.util.ReportParameterValues;
|
||||||
|
import org.pentaho.reporting.libraries.resourceloader.Resource;
|
||||||
|
import org.pentaho.reporting.libraries.resourceloader.ResourceException;
|
||||||
|
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.lowagie.text.Document;
|
||||||
|
import com.lowagie.text.PageSize;
|
||||||
|
import com.lowagie.text.pdf.PdfPTable;
|
||||||
|
import com.lowagie.text.pdf.PdfWriter;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ReadReportingServiceImpl implements ReadReportingService {
|
||||||
|
|
||||||
|
private final PlatformSecurityContext context;
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(ReadReportingServiceImpl.class);
|
||||||
|
|
||||||
|
private Boolean noPentaho = false;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ReadReportingServiceImpl(final PlatformSecurityContext context) {
|
||||||
|
// kick off pentaho reports server
|
||||||
|
ClassicEngineBoot.getInstance().start();
|
||||||
|
noPentaho = false;
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GenericDataService genericDataService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamingOutput retrieveReportCSV(final String name, final String type, final Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
return new StreamingOutput() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream out) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
GenericResultsetData result = retrieveGenericResultset(name, type, queryParams);
|
||||||
|
StringBuffer sb = generateCsvFileBuffer(result);
|
||||||
|
|
||||||
|
InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
|
||||||
|
|
||||||
|
byte[] outputByte = new byte[4096];
|
||||||
|
Integer readLen = in.read(outputByte, 0, 4096);
|
||||||
|
|
||||||
|
while (readLen != -1) {
|
||||||
|
out.write(outputByte, 0, readLen);
|
||||||
|
readLen = in.read(outputByte, 0, 4096);
|
||||||
|
}
|
||||||
|
// in.close();
|
||||||
|
// out.flush();
|
||||||
|
// out.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StringBuffer generateCsvFileBuffer(GenericResultsetData result) {
|
||||||
|
StringBuffer writer = new StringBuffer();
|
||||||
|
|
||||||
|
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders();
|
||||||
|
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||||
|
Integer chSize = columnHeaders.size();
|
||||||
|
for (int i = 0; i < chSize; i++) {
|
||||||
|
writer.append('"' + columnHeaders.get(i).getColumnName() + '"');
|
||||||
|
if (i < (chSize - 1)) writer.append(",");
|
||||||
|
}
|
||||||
|
writer.append('\n');
|
||||||
|
|
||||||
|
List<ResultsetDataRow> data = result.getData();
|
||||||
|
List<String> row;
|
||||||
|
Integer rSize;
|
||||||
|
// String currCol;
|
||||||
|
String currColType;
|
||||||
|
String currVal;
|
||||||
|
logger.info("NO. of Rows: " + data.size());
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
row = data.get(i).getRow();
|
||||||
|
rSize = row.size();
|
||||||
|
for (int j = 0; j < rSize; j++) {
|
||||||
|
// currCol = columnHeaders.get(j).getColumnName();
|
||||||
|
currColType = columnHeaders.get(j).getColumnType();
|
||||||
|
currVal = row.get(j);
|
||||||
|
if (currVal != null) {
|
||||||
|
if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|
||||||
|
|| currColType.equals("SMALLINT") || currColType.equals("INT"))
|
||||||
|
writer.append(currVal);
|
||||||
|
else
|
||||||
|
writer.append('"' + currVal + '"');
|
||||||
|
}
|
||||||
|
if (j < (rSize - 1)) writer.append(",");
|
||||||
|
}
|
||||||
|
writer.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
logger.info("STARTING REPORT: " + name + " Type: " + type);
|
||||||
|
|
||||||
|
String sql;
|
||||||
|
if (name.equals(".")) {
|
||||||
|
// this is to support api /reports - which isn't an important
|
||||||
|
// call. It isn't used in the default reporting UI. But there is a
|
||||||
|
// need to provide an api that does bring back 'permitted' reports
|
||||||
|
// PERMITTED REPORTS SQL
|
||||||
|
sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category,"
|
||||||
|
+ " rp.parameter_id, rp.report_parameter_name, p.parameter_name" + " from stretchy_report r"
|
||||||
|
+ " left join stretchy_report_parameter rp on rp.report_id = r.report_id"
|
||||||
|
+ " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + " where exists" + " (select 'f'"
|
||||||
|
+ " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
|
||||||
|
+ " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id"
|
||||||
|
+ " where ur.appuser_id = " + context.authenticatedUser().getId()
|
||||||
|
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) "
|
||||||
|
+ " order by r.report_name, rp.parameter_id";
|
||||||
|
} else {
|
||||||
|
sql = getSQLtoRun(name, type, queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericResultsetData result = genericDataService.fillGenericResultSet(sql);
|
||||||
|
|
||||||
|
long elapsed = System.currentTimeMillis() - startTime;
|
||||||
|
logger.info("FINISHING Report/Request Name: " + name + " - " + type + " Elapsed Time: " + elapsed);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
String sql = getSql(name, type);
|
||||||
|
|
||||||
|
Set<String> keys = queryParams.keySet();
|
||||||
|
for (String key : keys) {
|
||||||
|
String pValue = queryParams.get(key);
|
||||||
|
// logger.info("(" + key + " : " + pValue + ")");
|
||||||
|
sql = genericDataService.replace(sql, key, pValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppUser currentUser = context.authenticatedUser();
|
||||||
|
// Allows sql query to restrict data by office hierarchy if required
|
||||||
|
sql = genericDataService.replace(sql, "${currentUserHierarchy}", currentUser.getOffice().getHierarchy());
|
||||||
|
// Allows sql query to restrict data by current user Id if required
|
||||||
|
// (typically used to return report lists containing only reports
|
||||||
|
// permitted to be run by the user
|
||||||
|
sql = genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString());
|
||||||
|
|
||||||
|
sql = genericDataService.wrapSQL(sql);
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSql(String name, String type) {
|
||||||
|
|
||||||
|
String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'";
|
||||||
|
inputSql = genericDataService.wrapSQL(inputSql);
|
||||||
|
|
||||||
|
String sqlErrorMsg = "Sql: " + inputSql;
|
||||||
|
CachedRowSet rs = genericDataService.getCachedResultSet(inputSql, sqlErrorMsg);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (rs.next()) { return rs.getString("the_sql"); }
|
||||||
|
throw new ReportNotFoundException(inputSql);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.info("msg: " + e.getMessage() + " sql: " + inputSql);
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReportType(String reportName) {
|
||||||
|
String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "'";
|
||||||
|
|
||||||
|
sql = genericDataService.wrapSQL(sql);
|
||||||
|
|
||||||
|
String sqlErrorMsg = "Report Name: " + reportName + " Sql: " + sql;
|
||||||
|
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (rs.next()) { return rs.getString("report_type"); }
|
||||||
|
throw new ReportNotFoundException(sql);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response processPentahoRequest(String reportName, String outputTypeParam, Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
String outputType = "HTML";
|
||||||
|
if (StringUtils.isNotBlank(outputTypeParam)) outputType = outputTypeParam;
|
||||||
|
|
||||||
|
if (!(outputType.equalsIgnoreCase("HTML") || outputType.equalsIgnoreCase("PDF") || outputType.equalsIgnoreCase("XLS") || outputType
|
||||||
|
.equalsIgnoreCase("CSV")))
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
|
||||||
|
|
||||||
|
if (noPentaho)
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled", "Pentaho is not enabled");
|
||||||
|
|
||||||
|
// TODO - use pentaho location finder like Pawel does in Mifos
|
||||||
|
// String reportPath =
|
||||||
|
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
|
||||||
|
// + reportName + ".prpt";
|
||||||
|
String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator
|
||||||
|
+ ThreadLocalContextUtil.getTenant().getName().replaceAll(" ", "").trim() + File.separator + "reports" + File.separator
|
||||||
|
+ reportName + ".prpt";
|
||||||
|
logger.info("Report path: " + reportPath);
|
||||||
|
|
||||||
|
// load report definition
|
||||||
|
ResourceManager manager = new ResourceManager();
|
||||||
|
manager.registerDefaults();
|
||||||
|
Resource res;
|
||||||
|
|
||||||
|
try {
|
||||||
|
res = manager.createDirectly(reportPath, MasterReport.class);
|
||||||
|
MasterReport masterReport = (MasterReport) res.getResource();
|
||||||
|
|
||||||
|
addParametersToReport(masterReport, queryParams);
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
if ("PDF".equalsIgnoreCase(outputType)) {
|
||||||
|
PdfReportUtil.createPDF(masterReport, baos);
|
||||||
|
return Response.ok().entity(baos.toByteArray()).type("application/pdf").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("XLS".equalsIgnoreCase(outputType)) {
|
||||||
|
ExcelReportUtil.createXLS(masterReport, baos);
|
||||||
|
return Response.ok().entity(baos.toByteArray()).type("application/vnd.ms-excel")
|
||||||
|
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".xls").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("CSV".equalsIgnoreCase(outputType)) {
|
||||||
|
CSVReportUtil.createCSV(masterReport, baos, "UTF-8");
|
||||||
|
return Response.ok().entity(baos.toByteArray()).type("application/x-msdownload")
|
||||||
|
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("HTML".equalsIgnoreCase(outputType)) {
|
||||||
|
HtmlReportUtil.createStreamHTML(masterReport, baos);
|
||||||
|
return Response.ok().entity(baos.toByteArray()).type("text/html").build();
|
||||||
|
}
|
||||||
|
} catch (ResourceException e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||||
|
} catch (ReportProcessingException e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addParametersToReport(MasterReport report, Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ReportParameterValues rptParamValues = report.getParameterValues();
|
||||||
|
ReportParameterDefinition paramsDefinition = report.getParameterDefinition();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* only allow integer and string parameter types and assume all
|
||||||
|
* mandatory - could go more detailed like Pawel did in Mifos later
|
||||||
|
* and could match incoming and pentaho parameters better...
|
||||||
|
* currently assuming they come in ok... and if not an error
|
||||||
|
*/
|
||||||
|
for (ParameterDefinitionEntry paramDefEntry : paramsDefinition.getParameterDefinitions()) {
|
||||||
|
String paramName = paramDefEntry.getName();
|
||||||
|
String pValue = queryParams.get(paramName);
|
||||||
|
if (StringUtils.isBlank(pValue))
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.reporting.error", "Pentaho Parameter: " + paramName
|
||||||
|
+ " - not Provided");
|
||||||
|
|
||||||
|
Class<?> clazz = paramDefEntry.getValueType();
|
||||||
|
logger.info("addParametersToReport(" + paramName + " : " + pValue + " : " + clazz.getCanonicalName() + ")");
|
||||||
|
|
||||||
|
if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Integer"))
|
||||||
|
rptParamValues.put(paramName, Integer.parseInt(pValue));
|
||||||
|
else if (clazz.getCanonicalName().equalsIgnoreCase("java.sql.Date"))
|
||||||
|
rptParamValues.put(paramName, Date.valueOf(pValue));
|
||||||
|
else
|
||||||
|
rptParamValues.put(paramName, pValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams) {
|
||||||
|
|
||||||
|
String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + "";
|
||||||
|
if (!new File(fileLocation).isDirectory()) {
|
||||||
|
new File(fileLocation).mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
String genaratePdf = fileLocation + File.separator + reportName + ".pdf";
|
||||||
|
|
||||||
|
try {
|
||||||
|
GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams);
|
||||||
|
|
||||||
|
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders();
|
||||||
|
List<ResultsetDataRow> data = result.getData();
|
||||||
|
List<String> row;
|
||||||
|
|
||||||
|
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||||
|
Integer chSize = columnHeaders.size();
|
||||||
|
|
||||||
|
Document document = new Document(PageSize.B0.rotate());
|
||||||
|
|
||||||
|
PdfWriter.getInstance(document, new FileOutputStream(new File(fileLocation + reportName + ".pdf")));
|
||||||
|
document.open();
|
||||||
|
|
||||||
|
PdfPTable table = new PdfPTable(chSize);
|
||||||
|
table.setWidthPercentage(100);
|
||||||
|
|
||||||
|
for (int i = 0; i < chSize; i++) {
|
||||||
|
|
||||||
|
table.addCell(columnHeaders.get(i).getColumnName());
|
||||||
|
|
||||||
|
}
|
||||||
|
table.completeRow();
|
||||||
|
|
||||||
|
Integer rSize;
|
||||||
|
String currColType;
|
||||||
|
String currVal;
|
||||||
|
logger.info("NO. of Rows: " + data.size());
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
row = data.get(i).getRow();
|
||||||
|
rSize = row.size();
|
||||||
|
for (int j = 0; j < rSize; j++) {
|
||||||
|
currColType = columnHeaders.get(j).getColumnType();
|
||||||
|
currVal = row.get(j);
|
||||||
|
if (currVal != null) {
|
||||||
|
if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|
||||||
|
|| currColType.equals("SMALLINT") || currColType.equals("INT")) {
|
||||||
|
|
||||||
|
table.addCell(currVal.toString());
|
||||||
|
} else {
|
||||||
|
table.addCell(currVal.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.completeRow();
|
||||||
|
document.add(table);
|
||||||
|
document.close();
|
||||||
|
return genaratePdf;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-1
@@ -4,7 +4,17 @@ public class AccountingConstants {
|
|||||||
|
|
||||||
/*** Categories for Accounting **/
|
/*** Categories for Accounting **/
|
||||||
public static enum GL_ACCOUNT_CLASSIFICATION {
|
public static enum GL_ACCOUNT_CLASSIFICATION {
|
||||||
ASSETS, LIABILITIES, INCOME, EXPENDITURE, EQUITY;
|
ASSET, LIABILITY, INCOME, EXPENSE, EQUITY;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Types of Journal Entries **/
|
||||||
|
public static enum JOURNAL_ENTRY_TYPE {
|
||||||
|
DEBIT, CREDIT;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,6 @@
|
|||||||
package org.mifosplatform.accounting.api;
|
package org.mifosplatform.accounting.api;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@ import org.mifosplatform.accounting.service.GLClosureWritePlatformService;
|
|||||||
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||||
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.mifosplatform.organisation.office.data.OfficeLookup;
|
||||||
|
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -41,6 +44,9 @@ public class GLClosuresApiResource {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private GLClosureWritePlatformService glClosureWritePlatformService;
|
private GLClosureWritePlatformService glClosureWritePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OfficeReadPlatformService officeReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccountingApiDataConversionService accountingApiDataConversionService;
|
private AccountingApiDataConversionService accountingApiDataConversionService;
|
||||||
|
|
||||||
@@ -84,7 +90,7 @@ public class GLClosuresApiResource {
|
|||||||
|
|
||||||
final GLClosureData glClosureData = this.glClosureReadPlatformService.retrieveGLClosureById(glClosureId);
|
final GLClosureData glClosureData = this.glClosureReadPlatformService.retrieveGLClosureById(glClosureId);
|
||||||
if (template) {
|
if (template) {
|
||||||
// TODO: define templates
|
glClosureData.setAllowedOffices(new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.apiJsonSerializerService.serializeGLClosureDataToJson(prettyPrint, responseParameters, glClosureData);
|
return this.apiJsonSerializerService.serializeGLClosureDataToJson(prettyPrint, responseParameters, glClosureData);
|
||||||
|
|||||||
Executable
+123
@@ -0,0 +1,123 @@
|
|||||||
|
package org.mifosplatform.accounting.api;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
|
||||||
|
import org.mifosplatform.accounting.api.data.JournalEntryIdentifier;
|
||||||
|
import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService;
|
||||||
|
import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService;
|
||||||
|
import org.mifosplatform.accounting.api.infrastructure.DateParam;
|
||||||
|
import org.mifosplatform.accounting.service.GLJournalEntryReadPlatformService;
|
||||||
|
import org.mifosplatform.accounting.service.GLJournalEntryWritePlatformService;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
||||||
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Path("/journalentries")
|
||||||
|
@Component
|
||||||
|
@Scope("singleton")
|
||||||
|
public class GLJournalEntriesApiResource {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GLJournalEntryReadPlatformService glJournalEntryReadPlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GLJournalEntryWritePlatformService glJournalEntryWritePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountingApiDataConversionService accountingApiDataConversionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountingApiJsonSerializerService apiJsonSerializerService;
|
||||||
|
|
||||||
|
private final String entityType = "JOURNAL_ENTRY";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PlatformSecurityContext context;
|
||||||
|
|
||||||
|
// private final static Logger logger =
|
||||||
|
// LoggerFactory.getLogger(GLJournalEntriesApiResource.class);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String retrieveAllJournalEntries(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId,
|
||||||
|
@QueryParam("glAccountId") final Long glAccountId,
|
||||||
|
@QueryParam("portfolioGenerated") final Boolean portfolioGenerated, @QueryParam("fromDate") final DateParam fromDateParam,
|
||||||
|
@QueryParam("toDate") final DateParam toDateParam) {
|
||||||
|
|
||||||
|
// TODO: Vishwas Add pagination, approach at
|
||||||
|
// http://www.javaworld.com/community/node/8295 looks good
|
||||||
|
|
||||||
|
context.authenticatedUser().validateHasReadPermission(entityType);
|
||||||
|
|
||||||
|
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||||
|
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
|
||||||
|
List<GLJournalEntryData> glJournalEntryDatas = null;
|
||||||
|
// get dates from date params
|
||||||
|
Date fromDate = null;
|
||||||
|
if (fromDateParam != null) {
|
||||||
|
fromDate = fromDateParam.getDate();
|
||||||
|
}
|
||||||
|
Date toDate = null;
|
||||||
|
if (toDateParam != null) {
|
||||||
|
toDate = toDateParam.getDate();
|
||||||
|
}
|
||||||
|
glJournalEntryDatas = this.glJournalEntryReadPlatformService.retrieveAllGLJournalEntries(officeId, glAccountId,
|
||||||
|
portfolioGenerated, fromDate, toDate);
|
||||||
|
return this.apiJsonSerializerService.serializeGLJournalEntryDataToJson(prettyPrint, responseParameters, glJournalEntryDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("{glJournalEntryId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String retreiveAccount(@PathParam("glJournalEntryId") final Long glJournalEntryId, @Context final UriInfo uriInfo) {
|
||||||
|
|
||||||
|
context.authenticatedUser().validateHasReadPermission(entityType);
|
||||||
|
|
||||||
|
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||||
|
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
|
||||||
|
|
||||||
|
final GLJournalEntryData glJournalEntryData = this.glJournalEntryReadPlatformService.retrieveGLJournalEntryById(glJournalEntryId);
|
||||||
|
return this.apiJsonSerializerService.serializeGLJournalEntryDataToJson(prettyPrint, responseParameters, glJournalEntryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String createGLJournalEntry(final String jsonRequestBody) {
|
||||||
|
|
||||||
|
final GLJournalEntryCommand command = this.accountingApiDataConversionService.convertJsonToGLJournalEntryCommand(jsonRequestBody);
|
||||||
|
|
||||||
|
final String transactionId = glJournalEntryWritePlatformService.createJournalEntry(command);
|
||||||
|
return this.apiJsonSerializerService.serializeJournalEntryIdentifier(new JournalEntryIdentifier(transactionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("{transactionId}/reversal")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String createReversalJournalEntry(@PathParam("transactionId") final String transactionId) {
|
||||||
|
|
||||||
|
this.glJournalEntryWritePlatformService.revertJournalEntry(transactionId);
|
||||||
|
|
||||||
|
return this.apiJsonSerializerService.serializeJournalEntryIdentifier(new JournalEntryIdentifier(transactionId));
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
package org.mifosplatform.accounting.api.commands;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable command for adding an accounting closure
|
||||||
|
*/
|
||||||
|
public class GLJournalEntryCommand {
|
||||||
|
|
||||||
|
private final Long officeId;
|
||||||
|
private final LocalDate entryDate;
|
||||||
|
private final String comments;
|
||||||
|
|
||||||
|
private final SingleDebitOrCreditEntryCommand[] credits;
|
||||||
|
private final SingleDebitOrCreditEntryCommand[] debits;
|
||||||
|
|
||||||
|
private final Set<String> parametersPassedInRequest;
|
||||||
|
|
||||||
|
public GLJournalEntryCommand(Set<String> parametersPassedInRequest, Long officeId, LocalDate entryDate, String comments,
|
||||||
|
SingleDebitOrCreditEntryCommand[] credits, SingleDebitOrCreditEntryCommand[] debits) {
|
||||||
|
this.officeId = officeId;
|
||||||
|
this.entryDate = entryDate;
|
||||||
|
this.comments = comments;
|
||||||
|
this.credits = credits;
|
||||||
|
this.debits = debits;
|
||||||
|
this.parametersPassedInRequest = parametersPassedInRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOfficeIdChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("officeId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEntryDateChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("entryDate");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCommentsChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("comments");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCreditsChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("credits");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebitsChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("debits");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getOfficeId() {
|
||||||
|
return this.officeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getEntryDate() {
|
||||||
|
return this.entryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComments() {
|
||||||
|
return this.comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingleDebitOrCreditEntryCommand[] getCredits() {
|
||||||
|
return this.credits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingleDebitOrCreditEntryCommand[] getDebits() {
|
||||||
|
return this.debits;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package org.mifosplatform.accounting.api.commands;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable command for adding a "Credit" entry to the Journal
|
||||||
|
*/
|
||||||
|
public class SingleDebitOrCreditEntryCommand {
|
||||||
|
|
||||||
|
private final Long glAccountId;
|
||||||
|
private final BigDecimal amount;
|
||||||
|
private final String comments;
|
||||||
|
|
||||||
|
private final Set<String> parametersPassedInRequest;
|
||||||
|
|
||||||
|
public SingleDebitOrCreditEntryCommand(Set<String> parametersPassedInRequest, Long glAccountId, BigDecimal amount, String comments) {
|
||||||
|
this.parametersPassedInRequest = parametersPassedInRequest;
|
||||||
|
this.glAccountId = glAccountId;
|
||||||
|
this.amount = amount;
|
||||||
|
this.comments = comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGlAccountIdChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("glAccountId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGlAmountChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("amount");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCommentsChanged() {
|
||||||
|
return this.parametersPassedInRequest.contains("comments");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getGlAccountId() {
|
||||||
|
return this.glAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getComments() {
|
||||||
|
return this.comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getParametersPassedInRequest() {
|
||||||
|
return this.parametersPassedInRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+24
-3
@@ -1,6 +1,10 @@
|
|||||||
package org.mifosplatform.accounting.api.data;
|
package org.mifosplatform.accounting.api.data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.organisation.office.data.OfficeLookup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable object representing a General Ledger Account
|
* Immutable object representing a General Ledger Account
|
||||||
@@ -25,14 +29,21 @@ public class GLClosureData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final LocalDate lastUpdatedDate;
|
private final LocalDate lastUpdatedDate;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Long creatingByUserId;
|
private final Long createdByUserId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String createdByUsername;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final Long lastUpdatedByUserId;
|
private final Long lastUpdatedByUserId;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
private final String lastUpdatedByUsername;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private final String comments;
|
private final String comments;
|
||||||
|
|
||||||
|
private List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>();
|
||||||
|
|
||||||
public GLClosureData(Long id, Long officeId, String officeName, LocalDate closingDate, boolean deleted, LocalDate createdDate,
|
public GLClosureData(Long id, Long officeId, String officeName, LocalDate closingDate, boolean deleted, LocalDate createdDate,
|
||||||
LocalDate lastUpdatedDate, Long creatingByUserId, Long lastUpdatedByUserId, String comments) {
|
LocalDate lastUpdatedDate, Long createdByUserId, String createdByUsername, Long lastUpdatedByUserId,
|
||||||
|
String lastUpdatedByUsername, String comments) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.officeName = officeName;
|
this.officeName = officeName;
|
||||||
@@ -40,9 +51,19 @@ public class GLClosureData {
|
|||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
this.createdDate = createdDate;
|
this.createdDate = createdDate;
|
||||||
this.lastUpdatedDate = lastUpdatedDate;
|
this.lastUpdatedDate = lastUpdatedDate;
|
||||||
this.creatingByUserId = creatingByUserId;
|
this.createdByUserId = createdByUserId;
|
||||||
|
this.createdByUsername = createdByUsername;
|
||||||
this.lastUpdatedByUserId = lastUpdatedByUserId;
|
this.lastUpdatedByUserId = lastUpdatedByUserId;
|
||||||
|
this.lastUpdatedByUsername = lastUpdatedByUsername;
|
||||||
this.comments = comments;
|
this.comments = comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<OfficeLookup> getAllowedOffices() {
|
||||||
|
return this.allowedOffices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowedOffices(List<OfficeLookup> allowedOffices) {
|
||||||
|
this.allowedOffices = allowedOffices;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Executable
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package org.mifosplatform.accounting.api.data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable object representing a General Ledger Account
|
||||||
|
*
|
||||||
|
* Note: no getter/setters required as google will produce json from fields of
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
public class GLJournalEntryData {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long id;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long officeId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String officeName;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String glAccountName;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long glAccountId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String glAccountClassification;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final LocalDate entryDate;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String entryType;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final BigDecimal amount;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String transactionId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Boolean portfolioGenerated;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String entityType;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long entityId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long createdByUserId;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final LocalDate createdDate;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String createdByUserName;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String comments;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Boolean reversed;
|
||||||
|
|
||||||
|
public GLJournalEntryData(Long id, Long officeId, String officeName, String glAccountName, Long glAccountId,
|
||||||
|
String glAccountClassification, LocalDate entryDate, String entryType, BigDecimal amount, String transactionId,
|
||||||
|
Boolean portfolioGenerated, String entityType, Long entityId, Long createdByUserId, LocalDate createdDate,
|
||||||
|
String createdByUserName, String comments, Boolean reversed) {
|
||||||
|
this.id = id;
|
||||||
|
this.officeId = officeId;
|
||||||
|
this.officeName = officeName;
|
||||||
|
this.glAccountName = glAccountName;
|
||||||
|
this.glAccountId = glAccountId;
|
||||||
|
this.glAccountClassification = glAccountClassification;
|
||||||
|
this.entryDate = entryDate;
|
||||||
|
this.entryType = entryType;
|
||||||
|
this.amount = amount;
|
||||||
|
this.transactionId = transactionId;
|
||||||
|
this.portfolioGenerated = portfolioGenerated;
|
||||||
|
this.entityType = entityType;
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.createdByUserId = createdByUserId;
|
||||||
|
this.createdDate = createdDate;
|
||||||
|
this.createdByUserName = createdByUserName;
|
||||||
|
this.comments = comments;
|
||||||
|
this.reversed = reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package org.mifosplatform.accounting.api.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the successful result of an REST API call.
|
||||||
|
*/
|
||||||
|
public class JournalEntryIdentifier {
|
||||||
|
|
||||||
|
private String entityId;
|
||||||
|
|
||||||
|
// TODO - Rename variable to commandId or taskId or something that shows
|
||||||
|
// this is the id of a command in a table/queue for processing.
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private Long makerCheckerId;
|
||||||
|
|
||||||
|
public static JournalEntryIdentifier makerChecker(final Long makerCheckerId) {
|
||||||
|
return new JournalEntryIdentifier(null, makerCheckerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JournalEntryIdentifier makerChecker(final String resourceId, final Long makerCheckerId) {
|
||||||
|
return new JournalEntryIdentifier(resourceId, makerCheckerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JournalEntryIdentifier() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public JournalEntryIdentifier(final String entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JournalEntryIdentifier(final String entityId, final Long makerCheckerId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.makerCheckerId = makerCheckerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEntityId() {
|
||||||
|
return this.entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityId(final String entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -2,6 +2,7 @@ package org.mifosplatform.accounting.api.infrastructure;
|
|||||||
|
|
||||||
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
||||||
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
|
||||||
public interface AccountingApiDataConversionService {
|
public interface AccountingApiDataConversionService {
|
||||||
|
|
||||||
@@ -9,4 +10,6 @@ public interface AccountingApiDataConversionService {
|
|||||||
|
|
||||||
GLClosureCommand convertJsonToGLClosureCommand(Long resourceIdentifier, String json);
|
GLClosureCommand convertJsonToGLClosureCommand(Long resourceIdentifier, String json);
|
||||||
|
|
||||||
|
GLJournalEntryCommand convertJsonToGLJournalEntryCommand(String json);
|
||||||
|
|
||||||
}
|
}
|
||||||
+10
@@ -5,12 +5,17 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.mifosplatform.accounting.api.data.GLAccountData;
|
import org.mifosplatform.accounting.api.data.GLAccountData;
|
||||||
import org.mifosplatform.accounting.api.data.GLClosureData;
|
import org.mifosplatform.accounting.api.data.GLClosureData;
|
||||||
|
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
|
||||||
|
import org.mifosplatform.accounting.api.data.JournalEntryIdentifier;
|
||||||
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
||||||
|
|
||||||
|
|
||||||
public interface AccountingApiJsonSerializerService {
|
public interface AccountingApiJsonSerializerService {
|
||||||
|
|
||||||
String serializeEntityIdentifier(final EntityIdentifier identifier);
|
String serializeEntityIdentifier(final EntityIdentifier identifier);
|
||||||
|
|
||||||
|
String serializeJournalEntryIdentifier(final JournalEntryIdentifier identifier);
|
||||||
|
|
||||||
String serializeGLAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, GLAccountData accountData);
|
String serializeGLAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, GLAccountData accountData);
|
||||||
|
|
||||||
String serializeGLAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLAccountData> accountDatas);
|
String serializeGLAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLAccountData> accountDatas);
|
||||||
@@ -19,4 +24,9 @@ public interface AccountingApiJsonSerializerService {
|
|||||||
|
|
||||||
String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLClosureData> closureDatas);
|
String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLClosureData> closureDatas);
|
||||||
|
|
||||||
|
String serializeGLJournalEntryDataToJson(boolean prettyPrint, Set<String> responseParameters, GLJournalEntryData journalEntryData);
|
||||||
|
|
||||||
|
String serializeGLJournalEntryDataToJson(boolean prettyPrint, Set<String> responseParameters,
|
||||||
|
Collection<GLJournalEntryData> journalEntryDatas);
|
||||||
|
|
||||||
}
|
}
|
||||||
Executable
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package org.mifosplatform.accounting.api.infrastructure;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.ws.rs.WebApplicationException;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for parsing dates sent as query parameters
|
||||||
|
*
|
||||||
|
* TODO: Vishwas Should move this class to a more generic package
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DateParam {
|
||||||
|
|
||||||
|
private final Date date;
|
||||||
|
|
||||||
|
public DateParam(String dateStr) throws WebApplicationException {
|
||||||
|
if (StringUtils.isEmpty(dateStr)) {
|
||||||
|
this.date = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
try {
|
||||||
|
this.date = dateFormat.parse(dateStr);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
|
||||||
|
.entity("Couldn't parse date string: Expected format yyyy-mm-dd " + e.getMessage()).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
-1
@@ -1,10 +1,12 @@
|
|||||||
package org.mifosplatform.accounting.api.infrastructure.impl;
|
package org.mifosplatform.accounting.api.infrastructure.impl;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
||||||
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
import org.mifosplatform.accounting.api.commands.SingleDebitOrCreditEntryCommand;
|
||||||
import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService;
|
import org.mifosplatform.accounting.api.infrastructure.AccountingApiDataConversionService;
|
||||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||||
@@ -19,7 +23,9 @@ import org.mifosplatform.infrastructure.core.serialization.JsonParserHelper;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
@@ -69,7 +75,7 @@ public class AccountingApiDataConversionServiceImpl implements AccountingApiData
|
|||||||
final String glCode = helper.extractStringNamed("glCode", element, requestParamatersDetected);
|
final String glCode = helper.extractStringNamed("glCode", element, requestParamatersDetected);
|
||||||
final Boolean disabled = helper.extractBooleanNamed("disabled", element, requestParamatersDetected);
|
final Boolean disabled = helper.extractBooleanNamed("disabled", element, requestParamatersDetected);
|
||||||
final Boolean manualEntriesAllowed = helper.extractBooleanNamed("manualEntriesAllowed", element, requestParamatersDetected);
|
final Boolean manualEntriesAllowed = helper.extractBooleanNamed("manualEntriesAllowed", element, requestParamatersDetected);
|
||||||
final String category = helper.extractStringNamed("category", element, requestParamatersDetected);
|
final String category = helper.extractStringNamed("classification", element, requestParamatersDetected);
|
||||||
final Boolean headerAccount = helper.extractBooleanNamed("headerAccount", element, requestParamatersDetected);
|
final Boolean headerAccount = helper.extractBooleanNamed("headerAccount", element, requestParamatersDetected);
|
||||||
final String description = helper.extractStringNamed("description", element, requestParamatersDetected);
|
final String description = helper.extractStringNamed("description", element, requestParamatersDetected);
|
||||||
|
|
||||||
@@ -98,4 +104,66 @@ public class AccountingApiDataConversionServiceImpl implements AccountingApiData
|
|||||||
|
|
||||||
return new GLClosureCommand(requestParamatersDetected, resourceIdentifier, officeId, closingDate, comments);
|
return new GLClosureCommand(requestParamatersDetected, resourceIdentifier, officeId, closingDate, comments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GLJournalEntryCommand convertJsonToGLJournalEntryCommand(String json) {
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
final Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
|
||||||
|
|
||||||
|
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("officeId", "entryDate", "comments", "credits", "debits",
|
||||||
|
"locale", "dateFormat"));
|
||||||
|
|
||||||
|
checkForUnsupportedParameters(requestMap, supportedParams);
|
||||||
|
|
||||||
|
final JsonParser parser = new JsonParser();
|
||||||
|
final JsonElement element = parser.parse(json);
|
||||||
|
final JsonParserHelper helper = new JsonParserHelper();
|
||||||
|
|
||||||
|
final Set<String> requestParamatersDetected = new HashSet<String>();
|
||||||
|
final Long officeId = helper.extractLongNamed("officeId", element, requestParamatersDetected);
|
||||||
|
final String comments = helper.extractStringNamed("comments", element, requestParamatersDetected);
|
||||||
|
final LocalDate entryDate = helper.extractLocalDateNamed("entryDate", element, requestParamatersDetected);
|
||||||
|
|
||||||
|
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||||
|
final Locale locale = helper.extractLocaleParameter(topLevelJsonElement);
|
||||||
|
|
||||||
|
SingleDebitOrCreditEntryCommand[] credits = null;
|
||||||
|
SingleDebitOrCreditEntryCommand[] debits = null;
|
||||||
|
if (element.isJsonObject()) {
|
||||||
|
if (topLevelJsonElement.has("credits") && topLevelJsonElement.get("credits").isJsonArray()) {
|
||||||
|
credits = populateCreditsOrDebitsArray(topLevelJsonElement, helper, requestParamatersDetected, locale, credits, "credits");
|
||||||
|
}
|
||||||
|
if (topLevelJsonElement.has("debits") && topLevelJsonElement.get("debits").isJsonArray()) {
|
||||||
|
debits = populateCreditsOrDebitsArray(topLevelJsonElement, helper, requestParamatersDetected, locale, debits, "debits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GLJournalEntryCommand(requestParamatersDetected, officeId, entryDate, comments, credits, debits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param helper
|
||||||
|
* @param requestParamatersDetected
|
||||||
|
* @param comments
|
||||||
|
* @param topLevelJsonElement
|
||||||
|
* @param locale
|
||||||
|
*/
|
||||||
|
private SingleDebitOrCreditEntryCommand[] populateCreditsOrDebitsArray(final JsonObject topLevelJsonElement,
|
||||||
|
final JsonParserHelper helper, final Set<String> requestParamatersDetected, final Locale locale,
|
||||||
|
SingleDebitOrCreditEntryCommand[] debitOrCredits, String paramName) {
|
||||||
|
requestParamatersDetected.add(paramName);
|
||||||
|
final JsonArray array = topLevelJsonElement.get(paramName).getAsJsonArray();
|
||||||
|
debitOrCredits = new SingleDebitOrCreditEntryCommand[array.size()];
|
||||||
|
for (int i = 0; i < array.size(); i++) {
|
||||||
|
|
||||||
|
final JsonObject creditElement = array.get(i).getAsJsonObject();
|
||||||
|
final Set<String> parametersPassedInForCreditsCommand = new HashSet<String>();
|
||||||
|
|
||||||
|
final Long glAccountId = helper.extractLongNamed("glAccountId", creditElement, parametersPassedInForCreditsCommand);
|
||||||
|
final String comments = helper.extractStringNamed("comments", creditElement, parametersPassedInForCreditsCommand);
|
||||||
|
final BigDecimal amount = helper.extractBigDecimalNamed("amount", creditElement, locale, parametersPassedInForCreditsCommand);
|
||||||
|
|
||||||
|
debitOrCredits[i] = new SingleDebitOrCreditEntryCommand(parametersPassedInForCreditsCommand, glAccountId, amount, comments);
|
||||||
|
}
|
||||||
|
return debitOrCredits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+39
-8
@@ -7,6 +7,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.mifosplatform.accounting.api.data.GLAccountData;
|
import org.mifosplatform.accounting.api.data.GLAccountData;
|
||||||
import org.mifosplatform.accounting.api.data.GLClosureData;
|
import org.mifosplatform.accounting.api.data.GLClosureData;
|
||||||
|
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
|
||||||
|
import org.mifosplatform.accounting.api.data.JournalEntryIdentifier;
|
||||||
import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService;
|
import org.mifosplatform.accounting.api.infrastructure.AccountingApiJsonSerializerService;
|
||||||
import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService;
|
import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService;
|
||||||
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
|
||||||
@@ -23,11 +25,18 @@ import com.google.gson.Gson;
|
|||||||
@Service
|
@Service
|
||||||
public class GoogleGsonAccountingApiJsonSerializerService implements AccountingApiJsonSerializerService {
|
public class GoogleGsonAccountingApiJsonSerializerService implements AccountingApiJsonSerializerService {
|
||||||
|
|
||||||
|
private static final Set<String> DATA_PARAMETERS = new HashSet<String>(Arrays.asList("entityId"));
|
||||||
|
|
||||||
private static final Set<String> GL_ACCOUNT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "parentId", "glCode",
|
private static final Set<String> GL_ACCOUNT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "parentId", "glCode",
|
||||||
"disabled", "manualEntriesAllowed", "classification", "headerAccount", "description"));
|
"disabled", "manualEntriesAllowed", "classification", "headerAccount", "description"));
|
||||||
|
|
||||||
private static final Set<String> GL_ACCOUNT_CLOSURE_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName",
|
private static final Set<String> GL_ACCOUNT_CLOSURE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName",
|
||||||
"closingDate", "deleted", "createdDate", "lastUpdatedDate", "creatingByUserId", "lastUpdatedByUserId", "comments"));
|
"closingDate", "deleted", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername", "lastUpdatedByUserId",
|
||||||
|
"lastUpdatedByUsername", "comments", "allowedOffices"));
|
||||||
|
|
||||||
|
private static final Set<String> GL_JOURNAL_ENTRY_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "officeId", "officeName",
|
||||||
|
"glAccountName", "glAccountId", "glAccountClassification", "entryDate", "entryType", "amount", "transactionId",
|
||||||
|
"portfolioGenerated", "entityType", "entityId", "createdByUserId", "createdDate", "createdByUserName", "comments", "reversed"));
|
||||||
|
|
||||||
private final GoogleGsonSerializerHelper helper;
|
private final GoogleGsonSerializerHelper helper;
|
||||||
|
|
||||||
@@ -38,7 +47,13 @@ public class GoogleGsonAccountingApiJsonSerializerService implements AccountingA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String serializeEntityIdentifier(final EntityIdentifier identifier) {
|
public String serializeEntityIdentifier(final EntityIdentifier identifier) {
|
||||||
final Set<String> DATA_PARAMETERS = new HashSet<String>(Arrays.asList("entityId"));
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(DATA_PARAMETERS, false,
|
||||||
|
DATA_PARAMETERS);
|
||||||
|
return helper.serializedJsonFrom(gsonDeserializer, identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String serializeJournalEntryIdentifier(final JournalEntryIdentifier identifier) {
|
||||||
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(DATA_PARAMETERS, false,
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(DATA_PARAMETERS, false,
|
||||||
DATA_PARAMETERS);
|
DATA_PARAMETERS);
|
||||||
return helper.serializedJsonFrom(gsonDeserializer, identifier);
|
return helper.serializedJsonFrom(gsonDeserializer, identifier);
|
||||||
@@ -61,15 +76,31 @@ public class GoogleGsonAccountingApiJsonSerializerService implements AccountingA
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, GLClosureData closureData) {
|
public String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, GLClosureData closureData) {
|
||||||
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_CLOSURE_PARAMETERS,
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(
|
||||||
prettyPrint, responseParameters);
|
GL_ACCOUNT_CLOSURE_DATA_PARAMETERS, prettyPrint, responseParameters);
|
||||||
return helper.serializedJsonFrom(gsonDeserializer, closureData);
|
return helper.serializedJsonFrom(gsonDeserializer, closureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLClosureData> closureDatas) {
|
public String serializeGLClosureDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<GLClosureData> closureDatas) {
|
||||||
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_ACCOUNT_DATA_PARAMETERS,
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(
|
||||||
prettyPrint, responseParameters);
|
GL_ACCOUNT_CLOSURE_DATA_PARAMETERS, prettyPrint, responseParameters);
|
||||||
return helper.serializedJsonFrom(gsonDeserializer, closureDatas.toArray(new GLAccountData[closureDatas.size()]));
|
return helper.serializedJsonFrom(gsonDeserializer, closureDatas.toArray(new GLClosureData[closureDatas.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String serializeGLJournalEntryDataToJson(boolean prettyPrint, Set<String> responseParameters, GLJournalEntryData journalEntryData) {
|
||||||
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_JOURNAL_ENTRY_DATA_PARAMETERS,
|
||||||
|
prettyPrint, responseParameters);
|
||||||
|
return helper.serializedJsonFrom(gsonDeserializer, journalEntryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String serializeGLJournalEntryDataToJson(boolean prettyPrint, Set<String> responseParameters,
|
||||||
|
Collection<GLJournalEntryData> journalEntryDatas) {
|
||||||
|
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(GL_JOURNAL_ENTRY_DATA_PARAMETERS,
|
||||||
|
prettyPrint, responseParameters);
|
||||||
|
return helper.serializedJsonFrom(gsonDeserializer, journalEntryDatas.toArray(new GLJournalEntryData[journalEntryDatas.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ public class GLAccount extends AbstractPersistable<Long> {
|
|||||||
private boolean disabled = false;
|
private boolean disabled = false;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Column(name = "manual_entries_allowed", nullable = false)
|
@Column(name = "manual_journal_entries_allowed", nullable = false)
|
||||||
private boolean manualEntriesAllowed = true;
|
private boolean manualEntriesAllowed = true;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import org.mifosplatform.useradministration.domain.AppUser;
|
|||||||
@Table(name = "acc_gl_closure", uniqueConstraints = { @UniqueConstraint(columnNames = { "office_id", "closing_date" }, name = "office_id_closing_date") })
|
@Table(name = "acc_gl_closure", uniqueConstraints = { @UniqueConstraint(columnNames = { "office_id", "closing_date" }, name = "office_id_closing_date") })
|
||||||
public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
|
public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
@JoinColumn(name = "office_id", nullable = false)
|
@JoinColumn(name = "office_id", nullable = false)
|
||||||
private Office office;
|
private Office office;
|
||||||
@@ -31,7 +30,6 @@ public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
@Column(name = "is_deleted", nullable = false)
|
@Column(name = "is_deleted", nullable = false)
|
||||||
private boolean deleted = true;
|
private boolean deleted = true;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Column(name = "closing_date")
|
@Column(name = "closing_date")
|
||||||
@Temporal(TemporalType.DATE)
|
@Temporal(TemporalType.DATE)
|
||||||
private Date closingDate;
|
private Date closingDate;
|
||||||
@@ -64,4 +62,13 @@ public class GLClosure extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.comments = command.getComments().trim();
|
this.comments = command.getComments().trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getClosingDate() {
|
||||||
|
return this.closingDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Office getOffice() {
|
||||||
|
return this.office;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+5
-1
@@ -2,7 +2,11 @@ package org.mifosplatform.accounting.domain;
|
|||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
public interface GLClosureRepository extends JpaRepository<GLClosure, Long>, JpaSpecificationExecutor<GLClosure> {
|
public interface GLClosureRepository extends JpaRepository<GLClosure, Long>, JpaSpecificationExecutor<GLClosure> {
|
||||||
// no added behaviour
|
|
||||||
|
@Query("from GLClosure closure where closure.closingDate = (select max(closure1.closingDate) from GLClosure closure1 where closure1.office.id=:officeId) and closure.office.id= :officeId")
|
||||||
|
GLClosure getLatestGLClosureByBranch(@Param("officeId") Long officeId);
|
||||||
}
|
}
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
package org.mifosplatform.accounting.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
|
||||||
|
import org.mifosplatform.organisation.office.domain.Office;
|
||||||
|
import org.mifosplatform.useradministration.domain.AppUser;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "acc_gl_journal_entry")
|
||||||
|
public class GLJournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "office_id", nullable = false)
|
||||||
|
private Office office;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "account_id", nullable = false)
|
||||||
|
private GLAccount glAccount;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "reversal_id")
|
||||||
|
private GLJournalEntry reversalJournalEntry;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "transaction_id", nullable = false, length = 50)
|
||||||
|
private String transactionId;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "reversed", nullable = false)
|
||||||
|
private boolean reversed = false;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "portfolio_generated", nullable = false)
|
||||||
|
private boolean portfolioGenerated = false;
|
||||||
|
|
||||||
|
@Column(name = "entry_date")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date entryDate;
|
||||||
|
|
||||||
|
@Column(name = "type", nullable = false, length = 50)
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "description", length = 500)
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "entity_type", length = 50)
|
||||||
|
private String entityType;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "entity_id")
|
||||||
|
private Long entityId;
|
||||||
|
|
||||||
|
public static GLJournalEntry createNew(Office office, GLAccount glAccount, String transactionId, boolean portfolioGenerated,
|
||||||
|
Date entryDate, String type, BigDecimal amount, String description, String entityType, Long entityId) {
|
||||||
|
return new GLJournalEntry(office, glAccount, transactionId, portfolioGenerated, entryDate, type, amount, description, entityType,
|
||||||
|
entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GLJournalEntry() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLJournalEntry(Office office, GLAccount glAccount, String transactionId, boolean portfolioGenerated, Date entryDate,
|
||||||
|
String type, BigDecimal amount, String description, String entityType, Long entityId) {
|
||||||
|
this.office = office;
|
||||||
|
this.glAccount = glAccount;
|
||||||
|
this.reversalJournalEntry = null;
|
||||||
|
this.transactionId = transactionId;
|
||||||
|
this.reversed = false;
|
||||||
|
this.portfolioGenerated = portfolioGenerated;
|
||||||
|
this.entryDate = entryDate;
|
||||||
|
this.type = type;
|
||||||
|
this.amount = amount;
|
||||||
|
this.description = StringUtils.defaultIfEmpty(description, null);
|
||||||
|
this.entityType = StringUtils.defaultIfEmpty(entityType, null);
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Office getOffice() {
|
||||||
|
return this.office;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLAccount getGlAccount() {
|
||||||
|
return this.glAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getEntryDate() {
|
||||||
|
return this.entryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getAmount() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReversalJournalEntry(GLJournalEntry reversalJournalEntry) {
|
||||||
|
this.reversalJournalEntry = reversalJournalEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReversed(boolean reversed) {
|
||||||
|
this.reversed = reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package org.mifosplatform.accounting.domain;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
public interface GLJournalEntryRepository extends JpaRepository<GLJournalEntry, Long>, JpaSpecificationExecutor<GLJournalEntry>,
|
||||||
|
GLJournalEntryRepositoryCustom {
|
||||||
|
|
||||||
|
@Query("from GLJournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.portfolioGenerated is false")
|
||||||
|
List<GLJournalEntry> findUnReversedManualJournalEntriesByTransactionId(@Param("transactionId") String transactionId);
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package org.mifosplatform.accounting.domain;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface GLJournalEntryRepositoryCustom {
|
||||||
|
|
||||||
|
List<GLJournalEntry> findFirstJournalEntryForAccount(long glAccountId);
|
||||||
|
}
|
||||||
mifosng-provider/src/main/java/org/mifosplatform/accounting/domain/GLJournalEntryRepositoryImpl.java
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package org.mifosplatform.accounting.domain;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.PersistenceContext;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class GLJournalEntryRepositoryImpl implements GLJournalEntryRepositoryCustom {
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager entityManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public List<GLJournalEntry> findFirstJournalEntryForAccount(long glAccountId) {
|
||||||
|
List<GLJournalEntry> journalEntries = entityManager
|
||||||
|
.createQuery("SELECT journalEntry FROM GLJournalEntry journalEntry where journalEntry.glAccount.id= :glAccountId")
|
||||||
|
.setParameter("glAccountId", glAccountId).setFirstResult(0).setMaxResults(1).getResultList();
|
||||||
|
return journalEntries;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -18,6 +18,13 @@ public class GLAccountInvalidDeleteException extends AbstractPlatformDomainRuleE
|
|||||||
} else if (name().toString().equalsIgnoreCase("HAS_CHILDREN")) { return "Cannot delete this Header GL Account without first deleting or reassinging its children"; }
|
} else if (name().toString().equalsIgnoreCase("HAS_CHILDREN")) { return "Cannot delete this Header GL Account without first deleting or reassinging its children"; }
|
||||||
return name().toString();
|
return name().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String errorCode() {
|
||||||
|
if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) {
|
||||||
|
return "error.msg.glaccount.glcode.invalid.delete.transactions.logged";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("HAS_CHILDREN")) { return "error.msg.glaccount.glcode.invalid.delete.has.children"; }
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GLAccountInvalidDeleteException(final GL_ACCOUNT_INVALID_DELETE_REASON reason, final Long glAccountId) {
|
public GLAccountInvalidDeleteException(final GL_ACCOUNT_INVALID_DELETE_REASON reason, final Long glAccountId) {
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package org.mifosplatform.accounting.exceptions;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RuntimeException} thrown when a GL Closure Delte command is invalid
|
||||||
|
*/
|
||||||
|
public class GLClosureInvalidDeleteException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public GLClosureInvalidDeleteException(final Long officeId, final String officeName, final Date latestclosureDate) {
|
||||||
|
super("error.msg.glclosure.invalid.delete", "The latest closure for office with Id " + officeId + " and name " + officeName + " is on "
|
||||||
|
+ latestclosureDate.toString() + ", please delete this closure first", latestclosureDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package org.mifosplatform.accounting.exceptions;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RuntimeException} thrown when a GL Closure is Invalid
|
||||||
|
*/
|
||||||
|
public class GLClosureInvalidException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
/*** enum of reasons for invalid Accounting Closure **/
|
||||||
|
public static enum GL_CLOSURE_INVALID_REASON {
|
||||||
|
FUTURE_DATE, ACCOUNTING_CLOSED;
|
||||||
|
|
||||||
|
public String errorMessage() {
|
||||||
|
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||||
|
return "Accounting closures cannot be made for a future date";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) { return "Accounting Closure for this branch has already been defined for a greater date"; }
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String errorCode() {
|
||||||
|
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||||
|
return "error.msg.glclosure.invalid.future.date";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) { return "error.msg.glclosure.invalid.accounting.closed"; }
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLClosureInvalidException(final GL_CLOSURE_INVALID_REASON reason, final Date date) {
|
||||||
|
super(reason.errorCode(), reason.errorMessage(), date);
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package org.mifosplatform.accounting.exceptions;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RuntimeException} thrown when journal entry resources are not found.
|
||||||
|
*/
|
||||||
|
public class GLJournalEntriesNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
|
public GLJournalEntriesNotFoundException(final String transactionId) {
|
||||||
|
super("error.msg.journalEntries.transactionId.invalid", "Journal Entries with transaction Identifier " + transactionId
|
||||||
|
+ " does not exist or are not system generated/reversible ", transactionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLJournalEntriesNotFoundException(final Long entryId) {
|
||||||
|
super("error.msg.journalEntries.id.invalid", "Journal Entry with entry Id " + entryId + " does not exist ", entryId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package org.mifosplatform.accounting.exceptions;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RuntimeException} thrown when a GL Journal Entry is Invalid
|
||||||
|
*/
|
||||||
|
public class GLJournalEntryInvalidException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
/*** enum of reasons for invalid Journal Entry **/
|
||||||
|
public static enum GL_JOURNAL_ENTRY_INVALID_REASON {
|
||||||
|
FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY;
|
||||||
|
|
||||||
|
public String errorMessage() {
|
||||||
|
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||||
|
return "The journal entry cannot be made for a future date";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||||
|
return "Journal entry cannot be made prior to last account closing date for the branch";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("NO_DEBITS_OR_CREDITS")) {
|
||||||
|
return "Journal Entry must have atleast one Debit and one Credit";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH")) {
|
||||||
|
return "Sum of All Debits must equal the sum of all Credits for a Journal Entry";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) { return "Both account and amount must be specified for all Debits and Credits"; }
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String errorCode() {
|
||||||
|
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||||
|
return "error.msg.glJournalEntry.invalid.future.date";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||||
|
return "error.msg.glJournalEntry.invalid.accounting.closed";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("NO_DEBITS_OR_CREDITS")) {
|
||||||
|
return "error.msg.glJournalEntry.invalid.no.debits.or.credits";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH")) {
|
||||||
|
return "error.msg.glJournalEntry.invalid.mismatch.debits.credits";
|
||||||
|
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) { return "error.msg.glJournalEntry.invalid.empty.account.or.amount"; }
|
||||||
|
return name().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLJournalEntryInvalidException(final GL_JOURNAL_ENTRY_INVALID_REASON reason, final Date date) {
|
||||||
|
super(reason.errorCode(), reason.errorMessage(), date);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -32,6 +32,8 @@ public class GLAccountCommandValidator {
|
|||||||
|
|
||||||
baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500);
|
baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500);
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("manualEntriesAllowed").value(command.getManualEntriesAllowed()).notBlank();
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
"Validation errors exist.", dataValidationErrors); }
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package org.mifosplatform.accounting.service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
|
||||||
|
public class GLJournalEntryCommandValidator {
|
||||||
|
|
||||||
|
private final GLJournalEntryCommand command;
|
||||||
|
|
||||||
|
public GLJournalEntryCommandValidator(GLJournalEntryCommand command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateForCreate() {
|
||||||
|
|
||||||
|
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
|
||||||
|
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("GLJournalEntry");
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("entryDate").value(command.getEntryDate()).notBlank();
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("officeId").value(command.getOfficeId()).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
baseDataValidator.reset().parameter("comments").value(command.getComments()).ignoreIfNull().notExceedingLengthOf(500);
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||||
|
"Validation errors exist.", dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package org.mifosplatform.accounting.service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
|
||||||
|
|
||||||
|
public interface GLJournalEntryReadPlatformService {
|
||||||
|
|
||||||
|
List<GLJournalEntryData> retrieveAllGLJournalEntries(Long officeId, Long glAccountId, Boolean portfolioGenerated, Date fromDate,
|
||||||
|
Date toDate);
|
||||||
|
|
||||||
|
GLJournalEntryData retrieveGLJournalEntryById(long glJournalEntryId);
|
||||||
|
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package org.mifosplatform.accounting.service;
|
||||||
|
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
||||||
|
public interface GLJournalEntryWritePlatformService {
|
||||||
|
|
||||||
|
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'CREATE_JOURNAL_ENTRY')")
|
||||||
|
String createJournalEntry(GLJournalEntryCommand journalEntryCommand);
|
||||||
|
|
||||||
|
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'REVERT_JOURNAL_ENTRY')")
|
||||||
|
String revertJournalEntry(String transactionId);
|
||||||
|
|
||||||
|
}
|
||||||
+20
-8
@@ -2,6 +2,7 @@ package org.mifosplatform.accounting.service.impl;
|
|||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@@ -11,7 +12,6 @@ import org.mifosplatform.accounting.exceptions.GLAccountInvalidClassificationExc
|
|||||||
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
|
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
|
||||||
import org.mifosplatform.accounting.service.GLAccountReadPlatformService;
|
import org.mifosplatform.accounting.service.GLAccountReadPlatformService;
|
||||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.EmptyResultDataAccessException;
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@@ -22,19 +22,16 @@ import org.springframework.stereotype.Service;
|
|||||||
public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformService {
|
public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformService {
|
||||||
|
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final PlatformSecurityContext context;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GLAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
|
public GLAccountReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource) {
|
||||||
this.context = context;
|
|
||||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class GLAccountMapper implements RowMapper<GLAccountData> {
|
private static final class GLAccountMapper implements RowMapper<GLAccountData> {
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
return " id as id, name as name, parent_id as parentId, gl_code as glCode, disabled as disabled, manual_entries_allowed as manualEntriesAllowed, "
|
return " id as id, name as name, parent_id as parentId, gl_code as glCode, disabled as disabled, manual_journal_entries_allowed as manualEntriesAllowed, "
|
||||||
+ "classification as classification, header_account as headerAccount, description as description "
|
+ "classification as classification, header_account as headerAccount, description as description "
|
||||||
+ "from acc_gl_account";
|
+ "from acc_gl_account";
|
||||||
}
|
}
|
||||||
@@ -65,15 +62,30 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
|
|||||||
|
|
||||||
GLAccountMapper rm = new GLAccountMapper();
|
GLAccountMapper rm = new GLAccountMapper();
|
||||||
String sql = "select " + rm.schema();
|
String sql = "select " + rm.schema();
|
||||||
|
Object[] paramaterArray = new Object[3];
|
||||||
|
int arrayPos = 0;
|
||||||
if (StringUtils.isNotBlank(accountClassification) && searchParam != null) {
|
if (StringUtils.isNotBlank(accountClassification) && searchParam != null) {
|
||||||
sql += " where classification like ? and ( name like %?% or glCode like %?% )";
|
sql += " where classification like ? and ( name like %?% or glCode like %?% )";
|
||||||
|
paramaterArray[arrayPos] = accountClassification;
|
||||||
|
arrayPos = arrayPos++;
|
||||||
|
paramaterArray[arrayPos] = searchParam;
|
||||||
|
arrayPos = arrayPos++;
|
||||||
|
paramaterArray[arrayPos] = searchParam;
|
||||||
|
arrayPos = arrayPos++;
|
||||||
} else if (StringUtils.isNotBlank(accountClassification)) {
|
} else if (StringUtils.isNotBlank(accountClassification)) {
|
||||||
sql += " where classification like ?";
|
sql += " where classification like ?";
|
||||||
|
paramaterArray[arrayPos] = accountClassification;
|
||||||
|
arrayPos++;
|
||||||
} else if (searchParam != null) {
|
} else if (searchParam != null) {
|
||||||
sql += " where ( name like %?% or glCode like %?% )";
|
sql += " where ( name like %?% or glCode like %?% )";
|
||||||
|
paramaterArray[arrayPos] = searchParam;
|
||||||
|
arrayPos++;
|
||||||
|
paramaterArray[arrayPos] = searchParam;
|
||||||
|
arrayPos++;
|
||||||
}
|
}
|
||||||
sql = sql + " order by glCode";
|
sql = sql + " order by glCode";
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { accountClassification, searchParam });
|
Object[] finalObjectArray = Arrays.copyOf(paramaterArray, arrayPos);
|
||||||
|
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,7 +105,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
|
|||||||
|
|
||||||
private static boolean checkValidGLAccountClassification(final String entityType) {
|
private static boolean checkValidGLAccountClassification(final String entityType) {
|
||||||
for (GL_ACCOUNT_CLASSIFICATION classification : GL_ACCOUNT_CLASSIFICATION.values()) {
|
for (GL_ACCOUNT_CLASSIFICATION classification : GL_ACCOUNT_CLASSIFICATION.values()) {
|
||||||
if (classification.name().equalsIgnoreCase(entityType)) { return true; }
|
if (classification.name().toString().equalsIgnoreCase(entityType)) { return true; }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-19
@@ -1,13 +1,20 @@
|
|||||||
package org.mifosplatform.accounting.service.impl;
|
package org.mifosplatform.accounting.service.impl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.mifosplatform.accounting.AccountingConstants.GL_ACCOUNT_CLASSIFICATION;
|
||||||
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
import org.mifosplatform.accounting.api.commands.GLAccountCommand;
|
||||||
import org.mifosplatform.accounting.domain.GLAccount;
|
import org.mifosplatform.accounting.domain.GLAccount;
|
||||||
import org.mifosplatform.accounting.domain.GLAccountRepository;
|
import org.mifosplatform.accounting.domain.GLAccountRepository;
|
||||||
|
import org.mifosplatform.accounting.domain.GLJournalEntry;
|
||||||
|
import org.mifosplatform.accounting.domain.GLJournalEntryRepository;
|
||||||
import org.mifosplatform.accounting.exceptions.GLAccountDuplicateException;
|
import org.mifosplatform.accounting.exceptions.GLAccountDuplicateException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLAccountInvalidClassificationException;
|
||||||
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException;
|
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException.GL_ACCOUNT_INVALID_DELETE_REASON;
|
||||||
import org.mifosplatform.accounting.exceptions.GLAccountInvalidParentException;
|
import org.mifosplatform.accounting.exceptions.GLAccountInvalidParentException;
|
||||||
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
|
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
|
||||||
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException.GL_ACCOUNT_INVALID_DELETE_REASON;
|
|
||||||
import org.mifosplatform.accounting.service.GLAccountCommandValidator;
|
import org.mifosplatform.accounting.service.GLAccountCommandValidator;
|
||||||
import org.mifosplatform.accounting.service.GLAccountWritePlatformService;
|
import org.mifosplatform.accounting.service.GLAccountWritePlatformService;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
@@ -24,10 +31,13 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
|||||||
private final static Logger logger = LoggerFactory.getLogger(GLAccountWritePlatformServiceJpaRepositoryImpl.class);
|
private final static Logger logger = LoggerFactory.getLogger(GLAccountWritePlatformServiceJpaRepositoryImpl.class);
|
||||||
|
|
||||||
private final GLAccountRepository glAccountRepository;
|
private final GLAccountRepository glAccountRepository;
|
||||||
|
private final GLJournalEntryRepository glJournalEntryRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GLAccountWritePlatformServiceJpaRepositoryImpl(final GLAccountRepository glAccountRepository) {
|
public GLAccountWritePlatformServiceJpaRepositoryImpl(final GLAccountRepository glAccountRepository,
|
||||||
|
final GLJournalEntryRepository glJournalEntryRepository) {
|
||||||
this.glAccountRepository = glAccountRepository;
|
this.glAccountRepository = glAccountRepository;
|
||||||
|
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -37,12 +47,17 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
|||||||
GLAccountCommandValidator validator = new GLAccountCommandValidator(command);
|
GLAccountCommandValidator validator = new GLAccountCommandValidator(command);
|
||||||
validator.validateForCreate();
|
validator.validateForCreate();
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(command.getClassification())) {
|
||||||
|
if (!checkValidGLAccountClassification(command.getClassification())) { throw new GLAccountInvalidClassificationException(
|
||||||
|
command.getClassification()); }
|
||||||
|
}
|
||||||
|
|
||||||
// check parent is valid
|
// check parent is valid
|
||||||
GLAccount parentGLAccount = null;
|
GLAccount parentGLAccount = null;
|
||||||
if (command.getParentId() != null) {
|
if (command.getParentId() != null) {
|
||||||
parentGLAccount = validateParentGLAccount(command);
|
parentGLAccount = validateParentGLAccount(command);
|
||||||
}
|
}
|
||||||
GLAccount glAccount = GLAccount.createNew(parentGLAccount, command.getName(), command.getGlCode(), command.getDisabled(),
|
GLAccount glAccount = GLAccount.createNew(parentGLAccount, command.getName(), command.getGlCode(), false,
|
||||||
command.getManualEntriesAllowed(), command.getClassification(), command.getHeaderAccount(), command.getDescription());
|
command.getManualEntriesAllowed(), command.getClassification(), command.getHeaderAccount(), command.getDescription());
|
||||||
|
|
||||||
this.glAccountRepository.saveAndFlush(glAccount);
|
this.glAccountRepository.saveAndFlush(glAccount);
|
||||||
@@ -70,6 +85,12 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
|||||||
parentGLAccount = validateParentGLAccount(command);
|
parentGLAccount = validateParentGLAccount(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate new classification
|
||||||
|
if (command.isClassificationChanged()) {
|
||||||
|
if (!checkValidGLAccountClassification(command.getClassification())) { throw new GLAccountInvalidClassificationException(
|
||||||
|
command.getClassification()); }
|
||||||
|
}
|
||||||
|
|
||||||
glAccount.update(command, parentGLAccount);
|
glAccount.update(command, parentGLAccount);
|
||||||
|
|
||||||
this.glAccountRepository.saveAndFlush(glAccount);
|
this.glAccountRepository.saveAndFlush(glAccount);
|
||||||
@@ -77,6 +98,26 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
|||||||
return glAccount.getId();
|
return glAccount.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public Long deleteGLAccount(Long glAccountId) {
|
||||||
|
final GLAccount glAccount = this.glAccountRepository.findOne(glAccountId);
|
||||||
|
|
||||||
|
if (glAccount == null) { throw new GLAccountNotFoundException(glAccountId); }
|
||||||
|
|
||||||
|
// validate this isn't a header account that has children
|
||||||
|
if (glAccount.isHeaderAccount() && glAccount.getChildren().size() > 0) { throw new GLAccountInvalidDeleteException(
|
||||||
|
GL_ACCOUNT_INVALID_DELETE_REASON.HAS_CHILDREN, glAccountId); }
|
||||||
|
|
||||||
|
// TODO: does this account have transactions logged against it
|
||||||
|
List<GLJournalEntry> journalEntriesForAccount = glJournalEntryRepository.findFirstJournalEntryForAccount(glAccountId);
|
||||||
|
if (journalEntriesForAccount.size() > 0) { throw new GLAccountInvalidDeleteException(
|
||||||
|
GL_ACCOUNT_INVALID_DELETE_REASON.TRANSANCTIONS_LOGGED, glAccountId); }
|
||||||
|
this.glAccountRepository.delete(glAccount);
|
||||||
|
|
||||||
|
return glAccountId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param command
|
* @param command
|
||||||
* @return
|
* @return
|
||||||
@@ -106,21 +147,10 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
|||||||
"Unknown data integrity issue with resource GL Account: " + realCause.getMessage());
|
"Unknown data integrity issue with resource GL Account: " + realCause.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
private static boolean checkValidGLAccountClassification(final String entityType) {
|
||||||
@Override
|
for (GL_ACCOUNT_CLASSIFICATION classification : GL_ACCOUNT_CLASSIFICATION.values()) {
|
||||||
public Long deleteGLAccount(Long glAccountId) {
|
if (classification.name().toString().equalsIgnoreCase(entityType)) { return true; }
|
||||||
final GLAccount glAccount = this.glAccountRepository.findOne(glAccountId);
|
}
|
||||||
|
return false;
|
||||||
if (glAccount == null) { throw new GLAccountNotFoundException(glAccountId); }
|
|
||||||
|
|
||||||
// validate this isn't a header account that has children
|
|
||||||
if (glAccount.isHeaderAccount() && glAccount.getChildren().size() > 0) { throw new GLAccountInvalidDeleteException(
|
|
||||||
GL_ACCOUNT_INVALID_DELETE_REASON.HAS_CHILDREN, glAccountId); }
|
|
||||||
|
|
||||||
// TODO: does this account have transactions logged against it
|
|
||||||
|
|
||||||
this.glAccountRepository.delete(glAccount);
|
|
||||||
|
|
||||||
return glAccountId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-12
@@ -2,6 +2,7 @@ package org.mifosplatform.accounting.service.impl;
|
|||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
@@ -10,7 +11,6 @@ import org.mifosplatform.accounting.exceptions.GLClosureNotFoundException;
|
|||||||
import org.mifosplatform.accounting.service.GLClosureReadPlatformService;
|
import org.mifosplatform.accounting.service.GLClosureReadPlatformService;
|
||||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.EmptyResultDataAccessException;
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@@ -21,12 +21,9 @@ import org.springframework.stereotype.Service;
|
|||||||
public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformService {
|
public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformService {
|
||||||
|
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final PlatformSecurityContext context;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public GLClosureReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
|
public GLClosureReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource) {
|
||||||
this.context = context;
|
|
||||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +33,9 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
|
|||||||
return " glClosure.id as id, glClosure.office_id as officeId,office.name as officeName ,glClosure.closing_date as closingDate,"
|
return " glClosure.id as id, glClosure.office_id as officeId,office.name as officeName ,glClosure.closing_date as closingDate,"
|
||||||
+ " glClosure.is_deleted as isDeleted, creatingUser.id as creatingUserId,creatingUser.username as creatingUserName,"
|
+ " glClosure.is_deleted as isDeleted, creatingUser.id as creatingUserId,creatingUser.username as creatingUserName,"
|
||||||
+ " updatingUser.id as updatingUserId,updatingUser.username as updatingUserName, glClosure.created_date as createdDate,"
|
+ " updatingUser.id as updatingUserId,updatingUser.username as updatingUserName, glClosure.created_date as createdDate,"
|
||||||
+ " glClosure.lastmodified_date as updatedDate from acc_gl_Closure as glClosure, m_appuser as creatingUser, "
|
+ " glClosure.lastmodified_date as updatedDate, glClosure.comments as comments "
|
||||||
+ " glClosure.comments as comments "
|
+ " from acc_gl_Closure as glClosure, m_appuser as creatingUser, m_appuser as updatingUser,m_office as office"
|
||||||
+ " m_appuser as updatingUser,m_office as office where glClosure.createdby_id=creatingUser.id and "
|
+ " where glClosure.createdby_id=creatingUser.id and "
|
||||||
+ " glClosure.lastmodifiedby_id=updatingUser.id and glClosure.office_id=office.id";
|
+ " glClosure.lastmodifiedby_id=updatingUser.id and glClosure.office_id=office.id";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,11 +50,13 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
|
|||||||
LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
|
LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
|
||||||
LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
|
LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
|
||||||
Long creatingByUserId = rs.getLong("creatingUserId");
|
Long creatingByUserId = rs.getLong("creatingUserId");
|
||||||
|
String createdByUserName = rs.getString("creatingUserName");
|
||||||
Long lastUpdatedByUserId = rs.getLong("updatingUserId");
|
Long lastUpdatedByUserId = rs.getLong("updatingUserId");
|
||||||
|
String lastUpdatedByUserName = rs.getString("updatingUserName");
|
||||||
String comments = rs.getString("comments");
|
String comments = rs.getString("comments");
|
||||||
|
|
||||||
return new GLClosureData(id, officeId, officeName, closingDate, deleted, createdDate, lastUpdatedDate, creatingByUserId,
|
return new GLClosureData(id, officeId, officeName, closingDate, deleted, createdDate, lastUpdatedDate, creatingByUserId,
|
||||||
lastUpdatedByUserId, comments);
|
createdByUserName, lastUpdatedByUserId, lastUpdatedByUserName, comments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +65,18 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
|
|||||||
GLClosureMapper rm = new GLClosureMapper();
|
GLClosureMapper rm = new GLClosureMapper();
|
||||||
|
|
||||||
String sql = "select " + rm.schema() + " and glClosure.is_deleted = 0";
|
String sql = "select " + rm.schema() + " and glClosure.is_deleted = 0";
|
||||||
|
Object[] objectArray = new Object[1];
|
||||||
|
int arrayPos = 0;
|
||||||
if (officeId != null && officeId != 0) {
|
if (officeId != null && officeId != 0) {
|
||||||
sql += " and glClosure.office_id = ?";
|
sql += " and glClosure.office_id = ?";
|
||||||
|
objectArray[arrayPos] = officeId;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = sql + " glClosure.closing_date";
|
sql = sql + " order by glClosure.closing_date";
|
||||||
return this.jdbcTemplate.query(sql, rm, new Object[] { officeId });
|
|
||||||
|
Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
|
||||||
|
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,7 +84,7 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
GLClosureMapper rm = new GLClosureMapper();
|
GLClosureMapper rm = new GLClosureMapper();
|
||||||
String sql = "select " + rm.schema() + " and glClosure,id = ?";
|
String sql = "select " + rm.schema() + " and glClosure.id = ?";
|
||||||
|
|
||||||
GLClosureData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glClosureId });
|
GLClosureData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glClosureId });
|
||||||
|
|
||||||
|
|||||||
+24
-2
@@ -1,9 +1,15 @@
|
|||||||
package org.mifosplatform.accounting.service.impl;
|
package org.mifosplatform.accounting.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
import org.mifosplatform.accounting.api.commands.GLClosureCommand;
|
||||||
import org.mifosplatform.accounting.domain.GLClosure;
|
import org.mifosplatform.accounting.domain.GLClosure;
|
||||||
import org.mifosplatform.accounting.domain.GLClosureRepository;
|
import org.mifosplatform.accounting.domain.GLClosureRepository;
|
||||||
import org.mifosplatform.accounting.exceptions.GLClosureDuplicateException;
|
import org.mifosplatform.accounting.exceptions.GLClosureDuplicateException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLClosureInvalidDeleteException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLClosureInvalidException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLClosureInvalidException.GL_CLOSURE_INVALID_REASON;
|
||||||
import org.mifosplatform.accounting.exceptions.GLClosureNotFoundException;
|
import org.mifosplatform.accounting.exceptions.GLClosureNotFoundException;
|
||||||
import org.mifosplatform.accounting.service.GLClosureCommandValidator;
|
import org.mifosplatform.accounting.service.GLClosureCommandValidator;
|
||||||
import org.mifosplatform.accounting.service.GLClosureWritePlatformService;
|
import org.mifosplatform.accounting.service.GLClosureWritePlatformService;
|
||||||
@@ -44,6 +50,16 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
|
|||||||
final Office office = this.officeRepository.findOne(command.getOfficeId());
|
final Office office = this.officeRepository.findOne(command.getOfficeId());
|
||||||
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
|
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
|
||||||
|
|
||||||
|
// ensure closure date is not in the future
|
||||||
|
Date todaysDate = new Date();
|
||||||
|
Date closureDate = command.getClosingDate().toDateMidnight().toDate();
|
||||||
|
if (closureDate.after(todaysDate)) { throw new GLClosureInvalidException(GL_CLOSURE_INVALID_REASON.FUTURE_DATE, closureDate); }
|
||||||
|
// shouldn't be before an existing accounting closure
|
||||||
|
GLClosure latestGLClosure = glClosureRepository.getLatestGLClosureByBranch(command.getOfficeId());
|
||||||
|
if (latestGLClosure != null) {
|
||||||
|
if (latestGLClosure.getClosingDate().after(closureDate)) { throw new GLClosureInvalidException(
|
||||||
|
GL_CLOSURE_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate()); }
|
||||||
|
}
|
||||||
GLClosure glClosure = GLClosure.createNew(office, command.getClosingDate(), command.getComments());
|
GLClosure glClosure = GLClosure.createNew(office, command.getClosingDate(), command.getComments());
|
||||||
|
|
||||||
this.glClosureRepository.saveAndFlush(glClosure);
|
this.glClosureRepository.saveAndFlush(glClosure);
|
||||||
@@ -79,8 +95,14 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
|
|||||||
|
|
||||||
if (glClosure == null) { throw new GLClosureNotFoundException(glClosureId); }
|
if (glClosure == null) { throw new GLClosureNotFoundException(glClosureId); }
|
||||||
|
|
||||||
// TODO: check if any closures are present for this branch at a later
|
/**
|
||||||
// date than this closure
|
* check if any closures are present for this branch at a later date
|
||||||
|
* than this closure date
|
||||||
|
**/
|
||||||
|
Date closureDate = glClosure.getClosingDate();
|
||||||
|
GLClosure latestGLClosure = glClosureRepository.getLatestGLClosureByBranch(glClosure.getOffice().getId());
|
||||||
|
if (latestGLClosure.getClosingDate().after(closureDate)) { throw new GLClosureInvalidDeleteException(latestGLClosure.getOffice()
|
||||||
|
.getId(), latestGLClosure.getOffice().getName(), latestGLClosure.getClosingDate()); }
|
||||||
|
|
||||||
this.glClosureRepository.delete(glClosure);
|
this.glClosureRepository.delete(glClosure);
|
||||||
|
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
package org.mifosplatform.accounting.service.impl;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLJournalEntriesNotFoundException;
|
||||||
|
import org.mifosplatform.accounting.service.GLJournalEntryReadPlatformService;
|
||||||
|
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GLJournalEntryReadPlatformServiceImpl implements GLJournalEntryReadPlatformService {
|
||||||
|
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GLJournalEntryReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource) {
|
||||||
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class GLJournalEntryMapper implements RowMapper<GLJournalEntryData> {
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return " journalEntry.id as journalEntryId, glAccount.classification as classification ,"
|
||||||
|
+ " glAccount.name as glAccountName, journalEntry.account_id as glAccountId,"
|
||||||
|
+ " journalEntry.office_id as officeId, office.name as officeName, "
|
||||||
|
+ " journalEntry.portfolio_generated as portfolioGenerated,journalEntry.entry_date as entryDate, "
|
||||||
|
+ " journalEntry.type as entryType,journalEntry.amount as amount, journalEntry.transaction_id as transactionId,"
|
||||||
|
+ " journalEntry.entity_type as entityType, journalEntry.entity_id as entityId, creatingUser.id as createdByUserId, "
|
||||||
|
+ " creatingUser.username as createdByUserName, journalEntry.description as comments, "
|
||||||
|
+ " journalEntry.created_date as createdDate, journalEntry.reversed as reversed "
|
||||||
|
+ " from acc_gl_journal_entry journalEntry, acc_gl_account glAccount, m_office office, m_appuser creatingUser "
|
||||||
|
+ " where journalEntry.account_id = glAccount.id "
|
||||||
|
+ " and journalEntry.office_id = office.id and journalEntry.createdby_id = creatingUser.id ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GLJournalEntryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
|
Long journalEntryId = rs.getLong("journalEntryId");
|
||||||
|
Long officeId = rs.getLong("officeId");
|
||||||
|
String officeName = rs.getString("officeName");
|
||||||
|
String glAccountName = rs.getString("glAccountName");
|
||||||
|
Long glAccountId = rs.getLong("glAccountId");
|
||||||
|
String glAccountClassification = rs.getString("classification");
|
||||||
|
LocalDate entryDate = JdbcSupport.getLocalDate(rs, "entryDate");
|
||||||
|
Boolean portfolioGenerated = rs.getBoolean("portfolioGenerated");
|
||||||
|
BigDecimal amount = rs.getBigDecimal("amount");
|
||||||
|
String entryType = rs.getString("entryType");
|
||||||
|
String transactionId = rs.getString("transactionId");
|
||||||
|
String entityType = rs.getString("entityType");
|
||||||
|
Long entityId = rs.getLong("entityId");
|
||||||
|
Long createdByUserId = rs.getLong("createdByUserId");
|
||||||
|
LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
|
||||||
|
String createdByUserName = rs.getString("createdByUserName");
|
||||||
|
String comments = rs.getString("comments");
|
||||||
|
Boolean reversed = rs.getBoolean("reversed");
|
||||||
|
|
||||||
|
return new GLJournalEntryData(journalEntryId, officeId, officeName, glAccountName, glAccountId, glAccountClassification,
|
||||||
|
entryDate, entryType, amount, transactionId, portfolioGenerated, entityType, entityId, createdByUserId, createdDate,
|
||||||
|
createdByUserName, comments, reversed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GLJournalEntryData> retrieveAllGLJournalEntries(Long officeId, Long glAccountId, Boolean portfolioGenerated, Date fromDate,
|
||||||
|
Date toDate) {
|
||||||
|
GLJournalEntryMapper rm = new GLJournalEntryMapper();
|
||||||
|
|
||||||
|
String sql = "select " + rm.schema();
|
||||||
|
Object[] objectArray = new Object[4];
|
||||||
|
int arrayPos = 0;
|
||||||
|
|
||||||
|
if (officeId != null && officeId != 0) {
|
||||||
|
sql += " and journalEntry.office_id = ?";
|
||||||
|
objectArray[arrayPos] = officeId;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glAccountId != null && glAccountId != 0) {
|
||||||
|
sql += " and journalEntry.account_id = ?";
|
||||||
|
objectArray[arrayPos] = glAccountId;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromDate != null || toDate != null) {
|
||||||
|
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
String fromDateString = null;
|
||||||
|
String toDateString = null;
|
||||||
|
if (fromDate != null && toDate != null) {
|
||||||
|
sql += " and journalEntry.entry_date between ? and ? ";
|
||||||
|
fromDateString = df.format(fromDate);
|
||||||
|
toDateString = df.format(toDate);
|
||||||
|
objectArray[arrayPos] = fromDateString;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
objectArray[arrayPos] = toDateString;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
} else if (fromDate != null) {
|
||||||
|
sql += " and journalEntry.entry_date >= ? ";
|
||||||
|
fromDateString = df.format(fromDate);
|
||||||
|
objectArray[arrayPos] = fromDateString;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
} else if (toDate != null) {
|
||||||
|
sql += " and journalEntry.entry_date <= ? ";
|
||||||
|
toDateString = df.format(toDate);
|
||||||
|
objectArray[arrayPos] = toDateString;
|
||||||
|
arrayPos = arrayPos + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (portfolioGenerated != null) {
|
||||||
|
if (portfolioGenerated) {
|
||||||
|
sql += " and journalEntry.portfolio_generated = 1";
|
||||||
|
} else {
|
||||||
|
sql += " and journalEntry.portfolio_generated = 0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
|
||||||
|
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GLJournalEntryData retrieveGLJournalEntryById(long glJournalEntryId) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
GLJournalEntryMapper rm = new GLJournalEntryMapper();
|
||||||
|
String sql = "select " + rm.schema() + " and journalEntry.id = ?";
|
||||||
|
|
||||||
|
GLJournalEntryData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glJournalEntryId });
|
||||||
|
|
||||||
|
return glAccountData;
|
||||||
|
} catch (EmptyResultDataAccessException e) {
|
||||||
|
throw new GLJournalEntriesNotFoundException(glJournalEntryId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
package org.mifosplatform.accounting.service.impl;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.mifosplatform.accounting.AccountingConstants.JOURNAL_ENTRY_TYPE;
|
||||||
|
import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
|
||||||
|
import org.mifosplatform.accounting.api.commands.SingleDebitOrCreditEntryCommand;
|
||||||
|
import org.mifosplatform.accounting.domain.GLAccount;
|
||||||
|
import org.mifosplatform.accounting.domain.GLAccountRepository;
|
||||||
|
import org.mifosplatform.accounting.domain.GLClosure;
|
||||||
|
import org.mifosplatform.accounting.domain.GLClosureRepository;
|
||||||
|
import org.mifosplatform.accounting.domain.GLJournalEntry;
|
||||||
|
import org.mifosplatform.accounting.domain.GLJournalEntryRepository;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLJournalEntriesNotFoundException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLJournalEntryInvalidException;
|
||||||
|
import org.mifosplatform.accounting.exceptions.GLJournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||||
|
import org.mifosplatform.accounting.service.GLJournalEntryCommandValidator;
|
||||||
|
import org.mifosplatform.accounting.service.GLJournalEntryWritePlatformService;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
|
import org.mifosplatform.organisation.office.domain.Office;
|
||||||
|
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||||
|
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJournalEntryWritePlatformService {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(GLJournalEntryWritePlatformServiceJpaRepositoryImpl.class);
|
||||||
|
|
||||||
|
private final GLClosureRepository glClosureRepository;
|
||||||
|
private final GLAccountRepository glAccountRepository;
|
||||||
|
private final GLJournalEntryRepository glJournalEntryRepository;
|
||||||
|
private final OfficeRepository officeRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public GLJournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
|
||||||
|
final GLAccountRepository glAccountRepository, final GLJournalEntryRepository glJournalEntryRepository,
|
||||||
|
final OfficeRepository officeRepository) {
|
||||||
|
this.glClosureRepository = glClosureRepository;
|
||||||
|
this.officeRepository = officeRepository;
|
||||||
|
this.glAccountRepository = glAccountRepository;
|
||||||
|
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public String createJournalEntry(GLJournalEntryCommand command) {
|
||||||
|
try {
|
||||||
|
GLJournalEntryCommandValidator validator = new GLJournalEntryCommandValidator(command);
|
||||||
|
validator.validateForCreate();
|
||||||
|
|
||||||
|
// check office is valid
|
||||||
|
final Office office = this.officeRepository.findOne(command.getOfficeId());
|
||||||
|
if (office == null) { throw new OfficeNotFoundException(command.getOfficeId()); }
|
||||||
|
|
||||||
|
validateBusinessRulesForJournalEntries(command);
|
||||||
|
|
||||||
|
/** Set a transaction Id and save these Journal entries **/
|
||||||
|
Date entryDate = command.getEntryDate().toDateMidnight().toDate();
|
||||||
|
String transactionId = generateTransactionId();
|
||||||
|
|
||||||
|
saveAllDebitOrCreditEntries(command, office, entryDate, command.getDebits(), transactionId, JOURNAL_ENTRY_TYPE.DEBIT);
|
||||||
|
|
||||||
|
saveAllDebitOrCreditEntries(command, office, entryDate, command.getCredits(), transactionId, JOURNAL_ENTRY_TYPE.CREDIT);
|
||||||
|
|
||||||
|
return transactionId;
|
||||||
|
} catch (DataIntegrityViolationException dve) {
|
||||||
|
handleJournalEntryDataIntegrityIssues(dve);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public String revertJournalEntry(String transactionId) {
|
||||||
|
|
||||||
|
// is the transaction Id valid
|
||||||
|
List<GLJournalEntry> journalEntries = glJournalEntryRepository.findUnReversedManualJournalEntriesByTransactionId(transactionId);
|
||||||
|
|
||||||
|
if (journalEntries.size() <= 1) { throw new GLJournalEntriesNotFoundException(transactionId); }
|
||||||
|
|
||||||
|
String reversalTransactionId = generateTransactionId();
|
||||||
|
|
||||||
|
for (GLJournalEntry journalEntry : journalEntries) {
|
||||||
|
GLJournalEntry reversalJournalEntry;
|
||||||
|
String reversalComment = "Reversal entry for Journal Entry with Entry Id :" + journalEntry.getId() + " and transaction Id "
|
||||||
|
+ transactionId;
|
||||||
|
if (journalEntry.getType().equalsIgnoreCase(JOURNAL_ENTRY_TYPE.DEBIT.toString())) {
|
||||||
|
reversalJournalEntry = GLJournalEntry.createNew(journalEntry.getOffice(), journalEntry.getGlAccount(),
|
||||||
|
reversalTransactionId, false, journalEntry.getEntryDate(), JOURNAL_ENTRY_TYPE.CREDIT.toString(),
|
||||||
|
journalEntry.getAmount(), reversalComment, null, null);
|
||||||
|
} else {
|
||||||
|
reversalJournalEntry = GLJournalEntry.createNew(journalEntry.getOffice(), journalEntry.getGlAccount(),
|
||||||
|
reversalTransactionId, false, journalEntry.getEntryDate(), JOURNAL_ENTRY_TYPE.DEBIT.toString(),
|
||||||
|
journalEntry.getAmount(), reversalComment, null, null);
|
||||||
|
}
|
||||||
|
// save the reversal entry
|
||||||
|
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
|
||||||
|
journalEntry.setReversed(true);
|
||||||
|
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||||
|
// save the updated journal entry
|
||||||
|
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||||
|
}
|
||||||
|
return reversalTransactionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBusinessRulesForJournalEntries(GLJournalEntryCommand command) {
|
||||||
|
|
||||||
|
/** check if date of Journal entry is valid ***/
|
||||||
|
final LocalDate entryLocalDate = command.getEntryDate();
|
||||||
|
Date entryDate = entryLocalDate.toDateMidnight().toDate();
|
||||||
|
// shouldn't be in the future
|
||||||
|
Date todaysDate = new Date();
|
||||||
|
if (entryDate.after(todaysDate)) { throw new GLJournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.FUTURE_DATE, entryDate); }
|
||||||
|
// shouldn't be before an accounting closure
|
||||||
|
GLClosure latestGLClosure = glClosureRepository.getLatestGLClosureByBranch(command.getOfficeId());
|
||||||
|
if (latestGLClosure != null) {
|
||||||
|
if (latestGLClosure.getClosingDate().after(entryDate)) { throw new GLJournalEntryInvalidException(
|
||||||
|
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate()); }
|
||||||
|
}
|
||||||
|
/*** check if credits and debits are valid **/
|
||||||
|
SingleDebitOrCreditEntryCommand[] credits = command.getCredits();
|
||||||
|
SingleDebitOrCreditEntryCommand[] debits = command.getDebits();
|
||||||
|
|
||||||
|
// atleast one debit or credit must be present
|
||||||
|
if ((credits == null || credits.length <= 0) || (debits == null || debits.length <= 0)) { throw new GLJournalEntryInvalidException(
|
||||||
|
GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null); }
|
||||||
|
|
||||||
|
// sum of all debits must be = sum of all credits
|
||||||
|
BigDecimal creditsSum = BigDecimal.ZERO;
|
||||||
|
BigDecimal debitsSum = BigDecimal.ZERO;
|
||||||
|
for (SingleDebitOrCreditEntryCommand creditEntryCommand : credits) {
|
||||||
|
if (creditEntryCommand.getAmount() == null || creditEntryCommand.getGlAccountId() == null) { throw new GLJournalEntryInvalidException(
|
||||||
|
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null); }
|
||||||
|
creditsSum = creditsSum.add(creditEntryCommand.getAmount());
|
||||||
|
}
|
||||||
|
for (SingleDebitOrCreditEntryCommand debitEntryCommand : debits) {
|
||||||
|
if (debitEntryCommand.getAmount() == null || debitEntryCommand.getGlAccountId() == null) { throw new GLJournalEntryInvalidException(
|
||||||
|
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null); }
|
||||||
|
debitsSum = debitsSum.add(debitEntryCommand.getAmount());
|
||||||
|
}
|
||||||
|
if (creditsSum.compareTo(debitsSum) != 0) { throw new GLJournalEntryInvalidException(
|
||||||
|
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command
|
||||||
|
* @param office
|
||||||
|
* @param entryDate
|
||||||
|
* @param singleDebitOrCreditEntryCommands
|
||||||
|
* @param transactionId
|
||||||
|
*/
|
||||||
|
private void saveAllDebitOrCreditEntries(GLJournalEntryCommand command, final Office office, Date entryDate,
|
||||||
|
SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, String transactionId, JOURNAL_ENTRY_TYPE type) {
|
||||||
|
for (SingleDebitOrCreditEntryCommand singleDebitOrCreditEntryCommand : singleDebitOrCreditEntryCommands) {
|
||||||
|
GLAccount glAccount = glAccountRepository.findOne(singleDebitOrCreditEntryCommand.getGlAccountId());
|
||||||
|
if (glAccount == null) { throw new GLAccountNotFoundException(singleDebitOrCreditEntryCommand.getGlAccountId()); }
|
||||||
|
String comments = command.getComments();
|
||||||
|
if (!StringUtils.isBlank(singleDebitOrCreditEntryCommand.getComments())) {
|
||||||
|
comments = singleDebitOrCreditEntryCommand.getComments();
|
||||||
|
}
|
||||||
|
GLJournalEntry glJournalEntry = GLJournalEntry.createNew(office, glAccount, transactionId, false, entryDate, type.toString(),
|
||||||
|
singleDebitOrCreditEntryCommand.getAmount(), comments, null, null);
|
||||||
|
glJournalEntryRepository.saveAndFlush(glJournalEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command
|
||||||
|
* @param dve
|
||||||
|
*/
|
||||||
|
private void handleJournalEntryDataIntegrityIssues(DataIntegrityViolationException dve) {
|
||||||
|
Throwable realCause = dve.getMostSpecificCause();
|
||||||
|
logger.error(dve.getMessage(), dve);
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.glJournalEntry.unknown.data.integrity.issue",
|
||||||
|
"Unknown data integrity issue with resource Journal Entry: " + realCause.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Need a better implementation with guaranteed uniqueness (but not a
|
||||||
|
* long UUID)...maybe something tied to system clock..
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String generateTransactionId() {
|
||||||
|
return RandomStringUtils.random(15, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -20,6 +20,7 @@ import javax.ws.rs.core.StreamingOutput;
|
|||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||||
|
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
||||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
||||||
@@ -256,7 +257,9 @@ public class ReadReportingServiceImpl implements ReadReportingService {
|
|||||||
// String reportPath =
|
// String reportPath =
|
||||||
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
|
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
|
||||||
// + reportName + ".prpt";
|
// + reportName + ".prpt";
|
||||||
String reportPath = "/var/lib/tomcat7/webapps/ROOT/PentahoReports/" + reportName + ".prpt";
|
String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator
|
||||||
|
+ ThreadLocalContextUtil.getTenant().getName().replaceAll(" ", "").trim() + File.separator + "reports" + File.separator
|
||||||
|
+ reportName + ".prpt";
|
||||||
logger.info("Report path: " + reportPath);
|
logger.info("Report path: " + reportPath);
|
||||||
|
|
||||||
// load report definition
|
// load report definition
|
||||||
|
|||||||
Reference in New Issue
Block a user