From 6fc0c1b4a599284b8150f559c78b2aca090e091c Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Tue, 27 May 2014 18:55:30 +0530 Subject: [PATCH 1/2] MIFOSX-695 - accounting changes for account transfers --- ...V171__accounting_changes_for_transfers.sql | 21 ++ .../integrationtests/AccountTransferTest.java | 205 +++++++++++++++--- .../OfficeAccountingMappingsTest.java | 93 ++++++++ .../integrationtests/common/ClientHelper.java | 14 +- .../integrationtests/common/OfficeHelper.java | 38 ++++ .../OfficeAccountMappingBuilder.java | 15 ++ .../OfficeAccountMappingHelper.java | 44 ++++ .../common/savings/AccountTransferHelper.java | 2 +- .../api/OfficeGLAccountsApiResource.java | 158 ++++++++++++++ .../data/OfficeToGLAccountMappingData.java | 47 ++++ .../domain/OfficeToGLAccountMapping.java | 69 ++++++ .../OfficeToGLAccountMappingRepository.java | 23 ++ ...ceToGLAccountMappingRepositoryWrapper.java | 55 +++++ ...fficeToGLAccountMappingFoundException.java | 21 ++ .../MappingUpdateNotSupportedException.java | 19 ++ ...ceToGLAccountMappingNotFoundException.java | 24 ++ ...CreateOfficeToGLAccountMappingHandler.java | 32 +++ ...fficeToGLAccountMappingCommandHandler.java | 31 +++ ...fficeToGLAccountMappingCommandHandler.java | 31 +++ ...OfficeToGLAccountMappingDataValidator.java | 98 +++++++++ ...ToGLAccountMappingReadPlatformService.java | 21 ++ ...AccountMappingReadPlatformServiceImpl.java | 136 ++++++++++++ ...oGLAccountMappingWritePlatformService.java | 19 ++ ...ccountMappingWritePlatformServiceImpl.java | 157 ++++++++++++++ .../common/AccountingConstants.java | 89 +++++++- ...AccountingDropdownReadPlatformService.java | 2 + ...untingDropdownReadPlatformServiceImpl.java | 22 +- .../journalentry/data/LoanTransactionDTO.java | 9 +- .../data/SavingsTransactionDTO.java | 10 +- .../service/AccountingProcessorHelper.java | 185 +++++++++------- ...ccrualBasedAccountingProcessorForLoan.java | 77 +++++-- .../CashBasedAccountingProcessorForLoan.java | 58 +++-- ...ashBasedAccountingProcessorForSavings.java | 105 ++++++--- ...AccountMappingReadPlatformServiceImpl.java | 6 +- .../commands/domain/CommandWrapper.java | 4 + .../service/CommandWrapperBuilder.java | 39 +++- .../SynchronousCommandProcessingService.java | 16 +- ...ountTransfersWritePlatformServiceImpl.java | 22 +- .../portfolio/loanaccount/domain/Loan.java | 5 +- .../domain/LoanAccountDomainService.java | 2 +- .../domain/LoanAccountDomainServiceJpa.java | 18 +- .../LoanAccrualWritePlatformServiceImpl.java | 1 + ...WritePlatformServiceJpaRepositoryImpl.java | 15 +- .../DepositAccountDomainServiceJpa.java | 32 +-- .../savings/domain/SavingsAccount.java | 3 +- .../domain/SavingsAccountDomainService.java | 4 +- .../SavingsAccountDomainServiceJpa.java | 13 +- ...WritePlatformServiceJpaRepositoryImpl.java | 4 +- ...WritePlatformServiceJpaRepositoryImpl.java | 16 +- ...WritePlatformServiceJpaRepositoryImpl.java | 3 +- 50 files changed, 1859 insertions(+), 274 deletions(-) create mode 100755 mifosng-db/migrations/core_db/V171__accounting_changes_for_transfers.sql create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/OfficeAccountingMappingsTest.java create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/OfficeHelper.java create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingBuilder.java create mode 100755 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingHelper.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/api/OfficeGLAccountsApiResource.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/data/OfficeToGLAccountMappingData.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMapping.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepository.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepositoryWrapper.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/DuplicateOfficeToGLAccountMappingFoundException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/MappingUpdateNotSupportedException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/OfficeToGLAccountMappingNotFoundException.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/CreateOfficeToGLAccountMappingHandler.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/DeleteOfficeToGLAccountMappingCommandHandler.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/UpdateOfficeToGLAccountMappingCommandHandler.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/serialization/OfficeToGLAccountMappingDataValidator.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformService.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformServiceImpl.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformService.java create mode 100755 mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformServiceImpl.java diff --git a/mifosng-db/migrations/core_db/V171__accounting_changes_for_transfers.sql b/mifosng-db/migrations/core_db/V171__accounting_changes_for_transfers.sql new file mode 100755 index 000000000..3950e1aa9 --- /dev/null +++ b/mifosng-db/migrations/core_db/V171__accounting_changes_for_transfers.sql @@ -0,0 +1,21 @@ +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'READ_OFFICEGLACCOUNT', 'OFFICEGLACCOUNT', 'READ', 0); + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'CREATE_OFFICEGLACCOUNT', 'OFFICEGLACCOUNT', 'CREATE', 0); + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'DELETE_OFFICEGLACCOUNT', 'OFFICEGLACCOUNT', 'DELETE', 0); + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('accounting', 'UPDATE_OFFICEGLACCOUNT', 'OFFICEGLACCOUNT', 'UPDATE', 0); + +CREATE TABLE `acc_gl_office_mapping` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `gl_account_id` BIGINT(20) NOT NULL DEFAULT '0', + `office_id` BIGINT(20) NOT NULL, + `financial_account_type` SMALLINT(5) NOT NULL, + PRIMARY KEY (`id`), + INDEX `FK_office_mapping_acc_gl_account` (`gl_account_id`), + INDEX `FK_office_mapping_office` (`office_id`), + CONSTRAINT `FK_office_mapping_acc_gl_account` FOREIGN KEY (`gl_account_id`) REFERENCES `acc_gl_account` (`id`), + CONSTRAINT `FK_office_mapping_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB; diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountTransferTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountTransferTest.java index 82a70f19e..c7befd2a3 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountTransferTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountTransferTest.java @@ -13,7 +13,13 @@ import org.junit.Before; import org.junit.Test; import org.mifosplatform.integrationtests.common.ClientHelper; import org.mifosplatform.integrationtests.common.CommonConstants; +import org.mifosplatform.integrationtests.common.OfficeHelper; import org.mifosplatform.integrationtests.common.Utils; +import org.mifosplatform.integrationtests.common.accounting.Account; +import org.mifosplatform.integrationtests.common.accounting.AccountHelper; +import org.mifosplatform.integrationtests.common.accounting.JournalEntry; +import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper; +import org.mifosplatform.integrationtests.common.accounting.OfficeAccountMappingHelper; import org.mifosplatform.integrationtests.common.charges.ChargesHelper; import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder; import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder; @@ -54,6 +60,8 @@ public class AccountTransferTest { private SavingsAccountHelper savingsAccountHelper; private AccountTransferHelper accountTransferHelper; private LoanTransactionHelper loanTransactionHelper; + private AccountHelper accountHelper; + private JournalEntryHelper journalEntryHelper; Float TRANSFER_AMOUNT = new Float(ACCOUNT_TRANSFER_AMOUNT); Float TRANSFER_AMOUNT_ADJUST = new Float(ACCOUNT_TRANSFER_AMOUNT_ADJUST); @@ -64,6 +72,8 @@ public class AccountTransferTest { this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); + this.journalEntryHelper = new JournalEntryHelper(this.requestSpec, this.responseSpec); } @Test @@ -71,11 +81,31 @@ public class AccountTransferTest { this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.accountTransferHelper = new AccountTransferHelper(this.requestSpec, this.responseSpec); + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + + OfficeHelper officeHelper = new OfficeHelper(this.requestSpec, this.responseSpec); + Integer toOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(toOfficeId); + // Creating Savings Account to which fund to be Transferred - final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(toOfficeId)); Assert.assertNotNull(toClientID); - final Integer toSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + Account toTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(toTransferAccount); + + OfficeAccountMappingHelper accountMappingHelper = new OfficeAccountMappingHelper(this.requestSpec, + new ResponseSpecBuilder().build()); + Integer toTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(toOfficeId, + toTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(toTransferAccountMappingId); + + final Integer toSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, assetAccount, + incomeAccount, expenseAccount, liabilityAccount); Assert.assertNotNull(toSavingsProductID); final Integer toSavingsID = this.savingsAccountHelper.applyForSavingsApplication(toClientID, toSavingsProductID, @@ -93,11 +123,23 @@ public class AccountTransferTest { final HashMap toSavingsSummaryBefore = this.savingsAccountHelper.getSavingsSummary(toSavingsID); + Integer fromOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(fromOfficeId); + // Creating Savings Account from which the Fund has to be Transferred - final Integer fromClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + final Integer fromClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(fromOfficeId)); Assert.assertNotNull(fromClientID); - final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + Account fromTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(fromTransferAccount); + + Integer fromTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(fromOfficeId, + fromTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(fromTransferAccountMappingId); + + final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + assetAccount, incomeAccount, expenseAccount, liabilityAccount); Assert.assertNotNull(fromSavingsProductID); final Integer fromSavingsID = this.savingsAccountHelper.applyForSavingsApplication(fromClientID, fromSavingsProductID, @@ -118,7 +160,7 @@ public class AccountTransferTest { Float fromSavingsBalance = new Float(MINIMUM_OPENING_BALANCE); Float toSavingsBalance = new Float(MINIMUM_OPENING_BALANCE); - this.accountTransferHelper.accountTransfer(fromClientID, fromSavingsID, toClientID, toSavingsID, FROM_SAVINGS_ACCOUNT_TYPE, + this.accountTransferHelper.accountTransfer(fromClientID, fromSavingsID, fromClientID, toSavingsID, FROM_SAVINGS_ACCOUNT_TYPE, TO_SAVINGS_ACCOUNT_TYPE, ACCOUNT_TRANSFER_AMOUNT); fromSavingsBalance -= new Float(ACCOUNT_TRANSFER_AMOUNT); @@ -131,19 +173,53 @@ public class AccountTransferTest { HashMap toSavingsSummaryAfter = this.savingsAccountHelper.getSavingsSummary(toSavingsID); assertEquals("Verifying To Savings Account Balance after Account Transfer", toSavingsBalance, toSavingsSummaryAfter.get("accountBalance")); + final JournalEntry[] office1LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT), + JournalEntry.TransactionType.CREDIT) }; + final JournalEntry[] office2LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT), + JournalEntry.TransactionType.DEBIT) }; + + this.journalEntryHelper.checkJournalEntryForAssetAccount(fromTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office1LiabilityEntries); + this.journalEntryHelper.checkJournalEntryForAssetAccount(toTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office2LiabilityEntries); + } @Test public void testFromSavingsToLoanAccountTransfer() { + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + + final Account loanAssetAccount = this.accountHelper.createAssetAccount(); + final Account loanIncomeAccount = this.accountHelper.createIncomeAccount(); + final Account loanExpenseAccount = this.accountHelper.createExpenseAccount(); + final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); this.accountTransferHelper = new AccountTransferHelper(this.requestSpec, this.responseSpec); - // Creating Loan Account to which Fund to be Transferred. - final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + OfficeHelper officeHelper = new OfficeHelper(this.requestSpec, this.responseSpec); + Integer toOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(toOfficeId); + + // Creating Loan Account to which fund to be Transferred + final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(toOfficeId)); Assert.assertNotNull(toClientID); - final Integer toLoanProductID = createLoanProduct(); + Account toTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(toTransferAccount); + + OfficeAccountMappingHelper accountMappingHelper = new OfficeAccountMappingHelper(this.requestSpec, + new ResponseSpecBuilder().build()); + Integer toTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(toOfficeId, + toTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(toTransferAccountMappingId); + + final Integer toLoanProductID = createLoanProduct(loanAssetAccount, loanIncomeAccount, loanExpenseAccount, overpaymentAccount); Assert.assertNotNull(toLoanProductID); final Integer toLoanID = applyForLoanApplication(toClientID, toLoanProductID); @@ -158,11 +234,23 @@ public class AccountTransferTest { toLoanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSAL_DATE, toLoanID); LoanStatusChecker.verifyLoanIsActive(toLoanStatusHashMap); - // Creating Savings Account from which Fund to be Transferred - final Integer fromClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + Integer fromOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(fromOfficeId); + + // Creating Savings Account from which the Fund has to be Transferred + final Integer fromClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(fromOfficeId)); Assert.assertNotNull(fromClientID); - final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + Account fromTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(fromTransferAccount); + + Integer fromTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(fromOfficeId, + fromTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(fromTransferAccountMappingId); + + final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + assetAccount, incomeAccount, expenseAccount, liabilityAccount); Assert.assertNotNull(fromSavingsProductID); final Integer fromSavingsID = this.savingsAccountHelper.applyForSavingsApplication(fromClientID, fromSavingsProductID, @@ -192,20 +280,56 @@ public class AccountTransferTest { fromSavingsSummaryAfter.get("accountBalance")); HashMap toLoanSummaryAfter = this.loanTransactionHelper.getLoanSummary(requestSpec, responseSpec, toLoanID); - assertEquals("Verifying To Loan Repayment Amount after Account Transfer", TRANSFER_AMOUNT_ADJUST, toLoanSummaryAfter.get("totalRepayment")); + assertEquals("Verifying To Loan Repayment Amount after Account Transfer", TRANSFER_AMOUNT_ADJUST, + toLoanSummaryAfter.get("totalRepayment")); + + final JournalEntry[] office1LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT_ADJUST), + JournalEntry.TransactionType.CREDIT) }; + final JournalEntry[] office2LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT_ADJUST), + JournalEntry.TransactionType.DEBIT) }; + + this.journalEntryHelper.checkJournalEntryForAssetAccount(fromTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office1LiabilityEntries); + this.journalEntryHelper.checkJournalEntryForAssetAccount(toTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office2LiabilityEntries); } @Test public void testFromLoanToSavingsAccountTransfer() { + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); + + final Account loanAssetAccount = this.accountHelper.createAssetAccount(); + final Account loanIncomeAccount = this.accountHelper.createIncomeAccount(); + final Account loanExpenseAccount = this.accountHelper.createExpenseAccount(); + final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); this.accountTransferHelper = new AccountTransferHelper(this.requestSpec, this.responseSpec); - // Creating Savings Account to which Fund to be Transferred - final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + OfficeHelper officeHelper = new OfficeHelper(this.requestSpec, this.responseSpec); + Integer toOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(toOfficeId); + + // Creating Loan Account to which fund to be Transferred + final Integer toClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(toOfficeId)); Assert.assertNotNull(toClientID); - final Integer toSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + Account toTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(toTransferAccount); + + OfficeAccountMappingHelper accountMappingHelper = new OfficeAccountMappingHelper(this.requestSpec, + new ResponseSpecBuilder().build()); + Integer toTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(toOfficeId, + toTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(toTransferAccountMappingId); + + final Integer toSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, assetAccount, + incomeAccount, expenseAccount, liabilityAccount); Assert.assertNotNull(toSavingsProductID); final Integer toSavingsID = this.savingsAccountHelper.applyForSavingsApplication(toClientID, toSavingsProductID, @@ -221,14 +345,25 @@ public class AccountTransferTest { toSavingsStatusHashMap = this.savingsAccountHelper.activateSavings(toSavingsID); SavingsStatusChecker.verifySavingsIsActive(toSavingsStatusHashMap); - // Creating Loan Account to or from which Fund to be Transferred. - final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); - Assert.assertNotNull(clientID); + Integer fromOfficeId = officeHelper.createOffice("01 January 2011"); + Assert.assertNotNull(fromOfficeId); - final Integer loanProductID = createLoanProduct(); + // Creating Savings Account from which the Fund has to be Transferred + final Integer fromClientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2011", + String.valueOf(fromOfficeId)); + Assert.assertNotNull(fromClientID); + + Account fromTransferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(fromTransferAccount); + + Integer fromTransferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(fromOfficeId, + fromTransferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(fromTransferAccountMappingId); + + final Integer loanProductID = createLoanProduct(loanAssetAccount, loanIncomeAccount, loanExpenseAccount, overpaymentAccount); Assert.assertNotNull(loanProductID); - final Integer loanID = applyForLoanApplication(clientID, loanProductID); + final Integer loanID = applyForLoanApplication(fromClientID, loanProductID); Assert.assertNotNull(loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); @@ -240,14 +375,12 @@ public class AccountTransferTest { loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSAL_DATE, loanID); LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); - // Creating Savings Account from which Fund to be Transferred - final Integer fromClientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); - Assert.assertNotNull(fromClientId); - final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE); + final Integer fromSavingsProductID = createSavingsProduct(this.requestSpec, this.responseSpec, MINIMUM_OPENING_BALANCE, + assetAccount, incomeAccount, expenseAccount, liabilityAccount); Assert.assertNotNull(fromSavingsProductID); - final Integer fromSavingsID = this.savingsAccountHelper.applyForSavingsApplication(fromClientId, fromSavingsProductID, + final Integer fromSavingsID = this.savingsAccountHelper.applyForSavingsApplication(fromClientID, fromSavingsProductID, ACCOUNT_TYPE_INDIVIDUAL); Assert.assertNotNull(fromSavingsID); @@ -264,7 +397,7 @@ public class AccountTransferTest { Float fromSavingsBalance = new Float(MINIMUM_OPENING_BALANCE); - this.accountTransferHelper.accountTransfer(fromClientId, fromSavingsID, clientID, loanID, FROM_SAVINGS_ACCOUNT_TYPE, + this.accountTransferHelper.accountTransfer(fromClientID, fromSavingsID, fromClientID, loanID, FROM_SAVINGS_ACCOUNT_TYPE, TO_LOAN_ACCOUNT_TYPE, ACCOUNT_TRANSFER_AMOUNT); fromSavingsBalance -= TRANSFER_AMOUNT; @@ -277,7 +410,7 @@ public class AccountTransferTest { Float toSavingsBalance = new Float(MINIMUM_OPENING_BALANCE); - this.accountTransferHelper.accountTransfer(clientID, loanID, toClientID, toSavingsID, FROM_LOAN_ACCOUNT_TYPE, + this.accountTransferHelper.accountTransfer(fromClientID, loanID, toClientID, toSavingsID, FROM_LOAN_ACCOUNT_TYPE, TO_SAVINGS_ACCOUNT_TYPE, ACCOUNT_TRANSFER_AMOUNT_ADJUST); toSavingsBalance += TRANSFER_AMOUNT_ADJUST; @@ -287,21 +420,32 @@ public class AccountTransferTest { // Verifying toSavings Account Balance after Account Transfer assertEquals("Verifying From Savings Account Balance after Account Transfer", toSavingsBalance, toSavingsSummaryAfter.get("accountBalance")); + + final JournalEntry[] office1LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT_ADJUST), + JournalEntry.TransactionType.CREDIT) }; + final JournalEntry[] office2LiabilityEntries = { new JournalEntry(new Float(ACCOUNT_TRANSFER_AMOUNT_ADJUST), + JournalEntry.TransactionType.DEBIT) }; + + this.journalEntryHelper.checkJournalEntryForAssetAccount(fromTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office1LiabilityEntries); + this.journalEntryHelper.checkJournalEntryForAssetAccount(toTransferAccount, AccountTransferHelper.ACCOUNT_TRANSFER_DATE, + office2LiabilityEntries); + } private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, - final String minOpenningBalance) { + final String minOpenningBalance, final Account... accounts) { System.out.println("------------------------------CREATING NEW SAVINGS PRODUCT ---------------------------------------"); SavingsProductHelper savingsProductHelper = new SavingsProductHelper(); final String savingsProductJSON = savingsProductHelper // .withInterestCompoundingPeriodTypeAsDaily() // .withInterestPostingPeriodTypeAsMonthly() // .withInterestCalculationPeriodTypeAsDailyBalance() // - .withMinimumOpenningBalance(minOpenningBalance).build(); + .withMinimumOpenningBalance(minOpenningBalance).withAccountingRuleAsCashBased(accounts).build(); return SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec); } - private Integer createLoanProduct() { + private Integer createLoanProduct(final Account... accounts) { System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); final String loanProductJSON = new LoanProductTestBuilder() // .withPrincipal("8,000.00") // @@ -312,6 +456,7 @@ public class AccountTransferTest { .withInterestRateFrequencyTypeAsMonths() // .withAmortizationTypeAsEqualInstallments() // .withInterestTypeAsDecliningBalance() // + .withAccountingRuleAsCashBased(accounts)// .build(null); return this.loanTransactionHelper.getLoanProductId(loanProductJSON); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/OfficeAccountingMappingsTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/OfficeAccountingMappingsTest.java new file mode 100755 index 000000000..cc0d026b0 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/OfficeAccountingMappingsTest.java @@ -0,0 +1,93 @@ +package org.mifosplatform.integrationtests; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.List; + +import junit.framework.Assert; + +import org.junit.Before; +import org.junit.Test; +import org.mifosplatform.integrationtests.common.CommonConstants; +import org.mifosplatform.integrationtests.common.OfficeHelper; +import org.mifosplatform.integrationtests.common.Utils; +import org.mifosplatform.integrationtests.common.accounting.Account; +import org.mifosplatform.integrationtests.common.accounting.AccountHelper; +import org.mifosplatform.integrationtests.common.accounting.OfficeAccountMappingHelper; + +import com.jayway.restassured.builder.RequestSpecBuilder; +import com.jayway.restassured.builder.ResponseSpecBuilder; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +@SuppressWarnings("rawtypes") +public class OfficeAccountingMappingsTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + + @Before + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @SuppressWarnings("unchecked") + @Test + public void testOfficeAccountingMappings() { + + OfficeHelper officeHelper = new OfficeHelper(this.requestSpec, this.responseSpec); + Integer officeId = officeHelper.createOffice("01 January 2014"); + Assert.assertNotNull(officeId); + + Integer officeId2 = officeHelper.createOffice("01 January 2014"); + Assert.assertNotNull(officeId2); + + AccountHelper accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); + Account transferAccount = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(transferAccount); + + OfficeAccountMappingHelper accountMappingHelper = new OfficeAccountMappingHelper(this.requestSpec, + new ResponseSpecBuilder().build()); + Integer transferAccountMappingId = (Integer) accountMappingHelper.createOfficeAccountMapping(officeId, + transferAccount.getAccountID(), CommonConstants.RESPONSE_RESOURCE_ID); + Assert.assertNotNull(transferAccountMappingId); + + HashMap mappingDetails = accountMappingHelper.getOfficeAccountMapping(transferAccountMappingId); + Assert.assertEquals(officeId, ((HashMap) mappingDetails.get("officeData")).get("id")); + Assert.assertEquals(transferAccount.getAccountID(), ((HashMap) mappingDetails.get("glAccountData")).get("id")); + + Account transferAccount2 = accountHelper.createLiabilityAccount(); + Assert.assertNotNull(transferAccount2); + + HashMap changes = (HashMap) accountMappingHelper.updateOfficeAccountMapping(transferAccountMappingId, officeId, + transferAccount2.getAccountID(), CommonConstants.RESPONSE_CHANGES); + Assert.assertEquals(transferAccount2.getAccountID(), changes.get("liabilityTransferInSuspenseAccountId")); + + mappingDetails = accountMappingHelper.getOfficeAccountMapping(transferAccountMappingId); + Assert.assertEquals(officeId, ((HashMap) mappingDetails.get("officeData")).get("id")); + Assert.assertEquals(transferAccount2.getAccountID(), ((HashMap) mappingDetails.get("glAccountData")).get("id")); + + List error1 = (List) accountMappingHelper.updateOfficeAccountMapping(transferAccountMappingId, officeId2, + transferAccount2.getAccountID(), CommonConstants.RESPONSE_ERROR); + assertEquals("error.msg.officeToAccountMapping.update.of.officeId.is.not.supported", + error1.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + List error2 = (List) accountMappingHelper.createOfficeAccountMapping(officeId, transferAccount.getAccountID(), + CommonConstants.RESPONSE_ERROR); + assertEquals("error.msg.officeToAccountMapping.exists.for.office", error2.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + Account fundAccount = accountHelper.createAssetAccount(); + Assert.assertNotNull(fundAccount); + + List error3 = (List) accountMappingHelper.createOfficeAccountMapping(officeId2, fundAccount.getAccountID(), + CommonConstants.RESPONSE_ERROR); + assertEquals("error.msg.liabilityTransferInSuspenseAccountId.invalid.account.type", error3.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + } + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java index 6278dedd5..6442c555e 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java @@ -18,13 +18,19 @@ public class ClientHelper { public static Integer createClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String activationDate) { - System.out.println("---------------------------------CREATING A CLIENT---------------------------------------------"); - return Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, getTestClientAsJSON(activationDate), "clientId"); + return createClient(requestSpec, responseSpec, activationDate, "1"); } - public static String getTestClientAsJSON(final String dateOfJoining) { + public static Integer createClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String activationDate, final String officeId) { + System.out.println("---------------------------------CREATING A CLIENT---------------------------------------------"); + return Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, getTestClientAsJSON(activationDate, officeId), + "clientId"); + } + + public static String getTestClientAsJSON(final String dateOfJoining, final String officeId) { final HashMap map = new HashMap(); - map.put("officeId", "1"); + map.put("officeId", officeId); map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); map.put("externalId", randomIDGenerator("ID_", 7)); diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/OfficeHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/OfficeHelper.java new file mode 100755 index 000000000..b62c78eb3 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/OfficeHelper.java @@ -0,0 +1,38 @@ +package org.mifosplatform.integrationtests.common; + +import java.util.HashMap; + +import com.google.gson.Gson; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + + +public class OfficeHelper { + + private static final String OFFICE_URL = "/mifosng-provider/api/v1/offices"; + private final RequestSpecification requestSpec; + private final ResponseSpecification responseSpec; + + public OfficeHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { + this.requestSpec = requestSpec; + this.responseSpec = responseSpec; + } + + public Integer createOffice(final String openingDate) { + String json = getAsJSON(openingDate); + return Utils.performServerPost(this.requestSpec, this.responseSpec, OFFICE_URL + "?" + Utils.TENANT_IDENTIFIER, json, + CommonConstants.RESPONSE_RESOURCE_ID); + } + + + public static String getAsJSON(final String openingDate) { + final HashMap map = new HashMap(); + map.put("parentId", "1"); + map.put("name", Utils.randomNameGenerator("Office_", 4)); + map.put("dateFormat", "dd MMMM yyyy"); + map.put("locale", "en"); + map.put("openingDate", openingDate); + System.out.println("map : " + map); + return new Gson().toJson(map); + } +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingBuilder.java new file mode 100755 index 000000000..1fbdc24a8 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingBuilder.java @@ -0,0 +1,15 @@ +package org.mifosplatform.integrationtests.common.accounting; + +import java.util.HashMap; + +import com.google.gson.Gson; + +public class OfficeAccountMappingBuilder { + + public static String build(Integer officeId, Integer glAccountId) { + final HashMap map = new HashMap(); + map.put("officeId", officeId); + map.put("liabilityTransferInSuspenseAccountId", glAccountId); + return new Gson().toJson(map); + } +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingHelper.java new file mode 100755 index 000000000..a0e232caa --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/OfficeAccountMappingHelper.java @@ -0,0 +1,44 @@ +package org.mifosplatform.integrationtests.common.accounting; + +import java.util.HashMap; + +import org.mifosplatform.integrationtests.common.Utils; + +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +@SuppressWarnings("rawtypes") +public class OfficeAccountMappingHelper { + + private static final String ACCOUNT_MAPPING_URL = "/mifosng-provider/api/v1/officeglaccounts"; + private final RequestSpecification requestSpec; + private final ResponseSpecification responseSpec; + + public OfficeAccountMappingHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { + this.requestSpec = requestSpec; + this.responseSpec = responseSpec; + } + + public Object createOfficeAccountMapping(Integer officeId, Integer glAccountId, String jsonBack) { + String json = OfficeAccountMappingBuilder.build(officeId, glAccountId); + return Utils.performServerPost(this.requestSpec, this.responseSpec, ACCOUNT_MAPPING_URL + "?" + Utils.TENANT_IDENTIFIER, json, + jsonBack); + } + + public Object updateOfficeAccountMapping(Integer mappingId, Integer officeId, Integer glAccountId, String jsonBack) { + String json = OfficeAccountMappingBuilder.build(officeId, glAccountId); + return Utils.performServerPut(this.requestSpec, this.responseSpec, ACCOUNT_MAPPING_URL + "/" + mappingId + "?" + + Utils.TENANT_IDENTIFIER, json, jsonBack); + } + + public HashMap getOfficeAccountMapping(final Integer mappingId) { + final String URL = ACCOUNT_MAPPING_URL + "/" + mappingId + "?" + Utils.TENANT_IDENTIFIER; + return Utils.performServerGet(requestSpec, responseSpec, URL, ""); + } + + public HashMap getOfficeAccountMappings() { + final String URL = ACCOUNT_MAPPING_URL + "?" + Utils.TENANT_IDENTIFIER; + return Utils.performServerGet(requestSpec, responseSpec, URL, ""); + } + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/AccountTransferHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/AccountTransferHelper.java index 248bafe5a..e640afa08 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/AccountTransferHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/savings/AccountTransferHelper.java @@ -14,7 +14,7 @@ public class AccountTransferHelper { private static final String LOCALE = "en_GB"; private static final String OFFICE_ID = "1"; private static final String TRANSFER_DESCRIPTION = "Transfer"; - private static final String ACCOUNT_TRANSFER_DATE = "01 March 2013"; + public static final String ACCOUNT_TRANSFER_DATE = "01 March 2013"; private String transferDate = ""; private String officeId = OFFICE_ID; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/api/OfficeGLAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/api/OfficeGLAccountsApiResource.java new file mode 100755 index 000000000..68441d7f0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/api/OfficeGLAccountsApiResource.java @@ -0,0 +1,158 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.api; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +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.accountmapping.data.OfficeToGLAccountMappingData; +import org.mifosplatform.accounting.accountmapping.service.OfficeToGLAccountMappingReadPlatformService; +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.commands.service.CommandWrapperBuilder; +import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.portfolio.group.service.SearchParameters; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path("/officeglaccounts") +@Component +@Scope("singleton") +public class OfficeGLAccountsApiResource { + + private static final Set RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "officeData", "glAccountData", + "accountingMappingOptions", "officeOptions")); + + private final String resourceNameForPermission = "OFFICEGLACCOUNT"; + + private final OfficeToGLAccountMappingReadPlatformService officeToGLAccountMappingReadPlatformService; + private final DefaultToApiJsonSerializer apiJsonSerializerService; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final PlatformSecurityContext context; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + + @Autowired + public OfficeGLAccountsApiResource(final PlatformSecurityContext context, + final OfficeToGLAccountMappingReadPlatformService officeToGLAccountMappingReadPlatformService, + final DefaultToApiJsonSerializer toApiJsonSerializer, + final ApiRequestParameterHelper apiRequestParameterHelper, + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + this.context = context; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + this.apiJsonSerializerService = toApiJsonSerializer; + this.officeToGLAccountMappingReadPlatformService = officeToGLAccountMappingReadPlatformService; + } + + @GET + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveTemplate(@Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + + OfficeToGLAccountMappingData officeToGLAccountMappingData = this.officeToGLAccountMappingReadPlatformService.retrieveTemplate(); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.apiJsonSerializerService.serialize(settings, officeToGLAccountMappingData, RESPONSE_DATA_PARAMETERS); + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("sqlSearch") final String sqlSearch, + @QueryParam("externalId") final String externalId, @QueryParam("offset") final Integer offset, + @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy, + @QueryParam("sortOrder") final String sortOrder) { + + this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + final SearchParameters searchParameters = SearchParameters.forAccountTransfer(sqlSearch, externalId, offset, limit, orderBy, + sortOrder); + final Page mappings = this.officeToGLAccountMappingReadPlatformService.retrieveAll(searchParameters); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.apiJsonSerializerService.serialize(settings, mappings, RESPONSE_DATA_PARAMETERS); + } + + @GET + @Path("{mappingId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retreiveAccountMapping(@PathParam("mappingId") final Long mappingId, @Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + OfficeToGLAccountMappingData officeToGLAccountMappingData = this.officeToGLAccountMappingReadPlatformService.retrieve(mappingId); + if (settings.isTemplate()) { + OfficeToGLAccountMappingData templateData = this.officeToGLAccountMappingReadPlatformService.retrieveTemplate(); + officeToGLAccountMappingData = OfficeToGLAccountMappingData.associateTemplateData(templateData, officeToGLAccountMappingData); + } + + return this.apiJsonSerializerService.serialize(settings, officeToGLAccountMappingData, RESPONSE_DATA_PARAMETERS); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String createGLAccount(final String jsonRequestBody) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().createOfficeToGLAccountMapping().withJson(jsonRequestBody) + .build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.apiJsonSerializerService.serialize(result); + } + + @PUT + @Path("{mappingId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String updateGLAccount(@PathParam("mappingId") final Long mappingId, final String jsonRequestBody) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().updateOfficeToGLAccountMapping(mappingId) + .withJson(jsonRequestBody).build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.apiJsonSerializerService.serialize(result); + } + + @DELETE + @Path("{mappingId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String deleteGLAccount(@PathParam("mappingId") final Long mappingId) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteOfficeToGLAccountMapping(mappingId).build(); + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.apiJsonSerializerService.serialize(result); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/data/OfficeToGLAccountMappingData.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/data/OfficeToGLAccountMappingData.java new file mode 100755 index 000000000..f542a3b06 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/data/OfficeToGLAccountMappingData.java @@ -0,0 +1,47 @@ +package org.mifosplatform.accounting.accountmapping.data; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.mifosplatform.accounting.glaccount.data.GLAccountData; +import org.mifosplatform.organisation.office.data.OfficeData; + +public class OfficeToGLAccountMappingData { + + private final Long id; + private final OfficeData officeData; + private final GLAccountData glAccountData; + private final Map> accountingMappingOptions; + private final Collection officeOptions; + + public static OfficeToGLAccountMappingData instance(final Long id, final OfficeData officeData, final GLAccountData glAccountData) { + final Map> accountingMappingOptions = null; + final Collection officeOptions = null; + return new OfficeToGLAccountMappingData(id, officeData, glAccountData, accountingMappingOptions, officeOptions); + } + + public static OfficeToGLAccountMappingData template(final Map> accountingMappingOptions, + final Collection officeOptions) { + final Long id = null; + final OfficeData officeData = null; + final GLAccountData glAccountData = null; + return new OfficeToGLAccountMappingData(id, officeData, glAccountData, accountingMappingOptions, officeOptions); + } + + public static OfficeToGLAccountMappingData associateTemplateData(final OfficeToGLAccountMappingData templateData, + final OfficeToGLAccountMappingData accountMappingData) { + return new OfficeToGLAccountMappingData(accountMappingData.id, accountMappingData.officeData, accountMappingData.glAccountData, + templateData.accountingMappingOptions, templateData.officeOptions); + } + + private OfficeToGLAccountMappingData(final Long id, final OfficeData officeData, final GLAccountData glAccountData, + final Map> accountingMappingOptions, final Collection officeOptions) { + this.id = id; + this.officeData = officeData; + this.glAccountData = glAccountData; + this.accountingMappingOptions = accountingMappingOptions; + this.officeOptions = officeOptions; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMapping.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMapping.java new file mode 100755 index 000000000..f6e0ef642 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMapping.java @@ -0,0 +1,69 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.domain; + +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 org.mifosplatform.accounting.glaccount.domain.GLAccount; +import org.mifosplatform.organisation.office.domain.Office; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = "acc_gl_office_mapping") +public class OfficeToGLAccountMapping extends AbstractPersistable { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "gl_account_id") + private GLAccount glAccount; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "office_id") + private Office office; + + @Column(name = "financial_account_type", nullable = false) + private int financialAccountType; + + public static OfficeToGLAccountMapping createNew(final GLAccount glAccount, final Office office, final int financialAccountType) { + return new OfficeToGLAccountMapping(glAccount, office, financialAccountType); + } + + protected OfficeToGLAccountMapping() { + // + } + + private OfficeToGLAccountMapping(final GLAccount glAccount, final Office office, final int financialAccountType) { + this.glAccount = glAccount; + this.office = office; + this.financialAccountType = financialAccountType; + } + + public GLAccount glAccount() { + return this.glAccount; + } + + public void updateGlAccount(final GLAccount glAccount) { + this.glAccount = glAccount; + } + + public Office office() { + return this.office; + } + + public void updateOffice(Office office) { + this.office = office; + } + + public int getFinancialAccountType() { + return this.financialAccountType; + } + + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepository.java new file mode 100755 index 000000000..31eb0995d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepository.java @@ -0,0 +1,23 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.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 OfficeToGLAccountMappingRepository extends JpaRepository, + JpaSpecificationExecutor { + + @Query("from OfficeToGLAccountMapping otga where otga.office.id = :officeId and otga.financialAccountType = :financialAccountType") + OfficeToGLAccountMapping findByOfficeAndFinancialAccountType(@Param("officeId")Long officeId,@Param("financialAccountType") int financialAccountType); + + @Query("from OfficeToGLAccountMapping otga where otga.office.id =:officeId") + List findByOffice(@Param("officeId")Long officeId); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepositoryWrapper.java new file mode 100755 index 000000000..0e5c12d08 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/domain/OfficeToGLAccountMappingRepositoryWrapper.java @@ -0,0 +1,55 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.domain; + +import java.util.List; + +import org.mifosplatform.accounting.accountmapping.exception.OfficeToGLAccountMappingNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + *

+ * Wrapper for {@link OfficeToGLAccountMappingRepository} that adds NULL + * checking and Error handling capabilities + *

+ */ +@Service +public class OfficeToGLAccountMappingRepositoryWrapper { + + private final OfficeToGLAccountMappingRepository repository; + + @Autowired + public OfficeToGLAccountMappingRepositoryWrapper(final OfficeToGLAccountMappingRepository repository) { + this.repository = repository; + } + + public OfficeToGLAccountMapping findOneWithNotFoundDetection(final Long id) { + final OfficeToGLAccountMapping officeToGLAccountMapping = this.repository.findOne(id); + if (officeToGLAccountMapping == null) { throw new OfficeToGLAccountMappingNotFoundException(id); } + return officeToGLAccountMapping; + } + + public OfficeToGLAccountMapping findByOfficeAndFinancialAccountType(final Long officeId, final int financialAccountType) { + return this.repository.findByOfficeAndFinancialAccountType(officeId, financialAccountType); + } + + public List findByOffice(final Long officeId) { + return this.repository.findByOffice(officeId); + } + + public void save(final OfficeToGLAccountMapping entity) { + this.repository.save(entity); + } + + public void saveAndFlush(final OfficeToGLAccountMapping entity) { + this.repository.saveAndFlush(entity); + } + + public void delete(final OfficeToGLAccountMapping entity) { + this.repository.delete(entity); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/DuplicateOfficeToGLAccountMappingFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/DuplicateOfficeToGLAccountMappingFoundException.java new file mode 100755 index 000000000..dee5821e9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/DuplicateOfficeToGLAccountMappingFoundException.java @@ -0,0 +1,21 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when product to GL account mapping are not + * found. + */ +public class DuplicateOfficeToGLAccountMappingFoundException extends AbstractPlatformDomainRuleException { + + public DuplicateOfficeToGLAccountMappingFoundException(final Long officeId, final Integer accountType) { + super("error.msg.officeToAccountMapping.exists.for.office", "Mapping for office with Id " + officeId + + " exist for an account of type " + accountType, officeId, accountType); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/MappingUpdateNotSupportedException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/MappingUpdateNotSupportedException.java new file mode 100755 index 000000000..4088c59f7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/MappingUpdateNotSupportedException.java @@ -0,0 +1,19 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +/** + * A {@link RuntimeException} thrown when Calendar resources are not found. + */ +public class MappingUpdateNotSupportedException extends AbstractPlatformDomainRuleException { + + public MappingUpdateNotSupportedException(final String postFix, final String defaultUserMessage, + final Object... defaultUserMessageArgs) { + super("error.msg.officeToAccountMapping.update.of." + postFix + ".is.not.supported", defaultUserMessage, defaultUserMessageArgs); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/OfficeToGLAccountMappingNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/OfficeToGLAccountMappingNotFoundException.java new file mode 100755 index 000000000..6d61a52da --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/exception/OfficeToGLAccountMappingNotFoundException.java @@ -0,0 +1,24 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when product to GL account mapping are not + * found. + */ +public class OfficeToGLAccountMappingNotFoundException extends AbstractPlatformResourceNotFoundException { + + public OfficeToGLAccountMappingNotFoundException(final Long officeId, final String accountType) { + super("error.msg.officeToAccountMapping.not.found", "Mapping for office with Id " + officeId + + " does not exist for an account of type " + accountType, officeId, accountType); + } + + public OfficeToGLAccountMappingNotFoundException(final Long id) { + super("error.msg.officeToAccountMapping.not.found", "Mapping for GL Account with Id " + id + " does not exist", id); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/CreateOfficeToGLAccountMappingHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/CreateOfficeToGLAccountMappingHandler.java new file mode 100755 index 000000000..4c2cd4e6e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/CreateOfficeToGLAccountMappingHandler.java @@ -0,0 +1,32 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.handler; + +import org.mifosplatform.accounting.accountmapping.service.OfficeToGLAccountMappingWritePlatformService; +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class CreateOfficeToGLAccountMappingHandler implements NewCommandSourceHandler { + + private final OfficeToGLAccountMappingWritePlatformService writePlatformService; + + @Autowired + public CreateOfficeToGLAccountMappingHandler(final OfficeToGLAccountMappingWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + + return this.writePlatformService.createGLAccountMapping(command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/DeleteOfficeToGLAccountMappingCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/DeleteOfficeToGLAccountMappingCommandHandler.java new file mode 100755 index 000000000..9f4b4bc9d --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/DeleteOfficeToGLAccountMappingCommandHandler.java @@ -0,0 +1,31 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.handler; + +import org.mifosplatform.accounting.accountmapping.service.OfficeToGLAccountMappingWritePlatformService; +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DeleteOfficeToGLAccountMappingCommandHandler implements NewCommandSourceHandler { + + private final OfficeToGLAccountMappingWritePlatformService writePlatformService; + + @Autowired + public DeleteOfficeToGLAccountMappingCommandHandler(final OfficeToGLAccountMappingWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.deleteGLAccountMapping(command.entityId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/UpdateOfficeToGLAccountMappingCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/UpdateOfficeToGLAccountMappingCommandHandler.java new file mode 100755 index 000000000..3df80362f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/handler/UpdateOfficeToGLAccountMappingCommandHandler.java @@ -0,0 +1,31 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.handler; + +import org.mifosplatform.accounting.accountmapping.service.OfficeToGLAccountMappingWritePlatformService; +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class UpdateOfficeToGLAccountMappingCommandHandler implements NewCommandSourceHandler { + + private final OfficeToGLAccountMappingWritePlatformService writePlatformService; + + @Autowired + public UpdateOfficeToGLAccountMappingCommandHandler(final OfficeToGLAccountMappingWritePlatformService writePlatformService) { + this.writePlatformService = writePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.writePlatformService.updateGLAccountMapping(command.entityId(), command); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/serialization/OfficeToGLAccountMappingDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/serialization/OfficeToGLAccountMappingDataValidator.java new file mode 100755 index 000000000..8c5f35c13 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/serialization/OfficeToGLAccountMappingDataValidator.java @@ -0,0 +1,98 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.serialization; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTING_PARAMS; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +@Component +public final class OfficeToGLAccountMappingDataValidator { + + /** + * The parameters supported for this command. + */ + private final Set supportedParameters = new HashSet(Arrays.asList("locale", + ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), "officeId")); + + private final FromJsonHelper fromApiJsonHelper; + + @Autowired + public OfficeToGLAccountMappingDataValidator(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateForCreate(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproduct"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final Long liabilityTransferInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed( + ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), element); + baseDataValidator.reset().parameter(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue()) + .value(liabilityTransferInSuspenseAccountId).notNull().integerGreaterThanZero(); + + final Long officeID = this.fromApiJsonHelper.extractLongNamed("officeId", element); + baseDataValidator.reset().parameter("officeId").value(officeID).notNull().integerGreaterThanZero(); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + public void validateForUpdate(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); + + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loanproduct"); + + final JsonElement element = this.fromApiJsonHelper.parse(json); + + if (this.fromApiJsonHelper.parameterExists(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), element)) { + final Long liabilityTransferInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed( + ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), element); + baseDataValidator.reset().parameter(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue()) + .value(liabilityTransferInSuspenseAccountId).notNull().integerGreaterThanZero(); + } + + if (this.fromApiJsonHelper.parameterExists("officeId", element)) { + final Long officeID = this.fromApiJsonHelper.extractLongNamed("officeId", element); + baseDataValidator.reset().parameter("officeId").value(officeID).notNull().integerGreaterThanZero(); + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformService.java new file mode 100755 index 000000000..15f5718d5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformService.java @@ -0,0 +1,21 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.service; + + +import org.mifosplatform.accounting.accountmapping.data.OfficeToGLAccountMappingData; +import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.portfolio.group.service.SearchParameters; + +public interface OfficeToGLAccountMappingReadPlatformService { + + Page retrieveAll(final SearchParameters searchParameters); + + OfficeToGLAccountMappingData retrieve(Long mappingId); + + OfficeToGLAccountMappingData retrieveTemplate(); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformServiceImpl.java new file mode 100755 index 000000000..ee70cbfd0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingReadPlatformServiceImpl.java @@ -0,0 +1,136 @@ +package org.mifosplatform.accounting.accountmapping.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.joda.time.LocalDate; +import org.mifosplatform.accounting.accountmapping.data.OfficeToGLAccountMappingData; +import org.mifosplatform.accounting.accountmapping.exception.OfficeToGLAccountMappingNotFoundException; +import org.mifosplatform.accounting.common.AccountingDropdownReadPlatformService; +import org.mifosplatform.accounting.glaccount.data.GLAccountData; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.PaginationHelper; +import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.mifosplatform.organisation.office.data.OfficeData; +import org.mifosplatform.organisation.office.service.OfficeReadPlatformService; +import org.mifosplatform.portfolio.group.service.SearchParameters; +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 OfficeToGLAccountMappingReadPlatformServiceImpl implements OfficeToGLAccountMappingReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final OfficeToGLAccountMappingMapper accountMappingMapper; + private final PaginationHelper paginationHelper = new PaginationHelper(); + private final OfficeReadPlatformService officeReadPlatformService; + private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService; + + @Autowired + public OfficeToGLAccountMappingReadPlatformServiceImpl(final RoutingDataSource dataSource, + final OfficeReadPlatformService officeReadPlatformService, + final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService) { + accountMappingMapper = new OfficeToGLAccountMappingMapper(); + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.officeReadPlatformService = officeReadPlatformService; + this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService; + } + + @Override + public Page retrieveAll(final SearchParameters searchParameters) { + StringBuilder sqlBuilder = new StringBuilder(300); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlBuilder.append(this.accountMappingMapper.schema()); + Object[] finalObjectArray = {}; + if (searchParameters.isOrderByRequested()) { + sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()); + + if (searchParameters.isSortOrderProvided()) { + sqlBuilder.append(' ').append(searchParameters.getSortOrder()); + } + } + + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append(searchParameters.getOffset()); + } + } + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, + this.accountMappingMapper); + } + + @Override + public OfficeToGLAccountMappingData retrieve(Long mappingId) { + try { + StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("select "); + sqlBuilder.append(this.accountMappingMapper.schema()); + sqlBuilder.append(" where om.id=?"); + return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), this.accountMappingMapper, new Object[] { mappingId }); + } catch (final EmptyResultDataAccessException e) { + throw new OfficeToGLAccountMappingNotFoundException(mappingId); + } + } + + @Override + public OfficeToGLAccountMappingData retrieveTemplate() { + Collection officeOptions = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); + final Map> accountOptions = this.accountingDropdownReadPlatformService.retrieveAccountMappingOptions(); + return OfficeToGLAccountMappingData.template(accountOptions, officeOptions); + } + + private static final class OfficeToGLAccountMappingMapper implements RowMapper { + + private final String sql; + + public OfficeToGLAccountMappingMapper() { + StringBuilder sb = new StringBuilder(300); + sb.append("om.id , office.id as officeId, office.name as officeName, "); + sb.append(" glaccount.id as glAccountId,glaccount.name as glAccountName,glaccount.gl_code as glCode "); + sb.append(" from acc_gl_office_mapping om "); + sb.append("inner join m_office office on office.id = om.office_id "); + sb.append("inner join acc_gl_account glaccount on glaccount.id = om.gl_account_id"); + sql = sb.toString(); + } + + public String schema() { + return sql; + } + + @Override + public OfficeToGLAccountMappingData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = JdbcSupport.getLong(rs, "id"); + final Long officeId = JdbcSupport.getLong(rs, "officeId"); + final String officeName = rs.getString("officeName"); + final String nameDecorated = null; + final String externalId = null; + final LocalDate openingDate = null; + final String hierarchy = null; + final Long parentId = null; + final String parentName = null; + final Collection allowedParents = null; + final OfficeData officeData = new OfficeData(officeId, officeName, nameDecorated, externalId, openingDate, hierarchy, parentId, + parentName, allowedParents); + + final Long glAccountId = JdbcSupport.getLong(rs, "glAccountId"); + final String glAccountName = rs.getString("glAccountName"); + final String glCode = rs.getString("glCode"); + + final GLAccountData gLAccountData = new GLAccountData(glAccountId, glAccountName, glCode); + + final OfficeToGLAccountMappingData accountMappingData = OfficeToGLAccountMappingData.instance(id, officeData, gLAccountData); + return accountMappingData; + } + + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformService.java new file mode 100755 index 000000000..9f163d837 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformService.java @@ -0,0 +1,19 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.accounting.accountmapping.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + +public interface OfficeToGLAccountMappingWritePlatformService { + + CommandProcessingResult createGLAccountMapping(JsonCommand command); + + CommandProcessingResult updateGLAccountMapping(Long mappingId, JsonCommand command); + + CommandProcessingResult deleteGLAccountMapping(Long mappingId, JsonCommand command); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformServiceImpl.java new file mode 100755 index 000000000..2d827dc6e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/accountmapping/service/OfficeToGLAccountMappingWritePlatformServiceImpl.java @@ -0,0 +1,157 @@ +package org.mifosplatform.accounting.accountmapping.service; + +import java.util.HashMap; +import java.util.Map; + +import org.mifosplatform.accounting.accountmapping.domain.OfficeToGLAccountMapping; +import org.mifosplatform.accounting.accountmapping.domain.OfficeToGLAccountMappingRepositoryWrapper; +import org.mifosplatform.accounting.accountmapping.exception.DuplicateOfficeToGLAccountMappingFoundException; +import org.mifosplatform.accounting.accountmapping.exception.MappingUpdateNotSupportedException; +import org.mifosplatform.accounting.accountmapping.serialization.OfficeToGLAccountMappingDataValidator; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTING_PARAMS; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTS; +import org.mifosplatform.accounting.glaccount.domain.GLAccount; +import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper; +import org.mifosplatform.accounting.glaccount.domain.GLAccountType; +import org.mifosplatform.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingInvalidException; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.mifosplatform.organisation.office.domain.Office; +import org.mifosplatform.organisation.office.domain.OfficeRepositoryWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.google.gson.JsonElement; + +@Service +public class OfficeToGLAccountMappingWritePlatformServiceImpl implements OfficeToGLAccountMappingWritePlatformService { + + private final OfficeToGLAccountMappingRepositoryWrapper accountMappingRepository; + private final OfficeToGLAccountMappingDataValidator fromApiJsonDeserializer; + private final FromJsonHelper fromApiJsonHelper; + private final GLAccountRepositoryWrapper glAccountRepositoryWrapper; + private final OfficeRepositoryWrapper officeRepositoryWrapper; + + @Autowired + public OfficeToGLAccountMappingWritePlatformServiceImpl(final OfficeToGLAccountMappingRepositoryWrapper accountMappingRepository, + final OfficeToGLAccountMappingDataValidator fromApiJsonDeserializer, final FromJsonHelper fromApiJsonHelper, + final GLAccountRepositoryWrapper glAccountRepositoryWrapper, final OfficeRepositoryWrapper officeRepositoryWrapper) { + this.accountMappingRepository = accountMappingRepository; + this.fromApiJsonDeserializer = fromApiJsonDeserializer; + this.fromApiJsonHelper = fromApiJsonHelper; + this.glAccountRepositoryWrapper = glAccountRepositoryWrapper; + this.officeRepositoryWrapper = officeRepositoryWrapper; + } + + @Override + public CommandProcessingResult createGLAccountMapping(JsonCommand command) { + + this.fromApiJsonDeserializer.validateForCreate(command.json()); + final JsonElement element = this.fromApiJsonHelper.parse(command.json()); + final Long officeId = this.fromApiJsonHelper.extractLongNamed("officeId", element); + final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId); + OfficeToGLAccountMapping accountMapping = createLiabilityTrasferSuspenceMapping(office, element); + checkForExistingMapping(accountMapping); + this.accountMappingRepository.save(accountMapping); + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(accountMapping.getId()) // + .build(); + } + + private void checkForExistingMapping(final OfficeToGLAccountMapping accountMapping) { + OfficeToGLAccountMapping existingMapping = this.accountMappingRepository.findByOfficeAndFinancialAccountType(accountMapping + .office().getId(), accountMapping.getFinancialAccountType()); + if (existingMapping != null && !existingMapping.getId().equals(accountMapping.getId())) { throw new DuplicateOfficeToGLAccountMappingFoundException( + accountMapping.office().getId(), accountMapping.getFinancialAccountType()); } + } + + @Override + public CommandProcessingResult updateGLAccountMapping(Long mappingId, JsonCommand command) { + this.fromApiJsonDeserializer.validateForUpdate(command.json()); + final OfficeToGLAccountMapping officeToGLAccountMapping = this.accountMappingRepository.findOneWithNotFoundDetection(mappingId); + Map changes = findChanges(command, officeToGLAccountMapping); + final JsonElement element = this.fromApiJsonHelper.parse(command.json()); + + if (changes.containsKey(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue())) { + final GLAccount glAccount = fetchGLAccount(element, ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + GLAccountType.LIABILITY); + officeToGLAccountMapping.updateGlAccount(glAccount); + } + + if (!changes.isEmpty()) { + checkForExistingMapping(officeToGLAccountMapping); + this.accountMappingRepository.save(officeToGLAccountMapping); + } + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(mappingId) // + .with(changes) // + .build(); + } + + @Override + public CommandProcessingResult deleteGLAccountMapping(Long mappingId, JsonCommand command) { + final OfficeToGLAccountMapping officeToGLAccountMapping = this.accountMappingRepository.findOneWithNotFoundDetection(mappingId); + this.accountMappingRepository.delete(officeToGLAccountMapping); + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(mappingId) // + .build(); + } + + private OfficeToGLAccountMapping createLiabilityTrasferSuspenceMapping(final Office office, final JsonElement element) { + final GLAccount glAccount = fetchGLAccount(element, ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + GLAccountType.LIABILITY); + final Integer financialAccountType = ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(); + return OfficeToGLAccountMapping.createNew(glAccount, office, financialAccountType); + } + + private GLAccount fetchGLAccount(final JsonElement element, final String paramName, final GLAccountType expectedAccountType) { + final Long accountId = this.fromApiJsonHelper.extractLongNamed(paramName, element); + final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId); + return glAccount; + } + + /** + * Fetches account with a particular Id and throws and Exception it is not + * of the expected Account Category ('ASSET','liability' etc) + * + * @param paramName + * @param expectedAccountType + * @param accountId + * @return + */ + public GLAccount getAccountByIdAndType(final String paramName, final GLAccountType expectedAccountType, final Long accountId) { + final GLAccount glAccount = this.glAccountRepositoryWrapper.findOneWithNotFoundDetection(accountId); + // validate account is of the expected Type + if (glAccount.getType().intValue() != expectedAccountType.getValue()) { throw new ProductToGLAccountMappingInvalidException( + paramName, glAccount.getName(), accountId, GLAccountType.fromInt(glAccount.getType()).toString(), + expectedAccountType.toString()); } + return glAccount; + } + + public Map findChanges(JsonCommand command, OfficeToGLAccountMapping accountMapping) { + + Map changes = new HashMap(); + + final String officeParamName = "officeId"; + Long existingOfficeId = accountMapping.office().getId(); + if (command.isChangeInLongParameterNamed(officeParamName, existingOfficeId)) { + final Long newValue = command.longValueOfParameterNamed(officeParamName); + String defaultMsg = "Office updating not allowed "; + throw new MappingUpdateNotSupportedException("officeId", defaultMsg, newValue,existingOfficeId,accountMapping.getId()); + } + + Long existingGLAccountId = accountMapping.glAccount().getId(); + if (command + .isChangeInLongParameterNamed(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), existingGLAccountId)) { + final Long newValue = command.longValueOfParameterNamed(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue()); + changes.put(ORGANIZATION_ACCOUNTING_PARAMS.LIABILITY_TRANSFER_SUSPENSE.getValue(), newValue); + } + return changes; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java index 6991e696c..3a9b9c3d9 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingConstants.java @@ -13,7 +13,7 @@ public class AccountingConstants { /*** Accounting placeholders for cash based accounting for loan products ***/ public static enum CASH_ACCOUNTS_FOR_LOAN { FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(6), TRANSFERS_SUSPENSE( - 10), OVERPAYMENT(11),INCOME_FROM_RECOVERY(12); + 10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12); private final Integer value; @@ -46,7 +46,7 @@ public class AccountingConstants { /*** Accounting placeholders for accrual based accounting for loan products ***/ public static enum ACCRUAL_ACCOUNTS_FOR_LOAN { FUND_SOURCE(1), LOAN_PORTFOLIO(2), INTEREST_ON_LOANS(3), INCOME_FROM_FEES(4), INCOME_FROM_PENALTIES(5), LOSSES_WRITTEN_OFF(6), INTEREST_RECEIVABLE( - 7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11),INCOME_FROM_RECOVERY(12); + 7), FEES_RECEIVABLE(8), PENALTIES_RECEIVABLE(9), TRANSFERS_SUSPENSE(10), OVERPAYMENT(11), INCOME_FROM_RECOVERY(12); private final Integer value; @@ -88,8 +88,8 @@ public class AccountingConstants { "receivableFeeAccountId"), PENALTIES_RECEIVABLE("receivablePenaltyAccountId"), TRANSFERS_SUSPENSE( "transfersInSuspenseAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING("paymentChannelToFundSourceMappings"), PAYMENT_TYPE( "paymentTypeId"), FEE_INCOME_ACCOUNT_MAPPING("feeToIncomeAccountMappings"), PENALTY_INCOME_ACCOUNT_MAPPING( - "penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID("incomeAccountId"), - INCOME_FROM_RECOVERY("incomeFromRecoveryAccountId"); + "penaltyToIncomeAccountMappings"), CHARGE_ID("chargeId"), INCOME_ACCOUNT_ID("incomeAccountId"), INCOME_FROM_RECOVERY( + "incomeFromRecoveryAccountId"); private final String value; @@ -111,8 +111,8 @@ public class AccountingConstants { FUND_SOURCE("fundSourceAccount"), LOAN_PORTFOLIO("loanPortfolioAccount"), INTEREST_ON_LOANS("interestOnLoanAccount"), INCOME_FROM_FEES( "incomeFromFeeAccount"), INCOME_FROM_PENALTIES("incomeFromPenaltyAccount"), LOSSES_WRITTEN_OFF("writeOffAccount"), OVERPAYMENT( "overpaymentLiabilityAccount"), INTEREST_RECEIVABLE("receivableInterestAccount"), FEES_RECEIVABLE("receivableFeeAccount"), PENALTIES_RECEIVABLE( - "receivablePenaltyAccount"), TRANSFERS_SUSPENSE("transfersInSuspenseAccount"), INCOME_ACCOUNT_ID("incomeAccount"), - INCOME_FROM_RECOVERY("incomeFromRecoveryAccount"); + "receivablePenaltyAccount"), TRANSFERS_SUSPENSE("transfersInSuspenseAccount"), INCOME_ACCOUNT_ID("incomeAccount"), INCOME_FROM_RECOVERY( + "incomeFromRecoveryAccount"), LIABILITY_TRANSFER_SUSPENSE("liabilityTransferInSuspenseAccount"); private final String value; @@ -215,6 +215,83 @@ public class AccountingConstants { } } + public static enum ORGANIZATION_ACCOUNTS { + LIABILITY_TRANSFER_SUSPENSE(100); + + private final Integer value; + + private ORGANIZATION_ACCOUNTS(final Integer value) { + this.value = value; + } + + @Override + public String toString() { + return name().toString().replaceAll("_", " "); + } + + public Integer getValue() { + return this.value; + } + + private static final Map intToEnumMap = new HashMap(); + static { + for (final ORGANIZATION_ACCOUNTS type : ORGANIZATION_ACCOUNTS.values()) { + intToEnumMap.put(type.value, type); + } + } + + public static ORGANIZATION_ACCOUNTS fromInt(final int i) { + final ORGANIZATION_ACCOUNTS type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } + } + + /*** + * Enum of all accounting related input parameter names used while + * creating/updating a loan product + ***/ + public static enum ORGANIZATION_ACCOUNTING_PARAMS { + LIABILITY_TRANSFER_SUSPENSE("liabilityTransferInSuspenseAccountId"); + + private final String value; + + private ORGANIZATION_ACCOUNTING_PARAMS(final String value) { + this.value = value; + } + + @Override + public String toString() { + return name().toString().replaceAll("_", " "); + } + + public String getValue() { + return this.value; + } + } + + /*** + * Enum of all accounting related input parameter names used while + * creating/updating a loan product + ***/ + public static enum ORGANIZATION_ACCOUNTING_DATA_PARAMS { + LIABILITY_TRANSFER_SUSPENSE("liabilityTransferInSuspenseAccount"); + + private final String value; + + private ORGANIZATION_ACCOUNTING_DATA_PARAMS(final String value) { + this.value = value; + } + + @Override + public String toString() { + return name().toString().replaceAll("_", " "); + } + + public String getValue() { + return this.value; + } + } + public static final String ASSESTS_TAG_OPTION_CODE_NAME = "AssetAccountTags"; public static final String LIABILITIES_TAG_OPTION_CODE_NAME = "LiabilityAccountTags"; public static final String EQUITY_TAG_OPTION_CODE_NAME = "EquityAccountTags"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformService.java index 06eae08f0..b9f11ca12 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformService.java @@ -25,4 +25,6 @@ public interface AccountingDropdownReadPlatformService { public Map> retrieveAccountMappingOptionsForSavingsProducts(); + public Map> retrieveAccountMappingOptions(); + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformServiceImpl.java index a91d1188a..b89aef0ab 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/common/AccountingDropdownReadPlatformServiceImpl.java @@ -50,6 +50,16 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop @Override public Map> retrieveAccountMappingOptionsForLoanProducts() { + return retrieveAccountMappingOptions(); + } + + @Override + public Map> retrieveAccountMappingOptionsForSavingsProducts() { + return retrieveAccountMappingOptions(); + } + + @Override + public Map> retrieveAccountMappingOptions() { final Map> accountOptions = new HashMap>(); List assetAccountOptions = this.accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET); if (assetAccountOptions.isEmpty()) { @@ -79,16 +89,4 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop return accountOptions; } - @Override - public Map> retrieveAccountMappingOptionsForSavingsProducts() { - final Map> accountOptions = retrieveAccountMappingOptionsForLoanProducts(); - List liabilityAccountOptions = this.accountReadPlatformService - .retrieveAllEnabledDetailGLAccounts(GLAccountType.LIABILITY); - if (liabilityAccountOptions.isEmpty()) { - liabilityAccountOptions = null; - } - accountOptions.put("liabilityAccountOptions", liabilityAccountOptions); - return accountOptions; - } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java index 73ea17ecf..33553021c 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/LoanTransactionDTO.java @@ -36,10 +36,12 @@ public class LoanTransactionDTO { private final List penaltyPayments; private final List feePayments; + private final boolean isAccountTransfer; + public LoanTransactionDTO(final Long officeId, final Long paymentTypeId, final String transactionId, final Date transactionDate, final LoanTransactionEnumData transactionType, final BigDecimal amount, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees, final BigDecimal penalties, final BigDecimal overPayment, final boolean reversed, - final List feePayments, final List penaltyPayments) { + final List feePayments, final List penaltyPayments, boolean isAccountTransfer) { this.paymentTypeId = paymentTypeId; this.transactionId = transactionId; this.transactionDate = transactionDate; @@ -54,6 +56,7 @@ public class LoanTransactionDTO { this.penaltyPayments = penaltyPayments; this.overPayment = overPayment; this.officeId = officeId; + this.isAccountTransfer = isAccountTransfer; } public Long getOfficeId() { @@ -112,4 +115,8 @@ public class LoanTransactionDTO { return this.feePayments; } + public boolean isAccountTransfer() { + return this.isAccountTransfer; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java index d687245df..4d096b7a8 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/data/SavingsTransactionDTO.java @@ -29,9 +29,12 @@ public class SavingsTransactionDTO { private final List penaltyPayments; private final List feePayments; + private final boolean isAccountTransfer; + public SavingsTransactionDTO(final Long officeId, final Long paymentTypeId, final String transactionId, final Date transactionDate, final SavingsAccountTransactionEnumData transactionType, final BigDecimal amount, final boolean reversed, - final List feePayments, final List penaltyPayments, final BigDecimal overdraftAmount) { + final List feePayments, final List penaltyPayments, final BigDecimal overdraftAmount, + boolean isAccountTransfer) { this.paymentTypeId = paymentTypeId; this.transactionId = transactionId; this.transactionDate = transactionDate; @@ -42,6 +45,7 @@ public class SavingsTransactionDTO { this.penaltyPayments = penaltyPayments; this.officeId = officeId; this.overdraftAmount = overdraftAmount; + this.isAccountTransfer = isAccountTransfer; } public Long getOfficeId() { @@ -88,4 +92,8 @@ public class SavingsTransactionDTO { return this.overdraftAmount != null && this.overdraftAmount.doubleValue() > 0; } + public boolean isAccountTransfer() { + return this.isAccountTransfer; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java index 81874904c..6d775dae9 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccountingProcessorHelper.java @@ -14,11 +14,15 @@ import java.util.Map; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.accounting.accountmapping.domain.OfficeToGLAccountMapping; +import org.mifosplatform.accounting.accountmapping.domain.OfficeToGLAccountMappingRepository; +import org.mifosplatform.accounting.accountmapping.exception.OfficeToGLAccountMappingNotFoundException; import org.mifosplatform.accounting.closure.domain.GLClosure; import org.mifosplatform.accounting.closure.domain.GLClosureRepository; import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN; import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN; import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTS; import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO; import org.mifosplatform.accounting.journalentry.data.LoanDTO; @@ -55,6 +59,7 @@ public class AccountingProcessorHelper { public static final String SAVINGS_TRANSACTION_IDENTIFIER = "S"; private final JournalEntryRepository glJournalEntryRepository; private final ProductToGLAccountMappingRepository accountMappingRepository; + private final OfficeToGLAccountMappingRepository officeToGLAccountMappingRepository; private final GLClosureRepository closureRepository; private final OfficeRepository officeRepository; private final LoanTransactionRepository loanTransactionRepository; @@ -64,13 +69,15 @@ public class AccountingProcessorHelper { public AccountingProcessorHelper(final JournalEntryRepository glJournalEntryRepository, final ProductToGLAccountMappingRepository accountMappingRepository, final GLClosureRepository closureRepository, final OfficeRepository officeRepository, final LoanTransactionRepository loanTransactionRepository, - final SavingsAccountTransactionRepository savingsAccountTransactionRepository) { + final SavingsAccountTransactionRepository savingsAccountTransactionRepository, + final OfficeToGLAccountMappingRepository officeToGLAccountMappingRepository) { this.glJournalEntryRepository = glJournalEntryRepository; this.accountMappingRepository = accountMappingRepository; this.closureRepository = closureRepository; this.officeRepository = officeRepository; this.loanTransactionRepository = loanTransactionRepository; this.savingsAccountTransactionRepository = savingsAccountTransactionRepository; + this.officeToGLAccountMappingRepository = officeToGLAccountMappingRepository; } public LoanDTO populateLoanDtoFromMap(final Map accountingBridgeData, final boolean cashBasedAccountingEnabled, @@ -79,6 +86,7 @@ public class AccountingProcessorHelper { final Long loanProductId = (Long) accountingBridgeData.get("loanProductId"); final Long officeId = (Long) accountingBridgeData.get("officeId"); final CurrencyData currencyData = (CurrencyData) accountingBridgeData.get("currency"); + final boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer"); final List newLoanTransactions = new ArrayList(); @@ -121,7 +129,7 @@ public class AccountingProcessorHelper { final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionOfficeId, paymentTypeId, transactionId, transactionDate, transactionType, amount, principal, interest, fees, penalties, overPayments, reversed, - feePaymentDetails, penaltyPaymentDetails); + feePaymentDetails, penaltyPaymentDetails, isAccountTransfer); newLoanTransactions.add(transaction); @@ -137,6 +145,7 @@ public class AccountingProcessorHelper { final Long loanProductId = (Long) accountingBridgeData.get("savingsProductId"); final Long officeId = (Long) accountingBridgeData.get("officeId"); final CurrencyData currencyData = (CurrencyData) accountingBridgeData.get("currency"); + final boolean isAccountTransfer = (Boolean) accountingBridgeData.get("isAccountTransfer"); final List newSavingsTransactions = new ArrayList(); @SuppressWarnings("unchecked") @@ -173,7 +182,7 @@ public class AccountingProcessorHelper { } final SavingsTransactionDTO transaction = new SavingsTransactionDTO(transactionOfficeId, paymentTypeId, transactionId, - transactionDate, transactionType, amount, reversed, feePayments, penaltyPayments, overdraftAmount); + transactionDate, transactionType, amount, reversed, feePayments, penaltyPayments, overdraftAmount, isAccountTransfer); newSavingsTransactions.add(transaction); @@ -204,15 +213,15 @@ public class AccountingProcessorHelper { * @param isReversal */ public void createAccrualBasedJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode, - final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeDebited, final ACCRUAL_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, + final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - int accountTypeToDebitId = accountTypeToBeDebited.getValue(); - int accountTypeToCreditId = accountTypeToBeCredited.getValue(); + int accountTypeToDebitId = accountTypeToBeDebited; + int accountTypeToCreditId = accountTypeToBeCredited; // reverse debits and credits for reversals if (isReversal) { - accountTypeToDebitId = accountTypeToBeCredited.getValue(); - accountTypeToCreditId = accountTypeToBeDebited.getValue(); + accountTypeToDebitId = accountTypeToBeCredited; + accountTypeToCreditId = accountTypeToBeDebited; } createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount); @@ -239,15 +248,15 @@ public class AccountingProcessorHelper { * @param isReversal */ public void createCashBasedJournalEntriesAndReversalsForSavings(final Office office, final String currencyCode, - final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeDebited, final CASH_ACCOUNTS_FOR_SAVINGS accountTypeToBeCredited, - final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId, - final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - int accountTypeToDebitId = accountTypeToBeDebited.getValue(); - int accountTypeToCreditId = accountTypeToBeCredited.getValue(); + final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long savingsProductId, + final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, + final Boolean isReversal) { + int accountTypeToDebitId = accountTypeToBeDebited; + int accountTypeToCreditId = accountTypeToBeCredited; // reverse debits and credits for reversals if (isReversal) { - accountTypeToDebitId = accountTypeToBeCredited.getValue(); - accountTypeToCreditId = accountTypeToBeDebited.getValue(); + accountTypeToDebitId = accountTypeToBeCredited; + accountTypeToCreditId = accountTypeToBeDebited; } createJournalEntriesForSavings(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, savingsProductId, paymentTypeId, loanId, transactionId, transactionDate, amount); @@ -274,15 +283,15 @@ public class AccountingProcessorHelper { * @param isReversal */ public void createCashBasedJournalEntriesAndReversalsForLoan(final Office office, final String currencyCode, - final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeDebited, final CASH_ACCOUNTS_FOR_LOAN accountTypeToBeCredited, - final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, - final BigDecimal amount, final Boolean isReversal) { - int accountTypeToDebitId = accountTypeToBeDebited.getValue(); - int accountTypeToCreditId = accountTypeToBeCredited.getValue(); + final Integer accountTypeToBeDebited, final Integer accountTypeToBeCredited, final Long loanProductId, + final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, + final Boolean isReversal) { + int accountTypeToDebitId = accountTypeToBeDebited; + int accountTypeToCreditId = accountTypeToBeCredited; // reverse debits and credits for reversals if (isReversal) { - accountTypeToDebitId = accountTypeToBeCredited.getValue(); - accountTypeToCreditId = accountTypeToBeDebited.getValue(); + accountTypeToDebitId = accountTypeToBeCredited; + accountTypeToCreditId = accountTypeToBeDebited; } createJournalEntriesForLoan(office, currencyCode, accountTypeToDebitId, accountTypeToCreditId, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount); @@ -304,22 +313,6 @@ public class AccountingProcessorHelper { transactionId, transactionDate, amount, isReversal); } - public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, - final CASH_ACCOUNTS_FOR_LOAN accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId, - final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - final int accountMappingTypeId = accountMappingType.getValue(); - createDebitJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, - transactionId, transactionDate, amount, isReversal); - } - - public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, - final ACCRUAL_ACCOUNTS_FOR_LOAN accountMappingType, final Long loanProductId, final Long paymentTypeId, final Long loanId, - final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - final int accountMappingTypeId = accountMappingType.getValue(); - createDebitJournalEntryOrReversalForLoan(office, currencyCode, accountMappingTypeId, loanProductId, paymentTypeId, loanId, - transactionId, transactionDate, amount, isReversal); - } - /** * @param latestGLClosure * @param transactionDate @@ -346,8 +339,9 @@ public class AccountingProcessorHelper { private void createJournalEntriesForLoan(final Office office, final String currencyCode, final int accountTypeToDebitId, final int accountTypeToCreditId, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount) { - final GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId, paymentTypeId); - final GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId, paymentTypeId); + final GLAccount debitAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToDebitId, paymentTypeId, office.getId()); + final GLAccount creditAccount = getLinkedGLAccountForLoanProduct(loanProductId, accountTypeToCreditId, paymentTypeId, + office.getId()); createDebitJournalEntryForLoan(office, currencyCode, debitAccount, loanId, transactionId, transactionDate, amount); createCreditJournalEntryForLoan(office, currencyCode, creditAccount, loanId, transactionId, transactionDate, amount); } @@ -355,16 +349,18 @@ public class AccountingProcessorHelper { private void createJournalEntriesForSavings(final Office office, final String currencyCode, final int accountTypeToDebitId, final int accountTypeToCreditId, final Long savingsProductId, final Long paymentTypeId, final Long savingsId, final String transactionId, final Date transactionDate, final BigDecimal amount) { - final GLAccount debitAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToDebitId, paymentTypeId); - final GLAccount creditAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToCreditId, paymentTypeId); + final GLAccount debitAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToDebitId, paymentTypeId, + office.getId()); + final GLAccount creditAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToCreditId, paymentTypeId, + office.getId()); createDebitJournalEntryForSavings(office, currencyCode, debitAccount, savingsId, transactionId, transactionDate, amount); createCreditJournalEntryForSavings(office, currencyCode, creditAccount, savingsId, transactionId, transactionDate, amount); } - private void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId, + public void createDebitJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId); + final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId, office.getId()); if (isReversal) { createCreditJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount); } else { @@ -456,7 +452,7 @@ public class AccountingProcessorHelper { final GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(), chargePaymentDTO.getChargeId()); final GLAccount savingsControlAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToBeDebited.getValue(), - paymentTypeId); + paymentTypeId, office.getId()); if (isReversal) { createDebitJournalEntryForSavings(office, currencyCode, chargeSpecificAccount, loanId, transactionId, transactionDate, totalAmount); @@ -481,7 +477,7 @@ public class AccountingProcessorHelper { private void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final int accountMappingTypeId, final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal) { - final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId); + final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId, office.getId()); if (isReversal) { createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount); } else { @@ -561,27 +557,38 @@ public class AccountingProcessorHelper { this.glJournalEntryRepository.saveAndFlush(journalEntry); } - private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) { - ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId, - PortfolioProductType.LOAN.getValue(), accountMappingTypeId); - /**** - * Get more specific mapping for FUND source accounts (based on payment - * channels). Note that fund source placeholder ID would be same for - * both cash and accrual accounts - ***/ - if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()) { - final ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository - .findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(loanProductId, - PortfolioProductType.LOAN.getValue(), accountMappingTypeId, paymentTypeId); - if (paymentChannelSpecificAccountMapping != null) { - accountMapping = paymentChannelSpecificAccountMapping; + private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId, + Long officeId) { + GLAccount glAccount = null; + if (isOrganizationAccount(accountMappingTypeId)) { + OfficeToGLAccountMapping accountMapping = this.officeToGLAccountMappingRepository.findByOfficeAndFinancialAccountType(officeId, + accountMappingTypeId); + if (accountMapping == null) { throw new OfficeToGLAccountMappingNotFoundException(officeId, + String.valueOf(accountMappingTypeId)); } + glAccount = accountMapping.glAccount(); + } else { + ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId, + PortfolioProductType.LOAN.getValue(), accountMappingTypeId); + + /**** + * Get more specific mapping for FUND source accounts (based on + * payment channels). Note that fund source placeholder ID would be + * same for both cash and accrual accounts + ***/ + if (accountMappingTypeId == CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue()) { + final ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository + .findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(loanProductId, + PortfolioProductType.LOAN.getValue(), accountMappingTypeId, paymentTypeId); + if (paymentChannelSpecificAccountMapping != null) { + accountMapping = paymentChannelSpecificAccountMapping; + } } + + if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, loanProductId, + ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString()); } + glAccount = accountMapping.getGlAccount(); } - - if (accountMapping == null) { throw new ProductToGLAccountMappingNotFoundException(PortfolioProductType.LOAN, loanProductId, - ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.toString()); } - - return accountMapping.getGlAccount(); + return glAccount; } private GLAccount getLinkedGLAccountForLoanCharges(final Long loanProductId, final int accountMappingTypeId, final Long chargeId) { @@ -631,22 +638,40 @@ public class AccountingProcessorHelper { } private GLAccount getLinkedGLAccountForSavingsProduct(final Long savingsProductId, final int accountMappingTypeId, - final Long paymentTypeId) { - ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId, - PortfolioProductType.SAVING.getValue(), accountMappingTypeId); - /**** - * Get more specific mapping for FUND source accounts (based on payment - * channels). Note that fund source placeholder ID would be same for - * both cash and accrual accounts - ***/ - if (accountMappingTypeId == CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue()) { - final ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository - .findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(savingsProductId, - PortfolioProductType.SAVING.getValue(), accountMappingTypeId, paymentTypeId); - if (paymentChannelSpecificAccountMapping != null) { - accountMapping = paymentChannelSpecificAccountMapping; + final Long paymentTypeId, Long officeId) { + GLAccount glAccount = null; + if (isOrganizationAccount(accountMappingTypeId)) { + OfficeToGLAccountMapping accountMapping = this.officeToGLAccountMappingRepository.findByOfficeAndFinancialAccountType(officeId, + accountMappingTypeId); + if (accountMapping == null) { throw new OfficeToGLAccountMappingNotFoundException(officeId, + String.valueOf(accountMappingTypeId)); } + glAccount = accountMapping.glAccount(); + } else { + ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId, + PortfolioProductType.SAVING.getValue(), accountMappingTypeId); + /**** + * Get more specific mapping for FUND source accounts (based on + * payment channels). Note that fund source placeholder ID would be + * same for both cash and accrual accounts + ***/ + if (accountMappingTypeId == CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue()) { + final ProductToGLAccountMapping paymentChannelSpecificAccountMapping = this.accountMappingRepository + .findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(savingsProductId, + PortfolioProductType.SAVING.getValue(), accountMappingTypeId, paymentTypeId); + if (paymentChannelSpecificAccountMapping != null) { + accountMapping = paymentChannelSpecificAccountMapping; + } } + glAccount = accountMapping.getGlAccount(); } - return accountMapping.getGlAccount(); + return glAccount; + } + + private boolean isOrganizationAccount(final int accountMappingTypeId) { + boolean isOrganizationAccount = false; + if (ORGANIZATION_ACCOUNTS.fromInt(accountMappingTypeId) != null) { + isOrganizationAccount = true; + } + return isOrganizationAccount; } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index 88beda174..6334a7db8 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -10,6 +10,8 @@ import java.util.Date; import org.mifosplatform.accounting.closure.domain.GLClosure; import org.mifosplatform.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN; +import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTS; import org.mifosplatform.accounting.journalentry.data.LoanDTO; import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO; import org.mifosplatform.organisation.office.domain.Office; @@ -60,6 +62,11 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess createJournalEntriesForRecoveryRepayments(loanDTO, loanTransactionDTO, office); } + /** Logic for Refunds of Overpayments **/ + else if (loanTransactionDTO.getTransactionType().isRefund()) { + createJournalEntriesForRefund(loanDTO, loanTransactionDTO, office); + } + /** Handle Write Offs, waivers and their reversals **/ else if ((loanTransactionDTO.getTransactionType().isWriteOff() || loanTransactionDTO.getTransactionType().isWaiveInterest() || loanTransactionDTO .getTransactionType().isWaiveCharges())) { @@ -92,9 +99,15 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess // create journal entries for the disbursement (or disbursement // reversal) - this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, - ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, - disbursalAmount, isReversed); + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount, isReversed); + } else { + this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount, isReversed); + } } @@ -198,11 +211,19 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess * reversals) ***/ if (writeOff) { - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, - loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, + ACCRUAL_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, totalDebitAmount, isReversal); } else { - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, - loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, totalDebitAmount, isReversal); + } else { + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, + ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, totalDebitAmount, isReversal); + } } } @@ -227,9 +248,9 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess final boolean isReversal = loanTransactionDTO.isReversed(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); - this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE, - ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, - amount, isReversal); + this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + ACCRUAL_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY.getValue(), loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, amount, isReversal); } @@ -268,20 +289,44 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess // create journal entries for recognizing interest (or reversal) if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) { this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, - ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS, loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_ON_LOANS.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversed); } // create journal entries for the fees application (or reversal) if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) { this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, - ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES, loanProductId, paymentTypeId, - loanId, transactionId, transactionDate, feesAmount, isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feesAmount, isReversed); } // create journal entries for the penalties application (or reversal) if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) { this.helper.createAccrualBasedJournalEntriesAndReversalsForLoan(office, currencyCode, - ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE, ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES, loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed); + ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversed); + } + } + + private void createJournalEntriesForRefund(final LoanDTO loanDTO, final LoanTransactionDTO loanTransactionDTO, final Office office) { + // loan properties + final Long loanProductId = loanDTO.getLoanProductId(); + final Long loanId = loanDTO.getLoanId(); + final String currencyCode = loanDTO.getCurrencyCode(); + + // transaction properties + final String transactionId = loanTransactionDTO.getTransactionId(); + final Date transactionDate = loanTransactionDTO.getTransactionDate(); + final BigDecimal refundAmount = loanTransactionDTO.getAmount(); + final boolean isReversal = loanTransactionDTO.isReversed(); + final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); + + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal); + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal); } } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java index 374f3634b..023bda23a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForLoan.java @@ -10,6 +10,7 @@ import java.util.Date; import org.mifosplatform.accounting.closure.domain.GLClosure; import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTS; import org.mifosplatform.accounting.journalentry.data.LoanDTO; import org.mifosplatform.accounting.journalentry.data.LoanTransactionDTO; import org.mifosplatform.organisation.office.domain.Office; @@ -73,8 +74,9 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF else if (loanTransactionDTO.getTransactionType().isWriteOff()) { final BigDecimal principalAmount = loanTransactionDTO.getPrincipal(); this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, - CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, paymentTypeId, - loanId, transactionId, transactionDate, principalAmount, loanTransactionDTO.isReversed()); + CASH_ACCOUNTS_FOR_LOAN.LOSSES_WRITTEN_OFF.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount, + loanTransactionDTO.isReversed()); } else if (loanTransactionDTO.getTransactionType().isInitiateTransfer() || loanTransactionDTO.getTransactionType().isApproveTransfer() || loanTransactionDTO.getTransactionType().isWithdrawTransfer()) { @@ -107,10 +109,16 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF final BigDecimal disbursalAmount = loanTransactionDTO.getAmount(); final boolean isReversal = loanTransactionDTO.isReversed(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount, isReversal); + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount, isReversal); + } - this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, - CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, disbursalAmount, - isReversal); } /** @@ -137,9 +145,15 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF final boolean isReversal = loanTransactionDTO.isReversed(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); - this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT, - CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, refundAmount, - isReversal); + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal); + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId, + paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal); + } } /** @@ -203,8 +217,14 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF } /*** create a single debit entry (or reversal) for the entire amount **/ - this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, loanProductId, - paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); + if (loanTransactionDTO.isAccountTransfer()) { + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, totalDebitAmount, isReversal); + } else { + this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), + loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, isReversal); + } } /** @@ -228,9 +248,9 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF final boolean isReversal = loanTransactionDTO.isReversed(); final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); - this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE, - CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY, loanProductId, paymentTypeId, loanId, transactionId, transactionDate, amount, - isReversal); + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), + CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY.getValue(), loanProductId, paymentTypeId, loanId, transactionId, + transactionDate, amount, isReversal); } @@ -261,14 +281,14 @@ public class CashBasedAccountingProcessorForLoan implements AccountingProcessorF // final Long paymentTypeId = loanTransactionDTO.getPaymentTypeId(); if (loanTransactionDTO.getTransactionType().isInitiateTransfer()) { - this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.TRANSFERS_SUSPENSE, - CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, null, loanId, transactionId, transactionDate, principalAmount, - isReversal); + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.TRANSFERS_SUSPENSE.getValue(), CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), loanProductId, + null, loanId, transactionId, transactionDate, principalAmount, isReversal); } else if (loanTransactionDTO.getTransactionType().isApproveTransfer() || loanTransactionDTO.getTransactionType().isWithdrawTransfer()) { - this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, - CASH_ACCOUNTS_FOR_LOAN.TRANSFERS_SUSPENSE, loanProductId, null, loanId, transactionId, transactionDate, - principalAmount, isReversal); + this.helper.createCashBasedJournalEntriesAndReversalsForLoan(office, currencyCode, + CASH_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), CASH_ACCOUNTS_FOR_LOAN.TRANSFERS_SUSPENSE.getValue(), loanProductId, + null, loanId, transactionId, transactionDate, principalAmount, isReversal); } } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java index 3765b4868..0c07187f2 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/CashBasedAccountingProcessorForSavings.java @@ -11,6 +11,7 @@ import java.util.List; import org.mifosplatform.accounting.closure.domain.GLClosure; import org.mifosplatform.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_SAVINGS; +import org.mifosplatform.accounting.common.AccountingConstants.ORGANIZATION_ACCOUNTS; import org.mifosplatform.accounting.journalentry.data.ChargePaymentDTO; import org.mifosplatform.accounting.journalentry.data.SavingsDTO; import org.mifosplatform.accounting.journalentry.data.SavingsTransactionDTO; @@ -48,37 +49,81 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess this.helper.checkForBranchClosures(latestGLClosure, transactionDate); if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) { - this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, - savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal); - if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + if (savingsTransactionDTO.isAccountTransfer()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, overdraftAmount, isReversal); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + } + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, overdraftAmount, isReversal); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + } } } else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) { - this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, - savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); - if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + if (savingsTransactionDTO.isAccountTransfer()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount, isReversal); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + } + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount, isReversal); + if (amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) == 1) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal); + } } } /** Handle Deposits and reversals of deposits **/ else if (savingsTransactionDTO.getTransactionType().isDeposit()) { - this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + if (savingsTransactionDTO.isAccountTransfer()) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount, isReversal); + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + } } /** Handle withdrawals and reversals of withdrawals **/ else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) { - this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + if (savingsTransactionDTO.isAccountTransfer()) { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + ORGANIZATION_ACCOUNTS.LIABILITY_TRANSFER_SUSPENSE.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount, isReversal); + } else { + this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + } } /** @@ -86,11 +131,12 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess * Applications **/ else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) { - //Post journal entry if earned interest amount is greater than zero + // Post journal entry if earned interest amount is greater than + // zero if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) == 1) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); } } @@ -111,27 +157,28 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess /** Handle Transfers proposal **/ else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); } /** Handle Transfer Withdrawal or Acceptance **/ else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer() || savingsTransactionDTO.getTransactionType().isApproveTransfer()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); } /** overdraft **/ else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST, savingsProductId, - paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE.getValue(), CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_INTEREST.getValue(), + savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); } else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode, - CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF, CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL, - savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal); + CASH_ACCOUNTS_FOR_SAVINGS.LOSSES_WRITTEN_OFF.getValue(), + CASH_ACCOUNTS_FOR_SAVINGS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId, + transactionId, transactionDate, amount, isReversal); } else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) { this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_REFERENCE, CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES, savingsProductId, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java index ae5ff9be3..86b674de3 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/producttoaccountmapping/service/ProductToGLAccountMappingReadPlatformServiceImpl.java @@ -125,9 +125,9 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.LOSSES_WRITTEN_OFF.getValue(), gLAccountData); } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.OVERPAYMENT)) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.OVERPAYMENT.getValue(), gLAccountData); - } else if(glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY)) { + } else if (glAccountForLoan.equals(CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY)) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.INCOME_FROM_RECOVERY.getValue(), gLAccountData); - } + } } } else if (AccountingRuleType.ACCRUAL_UPFRONT.getValue().equals(accountingType) || AccountingRuleType.ACCRUAL_PERIODIC.getValue().equals(accountingType)) { @@ -163,7 +163,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.FEES_RECEIVABLE.getValue(), gLAccountData); } else if (glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE)) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.PENALTIES_RECEIVABLE.getValue(), gLAccountData); - } else if((glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY))){ + } else if ((glAccountForLoan.equals(ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_RECOVERY))) { accountMappingDetails.put(LOAN_PRODUCT_ACCOUNTING_DATA_PARAMS.INCOME_FROM_RECOVERY.getValue(), gLAccountData); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index 71d145d92..665149c03 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -799,4 +799,8 @@ public class CommandWrapper { public DepositAccountType depositAccountType(){ return this.depositAccountType; } + + public boolean isOfficeToGLAccountMapping() { + return this.entityName.equalsIgnoreCase("OFFICEGLACCOUNT"); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index 66a314e8d..7d6e62116 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -576,7 +576,7 @@ public class CommandWrapperBuilder { return this; } - public CommandWrapperBuilder loanRecoveryPaymentTransaction(final Long loanId){ + public CommandWrapperBuilder loanRecoveryPaymentTransaction(final Long loanId) { this.actionName = "RECOVERYPAYMENT"; this.entityName = "LOAN"; this.entityId = null; @@ -710,7 +710,7 @@ public class CommandWrapperBuilder { this.href = "/loans/" + loanId; return this; } - + public CommandWrapperBuilder disburseLoanToSavingsApplication(final Long loanId) { this.actionName = "DISBURSETOSAVINGS"; this.entityName = "LOAN"; @@ -1810,7 +1810,7 @@ public class CommandWrapperBuilder { this.href = "/fixeddepositaccounts/" + accountId + "?command=postInterest"; return this; } - + public CommandWrapperBuilder fixedDepositAccountDeposit(final Long accountId) { this.actionName = "DEPOSIT"; this.entityName = "FIXEDDEPOSITACCOUNT"; @@ -1820,7 +1820,7 @@ public class CommandWrapperBuilder { this.href = "/fixeddepositaccounts/" + accountId + "/transactions?command=deposit"; return this; } - + public CommandWrapperBuilder fixedDepositAccountWithdrawal(final Long accountId) { this.actionName = "WITHDRAWAL"; this.entityName = "FIXEDDEPOSITACCOUNT"; @@ -1858,7 +1858,7 @@ public class CommandWrapperBuilder { this.href = "/recurringdepositaccounts/" + accountId + "/transactions?command=deposit"; return this; } - + public CommandWrapperBuilder recurringAccountWithdrawal(final Long accountId) { this.actionName = "WITHDRAWAL"; this.entityName = "RECURRINGDEPOSITACCOUNT"; @@ -1880,7 +1880,7 @@ public class CommandWrapperBuilder { this.href = "/recurringdepositaccounts/" + accountId + "/transactions/" + transactionId + "?command=modify"; return this; } - + public CommandWrapperBuilder undoRecurringAccountTransaction(final Long accountId, final Long transactionId) { this.actionName = "UNDOTRANSACTION"; this.entityName = "RECURRINGDEPOSITACCOUNT"; @@ -1892,7 +1892,7 @@ public class CommandWrapperBuilder { this.href = "/recurringdepositaccounts/" + accountId + "/transactions/" + transactionId + "?command=undo"; return this; } - + public CommandWrapperBuilder deleteRecurringDepositAccount(final Long accountId) { this.actionName = "DELETE"; this.entityName = "RECURRINGDEPOSITACCOUNT"; @@ -1991,4 +1991,29 @@ public class CommandWrapperBuilder { this.href = "/recurringdepositaccounts/" + accountId + "?command=postInterest"; return this; } + + public CommandWrapperBuilder createOfficeToGLAccountMapping() { + this.actionName = "CREATE"; + this.entityName = "OFFICEGLACCOUNT"; + this.entityId = null; + this.href = "/organizationglaccounts/template"; + return this; + } + + public CommandWrapperBuilder updateOfficeToGLAccountMapping(final Long mappingId) { + this.actionName = "UPDATE"; + this.entityName = "OFFICEGLACCOUNT"; + this.entityId = mappingId; + this.href = "/organizationglaccounts/" + mappingId; + return this; + } + + public CommandWrapperBuilder deleteOfficeToGLAccountMapping(final Long mappingId) { + this.actionName = "DELETE"; + this.entityName = "OFFICEGLACCOUNT"; + this.entityId = mappingId; + this.href = "/organizationglaccounts/" + mappingId; + return this; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index f98c29e04..28a1b6c8e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -63,7 +63,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer CommandSource commandSourceResult = null; if (command.commandId() != null) { commandSourceResult = this.commandSourceRepository.findOne(command.commandId()); - commandSourceResult.markAsChecked(maker, DateTime.now()); + commandSourceResult.markAsChecked(maker, DateTime.now()); } else { commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker); } @@ -341,9 +341,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = this.applicationContext.getBean("undoDisbursalLoanCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isLoanRepayment()) { handler = this.applicationContext.getBean("loanRepaymentCommandHandler", NewCommandSourceHandler.class); - } else if (wrapper.isLoanRecoveryPayment()){ + } else if (wrapper.isLoanRecoveryPayment()) { handler = this.applicationContext.getBean("loanRecoveryPaymentCommandHandler", NewCommandSourceHandler.class); - }else if (wrapper.isLoanRepaymentAdjustment()) { + } else if (wrapper.isLoanRepaymentAdjustment()) { handler = this.applicationContext.getBean("loanRepaymentAdjustmentCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isWaiveInterestPortionOnLoan()) { handler = this.applicationContext.getBean("waiveInterestPortionOnLoanCommandHandler", NewCommandSourceHandler.class); @@ -733,6 +733,16 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer throw new UnsupportedCommandException(wrapper.commandName()); } + } else if (wrapper.isOfficeToGLAccountMapping()) { + if (wrapper.isCreate()) { + handler = this.applicationContext.getBean("createOfficeToGLAccountMappingHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = this.applicationContext.getBean("updateOfficeToGLAccountMappingCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = this.applicationContext.getBean("deleteOfficeToGLAccountMappingCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } } else { throw new UnsupportedCommandException(wrapper.commandName()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java index 983c3333e..9b202e6c8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java @@ -99,6 +99,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer Long fromSavingsAccountId = null; Long transferDetailId = null; boolean isInterestTransfer = false; + boolean isAccountTransfer = true; if (isSavingsToSavingsAccountTransfer(fromAccountType, toAccountType)) { fromSavingsAccountId = command.longValueOfParameterNamed(fromAccountIdParamName); @@ -106,13 +107,13 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), - isInterestTransfer); + isInterestTransfer, isAccountTransfer); final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName); final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail); + transactionDate, transactionAmount, paymentDetail, isAccountTransfer); final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(command, fromSavingsAccount, toSavingsAccount, withdrawal, deposit); @@ -126,7 +127,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, transactionDate, transactionAmount, paymentDetail, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), - isInterestTransfer); + isInterestTransfer, isAccountTransfer); final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName); final Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId); @@ -134,7 +135,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final boolean isRecoveryRepayment = false; final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(), transactionDate, transactionAmount, paymentDetail, null, null, - isRecoveryRepayment); + isRecoveryRepayment, isAccountTransfer); final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(command, fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction); @@ -156,7 +157,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail); + transactionDate, transactionAmount, paymentDetail, isAccountTransfer); final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command, fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction); @@ -230,6 +231,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer @Transactional public Long transferFunds(final AccountTransferDTO accountTransferDTO) { Long transferTransactionId = null; + boolean isAccountTransfer = true; AccountTransferDetails accountTransferDetails = accountTransferDTO.getAccountTransferDetails(); if (isSavingsToLoanAccountTransfer(accountTransferDTO.getFromAccountType(), accountTransferDTO.getToAccountType())) { // @@ -248,7 +250,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType - .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer()); + .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(), isAccountTransfer); LoanTransaction loanTransaction = null; @@ -262,7 +264,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final boolean isRecoveryRepayment = false; loanTransaction = this.loanAccountDomainService.makeRepayment(toLoanAccount, new CommandProcessingResultBuilder(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment); + accountTransferDTO.getPaymentDetail(), null, null, isRecoveryRepayment, isAccountTransfer); } accountTransferDetails = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO, fromSavingsAccount, @@ -289,11 +291,11 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), accountTransferDTO.getPaymentDetail(), fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), AccountTransferType - .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer()); + .fromInt(accountTransferDTO.getTransferType()).isInterestTransfer(), isAccountTransfer); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail()); + accountTransferDTO.getPaymentDetail(), isAccountTransfer); accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(accountTransferDTO, fromSavingsAccount, toSavingsAccount, withdrawal, deposit); @@ -331,7 +333,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail()); + accountTransferDTO.getPaymentDetail(), isAccountTransfer); accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(accountTransferDTO, fromLoanAccount, toSavingsAccount, deposit, loanTransaction); this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index c5005eb64..5d67a7e8e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -767,7 +767,7 @@ public class Loan extends AbstractPersistable { } return amount.getAmount(); } - + public BigDecimal getTotalWrittenOff() { return this.summary.getTotalWrittenOff(); } @@ -3304,7 +3304,7 @@ public class Loan extends AbstractPersistable { } public Map deriveAccountingBridgeData(final CurrencyData currencyData, final List existingTransactionIds, - final List existingReversedTransactionIds) { + final List existingReversedTransactionIds, boolean isAccountTransfer) { final Map accountingBridgeData = new LinkedHashMap(); accountingBridgeData.put("loanId", getId()); @@ -3315,6 +3315,7 @@ public class Loan extends AbstractPersistable { accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnLoanProduct()); accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", isUpfrontAccrualAccountingEnabledOnLoanProduct()); accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", isPeriodicAccrualAccountingEnabledOnLoanProduct()); + accountingBridgeData.put("isAccountTransfer", isAccountTransfer); final List> newLoanTransactions = new ArrayList>(); for (final LoanTransaction transaction : this.loanTransactions) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainService.java index 2ece441cf..c67c411e4 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainService.java @@ -15,7 +15,7 @@ public interface LoanAccountDomainService { LoanTransaction makeRepayment(Loan loan, CommandProcessingResultBuilder builderResult, LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId, - final boolean isRecoveryRepayment); + final boolean isRecoveryRepayment, boolean isAccountTransfer); LoanTransaction makeRefund(Long accountId, CommandProcessingResultBuilder builderResult, LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, String noteText, String txnExternalId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index 78383b97e..687073017 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -82,7 +82,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { @Override public LoanTransaction makeRepayment(final Loan loan, final CommandProcessingResultBuilder builderResult, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, - final String txnExternalId, final boolean isRecoveryRepayment) { + final String txnExternalId, final boolean isRecoveryRepayment, boolean isAccountTransfer) { checkClientOrGroupActive(loan); @@ -160,7 +160,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { this.noteRepository.save(note); } - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); builderResult.withEntityId(newRepaymentTransaction.getId()) // .withOfficeId(loan.getOfficeId()) // @@ -176,6 +176,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId, final Integer transactionType, Integer installmentNumber) { + boolean isAccountTransfer = true; checkClientOrGroupActive(loan); final List existingTransactionIds = new ArrayList(); @@ -206,18 +207,18 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { this.noteRepository.save(note); } - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return newPaymentTransaction; } private void postJournalEntries(final Loan loanAccount, final List existingTransactionIds, - final List existingReversedTransactionIds) { + final List existingReversedTransactionIds, boolean isAccountTransfer) { final MonetaryCurrency currency = loanAccount.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); final Map accountingBridgeData = loanAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -241,6 +242,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { public LoanTransaction makeRefund(final Long accountId, final CommandProcessingResultBuilder builderResult, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId) { + boolean isAccountTransfer = true; final Loan loan = this.loanAccountAssembler.assembleFrom(accountId); checkClientOrGroupActive(loan); @@ -267,7 +269,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { this.noteRepository.save(note); } - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); builderResult.withEntityId(newRefundTransaction.getId()) // .withOfficeId(loan.getOfficeId()) // @@ -283,7 +285,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { final PaymentDetail paymentDetail, final String noteText, final String txnExternalId) { final Loan loan = this.loanAccountAssembler.assembleFrom(loanId); checkClientOrGroupActive(loan); - + boolean isAccountTransfer = true; final List existingTransactionIds = new ArrayList(); final List existingReversedTransactionIds = new ArrayList(); final Money amount = Money.of(loan.getCurrency(), transactionAmount); @@ -311,7 +313,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { this.noteRepository.save(note); } - postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return disbursementTransaction; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java index 77e3712cb..14a26d25d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java @@ -147,6 +147,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat accountingBridgeData.put("cashBasedAccountingEnabled", false); accountingBridgeData.put("upfrontAccrualBasedAccountingEnabled", false); accountingBridgeData.put("periodicAccrualBasedAccountingEnabled", true); + accountingBridgeData.put("isAccountTransfer", false); final List> newLoanTransactions = new ArrayList>(); newLoanTransactions.add(transactionMap); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 994294b9b..a8701b2dd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -541,9 +541,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.noteRepository.save(note); } } - + boolean isAccountTransfer = false; final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -583,9 +583,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Loan loan = this.loanAssembler.assembleFrom(loanId); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + boolean isAccountTransfer = false; final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder(); this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, transactionDate, transactionAmount, - paymentDetail, noteText, txnExternalId, isRecoveryRepayment); + paymentDetail, noteText, txnExternalId, isRecoveryRepayment, isAccountTransfer); return commandProcessingResultBuilder.withCommandId(command.commandId()) // .withLoanId(loanId) // @@ -603,7 +604,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final boolean isRecoveryRepayment = false; if (repaymentCommand == null) { return changes; } - + boolean isAccountTransfer = false; for (final SingleRepaymentCommand singleLoanRepaymentCommand : repaymentCommand) { /**** * TODO Vishwas, have a re-look at this implementation, defaulting @@ -614,7 +615,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder(); this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(), singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null, - isRecoveryRepayment); + isRecoveryRepayment, isAccountTransfer); changes.put("bulkTransations", singleLoanRepaymentCommand); } @@ -1534,9 +1535,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final MonetaryCurrency currency = loan.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); - + boolean isAccountTransfer = false; final Map accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java index d829da2f1..6509972fa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java @@ -75,7 +75,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final boolean applyWithdrawFee) { - + boolean isAccountTransfer = false; final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); @@ -95,7 +95,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi saveTransactionToGenerateTransactionId(withdrawal); this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return withdrawal; } @@ -104,7 +104,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi @Override public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) { - + boolean isAccountTransfer = false; final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); @@ -125,7 +125,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return deposit; } @@ -135,6 +135,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi public SavingsAccountTransaction handleAccountClosure(final SavingsAccount account, final PaymentDetail paymentDetail, final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) { + boolean isAccountTransfer = false; final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); @@ -153,6 +154,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); } else if (fdAccount.isTransferToSavingsOnClosure()) { + isAccountTransfer = true; final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName); @@ -160,7 +162,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final SavingsAccount toSavingsAccount = this.depositAccountAssembler.assembleFrom(toSavingsId, DepositAccountType.SAVINGS_DEPOSIT); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null); + withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null, isAccountTransfer); final AccountTransferDetails accountTransferDetails = AccountTransferDetails.savingsToSavingsTransfer(fdAccount.office(), fdAccount.getClient(), fdAccount, toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount, @@ -195,6 +197,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); } else if (rdAccount.isTransferToSavingsOnClosure()) { + isAccountTransfer = true; final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName); @@ -202,7 +205,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final SavingsAccount toSavingsAccount = this.depositAccountAssembler.assembleFrom(toSavingsId, DepositAccountType.SAVINGS_DEPOSIT); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null); + withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null, isAccountTransfer); final AccountTransferDetails accountTransferDetails = AccountTransferDetails.savingsToSavingsTransfer(rdAccount.office(), rdAccount.getClient(), rdAccount, toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount, @@ -218,7 +221,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return withdrawal; } @@ -240,7 +243,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); - + boolean isAccountTransfer = false; final DepositAccountType depositAccountType = account.depositAccountType(); SavingsAccountTransaction withdrawal = null; if (depositAccountType.isFixedDeposit()) { @@ -249,6 +252,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final Money transactionAmount = withdrawal.getAmount(fdAccount.getCurrency()); final LocalDate transactionDate = withdrawal.transactionLocalDate(); if (fdAccount.isTransferToSavingsOnClosure()) { + isAccountTransfer = true; final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName); @@ -256,7 +260,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final SavingsAccount toSavingsAccount = this.depositAccountAssembler.assembleFrom(toSavingsId, DepositAccountType.SAVINGS_DEPOSIT); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null); + withdrawal.transactionLocalDate(), transactionAmount.getAmount(), null, isAccountTransfer); final AccountTransferDetails accountTransferDetails = AccountTransferDetails.savingsToSavingsTransfer(fdAccount.office(), fdAccount.getClient(), fdAccount, toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount, @@ -274,6 +278,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final Money transactionAmount = withdrawal.getAmount(rdAccount.getCurrency()); final LocalDate transactionDate = withdrawal.transactionLocalDate(); if (rdAccount.isTransferToSavingsOnClosure()) { + isAccountTransfer = true; final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName); @@ -281,7 +286,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final SavingsAccount toSavingsAccount = this.depositAccountAssembler.assembleFrom(toSavingsId, DepositAccountType.SAVINGS_DEPOSIT); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, - transactionDate, transactionAmount.getAmount(), null); + transactionDate, transactionAmount.getAmount(), null, isAccountTransfer); final AccountTransferDetails accountTransferDetails = AccountTransferDetails.savingsToSavingsTransfer(rdAccount.office(), rdAccount.getClient(), rdAccount, toSavingsAccount.office(), toSavingsAccount.getClient(), toSavingsAccount, @@ -300,7 +305,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return withdrawal; } @@ -317,13 +322,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi } private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, - final Set existingReversedTransactionIds) { + final Set existingReversedTransactionIds, boolean isAccountTransfer) { final MonetaryCurrency currency = savingsAccount.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 906de0c8a..d740111f7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -1016,7 +1016,7 @@ public class SavingsAccount extends AbstractPersistable { } public Map deriveAccountingBridgeData(final CurrencyData currencyData, final Set existingTransactionIds, - final Set existingReversedTransactionIds) { + final Set existingReversedTransactionIds, boolean isAccountTransfer) { final Map accountingBridgeData = new LinkedHashMap(); accountingBridgeData.put("savingsId", getId()); @@ -1025,6 +1025,7 @@ public class SavingsAccount extends AbstractPersistable { accountingBridgeData.put("officeId", officeId()); accountingBridgeData.put("cashBasedAccountingEnabled", isCashBasedAccountingEnabledOnSavingsProduct()); accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnSavingsProduct()); + accountingBridgeData.put("isAccountTransfer", isAccountTransfer); final List> newLoanTransactions = new ArrayList>(); for (final SavingsAccountTransaction transaction : this.transactions) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java index a16fad418..76e7152c3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainService.java @@ -14,8 +14,8 @@ import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; public interface SavingsAccountDomainService { SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isInterestTransfer); + BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isInterestTransfer, boolean isAccountTransfer); SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail); + BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index f3b7287c8..298df8a3f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -48,7 +48,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi @Override public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean applyWithdrawFee, boolean isInterestTransfer) { + final boolean applyWithdrawFee, boolean isInterestTransfer, final boolean isAccountTransfer) { final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); @@ -69,7 +69,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi saveTransactionToGenerateTransactionId(withdrawal); this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return withdrawal; } @@ -77,7 +77,8 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi @Transactional @Override public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt, - final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) { + final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, + final boolean isAccountTransfer) { boolean isInterestTransfer = false; final Set existingTransactionIds = new HashSet(); @@ -100,7 +101,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); return deposit; } @@ -117,13 +118,13 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi } private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, - final Set existingReversedTransactionIds) { + final Set existingReversedTransactionIds, boolean isAccountTransfer) { final MonetaryCurrency currency = savingsAccount.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index b239775ca..4d63f5ffe 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -939,9 +939,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final MonetaryCurrency currency = savingsAccount.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - + boolean isAccountTransfer = false; final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index fcaa554cc..5f3e53278 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -150,7 +150,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final Set existingTransactionIds = new HashSet(); final Set existingReversedTransactionIds = new HashSet(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); - + boolean isAccountTransfer = false; final Map changes = account.activate(user, command, DateUtils.getLocalDateOfTenant()); if (!changes.isEmpty()) { final Locale locale = command.extractLocale(); @@ -158,7 +158,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi Money amountForDeposit = account.activateWithBalance(); if (amountForDeposit.isGreaterThanZero()) { this.savingsAccountDomainService.handleDeposit(account, fmt, account.getActivationLocalDate(), - amountForDeposit.getAmount(), null); + amountForDeposit.getAmount(), null, isAccountTransfer); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); } account.processAccountUponActivation(); @@ -198,9 +198,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final Map changes = new LinkedHashMap(); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); - + boolean isAccountTransfer = false; final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail); + transactionAmount, paymentDetail, isAccountTransfer); return new CommandProcessingResultBuilder() // .withEntityId(deposit.getId()) // @@ -235,9 +235,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); checkClientOrGroupActive(account); boolean isInterestTransfer = false; - + boolean isAccountTransfer = false; final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, - transactionAmount, paymentDetail, true, isInterestTransfer); + transactionAmount, paymentDetail, true, isInterestTransfer, isAccountTransfer); return new CommandProcessingResultBuilder() // .withEntityId(withdrawal.getId()) // @@ -884,9 +884,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final MonetaryCurrency currency = savingsAccount.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency); - + boolean isAccountTransfer = false; final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(), - existingTransactionIds, existingReversedTransactionIds); + existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index a9351a34e..2eb027959 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -451,9 +451,10 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl savingsAccountDataDTO.getAppliedBy()); account.approveAndActivateApplication(savingsAccountDataDTO.getApplicationDate().toDate(), savingsAccountDataDTO.getAppliedBy()); Money amountForDeposit = account.activateWithBalance(); + boolean isAccountTransfer = false; if (amountForDeposit.isGreaterThanZero()) { this.savingsAccountDomainService.handleDeposit(account, savingsAccountDataDTO.getFmt(), account.getActivationLocalDate(), - amountForDeposit.getAmount(), null); + amountForDeposit.getAmount(), null, isAccountTransfer); } account.processAccountUponActivation(); this.savingAccountRepository.save(account); From c7e7a00071acaca343d6bbb66f0c447d1279d553 Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Wed, 28 May 2014 00:17:58 +0530 Subject: [PATCH 2/2] API doc changes --- api-docs/apiLive.htm | 244 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 11e1a2e41..be06e7613 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -1369,6 +1369,24 @@ Update a Accounting Rule Delete a Accounting Rule + + Office GL Account Mappings + officeglaccounts + Create Office GL Account Mapping
+ List Journal Entries + + + + + + officeglaccounts/{entryId} + + Retrieve a single Entry + Update Office GL Account Mapping + Delete Office GL Account Mapping + + + @@ -28241,6 +28259,232 @@ Content-Type: application/json + + +  +
+
+

Office GL Accounting Mappings

+

+ These are the Branch level intermediate accounts to move funds between banches +

+ + + + + + + + + + + + + + + + +
Field Descriptions
officeId
The identifier of the office ( + cost center) at which the financial activity + occurs
liabilityTransferInSuspenseAccountId
The identifier of the liability account ( + Ledger Account) against which transfer journal entry + should made +
+
+
+ +   +
+
+

List Office Level GL Account Mappings

+

The list of Account Mapping entries through pagination and sorting.

+
Optional Arguments
+
+
offset
+
+ Integer optional, defaults to 0 +
+
Indicates from what result to start from.
+ +
limit
+
+ Integer optional, defaults to 200 +
+
Restricts the size of results returned. To override the default and return all entries you must explicitly pass a non-positive integer value for limit e.g. limit=0, or limit=-1
+ +
orderBy
+
+ String optional, one of displayName, accountNo, officeId, officeName +
+
Orders the results by the field indicated.
+ +
sortBy
+
+ String optional, one of ASC, DESC +
+
Indicates what way to order results if orderBy is used.
+ +
officeId
+
+ Integer optional +
+
Provides ability to restrict list of centers returned based on the office there associated with.
+ + +
+

Example Requests:

+
officeglaccounts
+
+
officeglaccounts?orderBy=id&sortOrder=DESC
+
+
+ +GET https://DomainName/api/v1/officeglaccounts + + + +{ + "totalFilteredRecords": 1, + "pageItems": [ + { + "id": 1, + "officeData": { + "id": 2, + "name": "Office_BX38" + }, + "glAccountData": { + "id": 29, + "name": "ACCOUNT_NAME_P9UWO", + "glCode": "LIABILITY_7E1401198314394" + } + }]} + +
+
+ +   +
+
+

Create Office GL Account

+ + + + + + + + +
Mandatory Fields
officeId, liabilityTransferInSuspenseAccountId +
+
+ +
+
+ +POST https://DomainName/api/v1/officeglaccounts + + +POST officeglaccounts +Content-Type: application/json +Request Body: +{ +"officeId": 1, +"liabilityTransferInSuspenseAccountId" : 2 +} + + +{ + "resourceId": 1 +} + +
+
+ +   +
+
+

Update Office GL Account Mappings

+

+ the API Updates the mapping GL Accoiunt for office. +
+

+ +
+
+ +POST https://DomainName/api/v1/officeglaccounts/1 + + +POST officeglaccounts +Content-Type: application/json +Request Body: +{ +"liabilityTransferInSuspenseAccountId": 2 +} + + +{ + "liabilityTransferInSuspenseAccountId": 2 +} + + +
+
+ + +   +
+
+

Retrieve a single Entry

+

Example Requests:

+
officeglaccounts/1
+
+
+
+ +GET https://DomainName/api/v1/officeglaccounts/{entryId} + + +{ + "id": 1, + "officeData": { + "id": 2, + "name": "Office_BX38" + }, + "glAccountData": { + "id": 29, + "name": "ACCOUNT_NAME_P9UWO", + "glCode": "LIABILITY_7E1401198314394" + } +} + +
+
+ +   +
+
+

Delete Office GL Mapping

+
+
+ +GET https://DomainName/api/v1/officeglaccounts/{mappingId} + + +POST officeglaccounts/C1MAE935K0IAEYA?command=reverse +Content-Type: application/json + + +{ + "resourceId": "2" +} + +
+
+ +