minor bug fixes for accounting infrastructure

adding sql files
This commit is contained in:
Vishwas Babu AJ
2012-12-15 00:22:36 +05:30
parent adca69b0a0
commit b2639fea2c
14 changed files with 209 additions and 41 deletions
+19
View File
@@ -0,0 +1,19 @@
/**Balance sheet report**/
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Balance Sheet', 'Pentaho', NULL, 'Accounting', NULL, 'Balance Sheet', 1, 1);
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 5, 'branch');
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 81, 'date');
/**Income statement report**/
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Income Statement', 'Pentaho', NULL, 'Accounting', NULL, 'Profilt and Loss Statement', 1, 1);
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 5, 'branch');
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 80, 'fromDate');
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 81, 'toDate');
/**Trial Balance report**/
INSERT INTO `stretchy_report` (`report_name`, `report_type`, `report_subtype`, `report_category`, `report_sql`, `description`, `core_report`, `use_report`) VALUES ('Trial Balance', 'Pentaho', NULL, 'Accounting', NULL, 'Trial Balance Report', 1, 1);
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 5, 'branch');
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 80, 'fromDate');
INSERT INTO `stretchy_report_parameter` (`report_id`, `parameter_id`, `report_parameter_name`) VALUES ((select max(report_id) from stretchy_report), 81, 'toDate');
@@ -22,4 +22,14 @@ public class AccountingConstants {
}
}
/** USAGES of Accounts **/
public static enum GL_ACCOUNT_USAGE {
HEADER, DETAIL;
@Override
public String toString() {
return name().toString();
}
}
}
@@ -66,14 +66,16 @@ public class GLAccountsApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllAccounts(@Context final UriInfo uriInfo, @QueryParam("classification") final String classification,
@QueryParam("searchParam") final String searchParam) {
@QueryParam("searchParam") final String searchParam, @QueryParam("usage") final String usage,
@QueryParam("manualAdjustmentsAllowed") final Boolean manualTransactionsAllowed, @QueryParam("disabled") final Boolean disabled) {
context.authenticatedUser().validateHasReadPermission(entityType);
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final List<GLAccountData> glAccountDatas = this.glAccountReadPlatformService.retrieveAllGLAccounts(classification, searchParam);
final List<GLAccountData> glAccountDatas = this.glAccountReadPlatformService.retrieveAllGLAccounts(classification, searchParam,
usage, manualTransactionsAllowed, disabled);
return this.apiJsonSerializerService.serializeGLAccountDataToJson(prettyPrint, responseParameters, glAccountDatas);
}
@@ -30,19 +30,15 @@ public class GLAccount extends AbstractPersistable<Long> {
@JoinColumn(name = "parent_id")
private List<GLAccount> children = new LinkedList<GLAccount>();
@SuppressWarnings("unused")
@Column(name = "name", nullable = false, length = 45)
private String name;
@SuppressWarnings("unused")
@Column(name = "gl_code", nullable = false, length = 100)
private String glCode;
@SuppressWarnings("unused")
@Column(name = "disabled", nullable = false)
private boolean disabled = false;
@SuppressWarnings("unused")
@Column(name = "manual_journal_entries_allowed", nullable = false)
private boolean manualEntriesAllowed = true;
@@ -113,4 +109,24 @@ public class GLAccount extends AbstractPersistable<Long> {
return this.children;
}
public boolean isDisabled() {
return this.disabled;
}
public boolean isManualEntriesAllowed() {
return this.manualEntriesAllowed;
}
public String getGlCode() {
return this.glCode;
}
public void setGlCode(String glCode) {
this.glCode = glCode;
}
public String getName() {
return this.name;
}
}
@@ -28,6 +28,6 @@ public class GLAccountInvalidDeleteException extends AbstractPlatformDomainRuleE
}
public GLAccountInvalidDeleteException(final GL_ACCOUNT_INVALID_DELETE_REASON reason, final Long glAccountId) {
super("error.msg.glaccount.glcode.invalid.delete", reason.errorMessage(), glAccountId);
super(reason.errorCode(), reason.errorMessage(), glAccountId);
}
}
@@ -0,0 +1,29 @@
package org.mifosplatform.accounting.exceptions;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* A {@link RuntimeException} thrown when an error is encountered during
* updating a GL Account
*/
public class GLAccountInvalidUpdateException extends AbstractPlatformDomainRuleException {
/*** Enum of reasons for invalid delete **/
public static enum GL_ACCOUNT_INVALID_UPDATE_REASON {
TRANSANCTIONS_LOGGED;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) { return "This Usage of this (detail) GL Account as it already has transactions logged against it"; }
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) { return "error.msg.glaccount.glcode.invalid.update.transactions.logged"; }
return name().toString();
}
}
public GLAccountInvalidUpdateException(final GL_ACCOUNT_INVALID_UPDATE_REASON reason, final Long glAccountId) {
super(reason.errorCode(), reason.errorMessage(), glAccountId);
}
}
@@ -11,7 +11,7 @@ public class GLJournalEntryInvalidException extends AbstractPlatformDomainRuleEx
/*** 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;
FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
@@ -22,7 +22,11 @@ public class GLJournalEntryInvalidException extends AbstractPlatformDomainRuleEx
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"; }
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) {
return "Both account and amount must be specified for all Debits and Credits";
} else if (name().toString().equalsIgnoreCase("GL_ACCOUNT_DISABLED")) {
return "Target account has been disabled";
} else if (name().toString().equalsIgnoreCase("GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED")) { return "Target account does not allow maual adjustments"; }
return name().toString();
}
@@ -35,12 +39,17 @@ public class GLJournalEntryInvalidException extends AbstractPlatformDomainRuleEx
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"; }
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) {
return "error.msg.glJournalEntry.invalid.empty.account.or.amount";
} else if (name().toString().equalsIgnoreCase("GL_ACCOUNT_DISABLED")) {
return "error.msg.glJournalEntry.invalid.account.disabled";
} else if (name().toString().equalsIgnoreCase("GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED")) { return "error.msg.glJournalEntry.invalid.account.manual.adjustments.not.permitted"; }
return name().toString();
}
}
public GLJournalEntryInvalidException(final GL_JOURNAL_ENTRY_INVALID_REASON reason, final Date date) {
super(reason.errorCode(), reason.errorMessage(), date);
public GLJournalEntryInvalidException(final GL_JOURNAL_ENTRY_INVALID_REASON reason, final Date date, final String accountName,
final String accountGLCode) {
super(reason.errorCode(), reason.errorMessage(), date, accountName, accountGLCode);
}
}
@@ -31,7 +31,7 @@ public class GLAccountCommandValidator {
baseDataValidator.reset().parameter("classification").value(command.getClassification()).notBlank().notExceedingLengthOf(45);
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",
@@ -55,8 +55,10 @@ public class GLAccountCommandValidator {
baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notBlank()
.notExceedingLengthOf(500);
baseDataValidator.reset().parameter("disabled").value(command.getDisabled()).ignoreIfNull();
baseDataValidator.reset().anyOfNotNull(command.getName(), command.getGlCode(), command.getParentId(), command.getClassification(),
command.getDescription());
command.getDescription(), command.getDisabled());
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
@@ -6,7 +6,8 @@ import org.mifosplatform.accounting.api.data.GLAccountData;
public interface GLAccountReadPlatformService {
List<GLAccountData> retrieveAllGLAccounts(String accountClassification, String searchParam);
List<GLAccountData> retrieveAllGLAccounts(String accountClassification, String searchParam, String usage,
Boolean manualTransactionsAllowed, Boolean disabled);
GLAccountData retrieveGLAccountById(long glAccountId);
@@ -7,6 +7,7 @@ import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.AccountingConstants.GL_ACCOUNT_CLASSIFICATION;
import org.mifosplatform.accounting.AccountingConstants.GL_ACCOUNT_USAGE;
import org.mifosplatform.accounting.api.data.GLAccountData;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidClassificationException;
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
@@ -54,7 +55,8 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
}
@Override
public List<GLAccountData> retrieveAllGLAccounts(String accountClassification, String searchParam) {
public List<GLAccountData> retrieveAllGLAccounts(String accountClassification, String searchParam, String usage,
Boolean manualTransactionsAllowed, Boolean disabled) {
if (StringUtils.isNotBlank(accountClassification)) {
if (!checkValidGLAccountClassification(accountClassification)) { throw new GLAccountInvalidClassificationException(
accountClassification); }
@@ -64,25 +66,71 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
String sql = "select " + rm.schema();
Object[] paramaterArray = new Object[3];
int arrayPos = 0;
if (StringUtils.isNotBlank(accountClassification) && searchParam != null) {
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)) {
sql += " where classification like ?";
paramaterArray[arrayPos] = accountClassification;
arrayPos++;
} else if (searchParam != null) {
sql += " where ( name like %?% or glCode like %?% )";
paramaterArray[arrayPos] = searchParam;
arrayPos++;
paramaterArray[arrayPos] = searchParam;
arrayPos++;
boolean filtersPresent = false;
if (StringUtils.isNotBlank(accountClassification) || StringUtils.isNotBlank(searchParam) || StringUtils.isNotBlank(usage)
|| (manualTransactionsAllowed != null) || (disabled != null)) {
filtersPresent = true;
sql += " where";
}
if (filtersPresent) {
boolean firstWhereConditionAdded = false;
if (StringUtils.isNotBlank(accountClassification)) {
sql += " classification like ?";
paramaterArray[arrayPos] = accountClassification;
arrayPos = arrayPos + 1;
firstWhereConditionAdded = true;
}
if (StringUtils.isNotBlank(searchParam)) {
if (firstWhereConditionAdded) {
sql += " and ";
}
sql += " ( name like %?% or gl_code like %?% )";
paramaterArray[arrayPos] = searchParam;
arrayPos = arrayPos + 1;
paramaterArray[arrayPos] = searchParam;
arrayPos = arrayPos + 1;
firstWhereConditionAdded = true;
}
if (StringUtils.isNotBlank(usage)) {
if (firstWhereConditionAdded) {
sql += " and ";
}
if (usage.equalsIgnoreCase(GL_ACCOUNT_USAGE.HEADER.toString())) {
sql += " header_account = 1 ";
} else if (usage.equalsIgnoreCase(GL_ACCOUNT_USAGE.DETAIL.toString())) {
sql += " header_account = 0 ";
} else {
}
firstWhereConditionAdded = true;
}
if (manualTransactionsAllowed != null) {
if (firstWhereConditionAdded) {
sql += " and ";
}
if (manualTransactionsAllowed) {
sql += " manual_journal_entries_allowed = 1";
} else {
sql += " manual_journal_entries_allowed = 0";
}
firstWhereConditionAdded = true;
}
if (disabled != null) {
if (firstWhereConditionAdded) {
sql += " and ";
}
if (disabled) {
sql += " disabled = 1";
} else {
sql += " disabled = 0";
}
firstWhereConditionAdded = true;
}
}
sql = sql + " order by glCode";
Object[] finalObjectArray = Arrays.copyOf(paramaterArray, arrayPos);
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
@@ -13,7 +13,9 @@ import org.mifosplatform.accounting.exceptions.GLAccountDuplicateException;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidClassificationException;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidDeleteException.GL_ACCOUNT_INVALID_DELETE_REASON;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidUpdateException.GL_ACCOUNT_INVALID_UPDATE_REASON;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidParentException;
import org.mifosplatform.accounting.exceptions.GLAccountInvalidUpdateException;
import org.mifosplatform.accounting.exceptions.GLAccountNotFoundException;
import org.mifosplatform.accounting.service.GLAccountCommandValidator;
import org.mifosplatform.accounting.service.GLAccountWritePlatformService;
@@ -91,6 +93,18 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
command.getClassification()); }
}
/**
* a detail account cannot be changed to a header account if
* transactions are already logged against it
**/
if (command.isHeaderAccountFlagChanged()) {
if (command.getHeaderAccount() == true) {
List<GLJournalEntry> journalEntriesForAccount = glJournalEntryRepository.findFirstJournalEntryForAccount(glAccountId);
if (journalEntriesForAccount.size() > 0) { throw new GLAccountInvalidUpdateException(
GL_ACCOUNT_INVALID_UPDATE_REASON.TRANSANCTIONS_LOGGED, glAccountId); }
}
}
glAccount.update(command, parentGLAccount);
this.glAccountRepository.saveAndFlush(glAccount);
@@ -109,7 +123,7 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
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
// 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); }
@@ -129,6 +129,8 @@ public class GLJournalEntryReadPlatformServiceImpl implements GLJournalEntryRead
}
}
sql += " order by journalEntry.entry_date";
Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
}
@@ -115,6 +115,9 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo
return reversalTransactionId;
}
/**
* @param command
*/
private void validateBusinessRulesForJournalEntries(GLJournalEntryCommand command) {
/** check if date of Journal entry is valid ***/
@@ -122,12 +125,13 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo
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); }
if (entryDate.after(todaysDate)) { throw new GLJournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.FUTURE_DATE, entryDate,
null, null); }
// 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()); }
GL_JOURNAL_ENTRY_INVALID_REASON.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(), null, null); }
}
/*** check if credits and debits are valid **/
SingleDebitOrCreditEntryCommand[] credits = command.getCredits();
@@ -135,23 +139,23 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo
// 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); }
GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null, null, 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); }
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, 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); }
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
debitsSum = debitsSum.add(debitEntryCommand.getAmount());
}
if (creditsSum.compareTo(debitsSum) != 0) { throw new GLJournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null); }
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null, null, null); }
}
/**
@@ -166,6 +170,18 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo
for (SingleDebitOrCreditEntryCommand singleDebitOrCreditEntryCommand : singleDebitOrCreditEntryCommands) {
GLAccount glAccount = glAccountRepository.findOne(singleDebitOrCreditEntryCommand.getGlAccountId());
if (glAccount == null) { throw new GLAccountNotFoundException(singleDebitOrCreditEntryCommand.getGlAccountId()); }
/***
* validate that the account allows manual adjustments and is not
* disabled
**/
if (glAccount.isDisabled()) {
throw new GLJournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.GL_ACCOUNT_DISABLED, null, glAccount.getName(),
glAccount.getGlCode());
} else if (!glAccount.isManualEntriesAllowed()) { throw new GLJournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED, null, glAccount.getName(),
glAccount.getGlCode()); }
String comments = command.getComments();
if (!StringUtils.isBlank(singleDebitOrCreditEntryCommand.getComments())) {
comments = singleDebitOrCreditEntryCommand.getComments();