Persisting/creating accounts for import.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/domain/AccountAssignment.java b/api/src/main/java/io/mifos/portfolio/api/v1/domain/AccountAssignment.java
index db30e95..31fa303 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/domain/AccountAssignment.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/domain/AccountAssignment.java
@@ -40,10 +40,16 @@
@Length(max = 256)
@Nullable
- private String alternativeAccountIdentifier;
+ private String referenceAccountIdentifier;
public AccountAssignment() {
+ }
+ public AccountAssignment(final AccountAssignment toCopy) {
+ this.designator = toCopy.designator;
+ this.accountIdentifier = toCopy.accountIdentifier;
+ this.ledgerIdentifier = toCopy.ledgerIdentifier;
+ this.referenceAccountIdentifier = toCopy.referenceAccountIdentifier;
}
public AccountAssignment(String designator, String accountIdentifier) {
@@ -76,12 +82,12 @@
}
@Nullable
- public String getAlternativeAccountIdentifier() {
- return alternativeAccountIdentifier;
+ public String getReferenceAccountIdentifier() {
+ return referenceAccountIdentifier;
}
- public void setAlternativeAccountIdentifier(@Nullable String alternativeAccountIdentifier) {
- this.alternativeAccountIdentifier = alternativeAccountIdentifier;
+ public void setReferenceAccountIdentifier(@Nullable String referenceAccountIdentifier) {
+ this.referenceAccountIdentifier = referenceAccountIdentifier;
}
@Override
@@ -92,12 +98,12 @@
return Objects.equals(designator, that.designator) &&
Objects.equals(accountIdentifier, that.accountIdentifier) &&
Objects.equals(ledgerIdentifier, that.ledgerIdentifier) &&
- Objects.equals(alternativeAccountIdentifier, that.alternativeAccountIdentifier);
+ Objects.equals(referenceAccountIdentifier, that.referenceAccountIdentifier);
}
@Override
public int hashCode() {
- return Objects.hash(designator, accountIdentifier, ledgerIdentifier, alternativeAccountIdentifier);
+ return Objects.hash(designator, accountIdentifier, ledgerIdentifier, referenceAccountIdentifier);
}
@Override
@@ -106,7 +112,7 @@
"designator='" + designator + '\'' +
", accountIdentifier='" + accountIdentifier + '\'' +
", ledgerIdentifier='" + ledgerIdentifier + '\'' +
- ", alternativeAccountIdentifier='" + alternativeAccountIdentifier + '\'' +
+ ", referenceAccountIdentifier='" + referenceAccountIdentifier + '\'' +
'}';
}
}
\ No newline at end of file
diff --git a/api/src/test/java/io/mifos/portfolio/api/v1/domain/AccountAssignmentTest.java b/api/src/test/java/io/mifos/portfolio/api/v1/domain/AccountAssignmentTest.java
index f96cbc4..9778e8e 100644
--- a/api/src/test/java/io/mifos/portfolio/api/v1/domain/AccountAssignmentTest.java
+++ b/api/src/test/java/io/mifos/portfolio/api/v1/domain/AccountAssignmentTest.java
@@ -55,7 +55,7 @@
.adjustment(x -> { x.setLedgerIdentifier("zzz"); x.setAccountIdentifier(null); })
.valid(true));
ret.add(new ValidationTestCase<AccountAssignment>("alternativeAccountIdentifierSet")
- .adjustment(x -> x.setAlternativeAccountIdentifier("asd;lf///kjasdf"))
+ .adjustment(x -> x.setReferenceAccountIdentifier("asd;lf///kjasdf"))
.valid(true));
return ret;
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
index 16f932a..f49a28c 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
@@ -31,6 +31,7 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import javax.annotation.Nullable;
import javax.validation.Validation;
import javax.validation.Validator;
import java.math.BigDecimal;
@@ -69,6 +70,10 @@
static final String GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER = "3010";
static final String GENERAL_EXPENSE_ACCOUNT_IDENTIFIER = "3011";
+ static final String IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT = "clp.blah.blah2";
+ static final String IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT = "cli.blah.blah2";
+ static final String IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT = "clf.blah.blah3";
+
static final Map<String, AccountData> accountMap = new HashMap<>();
private static class AccountData {
@@ -264,6 +269,27 @@
return ret;
}
+ private static Account importedCustomerLoanPrincipalAccount() {
+ final Account ret = new Account();
+ ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT);
+ ret.setType(AccountType.ASSET.name());
+ return ret;
+ }
+
+ private static Account importedCustomerLoanInterestAccount() {
+ final Account ret = new Account();
+ ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT);
+ ret.setType(AccountType.ASSET.name());
+ return ret;
+ }
+
+ private static Account importedCustomerLoanFeeAccount() {
+ final Account ret = new Account();
+ ret.setIdentifier(IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT);
+ ret.setType(AccountType.ASSET.name());
+ return ret;
+ }
+
private static AccountPage customerLoanAccountsPage() {
final Account customerLoanAccount1 = new Account();
customerLoanAccount1.setIdentifier("customerLoanAccount1");
@@ -306,6 +332,7 @@
private static class AccountMatcher extends ArgumentMatcher<Account> {
private final String ledgerIdentifer;
private final String accountDesignator;
+ private final String referenceAccountIdentifier;
private final AccountType type;
private final BigDecimal balance;
private Account matchedArgument;
@@ -313,10 +340,12 @@
private AccountMatcher(
final String ledgerIdentifier,
final String accountDesignator,
+ final @Nullable String referenceAccountIdentifier,
final AccountType type,
final BigDecimal balance) {
this.ledgerIdentifer = ledgerIdentifier;
this.accountDesignator = accountDesignator;
+ this.referenceAccountIdentifier = referenceAccountIdentifier;
this.type = type;
this.balance = balance;
this.matchedArgument = null; //Set when matches called and returns true.
@@ -331,9 +360,10 @@
final Account checkedArgument = (Account) argument;
- final boolean ret = checkedArgument.getLedger().equals(ledgerIdentifer) &&
+ final boolean ret = Objects.equals(checkedArgument.getLedger(), ledgerIdentifer) &&
checkedArgument.getIdentifier().contains(accountDesignator) &&
- checkedArgument.getType().equals(type.name()) &&
+ Objects.equals(checkedArgument.getReferenceAccount(), referenceAccountIdentifier) &&
+ Objects.equals(checkedArgument.getType(), type.name()) &&
checkedArgument.getBalance().compareTo(balance.doubleValue()) == 0;
if (ret)
@@ -356,6 +386,7 @@
return "AccountMatcher{" +
"ledgerIdentifer='" + ledgerIdentifer + '\'' +
", accountDesignator='" + accountDesignator + '\'' +
+ ", referenceAccountIdentifier='" + referenceAccountIdentifier + '\'' +
", type=" + type +
", balance=" + balance +
'}';
@@ -570,6 +601,9 @@
makeAccountResponsive(productLossAllowanceAccount(), universalCreationDate, ledgerManagerMock);
makeAccountResponsive(generalLossAllowanceAccount(), universalCreationDate, ledgerManagerMock);
makeAccountResponsive(generalExpenseAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(importedCustomerLoanPrincipalAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(importedCustomerLoanInterestAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(importedCustomerLoanFeeAccount(), universalCreationDate, ledgerManagerMock);
Mockito.doReturn(incomeLedger()).when(ledgerManagerMock).findLedger(INCOME_LEDGER_IDENTIFIER);
Mockito.doReturn(feesAndChargesLedger()).when(ledgerManagerMock).findLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
@@ -594,9 +628,18 @@
final LedgerManager ledgerManager,
final String ledgerIdentifier,
final String accountDesignator,
+ final AccountType type) {
+ return verifyAccountCreationMatchingDesignator(ledgerManager, ledgerIdentifier, accountDesignator, null, type, BigDecimal.ZERO);
+ }
+
+ static String verifyAccountCreationMatchingDesignator(
+ final LedgerManager ledgerManager,
+ final String ledgerIdentifier,
+ final String accountDesignator,
+ final @Nullable String referenceAccountIdentifier,
final AccountType type,
final BigDecimal balance) {
- final AccountMatcher specifiesCorrectAccount = new AccountMatcher(ledgerIdentifier, accountDesignator, type, balance);
+ final AccountMatcher specifiesCorrectAccount = new AccountMatcher(ledgerIdentifier, accountDesignator, referenceAccountIdentifier, type, balance);
Mockito.verify(ledgerManager).createAccount(AdditionalMatchers.and(argThat(isValid()), argThat(specifiesCorrectAccount)));
return specifiesCorrectAccount.getMatchedArgument().getIdentifier();
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
index e4489ff..d9f391e 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -96,9 +96,36 @@
@Test
public void workflowImportingLoanFromExternalSystem() throws InterruptedException {
+ final LocalDateTime initialDisbursalDate = LocalDateTime.of(2017,11,8,0,0);
+ final LocalDateTime today = LocalDateTime.of(2017,11,22,0,0);
+
step1CreateProduct();
step2CreateCase();
- step3IImportCase(LocalDateTime.of(2017,11,8,0,0));
+ step3IImportCaseWhenAccountsDontExistYet(initialDisbursalDate);
+
+ //TODO: test that interest calculation works just like for "normal" loans.
+ step7PaybackPartialAmount(
+ expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued),
+ today,
+ BigDecimal.ZERO);
+ step8Close(today);
+ }
+
+
+ @Test
+ public void workflowImportingLoanFromExternalSystemConnectingToExistingAccounts() throws InterruptedException {
+ final LocalDateTime initialDisbursalDate = LocalDateTime.of(2017,11,8,0,0);
+ final LocalDateTime today = LocalDateTime.of(2017,11,22,0,0);
+
+ step1CreateProduct();
+ step2CreateCase();
+ step3IImportCaseWhenAccountsExist(initialDisbursalDate);
+
+ step7PaybackPartialAmount(
+ expectedCurrentPrincipal.add(nonLateFees).add(interestAccrued),
+ today,
+ BigDecimal.ZERO);
+ step8Close(today);
}
@Test
@@ -469,15 +496,32 @@
checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(), Action.APPROVE, Action.DENY);
}
- //Open the case and accept a processing fee.
- private void step3IImportCase(final LocalDateTime forDateTime) throws InterruptedException {
- logger.info("step3IImportCase");
+ //Import an active case.
+ private void step3IImportCaseWhenAccountsDontExistYet(final LocalDateTime forDateTime) throws InterruptedException {
+ logger.info("step3IImportCaseWhenAccountsDontExistYet");
final BigDecimal expectedNextRepaymentAmount = BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS);
final BigDecimal currentPrincipal = BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS);
+ final AccountAssignment customerLoanPrincipalAccountAssignment = new AccountAssignment();
+ customerLoanPrincipalAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
+ customerLoanPrincipalAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-principal-account-identifier");
+ customerLoanPrincipalAccountAssignment.setLedgerIdentifier(AccountDesignators.CUSTOMER_LOAN_GROUP);
+ final AccountAssignment customerLoanInterestAccountAssignment = new AccountAssignment();
+ customerLoanInterestAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+ customerLoanInterestAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-interest-account-identifier");
+ customerLoanInterestAccountAssignment.setLedgerIdentifier(AccountDesignators.CUSTOMER_LOAN_GROUP);
+ final AccountAssignment customerLoanFeeAccountAssignment = new AccountAssignment();
+ customerLoanFeeAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_FEES);
+ customerLoanFeeAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-fees-account-identifier");
+ customerLoanFeeAccountAssignment.setLedgerIdentifier(AccountDesignators.CUSTOMER_LOAN_GROUP);
+ final ArrayList<AccountAssignment> importAccountAssignments = new ArrayList<>();
+ importAccountAssignments.add(customerLoanPrincipalAccountAssignment);
+ importAccountAssignments.add(customerLoanInterestAccountAssignment);
+ importAccountAssignments.add(customerLoanFeeAccountAssignment);
+
final ImportParameters importParameters = new ImportParameters();
- importParameters.setCaseAccountAssignments(Collections.singletonList(assignEntryToTeller()));
+ importParameters.setCaseAccountAssignments(importAccountAssignments);
importParameters.setPaymentSize(expectedNextRepaymentAmount);
importParameters.setCreatedOn(DateConverter.toIsoString(forDateTime));
importParameters.setCurrentBalances(Collections.singletonMap(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, currentPrincipal));
@@ -492,11 +536,28 @@
AccountType.ASSET);
customerLoanPrincipalIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, AccountType.ASSET, currentPrincipal);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(
+ ledgerManager, customerLoanLedgerIdentifier,
+ AccountDesignators.CUSTOMER_LOAN_PRINCIPAL,
+ customerLoanPrincipalAccountAssignment.getReferenceAccountIdentifier(),
+ AccountType.ASSET,
+ currentPrincipal);
customerLoanInterestIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_INTEREST, AccountType.ASSET, BigDecimal.ZERO);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(
+ ledgerManager,
+ customerLoanLedgerIdentifier,
+ AccountDesignators.CUSTOMER_LOAN_INTEREST,
+ customerLoanInterestAccountAssignment.getReferenceAccountIdentifier(),
+ AccountType.ASSET,
+ BigDecimal.ZERO);
customerLoanFeeIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_FEES, AccountType.ASSET, BigDecimal.ZERO);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(
+ ledgerManager,
+ customerLoanLedgerIdentifier,
+ AccountDesignators.CUSTOMER_LOAN_FEES,
+ customerLoanFeeAccountAssignment.getReferenceAccountIdentifier(),
+ AccountType.ASSET,
+ BigDecimal.ZERO);
final CaseStatus changedCaseStatus = portfolioManager.getCaseStatus(product.getIdentifier(), customerCase.getIdentifier());
Assert.assertEquals(Case.State.ACTIVE.name(), changedCaseStatus.getCurrentState());
@@ -511,8 +572,88 @@
final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(forDateTime);
Assert.assertEquals(expectedNextRepaymentAmount, nextRepaymentAmount);
+ final Case changedCase = portfolioManager.getCase(product.getIdentifier(), customerCase.getIdentifier());
+ final Map<String, String> designatorsAssignedForCase = changedCase.getAccountAssignments().stream()
+ .collect(Collectors.toMap(AccountAssignment::getDesignator, AccountAssignment::getAccountIdentifier));
+ Assert.assertEquals(
+ customerLoanPrincipalIdentifier,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL));
+ Assert.assertEquals(
+ customerLoanInterestIdentifier,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_INTEREST));
+ Assert.assertEquals(
+ customerLoanFeeIdentifier,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_FEES));
+ }
- //TODO: check account assignments.
+ //Import an active case.
+ private void step3IImportCaseWhenAccountsExist(final LocalDateTime forDateTime) throws InterruptedException {
+ logger.info("step3IImportCaseWhenAccountsExist");
+
+ final BigDecimal expectedNextRepaymentAmount = BigDecimal.valueOf(20_00, MINOR_CURRENCY_UNIT_DIGITS);
+ final BigDecimal currentPrincipal = BigDecimal.valueOf(2_000_00, MINOR_CURRENCY_UNIT_DIGITS);
+
+ final AccountAssignment customerLoanPrincipalAccountAssignment = new AccountAssignment();
+ customerLoanPrincipalAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL);
+ customerLoanPrincipalAccountAssignment.setAccountIdentifier(AccountingFixture.IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT);
+ customerLoanPrincipalAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-principal-account-identifier");
+ final AccountAssignment customerLoanInterestAccountAssignment = new AccountAssignment();
+ customerLoanInterestAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_INTEREST);
+ customerLoanInterestAccountAssignment.setAccountIdentifier(AccountingFixture.IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT);
+ customerLoanInterestAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-interest-account-identifier");
+ final AccountAssignment customerLoanFeeAccountAssignment = new AccountAssignment();
+ customerLoanFeeAccountAssignment.setDesignator(AccountDesignators.CUSTOMER_LOAN_FEES);
+ customerLoanFeeAccountAssignment.setAccountIdentifier(AccountingFixture.IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT);
+ customerLoanFeeAccountAssignment.setReferenceAccountIdentifier("external-system-sourced-customer-loan-fees-account-identifier");
+ final ArrayList<AccountAssignment> importAccountAssignments = new ArrayList<>();
+ importAccountAssignments.add(customerLoanPrincipalAccountAssignment);
+ importAccountAssignments.add(customerLoanInterestAccountAssignment);
+ importAccountAssignments.add(customerLoanFeeAccountAssignment);
+
+ final ImportParameters importParameters = new ImportParameters();
+ importParameters.setCaseAccountAssignments(importAccountAssignments);
+ importParameters.setPaymentSize(expectedNextRepaymentAmount);
+ importParameters.setCreatedOn(DateConverter.toIsoString(forDateTime));
+ importParameters.setCurrentBalances(Collections.singletonMap(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, currentPrincipal));
+ importParameters.setStartOfTerm(DateConverter.toIsoString(forDateTime));
+ portfolioManager.executeImportCommand(product.getIdentifier(), customerCase.getIdentifier(), importParameters);
+
+ Assert.assertTrue(eventRecorder.wait(IndividualLoanEventConstants.IMPORT_INDIVIDUALLOAN_CASE, new IndividualLoanCommandEvent(product.getIdentifier(), customerCase.getIdentifier(), DateConverter.toIsoString(forDateTime))));
+
+ AccountingFixture.verifyLedgerCreation(
+ ledgerManager,
+ AccountingFixture.CUSTOMER_LOAN_LEDGER_IDENTIFIER,
+ AccountType.ASSET);
+
+ customerLoanPrincipalIdentifier = AccountingFixture.IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT;
+ customerLoanInterestIdentifier = AccountingFixture.IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT;
+ customerLoanFeeIdentifier = AccountingFixture.IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT;
+
+ final CaseStatus changedCaseStatus = portfolioManager.getCaseStatus(product.getIdentifier(), customerCase.getIdentifier());
+ Assert.assertEquals(Case.State.ACTIVE.name(), changedCaseStatus.getCurrentState());
+ Assert.assertEquals(DateConverter.toIsoString(forDateTime), changedCaseStatus.getStartOfTerm());
+ Assert.assertEquals("2018-02-08T00:00:00Z", changedCaseStatus.getEndOfTerm());
+ checkNextActionsCorrect(product.getIdentifier(), customerCase.getIdentifier(),
+ Action.APPLY_INTEREST, Action.MARK_LATE, Action.ACCEPT_PAYMENT, Action.DISBURSE, Action.MARK_IN_ARREARS, Action.WRITE_OFF, Action.CLOSE);
+
+ expectedCurrentPrincipal = currentPrincipal;
+ updateBalanceMock();
+
+ final BigDecimal nextRepaymentAmount = findNextRepaymentAmount(forDateTime);
+ Assert.assertEquals(expectedNextRepaymentAmount, nextRepaymentAmount);
+
+ final Case changedCase = portfolioManager.getCase(product.getIdentifier(), customerCase.getIdentifier());
+ final Map<String, String> designatorsAssignedForCase = changedCase.getAccountAssignments().stream()
+ .collect(Collectors.toMap(AccountAssignment::getDesignator, AccountAssignment::getAccountIdentifier));
+ Assert.assertEquals(
+ AccountingFixture.IMPORTED_CUSTOMER_LOAN_PRINCIPAL_ACCOUNT,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL));
+ Assert.assertEquals(
+ AccountingFixture.IMPORTED_CUSTOMER_LOAN_INTEREST_ACCOUNT,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_INTEREST));
+ Assert.assertEquals(
+ AccountingFixture.IMPORTED_CUSTOMER_LOAN_FEES_ACCOUNT,
+ designatorsAssignedForCase.get(AccountDesignators.CUSTOMER_LOAN_FEES));
}
@@ -570,11 +711,11 @@
AccountType.ASSET);
customerLoanPrincipalIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, AccountType.ASSET, BigDecimal.ZERO);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, AccountType.ASSET);
customerLoanInterestIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_INTEREST, AccountType.ASSET, BigDecimal.ZERO);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_INTEREST, AccountType.ASSET);
customerLoanFeeIdentifier =
- AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_FEES, AccountType.ASSET, BigDecimal.ZERO);
+ AccountingFixture.verifyAccountCreationMatchingDesignator(ledgerManager, customerLoanLedgerIdentifier, AccountDesignators.CUSTOMER_LOAN_FEES, AccountType.ASSET);
expectedCurrentPrincipal = BigDecimal.ZERO;
interestAccrued = BigDecimal.ZERO;
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
index e9db1cf..eccf069 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
@@ -209,8 +209,6 @@
caseParameters.setPaymentSize(command.getImportParameters().getPaymentSize());
caseParametersRepository.save(caseParameters);
- //TODO: create/connect to accounts in account assignments.
-
return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, command.getImportParameters().getCreatedOn());
}
@@ -725,7 +723,7 @@
.map(ledger -> {
final BigDecimal currentBalance = currentBalances.getOrDefault(ledger.getDesignator(), BigDecimal.ZERO);
return new AccountAssignment(ledger.getDesignator(),
- accountingAdapter.createCaseAccountForLedgerAssignment(
+ accountingAdapter.createOrFindCaseAccountForLedgerAssignment(
dataContextOfAction.getCaseParametersEntity().getCustomerIdentifier(),
ledger,
currentBalance));})
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapper.java b/service/src/main/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapper.java
index fbc0273..25b7379 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapper.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapper.java
@@ -177,6 +177,12 @@
final Set<String> accountAssignmentGroups = IndividualLendingPatternFactory.individualLendingPattern().getAccountAssignmentGroups();
final Set<RequiredAccountAssignment> accountAssignmentsRequired = IndividualLendingPatternFactory.individualLendingPattern().getAccountAssignmentsRequired();
final Map<String, RequiredAccountAssignment> accountAssignmentsRequiredMap = accountAssignmentsRequired.stream().collect(Collectors.toMap(RequiredAccountAssignment::getAccountDesignator, x -> x));
+ final Map<String, String> accountAssignmentAlternativeAccountIdsMap = oneTimeAccountAssignments.stream()
+ .filter(x -> x.getReferenceAccountIdentifier() != null)
+ .collect(Collectors.toMap(AccountAssignment::getDesignator, AccountAssignment::getReferenceAccountIdentifier));
+ final Map<String, String> existingAccountsAssignmentsMap = oneTimeAccountAssignments.stream()
+ .filter(x -> x.getAccountIdentifier() != null)
+ .collect(Collectors.toMap(AccountAssignment::getDesignator, AccountAssignment::getAccountIdentifier));
final Map<String, Optional<String>> groupToLedgerMapping = accountAssignmentGroups.stream()
.collect(Collectors.toMap(
Function.identity(),
@@ -188,20 +194,17 @@
return ledgerAccountAssignments
.map(ledgerAccountAssignment -> {
- final String accountAssignmentGroup = accountAssignmentsRequiredMap.get(ledgerAccountAssignment.getDesignator()).getGroup();
- if (accountAssignmentGroup == null)
- return ledgerAccountAssignment;
- else {
- final Optional<String> changedLedger = groupToLedgerMapping.get(accountAssignmentGroup);
- if (!changedLedger.isPresent())
- return ledgerAccountAssignment;
- else {
- final AccountAssignment ret = new AccountAssignment();
- ret.setDesignator(ledgerAccountAssignment.getDesignator());
- ret.setLedgerIdentifier(changedLedger.get());
- return ret;
- }
- }
+ final AccountAssignment ret = new AccountAssignment(ledgerAccountAssignment);
+ ret.setReferenceAccountIdentifier(accountAssignmentAlternativeAccountIdsMap.get(ledgerAccountAssignment.getDesignator()));
+
+ final String existingAccountSetting = existingAccountsAssignmentsMap.get(ledgerAccountAssignment.getDesignator());
+ if (existingAccountSetting != null) ret.setAccountIdentifier(existingAccountSetting);
+
+ final Optional<String> accountAssignmentGroup = Optional.ofNullable(accountAssignmentsRequiredMap.get(ledgerAccountAssignment.getDesignator())).map(RequiredAccountAssignment::getGroup);
+ final Optional<String> changedLedger = accountAssignmentGroup.flatMap(groupToLedgerMapping::get);
+ changedLedger.ifPresent(ret::setLedgerIdentifier);
+
+ return ret;
});
}
}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
index 651497b..9f395e5 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
@@ -272,10 +272,18 @@
productIdentifier, accountDesignator, ledgerIdentifier));
}
- public String createCaseAccountForLedgerAssignment(
+ public String createOrFindCaseAccountForLedgerAssignment(
final String customerIdentifier,
final AccountAssignment ledgerAssignment,
final BigDecimal currentBalance) {
+ if (ledgerAssignment.getAccountIdentifier() != null) try
+ {
+ final Account existingAccount = ledgerManager.findAccount(ledgerAssignment.getAccountIdentifier());
+ return existingAccount.getIdentifier();
+ }
+ catch (final AccountNotFoundException ignored) {
+ //If the "existing" account doesn't exist after all, create a new one.
+ }
final Ledger ledger = ledgerManager.findLedger(ledgerAssignment.getLedgerIdentifier());
final AccountPage accountsOfLedger = ledgerManager.fetchAccountsOfLedger(ledger.getIdentifier(), null, null, null, null);
@@ -291,6 +299,7 @@
final String accountNumber = createCaseAccountNumber(customerIdentifier, ledgerAssignment.getDesignator(), i);
generatedAccount.setIdentifier(accountNumber);
generatedAccount.setName(accountNumber);
+ generatedAccount.setReferenceAccount(ledgerAssignment.getReferenceAccountIdentifier());
try {
ledgerManager.createAccount(generatedAccount);
return Optional.of(accountNumber);
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapperTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapperTest.java
index be8a427..ba232f0 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapperTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/DesignatorToAccountIdentifierMapperTest.java
@@ -80,6 +80,12 @@
return this;
}
+ @SuppressWarnings("SameParameterValue")
+ TestCase expectedMapCustomerLoanPrincipalResult(final String newVal) {
+ this.expectedMapCustomerLoanPrincipalResult = Optional.of(newVal);
+ return this;
+ }
+
@Override
public String toString() {
return "TestCase{" +
@@ -127,6 +133,94 @@
Optional.empty())
.expectedGroupsNeedingLedgers(Collections.emptySet());
ret.add(groupingIgnoredTestCase);
+
+ final TestCase alternativeIdsGroupedInLedgerTestCase = new TestCase("for import alternative ids are necessary. Grouped in this case.")
+ .productAccountAssignments(new HashSet<>(Arrays.asList(
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "x"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_INTEREST, "x"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_FEES, "x")
+ )))
+ .caseAccountAssignments(new HashSet<>(Collections.singletonList(
+ cAssignLedger(AccountDesignators.CUSTOMER_LOAN_GROUP)
+ )))
+ .oneTimeAccountAssignments(Arrays.asList(
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "alternativeCLPName"),
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_INTEREST, "alternativeCLIName"),
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_FEES, "alternativeCLFName")
+ ))
+ .expectedLedgersNeedingAccounts(new HashSet<>(Arrays.asList(
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "y", "alternativeCLPName"),
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_INTEREST, "y", "alternativeCLIName"),
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_FEES, "y", "alternativeCLFName"))))
+ .expectedCaseAccountAssignmentMappingForCustomerLoanGroup(
+ Optional.of(assignAccount(AccountDesignators.CUSTOMER_LOAN_GROUP)))
+ .expectedGroupsNeedingLedgers(new HashSet<>(Collections.singletonList(
+ new DesignatorToAccountIdentifierMapper.GroupNeedingLedger(AccountDesignators.CUSTOMER_LOAN_GROUP, "x"))));
+ ret.add(alternativeIdsGroupedInLedgerTestCase);
+
+
+ final TestCase alternativeIdsNotGroupedTestCase = new TestCase("for import alternative ids are necessary. Not grouped in this case.")
+ .productAccountAssignments(new HashSet<>(Arrays.asList(
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "x"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_INTEREST, "y"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_FEES, "z")
+ )))
+ .caseAccountAssignments(Collections.emptySet())
+ .oneTimeAccountAssignments(Arrays.asList(
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "alternativeCLPName"),
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_INTEREST, "alternativeCLIName"),
+ importParameterAccountAssignment(AccountDesignators.CUSTOMER_LOAN_FEES, "alternativeCLFName")
+ ))
+ .expectedLedgersNeedingAccounts(new HashSet<>(Arrays.asList(
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "x", "alternativeCLPName"),
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_INTEREST, "y", "alternativeCLIName"),
+ assignLedger(AccountDesignators.CUSTOMER_LOAN_FEES, "z", "alternativeCLFName"))))
+ .expectedCaseAccountAssignmentMappingForCustomerLoanGroup(
+ Optional.empty())
+ .expectedGroupsNeedingLedgers(Collections.emptySet());
+ ret.add(alternativeIdsNotGroupedTestCase);
+
+ final TestCase existingAccountsTestCase = new TestCase("for import connecting to existing accounts. Grouping shouldn't be relevant.")
+ .productAccountAssignments(new HashSet<>(Arrays.asList(
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "x"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_INTEREST, "y"),
+ pAssignLedger(AccountDesignators.CUSTOMER_LOAN_FEES, "z")
+ )))
+ .caseAccountAssignments(Collections.emptySet())
+ .oneTimeAccountAssignments(Arrays.asList(
+ importParameterExistingAccountAssignment(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "existingCLPName"),
+ importParameterExistingAccountAssignment(AccountDesignators.CUSTOMER_LOAN_INTEREST, "existingCLIName"),
+ importParameterExistingAccountAssignment(AccountDesignators.CUSTOMER_LOAN_FEES, "existingCLFName")
+ ))
+ .expectedLedgersNeedingAccounts(new HashSet<>(Arrays.asList(
+ assignLedgerExistingAccount(AccountDesignators.CUSTOMER_LOAN_PRINCIPAL, "x", "existingCLPName"),
+ assignLedgerExistingAccount(AccountDesignators.CUSTOMER_LOAN_INTEREST, "y", "existingCLIName"),
+ assignLedgerExistingAccount(AccountDesignators.CUSTOMER_LOAN_FEES, "z", "existingCLFName")
+ )))
+ .expectedCaseAccountAssignmentMappingForCustomerLoanGroup(
+ Optional.empty())
+ .expectedGroupsNeedingLedgers(Collections.emptySet())
+ .expectedMapCustomerLoanPrincipalResult("existingCLPName");
+ ret.add(existingAccountsTestCase);
+
+ final TestCase alternativeIdsNotGroupedInPatternTestCase = new TestCase("for import alternative ids are necessary. Not grouped in this case.")
+ .productAccountAssignments(new HashSet<>(Arrays.asList(
+ pAssignLedger("rando1", "x"),
+ pAssignLedger("rando2", "y")
+ )))
+ .caseAccountAssignments(Collections.emptySet())
+ .oneTimeAccountAssignments(Arrays.asList(
+ importParameterAccountAssignment("rando1", "alternativeRando1Name"),
+ importParameterAccountAssignment("rando2", "alternativeRando2Name")
+ ))
+ .expectedLedgersNeedingAccounts(new HashSet<>(Arrays.asList(
+ assignLedger("rando1", "x", "alternativeRando1Name"),
+ assignLedger("rando2", "y", "alternativeRando2Name")
+ )))
+ .expectedCaseAccountAssignmentMappingForCustomerLoanGroup(
+ Optional.empty())
+ .expectedGroupsNeedingLedgers(Collections.emptySet());
+ ret.add(alternativeIdsNotGroupedInPatternTestCase);
return ret;
}
@@ -148,6 +242,24 @@
return ret;
}
+ private static AccountAssignment importParameterAccountAssignment(
+ final String accountDesignator,
+ final String referenceAccountIdentifier) {
+ final AccountAssignment ret = new AccountAssignment();
+ ret.setDesignator(accountDesignator);
+ ret.setReferenceAccountIdentifier(referenceAccountIdentifier);
+ return ret;
+ }
+
+ private static AccountAssignment importParameterExistingAccountAssignment(
+ final String accountDesignator,
+ final String existingAccountIdentifier) {
+ final AccountAssignment ret = new AccountAssignment();
+ ret.setDesignator(accountDesignator);
+ ret.setAccountIdentifier(existingAccountIdentifier);
+ return ret;
+ }
+
private static AccountAssignment assignLedger(
final String accountDesignator,
final String ledgerIdentifier) {
@@ -157,6 +269,28 @@
return ret;
}
+ private static AccountAssignment assignLedger(
+ final String accountDesignator,
+ final String ledgerIdentifier,
+ final String referenceAccountIdentifier) {
+ final AccountAssignment ret = new AccountAssignment();
+ ret.setDesignator(accountDesignator);
+ ret.setLedgerIdentifier(ledgerIdentifier);
+ ret.setReferenceAccountIdentifier(referenceAccountIdentifier);
+ return ret;
+ }
+
+ private static AccountAssignment assignLedgerExistingAccount(
+ final String accountDesignator,
+ final String ledgerIdentifier,
+ final String existingAccountIdentifier) {
+ final AccountAssignment ret = new AccountAssignment();
+ ret.setDesignator(accountDesignator);
+ ret.setLedgerIdentifier(ledgerIdentifier);
+ ret.setAccountIdentifier(existingAccountIdentifier);
+ return ret;
+ }
+
private static AccountAssignment assignAccount(
final String accountDesignator) {
final AccountAssignment ret = new AccountAssignment();