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 @@
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