Taking a brief break from more important things for clearing out some todos.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
index 58bba51..9a63006 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
@@ -452,6 +452,4 @@
CasePage getAllCases(
@RequestParam("pageIndex") final Integer pageIndex,
@RequestParam("size") final Integer size);
-
- //TODO: find a way to list cases by customer even though the portfolio contains products which may be associated with groups instead of customers.
}
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 091f0d4..60833f5 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
@@ -65,7 +65,9 @@
static final String CONSUMER_LOAN_INTEREST_ACCOUNT_IDENTIFIER = "1103";
static final String LATE_FEE_INCOME_ACCOUNT_IDENTIFIER = "1311";
static final String LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER = "7840";
- static final String ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER = "3010";
+ static final String PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER = "7353.0";
+ static final String GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER = "3010";
+ static final String GENERAL_EXPENSE_ACCOUNT_IDENTIFIER = "3011";
static final Map<String, AccountData> accountMap = new HashMap<>();
@@ -240,11 +242,24 @@
return ret;
}
- private static Account arrearsAllowanceAccount() {
+ private static Account productLossAllowanceAccount() {
final Account ret = new Account();
- ret.setIdentifier(ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER);
- //ret.setGroup(LOAN_INCOME_LEDGER_IDENTIFIER); //TODO: ??
- ret.setType(AccountType.LIABILITY.name()); //TODO: ??
+ ret.setIdentifier(PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER);
+ ret.setType(AccountType.ASSET.name());
+ return ret;
+ }
+
+ private static Account generalLossAllowanceAccount() {
+ final Account ret = new Account();
+ ret.setIdentifier(GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER);
+ ret.setType(AccountType.EXPENSE.name());
+ return ret;
+ }
+
+ private static Account generalExpenseAccount() {
+ final Account ret = new Account();
+ ret.setIdentifier(GENERAL_EXPENSE_ACCOUNT_IDENTIFIER);
+ ret.setType(AccountType.EXPENSE.name());
return ret;
}
@@ -531,7 +546,9 @@
makeAccountResponsive(consumerLoanInterestAccount(), universalCreationDate, ledgerManagerMock);
makeAccountResponsive(lateFeeIncomeAccount(), universalCreationDate, ledgerManagerMock);
makeAccountResponsive(lateFeeAccrualAccount(), universalCreationDate, ledgerManagerMock);
- makeAccountResponsive(arrearsAllowanceAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(productLossAllowanceAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(generalLossAllowanceAccount(), universalCreationDate, ledgerManagerMock);
+ makeAccountResponsive(generalExpenseAccount(), universalCreationDate, ledgerManagerMock);
Mockito.doReturn(incomeLedger()).when(ledgerManagerMock).findLedger(INCOME_LEDGER_IDENTIFIER);
Mockito.doReturn(feesAndChargesLedger()).when(ledgerManagerMock).findLedger(FEES_AND_CHARGES_LEDGER_IDENTIFIER);
diff --git a/component-test/src/main/java/io/mifos/portfolio/Fixture.java b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
index 5054006..092052b 100644
--- a/component-test/src/main/java/io/mifos/portfolio/Fixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
@@ -67,9 +67,9 @@
accountAssignments.add(new AccountAssignment(INTEREST_ACCRUAL, LOAN_INTEREST_ACCRUAL_ACCOUNT_IDENTIFIER));
accountAssignments.add(new AccountAssignment(LATE_FEE_INCOME, LATE_FEE_INCOME_ACCOUNT_IDENTIFIER));
accountAssignments.add(new AccountAssignment(LATE_FEE_ACCRUAL, LATE_FEE_ACCRUAL_ACCOUNT_IDENTIFIER));
- accountAssignments.add(new AccountAssignment(PRODUCT_LOSS_ALLOWANCE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
- accountAssignments.add(new AccountAssignment(GENERAL_LOSS_ALLOWANCE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
- accountAssignments.add(new AccountAssignment(GENERAL_EXPENSE, ARREARS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+ accountAssignments.add(new AccountAssignment(PRODUCT_LOSS_ALLOWANCE, PRODUCT_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+ accountAssignments.add(new AccountAssignment(GENERAL_LOSS_ALLOWANCE, GENERAL_LOSS_ALLOWANCE_ACCOUNT_IDENTIFIER));
+ accountAssignments.add(new AccountAssignment(GENERAL_EXPENSE, GENERAL_EXPENSE_ACCOUNT_IDENTIFIER));
//accountAssignments.add(new AccountAssignment(ENTRY, ...));
// Don't assign entry account in test since it usually will not be assigned IRL.
accountAssignments.add(new AccountAssignment(LOAN_FUNDS_SOURCE, LOAN_FUNDS_SOURCE_ACCOUNT_IDENTIFIER));
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 cae6d77..63b306c 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -95,6 +95,43 @@
}
@Test
+ public void cantChangeDeniedCase() throws InterruptedException {
+ final LocalDateTime today = midnightToday();
+ step1CreateProduct();
+ step2CreateCase();
+ step3OpenCase(today);
+ step4DenyCase(today);
+
+ try {
+ customerCase.setInterest(BigDecimal.ONE);
+ portfolioManager.changeCase(product.getIdentifier(), customerCase.getIdentifier(), customerCase);
+ Assert.fail("Changing a denied case should fail.");
+ }
+ catch (IllegalArgumentException ignored) {
+
+ }
+ }
+
+ @Test
+ public void cantChangeApprovedCase() throws InterruptedException {
+ final LocalDateTime today = midnightToday();
+
+ step1CreateProduct();
+ step2CreateCase();
+ step3OpenCase(today);
+ step4ApproveCase(today);
+
+ try {
+ customerCase.setInterest(BigDecimal.ONE);
+ portfolioManager.changeCase(product.getIdentifier(), customerCase.getIdentifier(), customerCase);
+ Assert.fail("Changing a denied case should fail.");
+ }
+ catch (IllegalArgumentException ignored) {
+
+ }
+ }
+
+ @Test
public void workflowTerminatingInEarlyLoanPayoff() throws InterruptedException {
final LocalDateTime today = midnightToday();
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
index 6bb7b51..6d7b0ca 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/costcomponent/CostComponentService.java
@@ -152,7 +152,6 @@
default:
return BigDecimal.ZERO;
}
-//TODO: correctly implement charges which are proportional to other charges.
}
private static Function<BigDecimal, BigDecimal> howToApplyScheduledChargeToAmount(
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/checker/CaseChecker.java b/service/src/main/java/io/mifos/portfolio/service/internal/checker/CaseChecker.java
index 11b422f..e7b5510 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/checker/CaseChecker.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/checker/CaseChecker.java
@@ -29,7 +29,6 @@
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
-import java.util.Optional;
/**
* @author Myrle Krantz
@@ -56,16 +55,30 @@
caseService.findByIdentifier(productIdentifier, instance.getIdentifier())
.ifPresent(x -> {throw ServiceException.conflict("Duplicate identifier: " + productIdentifier + "." + x.getIdentifier());});
- final Optional<Boolean> productEnabled = productService.findEnabledByIdentifier(productIdentifier);
- if (!productEnabled.orElseThrow(() -> ServiceException.internalError("Product should exist, but doesn't"))) {
+ final Product product = productService.findByIdentifier(productIdentifier)
+ .orElseThrow(() -> ServiceException.badRequest("Product must exist ''{0}''.", productIdentifier));
+ final Boolean productEnabled = product.isEnabled();
+ if (!productEnabled) {
throw ServiceException.badRequest("Product must be enabled before cases for it can be created: " + productIdentifier);}
- checkForChange(productIdentifier, instance);
+ validateParameters(productIdentifier, instance, product);
}
public void checkForChange(final String productIdentifier, final Case instance) {
final Product product = productService.findByIdentifier(productIdentifier)
.orElseThrow(() -> ServiceException.badRequest("Product must exist ''{0}''.", productIdentifier));
+
+ final Case.State currentState = Case.State.valueOf(instance.getCurrentState());
+ if (currentState.equals(Case.State.ACTIVE) || currentState.equals(Case.State.CLOSED) || currentState.equals(Case.State.APPROVED))
+ throw ServiceException.badRequest("You may not change a case after it has been approved or closed.");
+
+ validateParameters(productIdentifier, instance, product);
+ }
+
+ private void validateParameters(
+ final String productIdentifier,
+ final Case instance,
+ final Product product) {
final InterestRange interestRange = product.getInterestRange();
final BigDecimal interest = instance.getInterest();
diff --git a/service/src/main/java/io/mifos/portfolio/service/rest/CaseRestController.java b/service/src/main/java/io/mifos/portfolio/service/rest/CaseRestController.java
index c24e7de..086a9c8 100644
--- a/service/src/main/java/io/mifos/portfolio/service/rest/CaseRestController.java
+++ b/service/src/main/java/io/mifos/portfolio/service/rest/CaseRestController.java
@@ -166,7 +166,6 @@
this.commandGateway.process(new ChangeCaseCommand(instance));
return new ResponseEntity<>(HttpStatus.ACCEPTED);
- //TODO: Make sure case can't be changed from certain states.
}
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_MANAGEMENT)