Add Predefined Journal Entries with optional tag fields

This commit is contained in:
mifoscontributer
2013-05-29 12:07:43 +05:30
parent 42a2428774
commit 96789be7ad
8 changed files with 232 additions and 86 deletions
@@ -0,0 +1,15 @@
package org.mifosplatform.accounting.glaccount.data;
public class GLAccountDataForLookup {
private final Long id;
public GLAccountDataForLookup(final Long id) {
this.id = id;
}
public Long getId() {
return this.id;
}
}
@@ -8,6 +8,7 @@ package org.mifosplatform.accounting.glaccount.service;
import java.util.List; import java.util.List;
import org.mifosplatform.accounting.glaccount.data.GLAccountData; import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType; import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
public interface GLAccountReadPlatformService { public interface GLAccountReadPlatformService {
@@ -24,4 +25,6 @@ public interface GLAccountReadPlatformService {
List<GLAccountData> retrieveAllEnabledHeaderGLAccounts(GLAccountType accountType); List<GLAccountData> retrieveAllEnabledHeaderGLAccounts(GLAccountType accountType);
GLAccountData retrieveNewGLAccountDetails(final Integer type); GLAccountData retrieveNewGLAccountDetails(final Integer type);
List<GLAccountDataForLookup> retrieveAccountsByTagId(final Long ruleId, final Integer transactionType);
} }
@@ -13,6 +13,7 @@ import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.common.AccountingEnumerations; import org.mifosplatform.accounting.common.AccountingEnumerations;
import org.mifosplatform.accounting.glaccount.data.GLAccountData; import org.mifosplatform.accounting.glaccount.data.GLAccountData;
import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
import org.mifosplatform.accounting.glaccount.domain.GLAccountType; import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
import org.mifosplatform.accounting.glaccount.domain.GLAccountUsage; import org.mifosplatform.accounting.glaccount.domain.GLAccountUsage;
import org.mifosplatform.accounting.glaccount.exception.GLAccountInvalidClassificationException; import org.mifosplatform.accounting.glaccount.exception.GLAccountInvalidClassificationException;
@@ -65,7 +66,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
final String nameDecorated = rs.getString("nameDecorated"); final String nameDecorated = rs.getString("nameDecorated");
final Long codeId = rs.wasNull() ? null : rs.getLong("codeId"); final Long codeId = rs.wasNull() ? null : rs.getLong("codeId");
final String codeValue = rs.getString("codeValue"); final String codeValue = rs.getString("codeValue");
CodeValueData tagId = CodeValueData.instance(codeId, codeValue); final CodeValueData tagId = CodeValueData.instance(codeId, codeValue);
return new GLAccountData(id, name, parentId, glCode, disabled, manualEntriesAllowed, accountType, usage, description, return new GLAccountData(id, name, parentId, glCode, disabled, manualEntriesAllowed, accountType, usage, description,
nameDecorated, tagId); nameDecorated, tagId);
} }
@@ -202,4 +203,25 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
public List<GLAccountData> retrieveAllEnabledHeaderGLAccounts(final GLAccountType accountType) { public List<GLAccountData> retrieveAllEnabledHeaderGLAccounts(final GLAccountType accountType) {
return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.HEADER.getValue(), null, false); return retrieveAllGLAccounts(accountType.getValue(), null, GLAccountUsage.HEADER.getValue(), null, false);
} }
@Override
public List<GLAccountDataForLookup> retrieveAccountsByTagId(final Long ruleId, final Integer transactionType) {
final GLAccountDataLookUpMapper mapper = new GLAccountDataLookUpMapper();
final String sql = "Select " + mapper.schema() + " where rule.id=? and tags.acc_type_enum=?";
return this.jdbcTemplate.query(sql, mapper, new Object[] { ruleId, transactionType });
}
private static final class GLAccountDataLookUpMapper implements RowMapper<GLAccountDataForLookup> {
public String schema() {
return " gl.id as id from acc_accounting_rule rule join acc_rule_tags tags on tags.acc_rule_id = rule.id join acc_gl_account gl on gl.tag_id=tags.tag_id";
}
@Override
public GLAccountDataForLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
return new GLAccountDataForLookup(id);
}
}
} }
@@ -30,8 +30,8 @@ public class JournalEntryCommand {
private final SingleDebitOrCreditEntryCommand[] debits; private final SingleDebitOrCreditEntryCommand[] debits;
public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments, public JournalEntryCommand(final Long officeId, final LocalDate transactionDate, final String comments,
final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits, final String referenceNumber,
final String referenceNumber, final Long accountingRuleId, final BigDecimal amount) { final Long accountingRuleId, final BigDecimal amount) {
this.officeId = officeId; this.officeId = officeId;
this.transactionDate = transactionDate; this.transactionDate = transactionDate;
this.comments = comments; this.comments = comments;
@@ -53,46 +53,42 @@ public class JournalEntryCommand {
baseDataValidator.reset().parameter("officeId").value(this.officeId).notNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("officeId").value(this.officeId).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("comments").value(this.comments).ignoreIfNull().notExceedingLengthOf(500); baseDataValidator.reset().parameter("comments").value(this.comments).ignoreIfNull().notExceedingLengthOf(500);
baseDataValidator.reset().parameter("referenceNumber").value(this.referenceNumber).ignoreIfNull().notExceedingLengthOf(100); baseDataValidator.reset().parameter("referenceNumber").value(this.referenceNumber).ignoreIfNull().notExceedingLengthOf(100);
baseDataValidator.reset().parameter("accountingRule").value(this.accountingRuleId).ignoreIfNull().longGreaterThanZero(); baseDataValidator.reset().parameter("accountingRule").value(this.accountingRuleId).ignoreIfNull().longGreaterThanZero();
if (this.accountingRuleId == null) { baseDataValidator.reset().parameter("credits").value(this.credits).ignoreIfNull();
baseDataValidator.reset().parameter("credits").value(this.credits).notNull(); baseDataValidator.reset().parameter("debits").value(this.debits).ignoreIfNull();
baseDataValidator.reset().parameter("debits").value(this.debits).notNull(); // validation for credit array elements
if (this.credits != null) {
// validation for credit array elements if (this.credits.length == 0) {
if (this.credits != null) { validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
if (this.credits.length == 0) { } else {
validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null)); int i = 0;
} else { for (final SingleDebitOrCreditEntryCommand credit : this.credits) {
int i = 0; validateSingleDebitOrCredit(baseDataValidator, "credits", i, credit);
for (final SingleDebitOrCreditEntryCommand credit : this.credits) { i++;
validateSingleDebitOrCredit(baseDataValidator, "credits", i, credit);
i++;
}
} }
} }
// validation for debit array elements
if (this.debits != null) {
if (this.debits.length == 0) {
validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
} else {
int i = 0;
for (final SingleDebitOrCreditEntryCommand debit : this.debits) {
validateSingleDebitOrCredit(baseDataValidator, "debits", i, debit);
i++;
}
}
}
} else {
baseDataValidator.reset().parameter("amount").value(this.amount).notNull().zeroOrPositiveAmount();
} }
// validation for debit array elements
if (this.debits != null) {
if (this.debits.length == 0) {
validateSingleDebitOrCredit(baseDataValidator, "credits", 0, new SingleDebitOrCreditEntryCommand(null, null, null, null));
} else {
int i = 0;
for (final SingleDebitOrCreditEntryCommand debit : this.debits) {
validateSingleDebitOrCredit(baseDataValidator, "debits", i, debit);
i++;
}
}
}
baseDataValidator.reset().parameter("amount").value(this.amount).ignoreIfNull().zeroOrPositiveAmount();
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); }
} }
@@ -134,8 +130,8 @@ public class JournalEntryCommand {
return this.referenceNumber; return this.referenceNumber;
} }
public Long getAccountingRuleId() { public Long getAccountingRuleId() {
return this.accountingRuleId; return this.accountingRuleId;
} }
} }
@@ -16,7 +16,7 @@ public class JournalEntryInvalidException extends AbstractPlatformDomainRuleExce
/*** enum of reasons for invalid Journal Entry **/ /*** enum of reasons for invalid Journal Entry **/
public static enum GL_JOURNAL_ENTRY_INVALID_REASON { 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, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED; FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED;
public String errorMessage() { public String errorMessage() {
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) { if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
@@ -25,6 +25,8 @@ public class JournalEntryInvalidException extends AbstractPlatformDomainRuleExce
return "Journal entry cannot be made prior to last account closing date for the branch"; return "Journal entry cannot be made prior to last account closing date for the branch";
} else if (name().toString().equalsIgnoreCase("NO_DEBITS_OR_CREDITS")) { } else if (name().toString().equalsIgnoreCase("NO_DEBITS_OR_CREDITS")) {
return "Journal Entry must have atleast one Debit and one Credit"; return "Journal Entry must have atleast one Debit and one Credit";
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT")) {
return "Sum of All Debits OR Credits must equal the Amount for a Journal Entry";
} else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_SUM_MISMATCH")) { } 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"; 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")) { } else if (name().toString().equalsIgnoreCase("DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY")) {
@@ -6,6 +6,7 @@
package org.mifosplatform.accounting.journalentry.service; package org.mifosplatform.accounting.journalentry.service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -15,9 +16,11 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.accounting.closure.domain.GLClosure; import org.mifosplatform.accounting.closure.domain.GLClosure;
import org.mifosplatform.accounting.closure.domain.GLClosureRepository; import org.mifosplatform.accounting.closure.domain.GLClosureRepository;
import org.mifosplatform.accounting.glaccount.data.GLAccountDataForLookup;
import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.glaccount.domain.GLAccount;
import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository; import org.mifosplatform.accounting.glaccount.domain.GLAccountRepository;
import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException; import org.mifosplatform.accounting.glaccount.exception.GLAccountNotFoundException;
import org.mifosplatform.accounting.glaccount.service.GLAccountReadPlatformService;
import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams; import org.mifosplatform.accounting.journalentry.api.JournalEntryJsonInputParams;
import org.mifosplatform.accounting.journalentry.command.JournalEntryCommand; import org.mifosplatform.accounting.journalentry.command.JournalEntryCommand;
import org.mifosplatform.accounting.journalentry.command.SingleDebitOrCreditEntryCommand; import org.mifosplatform.accounting.journalentry.command.SingleDebitOrCreditEntryCommand;
@@ -61,6 +64,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
private final AccountingProcessorHelper helper; private final AccountingProcessorHelper helper;
private final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final AccountingRuleRepository accountingRuleRepository; private final AccountingRuleRepository accountingRuleRepository;
private final GLAccountReadPlatformService glAccountReadPlatformService;
@Autowired @Autowired
public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository, public JournalEntryWritePlatformServiceJpaRepositoryImpl(final GLClosureRepository glClosureRepository,
@@ -68,7 +72,8 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
final GLAccountRepository glAccountRepository, final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer, final GLAccountRepository glAccountRepository, final JournalEntryCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final AccountingProcessorHelper accountingProcessorHelper, final AccountingRuleRepository accountingRuleRepository, final AccountingProcessorHelper accountingProcessorHelper, final AccountingRuleRepository accountingRuleRepository,
final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory, final AccountingProcessorForLoanFactory accountingProcessorForLoanFactory,
final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory) { final AccountingProcessorForSavingsFactory accountingProcessorForSavingsFactory,
final GLAccountReadPlatformService glAccountReadPlatformService) {
this.glClosureRepository = glClosureRepository; this.glClosureRepository = glClosureRepository;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.glJournalEntryRepository = glJournalEntryRepository; this.glJournalEntryRepository = glJournalEntryRepository;
@@ -78,6 +83,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
this.accountingProcessorForSavingsFactory = accountingProcessorForSavingsFactory; this.accountingProcessorForSavingsFactory = accountingProcessorForSavingsFactory;
this.helper = accountingProcessorHelper; this.helper = accountingProcessorHelper;
this.accountingRuleRepository = accountingRuleRepository; this.accountingRuleRepository = accountingRuleRepository;
this.glAccountReadPlatformService = glAccountReadPlatformService;
} }
@Transactional @Transactional
@@ -99,32 +105,65 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
/** Set a transaction Id and save these Journal entries **/ /** Set a transaction Id and save these Journal entries **/
final Date transactionDate = command.DateValueOfParameterNamed(JournalEntryJsonInputParams.TRANSACTION_DATE.getValue()); final Date transactionDate = command.DateValueOfParameterNamed(JournalEntryJsonInputParams.TRANSACTION_DATE.getValue());
final String transactionId = generateTransactionId(); final String transactionId = generateTransactionId();
final String referenceNumber = journalEntryCommand.getReferenceNumber(); final String referenceNumber = command.stringValueOfParameterNamed(JournalEntryJsonInputParams.REFERENCE_NUMBER.getValue());
final boolean manualEntry = true; final boolean manualEntry = true;
if (accountRuleId != null) { if (accountRuleId != null) {
final Long accountingRuleId = command.longValueOfParameterNamed(JournalEntryJsonInputParams.ACCOUNTING_RULE.getValue());
final BigDecimal amount = command.bigDecimalValueOfParameterNamed(JournalEntryJsonInputParams.AMOUNT.getValue()); final BigDecimal amount = command.bigDecimalValueOfParameterNamed(JournalEntryJsonInputParams.AMOUNT.getValue());
final AccountingRule accountingRule = this.accountingRuleRepository.findOne(accountingRuleId);
if (accountingRule == null) { throw new AccountingRuleNotFoundException(accountingRuleId); }
final GLAccount creditAccountHead = accountingRule.getAccountToCredit();
validateGLAccountForTransaction(creditAccountHead);
final GLAccount debitAccountHead = accountingRule.getAccountToDebit();
validateGLAccountForTransaction(debitAccountHead);
String description = null; String description = null;
if (StringUtils.isNotBlank(journalEntryCommand.getComments())) { if (StringUtils.isNotBlank(journalEntryCommand.getComments())) {
description = journalEntryCommand.getComments(); description = journalEntryCommand.getComments();
} }
JournalEntry creditEntry = JournalEntry.createNew(office, creditAccountHead, transactionId, manualEntry, transactionDate, final AccountingRule accountingRule = this.accountingRuleRepository.findOne(accountRuleId);
JournalEntryType.CREDIT, amount, description, null, null, referenceNumber); if (accountingRule == null) { throw new AccountingRuleNotFoundException(accountRuleId); }
this.glJournalEntryRepository.saveAndFlush(creditEntry);
JournalEntry debitEntry = JournalEntry.createNew(office, debitAccountHead, transactionId, manualEntry, transactionDate, if (accountingRule.getAccountToCredit() == null) {
JournalEntryType.DEBIT, amount, description, null, null, referenceNumber); if (journalEntryCommand.getCredits() == null) { throw new RuntimeException(
this.glJournalEntryRepository.saveAndFlush(debitEntry); "You have to pass atleast one value for credits"); }
if (journalEntryCommand.getDebits() != null) {
checkDebitOrCreditAccountsAreValid(accountingRule, journalEntryCommand.getCredits(),
journalEntryCommand.getDebits());
checkDebitAndCreditAmounts(journalEntryCommand.getCredits(), journalEntryCommand.getDebits());
} else {
checkDebitAndCreditAmounts(journalEntryCommand.getCredits(), amount);
}
saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getCredits(),
transactionId, JournalEntryType.CREDIT, referenceNumber);
} else {
if (journalEntryCommand.getCredits() != null) { throw new RuntimeException(
"You can not pass credits for this rule please verify your rule"); }
final GLAccount creditAccountHead = accountingRule.getAccountToCredit();
validateGLAccountForTransaction(creditAccountHead);
final JournalEntry creditEntry = JournalEntry.createNew(office, creditAccountHead, transactionId, manualEntry,
transactionDate, JournalEntryType.CREDIT, amount, description, null, null, referenceNumber);
this.glJournalEntryRepository.saveAndFlush(creditEntry);
}
if (accountingRule.getAccountToDebit() == null) {
if (journalEntryCommand.getDebits() == null) { throw new RuntimeException(
"You have to pass atleast one parameter for debits"); }
if (journalEntryCommand.getCredits() != null) {
checkDebitOrCreditAccountsAreValid(accountingRule, journalEntryCommand.getCredits(),
journalEntryCommand.getDebits());
checkDebitAndCreditAmounts(journalEntryCommand.getCredits(), journalEntryCommand.getDebits());
} else {
checkDebitAndCreditAmounts(journalEntryCommand.getDebits(), amount);
}
saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getDebits(),
transactionId, JournalEntryType.DEBIT, referenceNumber);
} else {
if (journalEntryCommand.getDebits() != null) { throw new RuntimeException(
"You can not pass debits for this rule please verify your rule"); }
final GLAccount debitAccountHead = accountingRule.getAccountToDebit();
validateGLAccountForTransaction(debitAccountHead);
final JournalEntry debitEntry = JournalEntry.createNew(office, debitAccountHead, transactionId, manualEntry,
transactionDate, JournalEntryType.DEBIT, amount, description, null, null, referenceNumber);
this.glJournalEntryRepository.saveAndFlush(debitEntry);
}
} else { } else {
saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getDebits(), transactionId, saveAllDebitOrCreditEntries(journalEntryCommand, office, transactionDate, journalEntryCommand.getDebits(), transactionId,
@@ -143,7 +182,76 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
} }
} }
private void validateGLAccountForTransaction(GLAccount creditOrDebitAccountHead) { @SuppressWarnings("null")
private void checkDebitOrCreditAccountsAreValid(final AccountingRule accountingRule, final SingleDebitOrCreditEntryCommand[] credits,
final SingleDebitOrCreditEntryCommand[] debits) {
// Validate the debit and credit arrays are appropriate accounts
List<GLAccountDataForLookup> allowedCreditGLAccounts = new ArrayList<GLAccountDataForLookup>();
List<GLAccountDataForLookup> allowedDebitGLAccounts = new ArrayList<GLAccountDataForLookup>();
final SingleDebitOrCreditEntryCommand[] validCredits = new SingleDebitOrCreditEntryCommand[credits.length];
final SingleDebitOrCreditEntryCommand[] validDebits = new SingleDebitOrCreditEntryCommand[debits.length];
if (credits != null && credits.length > 0) {
allowedCreditGLAccounts = this.glAccountReadPlatformService.retrieveAccountsByTagId(accountingRule.getId(),
JournalEntryType.CREDIT.getValue());
for (final GLAccountDataForLookup accountDataForLookup : allowedCreditGLAccounts) {
for (int i = 0; i < credits.length; i++) {
final SingleDebitOrCreditEntryCommand credit = credits[i];
if (credit.getGlAccountId().equals(accountDataForLookup.getId())) {
validCredits[i] = credit;
}
}
}
if (credits.length != validCredits.length) { throw new RuntimeException("Invalid credits"); }
}
if (debits != null && debits.length > 0) {
allowedDebitGLAccounts = this.glAccountReadPlatformService.retrieveAccountsByTagId(accountingRule.getId(),
JournalEntryType.DEBIT.getValue());
for (final GLAccountDataForLookup accountDataForLookup : allowedDebitGLAccounts) {
for (int i = 0; i < debits.length; i++) {
final SingleDebitOrCreditEntryCommand debit = debits[i];
if (debit.getGlAccountId().equals(accountDataForLookup.getId())) {
validDebits[i] = debit;
}
}
}
if (debits.length != validDebits.length) { throw new RuntimeException("Invalid debits"); }
}
}
private void checkDebitAndCreditAmounts(final SingleDebitOrCreditEntryCommand[] credits, final SingleDebitOrCreditEntryCommand[] debits) {
// sum of all debits must be = sum of all credits
BigDecimal creditsSum = BigDecimal.ZERO;
BigDecimal debitsSum = BigDecimal.ZERO;
for (final SingleDebitOrCreditEntryCommand creditEntryCommand : credits) {
if (creditEntryCommand.getAmount() == null || creditEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
creditsSum = creditsSum.add(creditEntryCommand.getAmount());
}
for (final SingleDebitOrCreditEntryCommand debitEntryCommand : debits) {
if (debitEntryCommand.getAmount() == null || debitEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
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 JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null, null, null); }
}
private void checkDebitAndCreditAmounts(final SingleDebitOrCreditEntryCommand[] creditOrDebits, final BigDecimal amount) {
if (amount == null) { throw new JournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT,
null, null, null); }
BigDecimal creditOrDebitSum = BigDecimal.ZERO;
for (final SingleDebitOrCreditEntryCommand creditEntryCommand : creditOrDebits) {
if (creditEntryCommand.getAmount() == null || creditEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
creditOrDebitSum = creditOrDebitSum.add(creditEntryCommand.getAmount());
}
if (creditOrDebitSum.compareTo(amount) != 0) { throw new JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null, null, null); }
}
private void validateGLAccountForTransaction(final GLAccount creditOrDebitAccountHead) {
/*** /***
* validate that the account allows manual adjustments and is not * validate that the account allows manual adjustments and is not
* disabled * disabled
@@ -199,7 +307,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled"); final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled");
if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) { if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) {
final LoanDTO loanDTO = helper.populateLoanDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled, final LoanDTO loanDTO = this.helper.populateLoanDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
accrualBasedAccountingEnabled); accrualBasedAccountingEnabled);
final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory final AccountingProcessorForLoan accountingProcessorForLoan = this.accountingProcessorForLoanFactory
.determineProcessor(loanDTO); .determineProcessor(loanDTO);
@@ -209,13 +317,13 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
@Transactional @Transactional
@Override @Override
public void createJournalEntriesForSavings(Map<String, Object> accountingBridgeData) { public void createJournalEntriesForSavings(final Map<String, Object> accountingBridgeData) {
final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled"); final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled");
final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled"); final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled");
if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) { if (cashBasedAccountingEnabled || accrualBasedAccountingEnabled) {
final SavingsDTO savingsDTO = helper.populateSavingsDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled, final SavingsDTO savingsDTO = this.helper.populateSavingsDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled,
accrualBasedAccountingEnabled); accrualBasedAccountingEnabled);
final AccountingProcessorForSavings accountingProcessorForSavings = this.accountingProcessorForSavingsFactory final AccountingProcessorForSavings accountingProcessorForSavings = this.accountingProcessorForSavingsFactory
.determineProcessor(savingsDTO); .determineProcessor(savingsDTO);
@@ -247,21 +355,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
if ((credits == null || credits.length <= 0) || (debits == null || debits.length <= 0)) { throw new JournalEntryInvalidException( if ((credits == null || credits.length <= 0) || (debits == null || debits.length <= 0)) { throw new JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null, null, null); } GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null, null, null); }
// sum of all debits must be = sum of all credits checkDebitAndCreditAmounts(credits, debits);
BigDecimal creditsSum = BigDecimal.ZERO;
BigDecimal debitsSum = BigDecimal.ZERO;
for (final SingleDebitOrCreditEntryCommand creditEntryCommand : credits) {
if (creditEntryCommand.getAmount() == null || creditEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, null, null, null); }
creditsSum = creditsSum.add(creditEntryCommand.getAmount());
}
for (final SingleDebitOrCreditEntryCommand debitEntryCommand : debits) {
if (debitEntryCommand.getAmount() == null || debitEntryCommand.getGlAccountId() == null) { throw new JournalEntryInvalidException(
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 JournalEntryInvalidException(
GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null, null, null); }
} }
} }
@@ -24,10 +24,10 @@ public class AccountingTagRule extends AbstractPersistable<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "tag_id", nullable = false) @JoinColumn(name = "tag_id", nullable = false)
private final CodeValue tagId; private CodeValue tagId;
@Column(name = "acc_type_enum", nullable = false) @Column(name = "acc_type_enum", nullable = false)
private final Integer accountType; private Integer accountType;
public static AccountingTagRule create(final CodeValue tagId, final Integer accountType) { public static AccountingTagRule create(final CodeValue tagId, final Integer accountType) {
return new AccountingTagRule(tagId, accountType); return new AccountingTagRule(tagId, accountType);
@@ -42,4 +42,12 @@ public class AccountingTagRule extends AbstractPersistable<Long> {
this.accountingRule = accountingRule; this.accountingRule = accountingRule;
} }
public AccountingTagRule() {
// TODO Auto-generated constructor stub
}
public Integer getAccountType() {
return this.accountType;
}
} }
@@ -21,6 +21,7 @@ import org.mifosplatform.accounting.rule.domain.AccountingTagRule;
import org.mifosplatform.accounting.rule.exception.AccountingRuleDuplicateException; import org.mifosplatform.accounting.rule.exception.AccountingRuleDuplicateException;
import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository; import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository;
import org.mifosplatform.infrastructure.codes.exception.CodeValueNotFoundException;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -109,20 +110,22 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
GLAccount creditAccount = null; GLAccount creditAccount = null;
List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>(); List<AccountingTagRule> accountingTagRules = new ArrayList<AccountingTagRule>();
if (accountToDebitId != null) { if ((accountToDebitId != null && debitTags != null) || (accountToDebitId == null && debitTags == null)) {
// TODO- Throw Appropriate exception
throw new RuntimeException("Please Specify debitTags or accountToDebitId");
} else if (accountToDebitId != null) {
debitAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId); debitAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToDebitId);
} else if (debitTags != null) { } else if (debitTags != null) {
accountingTagRules = saveDebitOrCreditTags(debitTags, JournalEntryType.DEBIT, accountingTagRules); accountingTagRules = saveDebitOrCreditTags(debitTags, JournalEntryType.DEBIT, accountingTagRules);
} else {
throw new RuntimeException("Please Specify debitTags or accountToDebitId");
} }
if (accountToCreditId != null) { if ((accountToCreditId != null && creditTags != null) || (accountToCreditId == null && creditTags == null)) {
creditAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId); // TODO- Throw Appropriate exception
} else if (debitTags != null) {
accountingTagRules = saveDebitOrCreditTags(creditTags, JournalEntryType.CREDIT, accountingTagRules);
} else {
throw new RuntimeException("Please Specify debitTags or accountToDebitId"); throw new RuntimeException("Please Specify debitTags or accountToDebitId");
} else if (accountToCreditId != null) {
creditAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountToCreditId);
} else if (creditTags != null) {
accountingTagRules = saveDebitOrCreditTags(creditTags, JournalEntryType.CREDIT, accountingTagRules);
} }
final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command); final AccountingRule accountingRule = AccountingRule.fromJson(office, debitAccount, creditAccount, command);
@@ -131,6 +134,8 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
return accountingRule; return accountingRule;
} }
// TODO- This update mehtod should update based on new changes made for
// createAccountingRule.
@Transactional @Transactional
@Override @Override
public CommandProcessingResult updateAccountingRule(final Long accountingRuleId, final JsonCommand command) { public CommandProcessingResult updateAccountingRule(final Long accountingRuleId, final JsonCommand command) {
@@ -205,6 +210,7 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
for (final String creditOrDebitTag : creditOrDebitTagArray) { for (final String creditOrDebitTag : creditOrDebitTagArray) {
final Long creditOrDebitTagIdLongValue = Long.valueOf(creditOrDebitTag); final Long creditOrDebitTagIdLongValue = Long.valueOf(creditOrDebitTag);
final CodeValue creditOrDebitAccount = this.codeValueRepository.findOne(creditOrDebitTagIdLongValue); final CodeValue creditOrDebitAccount = this.codeValueRepository.findOne(creditOrDebitTagIdLongValue);
if (creditOrDebitAccount == null) { throw new CodeValueNotFoundException(creditOrDebitTagIdLongValue); }
final AccountingTagRule accountingTagRule = AccountingTagRule.create(creditOrDebitAccount, transactionType.getValue()); final AccountingTagRule accountingTagRule = AccountingTagRule.create(creditOrDebitAccount, transactionType.getValue());
accountingTagRules.add(accountingTagRule); accountingTagRules.add(accountingTagRule);
} }