From 16ae622590a8fc2914168f4e770e7d8094e94119 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Fri, 15 Feb 2013 17:42:01 +0000 Subject: [PATCH] WIP: change to approach for undo disbursal to just reverse transactions rather than clear them down. Doing this leads to observation that need to change the way we are supported reversing or contra entries in the portfolio area for loan transactions. --- .../accounting/api/data/LoanDTO.java | 19 +- .../GLJournalEntryWritePlatformService.java | 16 +- ...WritePlatformServiceJpaRepositoryImpl.java | 114 ++-- .../core/data/EnumOptionData.java | 2 +- .../monetary/domain/ApplicationCurrency.java | 5 + ...WritePlatformServiceJpaRepositoryImpl.java | 13 +- .../loanaccount/api/LoansApiResource.java | 49 +- .../loanaccount/data/LoanAccountData.java | 3 +- .../data/LoanBasicDetailsData.java | 567 ------------------ .../loanaccount/data/LoanStatusEnumData.java | 16 +- .../loanaccount/data/LoanTransactionData.java | 88 ++- .../data/LoanTransactionEnumData.java | 44 ++ .../portfolio/loanaccount/domain/Loan.java | 110 +++- .../loanaccount/domain/LoanTransaction.java | 51 +- .../domain/LoanTransactionType.java | 150 +++-- .../service/LoanReadPlatformServiceImpl.java | 10 +- ...WritePlatformServiceJpaRepositoryImpl.java | 44 +- .../loanproduct/service/LoanEnumerations.java | 41 +- 18 files changed, 492 insertions(+), 850 deletions(-) delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanBasicDetailsData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/LoanDTO.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/LoanDTO.java index 8541e538b..f91aa980b 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/LoanDTO.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/api/data/LoanDTO.java @@ -16,8 +16,8 @@ public class LoanDTO { private boolean accrualBasedAccountingEnabled; private List newLoanTransactions; - public LoanDTO(Long loanId, Long loanProductId, Long officeId, boolean cashBasedAccountingEnabled, - boolean accrualBasedAccountingEnabled, List newLoanTransactions) { + public LoanDTO(final Long loanId, final Long loanProductId, final Long officeId, final boolean cashBasedAccountingEnabled, + final boolean accrualBasedAccountingEnabled, final List newLoanTransactions) { this.loanId = loanId; this.loanProductId = loanProductId; this.officeId = officeId; @@ -30,7 +30,7 @@ public class LoanDTO { return this.loanId; } - public void setLoanId(Long loanId) { + public void setLoanId(final Long loanId) { this.loanId = loanId; } @@ -38,7 +38,7 @@ public class LoanDTO { return this.loanProductId; } - public void setLoanProductId(Long loanProductId) { + public void setLoanProductId(final Long loanProductId) { this.loanProductId = loanProductId; } @@ -46,7 +46,7 @@ public class LoanDTO { return this.officeId; } - public void setOfficeId(Long officeId) { + public void setOfficeId(final Long officeId) { this.officeId = officeId; } @@ -54,7 +54,7 @@ public class LoanDTO { return this.cashBasedAccountingEnabled; } - public void setCashBasedAccountingEnabled(boolean cashBasedAccountingEnabled) { + public void setCashBasedAccountingEnabled(final boolean cashBasedAccountingEnabled) { this.cashBasedAccountingEnabled = cashBasedAccountingEnabled; } @@ -62,7 +62,7 @@ public class LoanDTO { return this.accrualBasedAccountingEnabled; } - public void setAccrualBasedAccountingEnabled(boolean accrualBasedAccountingEnabled) { + public void setAccrualBasedAccountingEnabled(final boolean accrualBasedAccountingEnabled) { this.accrualBasedAccountingEnabled = accrualBasedAccountingEnabled; } @@ -70,8 +70,7 @@ public class LoanDTO { return this.newLoanTransactions; } - public void setNewLoanTransactions(List newLoanTransactions) { + public void setNewLoanTransactions(final List newLoanTransactions) { this.newLoanTransactions = newLoanTransactions; } - -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLJournalEntryWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLJournalEntryWritePlatformService.java index acdd9aff4..659ee9792 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLJournalEntryWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/GLJournalEntryWritePlatformService.java @@ -5,6 +5,8 @@ */ package org.mifosplatform.accounting.service; +import java.util.Map; + import org.mifosplatform.accounting.api.commands.GLJournalEntryCommand; import org.mifosplatform.accounting.api.data.LoanDTO; import org.springframework.security.access.prepost.PreAuthorize; @@ -18,6 +20,16 @@ public interface GLJournalEntryWritePlatformService { String revertJournalEntry(String transactionId); void createJournalEntriesForLoan(LoanDTO loanDTO); - -} + /** + * Using this interface over createJournalEntriesForLoan(LoanDTO loanDTO) to + * remove the Object contract and have a 'Data' contract between portfolio + * and accounting subsystems. (portfolio had to know about DTO objects that + * belong in downstream system 'accounting') + * + * If the only thing portfolio knows about how to talk to account is a + * service with a data contract it will be easier move to other means of + * making that communication happen in the future + */ + void createJournalEntriesForLoan(Map accountingBridgeData); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLJournalEntryWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLJournalEntryWritePlatformServiceJpaRepositoryImpl.java index ce7f8aa62..bd3aab7da 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLJournalEntryWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/service/impl/GLJournalEntryWritePlatformServiceJpaRepositoryImpl.java @@ -6,8 +6,10 @@ package org.mifosplatform.accounting.service.impl; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; @@ -68,7 +70,7 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo @Transactional @Override - public String createJournalEntry(GLJournalEntryCommand command) { + public String createJournalEntry(final GLJournalEntryCommand command) { try { GLJournalEntryCommandValidator validator = new GLJournalEntryCommandValidator(command); validator.validateForCreate(); @@ -96,7 +98,7 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo @Transactional @Override - public String revertJournalEntry(String transactionId) { + public String revertJournalEntry(final String transactionId) { // is the transaction Id valid List journalEntries = glJournalEntryRepository.findUnReversedManualJournalEntriesByTransactionId(transactionId); @@ -130,7 +132,7 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo @Transactional @Override - public void createJournalEntriesForLoan(LoanDTO loanDTO) { + public void createJournalEntriesForLoan(final LoanDTO loanDTO) { // shouldn't be before an accounting closure if (loanDTO.isCashBasedAccountingEnabled()) { createJournalEntriesUsingCashRules(loanDTO); @@ -139,11 +141,58 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo } } - /** - * @param loanDTO - * @param loanTransactions - */ - private void createJournalEntriesUsingCashRules(LoanDTO loanDTO) { + @Transactional + @Override + public void createJournalEntriesForLoan(final Map accountingBridgeData) { + + final boolean cashBasedAccountingEnabled = (Boolean) accountingBridgeData.get("cashBasedAccountingEnabled"); + final boolean accrualBasedAccountingEnabled = (Boolean) accountingBridgeData.get("accrualBasedAccountingEnabled"); + + if (cashBasedAccountingEnabled) { + final LoanDTO loanDTO = populateDtoFromMap(accountingBridgeData, cashBasedAccountingEnabled, accrualBasedAccountingEnabled); + + createJournalEntriesUsingCashRules(loanDTO); + } else if (accrualBasedAccountingEnabled) { + // TODO Vishwas: add accrual based accounting rules + } + } + + private LoanDTO populateDtoFromMap(final Map accountingBridgeData, final boolean cashBasedAccountingEnabled, + final boolean accrualBasedAccountingEnabled) { + final Long loanId = (Long) accountingBridgeData.get("loanId"); + final Long loanProductId = (Long) accountingBridgeData.get("loanProductId"); + final Long officeId = (Long) accountingBridgeData.get("officeId"); + + final List newLoanTransactions = new ArrayList(); + + @SuppressWarnings("unchecked") + final List> newTransactionsMap = (List>) accountingBridgeData.get("newLoanTransactions"); + + for (Map map : newTransactionsMap) { + String transactionId = ((Long) map.get("id")).toString(); + Date transactionDate = ((LocalDate) map.get("date")).toDate(); + BigDecimal amount = (BigDecimal) map.get("amount"); + BigDecimal principal = (BigDecimal) map.get("principalPortion"); + BigDecimal interest = (BigDecimal) map.get("interestPortion"); + BigDecimal fees = (BigDecimal) map.get("feeChargesPortion"); + BigDecimal penalties = (BigDecimal) map.get("penaltyChargesPortion"); + boolean disbursement = (Boolean) map.get("disbursement"); + boolean repayment = (Boolean) map.get("repayment"); + boolean repaymentAtDisbursement = (Boolean) map.get("repaymentAtDisbursement"); + boolean contra = (Boolean) map.get("contra"); + boolean writeOff = (Boolean) map.get("writeOff"); + + final LoanTransactionDTO transaction = new LoanTransactionDTO(transactionId, transactionDate, amount, principal, interest, + fees, penalties, disbursement, repayment, repaymentAtDisbursement, contra, writeOff); + + newLoanTransactions.add(transaction); + + } + + return new LoanDTO(loanId, loanProductId, officeId, cashBasedAccountingEnabled, accrualBasedAccountingEnabled, newLoanTransactions); + } + + private void createJournalEntriesUsingCashRules(final LoanDTO loanDTO) { GLClosure latestGLClosure = glClosureRepository.getLatestGLClosureByBranch(loanDTO.getOfficeId()); Office office = officeRepository.findOne(loanDTO.getOfficeId()); Long loanProductId = loanDTO.getLoanProductId(); @@ -198,16 +247,9 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo * * In case the loan transaction is a contra, all debits are turned into * credits and vice versa - * - * @param office - * @param loanProductId - * @param loanTransaction - * @param entryDate - * @param transactionId - * @param loanId */ - private void createJournalEntriesForRepaymentOrContraUsingCashRules(Office office, Long loanProductId, - LoanTransactionDTO loanTransactionDTO, Date entryDate, String transactionId, Long loanId) { + private void createJournalEntriesForRepaymentOrContraUsingCashRules(final Office office, final Long loanProductId, + final LoanTransactionDTO loanTransactionDTO, final Date entryDate, String transactionId, final Long loanId) { BigDecimal principalAmount = loanTransactionDTO.getPrincipal(); BigDecimal interestAmount = loanTransactionDTO.getInterest(); BigDecimal feesAmount = loanTransactionDTO.getFees(); @@ -270,30 +312,27 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo } } - private GLAccount getLinkedFinAccountForLoanProduct(Long loanProductId, CASH_ACCOUNTS_FOR_LOAN finAccountType) { + private GLAccount getLinkedFinAccountForLoanProduct(final Long loanProductId, final CASH_ACCOUNTS_FOR_LOAN finAccountType) { ProductToGLAccountMapping accountMapping = accountMappingRepository.findByProductIdAndProductTypeAndFinancialAccountType( loanProductId, PortfolioProductType.LOAN.getValue(), finAccountType.getValue()); return accountMapping.getGlAccount(); } - private void createCreditJournalEntryForLoanProduct(Office office, GLAccount account, Long loanId, String transactionId, - Date entryDate, BigDecimal amount) { + private void createCreditJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId, + final String transactionId, final Date entryDate, final BigDecimal amount) { GLJournalEntry journalEntry = GLJournalEntry.createNew(office, account, transactionId, true, entryDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.LOAN.toString(), loanId); glJournalEntryRepository.saveAndFlush(journalEntry); } - private void createDebitJournalEntryForLoanProduct(Office office, GLAccount account, Long loanId, String transactionId, Date entryDate, - BigDecimal amount) { + private void createDebitJournalEntryForLoanProduct(final Office office, final GLAccount account, final Long loanId, + final String transactionId, final Date entryDate, final BigDecimal amount) { GLJournalEntry journalEntry = GLJournalEntry.createNew(office, account, transactionId, true, entryDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.LOAN.toString(), loanId); glJournalEntryRepository.saveAndFlush(journalEntry); } - /** - * @param command - */ - private void validateBusinessRulesForJournalEntries(GLJournalEntryCommand command) { + private void validateBusinessRulesForJournalEntries(final GLJournalEntryCommand command) { /** check if date of Journal entry is valid ***/ final LocalDate entryLocalDate = command.getEntryDate(); @@ -333,15 +372,9 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo GL_JOURNAL_ENTRY_INVALID_REASON.DEBIT_CREDIT_SUM_MISMATCH, null, null, null); } } - /** - * @param command - * @param office - * @param entryDate - * @param singleDebitOrCreditEntryCommands - * @param transactionId - */ - private void saveAllDebitOrCreditEntries(GLJournalEntryCommand command, final Office office, Date entryDate, - SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, String transactionId, JournalEntryType type) { + private void saveAllDebitOrCreditEntries(final GLJournalEntryCommand command, final Office office, final Date entryDate, + final SingleDebitOrCreditEntryCommand[] singleDebitOrCreditEntryCommands, final String transactionId, + final JournalEntryType type) { for (SingleDebitOrCreditEntryCommand singleDebitOrCreditEntryCommand : singleDebitOrCreditEntryCommands) { GLAccount glAccount = glAccountRepository.findOne(singleDebitOrCreditEntryCommand.getGlAccountId()); if (glAccount == null) { throw new GLAccountNotFoundException(singleDebitOrCreditEntryCommand.getGlAccountId()); } @@ -367,11 +400,7 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo } } - /** - * @param command - * @param dve - */ - private void handleJournalEntryDataIntegrityIssues(DataIntegrityViolationException dve) { + private void handleJournalEntryDataIntegrityIssues(final DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); logger.error(dve.getMessage(), dve); throw new PlatformDataIntegrityException("error.msg.glJournalEntry.unknown.data.integrity.issue", @@ -381,11 +410,8 @@ public class GLJournalEntryWritePlatformServiceJpaRepositoryImpl implements GLJo /** * TODO: Need a better implementation with guaranteed uniqueness (but not a * long UUID)...maybe something tied to system clock.. - * - * @return */ private String generateTransactionId() { return RandomStringUtils.random(15, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); } - -} +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EnumOptionData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EnumOptionData.java index 502751c3c..aa34ddaad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EnumOptionData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/EnumOptionData.java @@ -7,7 +7,7 @@ package org.mifosplatform.infrastructure.core.data; /** *

- * Immutable data object represent generic enumeration value. + * Immutable data object representing generic enumeration value. *

*/ @SuppressWarnings("unused") diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/ApplicationCurrency.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/ApplicationCurrency.java index 6232bcf37..6bc72d6cf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/ApplicationCurrency.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/ApplicationCurrency.java @@ -9,6 +9,7 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.springframework.data.jpa.domain.AbstractPersistable; @Entity @@ -66,4 +67,8 @@ public class ApplicationCurrency extends AbstractPersistable { public String getDisplaySymbol() { return displaySymbol; } + + public CurrencyData toData() { + return new CurrencyData(this.code, this.name, this.decimalPlaces, this.displaySymbol, this.nameCode); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java index e47bfc6f1..c8445b030 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java @@ -18,7 +18,6 @@ import org.mifosplatform.organisation.office.exception.OfficeNotFoundException; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepository; import org.mifosplatform.organisation.staff.exception.StaffNotFoundException; -import org.mifosplatform.organisation.staff.exception.StaffRoleException; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepository; import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; @@ -52,8 +51,8 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla private final StaffRepository staffRepository; @Autowired - public GroupWritePlatformServiceJpaRepositoryImpl(PlatformSecurityContext context, GroupRepository groupRepository, - ClientRepository clientRepository, OfficeRepository officeRepository , StaffRepository staffRepository) { + public GroupWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final GroupRepository groupRepository, + final ClientRepository clientRepository, final OfficeRepository officeRepository , final StaffRepository staffRepository) { this.context = context; this.groupRepository = groupRepository; this.clientRepository = clientRepository; @@ -63,7 +62,7 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla @Transactional @Override - public CommandProcessingResult createGroup(GroupCommand command) { + public CommandProcessingResult createGroup(final GroupCommand command) { try { this.context.authenticatedUser(); @@ -103,7 +102,7 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla @Transactional @Override - public CommandProcessingResult updateGroup(GroupCommand command) { + public CommandProcessingResult updateGroup(final GroupCommand command) { try { context.authenticatedUser(); @@ -150,7 +149,7 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla @Transactional @Override - public CommandProcessingResult deleteGroup(Long groupId) { + public CommandProcessingResult deleteGroup(final Long groupId) { context.authenticatedUser(); @@ -190,7 +189,7 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla /* * Guaranteed to throw an exception no matter what the data integrity issue is. */ - private void handleGroupDataIntegrityIssues(final GroupCommand command, DataIntegrityViolationException dve) { + private void handleGroupDataIntegrityIssues(final GroupCommand command, final DataIntegrityViolationException dve) { Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("external_id")) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java index 624ee90d0..b11d5a7b0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java @@ -75,18 +75,17 @@ import com.google.gson.JsonElement; @Scope("singleton") public class LoansApiResource { - private final Set LOAN_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "accountNo", "externalId", "clientId", - "groupId", "clientName", "groupName", "fundId", "fundName", "loanPurposeId", "loanOfficerId", "loanOfficerName", - "loanPurposeName", "loanProductId", "loanProductName", "loanProductDescription", "currency", "principal", "inArrearsTolerance", - "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", - "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "submittedOnDate", - "approvedOnDate", "expectedDisbursementDate", "actualDisbursementDate", "expectedFirstRepaymentOnDate", - "interestChargedFromDate", "closedOnDate", "expectedMaturityDate", "status", "lifeCycleStatusDate", "repaymentSchedule", - "transactions", "convenienceData", "charges", "guarantor", "collateral", "productOptions", "amortizationTypeOptions", - "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "termFrequencyTypeOptions", + private final Set LOAN_DATA_PARAMETERS = new HashSet(Arrays.asList("id", "accountNo", "status", "externalId", + "clientId", "groupId", "clientName", "groupName", "loanProductId", "loanProductName", "loanProductDescription", "fundId", + "fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", + "inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", + "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", + "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", + "expectedFirstRepaymentOnDate", "interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "repaymentSchedule", + "transactions", "charges", "collateral", "guarantors", "productOptions", "amortizationTypeOptions", "interestTypeOptions", + "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions", - "chargeTemplate", "transactionProcessingStrategyId", "termFrequency", "termPeriodFrequencyType", "loanPurposeOptions", - "loanCollateralOptions")); + "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate")); private final String resourceNameForPermissions = "LOAN"; @@ -189,23 +188,23 @@ public class LoansApiResource { final Long officeId = loanBasicDetails.officeId(); final Collection allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId); - newLoanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, - loanRepayments, charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, - interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, - allowedLoanOfficers, loanPurposeOptions, loanCollateralOptions); + newLoanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments, charges, + collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, + loanPurposeOptions, loanCollateralOptions); } else if (groupId != null) { final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveGroupAndProductDetails(groupId, productId); final Collection charges = loanBasicDetails.charges(); final Long officeId = loanBasicDetails.officeId(); - final CollectionallowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId); + final Collection allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId); - newLoanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, - loanRepayments, charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, - repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, - interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, - allowedLoanOfficers, loanPurposeOptions, loanCollateralOptions); + newLoanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments, charges, + collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, + loanPurposeOptions, loanCollateralOptions); } else { newLoanAccount = LoanAccountData.collateralTemplate(loanCollateralOptions); } @@ -235,12 +234,12 @@ public class LoansApiResource { if (!associationParameters.isEmpty()) { if (associationParameters.contains("all")) { - associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "charges", "guarantor", + associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "charges", "guarantors", "collateral")); } - if (associationParameters.contains("guarantor")) { - mandatoryResponseParameters.add("guarantor"); + if (associationParameters.contains("guarantors")) { + mandatoryResponseParameters.add("guarantors"); guarantors = this.guarantorReadPlatformService.retrieveGuarantorsForLoan(loanId); if (CollectionUtils.isEmpty(guarantors)) { guarantors = null; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java index 9410a0783..aeb0979d1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java @@ -90,10 +90,11 @@ public class LoanAccountData { private final Collection interestCalculationPeriodTypeOptions; private final Collection fundOptions; private final Collection chargeOptions; - private final ChargeData chargeTemplate; private final Collection loanPurposeOptions; private final Collection loanCollateralOptions; + private final ChargeData chargeTemplate; + /** * Used to produce a {@link LoanAccountData} with only collateral options * for now. diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanBasicDetailsData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanBasicDetailsData.java deleted file mode 100644 index 309ffd436..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanBasicDetailsData.java +++ /dev/null @@ -1,567 +0,0 @@ -/** - * 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.portfolio.loanaccount.data; - -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collection; - -import org.joda.time.DateTime; -import org.joda.time.Days; -import org.joda.time.LocalDate; -import org.joda.time.Months; -import org.mifosplatform.infrastructure.core.data.EnumOptionData; -import org.mifosplatform.organisation.monetary.data.CurrencyData; -import org.mifosplatform.portfolio.charge.data.ChargeData; -import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; - -/** - * Immutable data object for core details of loan to be combined with - * {@link LoanAccountData} usage. - */ -public class LoanBasicDetailsData { - - private final Long id; - private final String accountNo; - private final String externalId; - private final Long clientId; - private final Long clientOfficeId; - private final String clientName; - private final Long groupId; - private final Long groupOfficeId; - private final String groupName; - private final Long loanProductId; - private final String loanProductName; - private final String loanProductDescription; - private final LoanStatusEnumData status; - private final Long fundId; - private final String fundName; - private final Long loanPurposeId; - private final String loanPurposeName; - private final Long loanOfficerId; - private final String loanOfficerName; - private final CurrencyData currency; - private final BigDecimal principal; - private final BigDecimal inArrearsTolerance; - - private final Integer termFrequency; - private final EnumOptionData termPeriodFrequencyType; - private final Integer numberOfRepayments; - private final Integer repaymentEvery; - private final EnumOptionData repaymentFrequencyType; - private final Long transactionProcessingStrategyId; - private final EnumOptionData amortizationType; - private final BigDecimal interestRatePerPeriod; - private final EnumOptionData interestRateFrequencyType; - private final BigDecimal annualInterestRate; - private final EnumOptionData interestType; - private final EnumOptionData interestCalculationPeriodType; - - private final LocalDate submittedOnDate; - private final String submittedByUsername; - private final String submittedByFirstname; - private final String submittedByLastname; - private final LocalDate approvedOnDate; - private final LocalDate expectedDisbursementDate; - private final LocalDate actualDisbursementDate; - private final LocalDate repaymentsStartingFromDate; - private final LocalDate interestChargedFromDate; - private final LocalDate closedOnDate; - private final LocalDate expectedMaturityDate; - - private final BigDecimal totalDisbursementCharges; - private final Collection charges; - - public static LoanBasicDetailsData populateForNewIndividualClientLoanCreation(final Long clientId, final String clientName, - final LocalDate expectedDisbursementDate, final Long clientOfficeId) { - return new LoanBasicDetailsData(clientId, clientName, clientOfficeId, null, null, null, expectedDisbursementDate); - } - - public static LoanBasicDetailsData populateForNewGroupLoanCreation(final Long groupId, final String groupName, - final LocalDate expectedDisbursementDate, final Long groupOfficeId) { - return new LoanBasicDetailsData(null, null, null, groupId, groupName, groupOfficeId, expectedDisbursementDate); - } - - public static LoanBasicDetailsData populateForNewLoanCreation(final LoanBasicDetailsData loanAccount, final LoanProductData product) { - - final Integer termFrequency = product.getNumberOfRepayments() * product.getRepaymentEvery(); - final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType(); - final Collection charges = new ArrayList(); - - for (ChargeData charge : product.charges()) { - charges.add(LoanChargeData.newLoanChargeDetails(charge.getId(), charge.getName(), charge.getCurrency(), charge.getAmount(), - charge.getChargeTimeType(), charge.getChargeCalculationType(), charge.isPenalty())); - } - - return new LoanBasicDetailsData(loanAccount.clientId, loanAccount.clientName, loanAccount.clientOfficeId, loanAccount.groupId, - loanAccount.groupName, loanAccount.groupOfficeId, product.getId(), product.getName(), product.getDescription(), - product.getFundId(), product.getFundName(), product.getCurrency(), product.getPrincipal(), product.getInArrearsTolerance(), - termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), product.getRepaymentEvery(), - product.getRepaymentFrequencyType(), product.getTransactionProcessingStrategyId(), product.getAmortizationType(), - product.getInterestRatePerPeriod(), product.getInterestRateFrequencyType(), product.getInterestType(), - product.getInterestCalculationPeriodType(), loanAccount.expectedDisbursementDate, charges); - } - - private LoanBasicDetailsData(final Long clientId, final String clientName, final Long clientOfficeId, final Long groupId, - final String groupName, final Long groupOfficeId, final Long productId, final String productName, - final String productDescription, final Long fundId, final String fundName, final CurrencyData currency, - final BigDecimal principal, final BigDecimal inArrearsTolerance, final Integer termFrequency, - final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, - final EnumOptionData repaymentFrequencyType, final Long transactionStrategyId, final EnumOptionData amortizationType, - final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final EnumOptionData interestType, - final EnumOptionData interestCalculationPeriodType, final LocalDate expectedDisbursementDate, - final Collection charges) { - this.id = null; - this.accountNo = null; - this.externalId = null; - this.clientId = clientId; - this.clientName = clientName; - this.clientOfficeId = clientOfficeId; - this.groupId = groupId; - this.groupName = groupName; - this.groupOfficeId = groupOfficeId; - this.loanProductId = productId; - this.loanProductName = productName; - this.loanProductDescription = productDescription; - this.status = null; - this.fundId = fundId; - this.fundName = fundName; - this.loanPurposeId = null; - this.loanPurposeName = null; - this.loanOfficerId = null; - this.loanOfficerName = null; - this.currency = currency; - this.principal = principal; - this.inArrearsTolerance = inArrearsTolerance; - - this.termFrequency = termFrequency; - this.termPeriodFrequencyType = termPeriodFrequencyType; - this.numberOfRepayments = numberOfRepayments; - this.repaymentEvery = repaymentEvery; - this.repaymentFrequencyType = repaymentFrequencyType; - this.transactionProcessingStrategyId = transactionStrategyId; - this.amortizationType = amortizationType; - - this.interestRatePerPeriod = interestRatePerPeriod; - this.annualInterestRate = null; - this.interestRateFrequencyType = interestRateFrequencyType; - this.interestType = interestType; - this.interestCalculationPeriodType = interestCalculationPeriodType; - - this.submittedOnDate = null; - this.submittedByUsername = null; - this.submittedByFirstname = null; - this.submittedByLastname = null; - this.approvedOnDate = null; - this.expectedDisbursementDate = expectedDisbursementDate; - - this.actualDisbursementDate = null; - this.closedOnDate = null; - this.expectedMaturityDate = null; - this.repaymentsStartingFromDate = null; - this.interestChargedFromDate = null; - - this.charges = charges; - this.totalDisbursementCharges = BigDecimal.ZERO; - } - - private LoanBasicDetailsData(final Long clientId, final String clientName, final Long clientOfficeId, final Long groupId, - final String groupName, final Long groupOfficeId, final LocalDate expectedDisbursementDate) { - this.id = null; - this.accountNo = null; - this.externalId = null; - this.clientId = clientId; - this.clientName = clientName; - this.clientOfficeId = clientOfficeId; - this.groupId = groupId; - this.groupName = groupName; - this.groupOfficeId = groupOfficeId; - this.loanProductId = null; - this.loanProductName = null; - this.loanProductDescription = null; - this.status = null; - this.fundId = null; - this.fundName = null; - this.loanPurposeId = null; - this.loanPurposeName = null; - this.loanOfficerId = null; - this.loanOfficerName = null; - this.currency = null; - this.principal = null; - this.inArrearsTolerance = null; - this.termFrequency = null; - this.termPeriodFrequencyType = null; - this.numberOfRepayments = null; - this.repaymentEvery = null; - this.transactionProcessingStrategyId = null; - this.interestRatePerPeriod = null; - this.annualInterestRate = null; - this.repaymentFrequencyType = null; - this.interestRateFrequencyType = null; - this.amortizationType = null; - this.interestType = null; - this.interestCalculationPeriodType = null; - - this.submittedOnDate = null; - this.submittedByUsername = null; - this.submittedByFirstname = null; - this.submittedByLastname = null; - this.approvedOnDate = null; - this.expectedDisbursementDate = expectedDisbursementDate; - - this.actualDisbursementDate = null; - this.closedOnDate = null; - this.expectedMaturityDate = null; - this.repaymentsStartingFromDate = null; - this.interestChargedFromDate = null; - - this.charges = null; - this.totalDisbursementCharges = BigDecimal.ZERO; - } - - public LoanBasicDetailsData(final Long id, final String accountNo, final String externalId, final Long clientId, - final String clientName, final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId, - final Long loanProductId, final String loanProductName, final String loanProductDescription, final Long fundId, - final String fundName, final Long loanPurposeId, final String loanPurposeName, final LocalDate closedOnDate, - final LocalDate submittedOnDate, final String submittedByUsername, final String submittedByFirstname, - final String submittedByLastname, final LocalDate approvedOnDate, final LocalDate expectedDisbursementDate, - final LocalDate actualDisbursementDate, final LocalDate expectedMaturityDate, final LocalDate repaymentsStartingFromDate, - final LocalDate interestChargedFromDate, final CurrencyData currency, final BigDecimal principal, - final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery, - final BigDecimal interestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType, - final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, - final EnumOptionData interestCalculationPeriodType, final LoanStatusEnumData status, final Integer termFrequency, - final EnumOptionData termPeriodFrequencyType, final Long transactionStrategyId, final Collection charges, - final Long loanOfficerId, final String loanOfficerName, final BigDecimal totalDisbursementCharges) { - this.id = id; - this.accountNo = accountNo; - this.externalId = externalId; - this.clientId = clientId; - this.clientName = clientName; - this.clientOfficeId = clientOfficeId; - this.groupId = groupId; - this.groupName = groupName; - this.groupOfficeId = groupOfficeId; - this.loanProductId = loanProductId; - this.loanProductName = loanProductName; - this.loanProductDescription = loanProductDescription; - this.fundId = fundId; - this.fundName = fundName; - this.loanPurposeId = loanPurposeId; - this.loanPurposeName = loanPurposeName; - this.loanOfficerId = loanOfficerId; - this.loanOfficerName = loanOfficerName; - this.closedOnDate = closedOnDate; - this.submittedOnDate = submittedOnDate; - this.submittedByUsername = submittedByUsername; - this.submittedByFirstname = submittedByFirstname; - this.submittedByLastname = submittedByLastname; - this.approvedOnDate = approvedOnDate; - this.expectedDisbursementDate = expectedDisbursementDate; - this.actualDisbursementDate = actualDisbursementDate; - this.expectedMaturityDate = expectedMaturityDate; - this.repaymentsStartingFromDate = repaymentsStartingFromDate; - this.interestChargedFromDate = interestChargedFromDate; - this.currency = currency; - this.principal = principal; - this.inArrearsTolerance = inArrearsTolerance; - this.numberOfRepayments = numberOfRepayments; - this.repaymentEvery = repaymentEvery; - this.interestRatePerPeriod = interestRatePerPeriod; - this.annualInterestRate = annualInterestRate; - this.repaymentFrequencyType = repaymentFrequencyType; - this.interestRateFrequencyType = interestRateFrequencyType; - this.amortizationType = amortizationType; - this.interestType = interestType; - this.interestCalculationPeriodType = interestCalculationPeriodType; - this.status = status; - this.termFrequency = termFrequency; - this.termPeriodFrequencyType = termPeriodFrequencyType; - this.transactionProcessingStrategyId = transactionStrategyId; - this.charges = charges; - this.totalDisbursementCharges = totalDisbursementCharges; - } - - public int getMaxSubmittedOnOffsetFromToday() { - return Days.daysBetween(new DateTime(), this.getSubmittedOnDate().toDateMidnight().toDateTime()).getDays(); - } - - public int getMaxApprovedOnOffsetFromToday() { - - int offset = 0; - if (this.getApprovedOnDate() != null) { - offset = Days.daysBetween(new DateTime(), this.getApprovedOnDate().toDateMidnight().toDateTime()).getDays(); - } - - return offset; - } - - public int getMaxDisbursedOnOffsetFromToday() { - - int offset = 0; - if (this.getActualDisbursementDate() != null) { - offset = Days.daysBetween(new DateTime(), this.getActualDisbursementDate().toDateMidnight().toDateTime()).getDays(); - } - - return offset; - } - - public int getActualLoanTermInDays() { - - LocalDate dateToUse = getExpectedDisbursementDate(); - if (getActualDisbursementDate() != null) { - dateToUse = getActualDisbursementDate(); - } - - LocalDate closingDateToUse = getExpectedMaturityDate(); - if (getClosedOnDate() != null) { - closingDateToUse = getClosedOnDate(); - } - - return Days.daysBetween(dateToUse.toDateMidnight().toDateTime(), closingDateToUse.toDateMidnight().toDateTime()).getDays(); - } - - public int getActualLoanTermInMonths() { - - LocalDate dateToUse = getExpectedDisbursementDate(); - if (getActualDisbursementDate() != null) { - dateToUse = getActualDisbursementDate(); - } - - LocalDate closingDateToUse = getExpectedMaturityDate(); - if (getClosedOnDate() != null) { - closingDateToUse = getClosedOnDate(); - } - - return Months.monthsBetween(dateToUse.toDateMidnight().toDateTime(), closingDateToUse.toDateMidnight().toDateTime()).getMonths(); - } - - public int getLoanTermInDays() { - - LocalDate dateToUse = getExpectedDisbursementDate(); - if (getActualDisbursementDate() != null) { - dateToUse = getActualDisbursementDate(); - } - - LocalDate closingDateToUse = getExpectedMaturityDate(); - - return Days.daysBetween(dateToUse.toDateMidnight().toDateTime(), closingDateToUse.toDateMidnight().toDateTime()).getDays(); - } - - public int getLoanTermInMonths() { - - LocalDate dateToUse = getExpectedDisbursementDate(); - if (getActualDisbursementDate() != null) { - dateToUse = getActualDisbursementDate(); - } - - LocalDate closingDateToUse = getExpectedMaturityDate(); - - return Months.monthsBetween(dateToUse.toDateMidnight().toDateTime(), closingDateToUse.toDateMidnight().toDateTime()).getMonths(); - } - - public Long getId() { - return id; - } - - public String getAccountNo() { - return this.accountNo; - } - - public String getExternalId() { - return externalId; - } - - public Long getClientId() { - return clientId; - } - - public String getClientName() { - return clientName; - } - - public Long getClientOfficeId() { - return clientOfficeId; - } - - public Long getGroupId() { - return groupId; - } - - public Long getGroupOfficeId() { - return groupOfficeId; - } - - public String getGroupName() { - return groupName; - } - - public Long getFundId() { - return fundId; - } - - public String getFundName() { - return fundName; - } - - public Long getLoanPurposeId() { - return this.loanPurposeId; - } - - public String getLoanPurposeName() { - return this.loanPurposeName; - } - - public Long getLoanProductId() { - return loanProductId; - } - - public String getLoanProductName() { - return loanProductName; - } - - public String getLoanProductDescription() { - return loanProductDescription; - } - - public LoanStatusEnumData getStatus() { - return status; - } - - public Integer getTermFrequency() { - return termFrequency; - } - - public EnumOptionData getTermPeriodFrequencyType() { - return termPeriodFrequencyType; - } - - public LocalDate getSubmittedOnDate() { - return submittedOnDate; - } - - public String getSubmittedByUsername() { - return this.submittedByUsername; - } - - public String getSubmittedByFirstname() { - return this.submittedByFirstname; - } - - public String getSubmittedByLastname() { - return this.submittedByLastname; - } - - public LocalDate getApprovedOnDate() { - return approvedOnDate; - } - - public LocalDate getExpectedDisbursementDate() { - return expectedDisbursementDate; - } - - public LocalDate getActualDisbursementDate() { - return actualDisbursementDate; - } - - public LocalDate getRepaymentsStartingFromDate() { - return repaymentsStartingFromDate; - } - - public LocalDate getInterestChargedFromDate() { - return interestChargedFromDate; - } - - public LocalDate getClosedOnDate() { - return closedOnDate; - } - - public LocalDate getExpectedMaturityDate() { - return expectedMaturityDate; - } - - public CurrencyData getCurrency() { - return currency; - } - - public BigDecimal getPrincipal() { - return principal; - } - - public BigDecimal getInArrearsTolerance() { - return inArrearsTolerance; - } - - public Integer getNumberOfRepayments() { - return numberOfRepayments; - } - - public Integer getRepaymentEvery() { - return repaymentEvery; - } - - public BigDecimal getInterestRatePerPeriod() { - return interestRatePerPeriod; - } - - public BigDecimal getAnnualInterestRate() { - return annualInterestRate; - } - - public EnumOptionData getRepaymentFrequencyType() { - return repaymentFrequencyType; - } - - public EnumOptionData getInterestRateFrequencyType() { - return interestRateFrequencyType; - } - - public EnumOptionData getAmortizationType() { - return amortizationType; - } - - public EnumOptionData getInterestType() { - return interestType; - } - - public EnumOptionData getInterestCalculationPeriodType() { - return interestCalculationPeriodType; - } - - public Long getTransactionStrategyId() { - return this.transactionProcessingStrategyId; - } - - public Collection getCharges() { - return charges; - } - - public Long getLoanOfficerId() { - return loanOfficerId; - } - - public String getLoanOfficerName() { - return loanOfficerName; - } - - public BigDecimal getTotalDisbursementCharges() { - return totalDisbursementCharges; - } - - public DisbursementData toDisburementData() { - return new DisbursementData(this.expectedDisbursementDate, this.actualDisbursementDate, this.principal); - } - - public Long getOfficeId() { - Long officeId = this.clientOfficeId; - - if (officeId == null) { - officeId = this.groupOfficeId; - } - - return officeId; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanStatusEnumData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanStatusEnumData.java index f84e8b8d6..5dba5c35f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanStatusEnumData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanStatusEnumData.java @@ -14,14 +14,14 @@ public class LoanStatusEnumData { private final Long id; private final String code; private final String value; - private boolean pendingApproval; - private boolean waitingForDisbursal; - private boolean active; - private boolean closedObligationsMet; - private boolean closedWrittenOff; - private boolean closedRescheduled; - private boolean closed; - private boolean overpaid; + private final boolean pendingApproval; + private final boolean waitingForDisbursal; + private final boolean active; + private final boolean closedObligationsMet; + private final boolean closedWrittenOff; + private final boolean closedRescheduled; + private final boolean closed; + private final boolean overpaid; public LoanStatusEnumData(final Long id, final String code, final String value) { this.id = id; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java index 087661e04..e4291d7a1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionData.java @@ -8,7 +8,6 @@ package org.mifosplatform.portfolio.loanaccount.data; import java.math.BigDecimal; import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.organisation.monetary.data.CurrencyData; /** @@ -16,53 +15,46 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData; */ public class LoanTransactionData { - @SuppressWarnings("unused") - private Long id; - - private EnumOptionData type; - - private LocalDate date; - - @SuppressWarnings("unused") - private CurrencyData currency; - - @SuppressWarnings("unused") - private BigDecimal amount; - @SuppressWarnings("unused") - private final BigDecimal principalPortion; - @SuppressWarnings("unused") - private final BigDecimal interestPortion; - @SuppressWarnings("unused") - private final BigDecimal feeChargesPortion; - @SuppressWarnings("unused") - private final BigDecimal penaltyChargesPortion; - - public LoanTransactionData( - final Long id, - final EnumOptionData transactionType, - final CurrencyData currency, - final LocalDate date, - final BigDecimal amount, - final BigDecimal principalPortion, - final BigDecimal interestPortion, - final BigDecimal feeChargesPortion, - final BigDecimal penaltyChargesPortion) { - this.id = id; - this.type = transactionType; - this.currency = currency; - this.date = date; - this.amount = amount; - this.principalPortion = principalPortion; - this.interestPortion = interestPortion; - this.feeChargesPortion = feeChargesPortion; - this.penaltyChargesPortion = penaltyChargesPortion; - } + @SuppressWarnings("unused") + private final Long id; - public LocalDate dateOf() { - return this.date; - } + private final LoanTransactionEnumData type; - public boolean isNotDisbursement() { - return type.getId().equals(Integer.valueOf(1)); - } + private final LocalDate date; + + @SuppressWarnings("unused") + private final CurrencyData currency; + + @SuppressWarnings("unused") + private final BigDecimal amount; + @SuppressWarnings("unused") + private final BigDecimal principalPortion; + @SuppressWarnings("unused") + private final BigDecimal interestPortion; + @SuppressWarnings("unused") + private final BigDecimal feeChargesPortion; + @SuppressWarnings("unused") + private final BigDecimal penaltyChargesPortion; + + public LoanTransactionData(final Long id, final LoanTransactionEnumData transactionType, final CurrencyData currency, + final LocalDate date, final BigDecimal amount, final BigDecimal principalPortion, final BigDecimal interestPortion, + final BigDecimal feeChargesPortion, final BigDecimal penaltyChargesPortion) { + this.id = id; + this.type = transactionType; + this.currency = currency; + this.date = date; + this.amount = amount; + this.principalPortion = principalPortion; + this.interestPortion = interestPortion; + this.feeChargesPortion = feeChargesPortion; + this.penaltyChargesPortion = penaltyChargesPortion; + } + + public LocalDate dateOf() { + return this.date; + } + + public boolean isNotDisbursement() { + return Integer.valueOf(1).equals(type.id()); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java new file mode 100644 index 000000000..fcb6854e3 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanTransactionEnumData.java @@ -0,0 +1,44 @@ +/** + * 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.portfolio.loanaccount.data; + +/** + * Immutable data object represent loan status enumerations. + */ +@SuppressWarnings("unused") +public class LoanTransactionEnumData { + + private final Long id; + private final String code; + private final String value; + + private final boolean disbursement; + private final boolean repaymentAtDisbursement; + private final boolean repayment; + private final boolean contra; + private final boolean waiveInterest; + private final boolean waiveCharges; + private final boolean writeOff; + private final boolean recoveryRepayment; + + public LoanTransactionEnumData(final Long id, final String code, final String value) { + this.id = id; + this.code = code; + this.value = value; + this.disbursement = Long.valueOf(1).equals(this.id); + this.repaymentAtDisbursement = Long.valueOf(5).equals(this.id); + this.repayment = Long.valueOf(2).equals(this.id); + this.contra = Long.valueOf(3).equals(this.id); + this.waiveInterest = Long.valueOf(4).equals(this.id); + this.waiveCharges = Long.valueOf(9).equals(this.id); + this.writeOff = Long.valueOf(6).equals(this.id); + this.recoveryRepayment = Long.valueOf(8).equals(this.id); + } + + public Long id() { + return this.id; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index 88a162c2d..288431bc8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.domain; import java.math.BigDecimal; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; @@ -42,6 +43,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator; +import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; @@ -1104,9 +1106,51 @@ public class Loan extends AbstractAuditableCustom { handleDisbursementTransaction(expectedDisbursedOnLocalDate); } + public Map deriveDisbursementData(final CurrencyData currencyData) { + + final Map accountingBridgeData = new LinkedHashMap(20); + + accountingBridgeData.put("loanId", this.getId()); + accountingBridgeData.put("loanProductId", this.productId()); + accountingBridgeData.put("officeId", this.getOfficeId()); + accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnLoanProduct()); + accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnLoanProduct()); + + final List> newLoanTransactions = new ArrayList>(); + final List disbursementTransactions = findDisbursementTransactions(); + for (LoanTransaction loanTransaction : disbursementTransactions) { + newLoanTransactions.add(loanTransaction.toMapData(currencyData)); + } + + accountingBridgeData.put("newLoanTransactions", newLoanTransactions); + + return accountingBridgeData; + } + + private List findDisbursementTransactions() { + List found = new ArrayList(); + for (LoanTransaction transaction : this.loanTransactions) { + if (transaction.isDisbursement() || transaction.isRepaymentAtDisbursement()) { + found.add(transaction); + } + } + + return found; + } + + private Collection findExistingTransactionIds() { + + Collection ids = new ArrayList(); + + for (LoanTransaction transaction : this.loanTransactions) { + ids.add(transaction.getId()); + } + + return ids; + } + public Map disburse(final AppUser currentUser, final JsonCommand command, - final LoanLifecycleStateMachine loanLifecycleStateMachine, - final ApplicationCurrency currency) { + final LoanLifecycleStateMachine loanLifecycleStateMachine, final ApplicationCurrency currency) { final Map actualChanges = new LinkedHashMap(); @@ -1179,11 +1223,12 @@ public class Loan extends AbstractAuditableCustom { updateLoanSchedule(generatedData); } - private void handleDisbursementTransaction(final LocalDate disbursedOn) { + private LoanTransaction handleDisbursementTransaction(final LocalDate disbursedOn) { // track disbursement transaction - final LoanTransaction loanTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), disbursedOn); - loanTransaction.updateLoan(this); - this.loanTransactions.add(loanTransaction); + final LoanTransaction disbursementTransaction = LoanTransaction.disbursement(this.loanRepaymentScheduleDetail.getPrincipal(), + disbursedOn); + disbursementTransaction.updateLoan(this); + this.loanTransactions.add(disbursementTransaction); // add repayment transaction to track incoming money from client to mfi // for (charges due at time of disbursement) @@ -1221,9 +1266,12 @@ public class Loan extends AbstractAuditableCustom { throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.after.first.repayment.due.date", errorMessage, disbursedOn, firstRepaymentDueDate); } + + return disbursementTransaction; } - public Map undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine) { + public Map undoDisbursal(final LoanLifecycleStateMachine loanLifecycleStateMachine, + final List existingTransactionIds) { final Map actualChanges = new LinkedHashMap(); @@ -1237,14 +1285,31 @@ public class Loan extends AbstractAuditableCustom { this.disbursedBy = null; actualChanges.put("disbursedOnDate", ""); + existingTransactionIds.addAll(findExistingTransactionIds()); + + contraExistingTransactions(); + updateLoanToPreDisbursalState(); } return actualChanges; } + private final void contraExistingTransactions() { + + // final List contras = new + // ArrayList(); + for (LoanTransaction transaction : this.loanTransactions) { + if (transaction.isNotContra()) { + LoanTransaction contra = transaction.contra(); + // contras.add(contra); + } + } + + // this.loanTransactions.addAll(contras); + } + private void updateLoanToPreDisbursalState() { - this.loanTransactions.clear(); this.disbursedOnDate = null; for (LoanCharge charge : getNullPointerSafeLoanCharges()) { @@ -2165,22 +2230,19 @@ public class Loan extends AbstractAuditableCustom { return officeId; } - public List getLoanTransactions() { - return this.loanTransactions; - } - public boolean isAccountingEnabledOnLoanProduct() { return this.loanProduct.isAccountingEnabled(); } - public boolean isCashBasedAccountingEnabledOnLoanProduct() { + public Boolean isCashBasedAccountingEnabledOnLoanProduct() { return this.loanProduct.isCashBasedAccountingEnabled(); } - public boolean isAccrualBasedAccountingEnabledOnLoanProduct() { + public Boolean isAccrualBasedAccountingEnabledOnLoanProduct() { return this.loanProduct.isAccrualBasedAccountingEnabled(); } + // TODO - make private if possible public Long productId() { return this.loanProduct.getId(); } @@ -2188,4 +2250,24 @@ public class Loan extends AbstractAuditableCustom { public Staff getLoanOfficer() { return this.loanOfficer; } + + public Map deriveAccountingBridgeData(final CurrencyData currencyData, final List existingTransactionIds) { + + final Map accountingBridgeData = new LinkedHashMap(); + accountingBridgeData.put("loanId", this.getId()); + accountingBridgeData.put("loanProductId", this.productId()); + accountingBridgeData.put("officeId", this.getOfficeId()); + accountingBridgeData.put("cashBasedAccountingEnabled", this.isCashBasedAccountingEnabledOnLoanProduct()); + accountingBridgeData.put("accrualBasedAccountingEnabled", this.isAccrualBasedAccountingEnabledOnLoanProduct()); + + final List> newLoanTransactions = new ArrayList>(); + for (LoanTransaction transaction : this.loanTransactions) { + if (!existingTransactionIds.contains(transaction.getId())) { + newLoanTransactions.add(transaction.toMapData(currencyData)); + } + } + + accountingBridgeData.put("newLoanTransactions", newLoanTransactions); + return accountingBridgeData; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java index b042cd30f..316307431 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransaction.java @@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.loanaccount.domain; import java.math.BigDecimal; import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -19,15 +21,14 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; +import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations; import org.mifosplatform.useradministration.domain.AppUser; -import org.springframework.format.annotation.DateTimeFormat; /** * All monetary transactions against a loan are modelled through this entity. @@ -61,7 +62,7 @@ public class LoanTransaction extends AbstractAuditableCustom { private final Date dateOf; @Column(name = "transaction_type_enum", nullable = false) - private Integer typeOf; + private final Integer typeOf; @OneToOne(optional = true, cascade = { CascadeType.PERSIST }) @JoinColumn(name = "contra_id") @@ -123,11 +124,10 @@ public class LoanTransaction extends AbstractAuditableCustom { return this.amount; } - public Money getAmount(MonetaryCurrency currency) { + public Money getAmount(final MonetaryCurrency currency) { return Money.of(currency, this.amount); } - @DateTimeFormat(style = "-M") public LocalDate getTransactionDate() { return new LocalDate(this.dateOf); } @@ -200,11 +200,20 @@ public class LoanTransaction extends AbstractAuditableCustom { return !isBelongingToLoanOf(check); } - public void contra() { + public LoanTransaction contra() { this.contra = LoanTransaction.contra(this); contra.updateLoan(this.loan); + + return this.contra; } + // public LoanTransaction newContra() { + // // should update some flag old entry being contra'd + // LoanTransaction contra = LoanTransaction.contra(this); + // contra.updateLoan(this.loan); + // return contra; + // } + public void updateLoan(final Loan loan) { this.loan = loan; } @@ -301,8 +310,36 @@ public class LoanTransaction extends AbstractAuditableCustom { } public LoanTransactionData toData(final CurrencyData currencyData) { - final EnumOptionData transactionType = LoanEnumerations.transactionType(this.typeOf); + final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf); return new LoanTransactionData(this.getId(), transactionType, currencyData, getTransactionDate(), this.amount, this.principalPortion, this.interestPortion, this.feeChargesPortion, this.penaltyChargesPortion); } + + public Map toMapData(final CurrencyData currencyData) { + final Map thisTransactionData = new LinkedHashMap(); + + LoanTransactionType type = LoanTransactionType.fromInt(this.typeOf); + final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(this.typeOf); + + thisTransactionData.put("id", this.getId()); + thisTransactionData.put("type", transactionType); + thisTransactionData.put("disbursement", type.isDisbursement()); + thisTransactionData.put("repaymentAtDisbursement", type.isRepaymentAtDisbursement()); + thisTransactionData.put("repayment", type.isRepayment()); + thisTransactionData.put("recoveryRepayment", type.isRecoveryRepayment()); + thisTransactionData.put("contra", type.isContra()); + thisTransactionData.put("waiveInterest", type.isWaiveInterest()); + thisTransactionData.put("waiveCharges", type.isWaiveCharges()); + thisTransactionData.put("writeOff", type.isWriteOff()); + + thisTransactionData.put("date", this.getTransactionDate()); + thisTransactionData.put("currency", currencyData); + thisTransactionData.put("amount", this.amount); + thisTransactionData.put("principalPortion", this.principalPortion); + thisTransactionData.put("interestPortion", this.interestPortion); + thisTransactionData.put("feeChargesPortion", this.feeChargesPortion); + thisTransactionData.put("penaltyChargesPortion", this.penaltyChargesPortion); + + return thisTransactionData; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java index 01534ffcc..955194f98 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/LoanTransactionType.java @@ -6,80 +6,106 @@ package org.mifosplatform.portfolio.loanaccount.domain; public enum LoanTransactionType { - - INVALID(0, "loanTransactionType.invalid"), // - DISBURSEMENT(1, "loanTransactionType.disbursement"), // - REPAYMENT(2, "loanTransactionType.repayment"), // - CONTRA(3, "loanTransactionType.contra"), // - WAIVE_INTEREST(4, "loanTransactionType.waiver"), // - REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement"), // - WRITEOFF(6, "loanTransactionType.writeOff"), - MARKED_FOR_RESCHEDULING(7, "loanTransactionType.marked.for.rescheduling"), // - /** - * This type of transactions is allowed on written-off loans where mfi still attempts to recover payments from applicant after writing-off. - */ - RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), - WAIVE_CHARGES(9, "loanTransactionType.waiveCharges"); + + INVALID(0, "loanTransactionType.invalid"), // + DISBURSEMENT(1, "loanTransactionType.disbursement"), // + REPAYMENT(2, "loanTransactionType.repayment"), // + CONTRA(3, "loanTransactionType.contra"), // + WAIVE_INTEREST(4, "loanTransactionType.waiver"), // + REPAYMENT_AT_DISBURSEMENT(5, "loanTransactionType.repaymentAtDisbursement"), // + WRITEOFF(6, "loanTransactionType.writeOff"), MARKED_FOR_RESCHEDULING(7, "loanTransactionType.marked.for.rescheduling"), // + /** + * This type of transactions is allowed on written-off loans where mfi still + * attempts to recover payments from applicant after writing-off. + */ + RECOVERY_REPAYMENT(8, "loanTransactionType.recoveryRepayment"), // + WAIVE_CHARGES(9, "loanTransactionType.waiveCharges"); private final Integer value; private final String code; private LoanTransactionType(final Integer value, final String code) { this.value = value; - this.code = code; + this.code = code; } public Integer getValue() { return this.value; } - - public String getCode() { - return code; - } - public static LoanTransactionType fromInt(final Integer transactionType) { + public String getCode() { + return code; + } - if (transactionType == null) { - return LoanTransactionType.INVALID; - } + public static LoanTransactionType fromInt(final Integer transactionType) { - LoanTransactionType loanTransactionType = null; - switch (transactionType) { - case 1: - loanTransactionType = LoanTransactionType.DISBURSEMENT; - break; - case 2: - loanTransactionType = LoanTransactionType.REPAYMENT; - break; - case 3: - loanTransactionType = LoanTransactionType.CONTRA; - break; - case 4: - loanTransactionType = LoanTransactionType.WAIVE_INTEREST; - break; - case 5: - loanTransactionType = LoanTransactionType.REPAYMENT_AT_DISBURSEMENT; - break; - case 6: - loanTransactionType = LoanTransactionType.WRITEOFF; - break; - case 7: - loanTransactionType = LoanTransactionType.MARKED_FOR_RESCHEDULING; - break; - case 8: - loanTransactionType = LoanTransactionType.RECOVERY_REPAYMENT; - break; - case 9: - loanTransactionType = LoanTransactionType.WAIVE_CHARGES; - break; - default: - loanTransactionType = LoanTransactionType.INVALID; - break; - } - return loanTransactionType; - } - - public boolean isWriteOff() { - return this.value.equals(LoanTransactionType.WRITEOFF.getValue()); - } + if (transactionType == null) { return LoanTransactionType.INVALID; } + + LoanTransactionType loanTransactionType = null; + switch (transactionType) { + case 1: + loanTransactionType = LoanTransactionType.DISBURSEMENT; + break; + case 2: + loanTransactionType = LoanTransactionType.REPAYMENT; + break; + case 3: + loanTransactionType = LoanTransactionType.CONTRA; + break; + case 4: + loanTransactionType = LoanTransactionType.WAIVE_INTEREST; + break; + case 5: + loanTransactionType = LoanTransactionType.REPAYMENT_AT_DISBURSEMENT; + break; + case 6: + loanTransactionType = LoanTransactionType.WRITEOFF; + break; + case 7: + loanTransactionType = LoanTransactionType.MARKED_FOR_RESCHEDULING; + break; + case 8: + loanTransactionType = LoanTransactionType.RECOVERY_REPAYMENT; + break; + case 9: + loanTransactionType = LoanTransactionType.WAIVE_CHARGES; + break; + default: + loanTransactionType = LoanTransactionType.INVALID; + break; + } + return loanTransactionType; + } + + public Boolean isDisbursement() { + return this.value.equals(LoanTransactionType.DISBURSEMENT.getValue()); + } + + public Boolean isRepaymentAtDisbursement() { + return this.value.equals(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue()); + } + + public Boolean isRepayment() { + return this.value.equals(LoanTransactionType.REPAYMENT.getValue()); + } + + public Boolean isRecoveryRepayment() { + return this.value.equals(LoanTransactionType.RECOVERY_REPAYMENT.getValue()); + } + + public Boolean isContra() { + return this.value.equals(LoanTransactionType.CONTRA.getValue()); + } + + public Boolean isWaiveInterest() { + return this.value.equals(LoanTransactionType.WAIVE_INTEREST.getValue()); + } + + public Boolean isWaiveCharges() { + return this.value.equals(LoanTransactionType.WAIVE_CHARGES.getValue()); + } + + public Boolean isWriteOff() { + return this.value.equals(LoanTransactionType.WRITEOFF.getValue()); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index be2ffdd12..5611acc85 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -32,6 +32,7 @@ import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData; import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; +import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; @@ -262,7 +263,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LocalDate earliestUnpaidInstallmentDate = loan.possibleNextRepaymentDate(); final Money possibleNextRepaymentAmount = loan.possibleNextRepaymentAmount(); - final EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); + final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT); return new LoanTransactionData(null, transactionType, currencyData, earliestUnpaidInstallmentDate, possibleNextRepaymentAmount.getAmount(), null, null, null, null); } @@ -287,7 +288,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final LoanTransaction waiveOfInterest = loan.deriveDefaultInterestWaiverTransaction(); - final EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST); + final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST); return new LoanTransactionData(null, transactionType, currencyData, waiveOfInterest.getTransactionDate(), waiveOfInterest.getAmount(), null, null, null, null); @@ -298,8 +299,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { context.authenticatedUser(); - EnumOptionData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); - + LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF); return new LoanTransactionData(null, transactionType, null, new LocalDate(), null, null, null, null, null); } @@ -605,7 +605,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Long id = rs.getLong("id"); final int transactionTypeInt = JdbcSupport.getInteger(rs, "transactionType"); - final EnumOptionData transactionType = LoanEnumerations.transactionType(transactionTypeInt); + final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(transactionTypeInt); final LocalDate date = JdbcSupport.getLocalDate(rs, "date"); final BigDecimal totalAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "total"); final BigDecimal principalPortion = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "principal"); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 909ba5f79..15bd5275e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -8,11 +8,9 @@ package org.mifosplatform.portfolio.loanaccount.service; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; @@ -22,6 +20,7 @@ import org.mifosplatform.accounting.service.GLJournalEntryWritePlatformService; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; @@ -104,7 +103,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } private boolean isBeforeToday(final LocalDate date) { - return date.isBefore(new LocalDate()); + return date.isBefore(DateUtils.getLocalDateOfTenant()); } private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { @@ -133,37 +132,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Map changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency); if (!changes.isEmpty()) { - // variable stores Id's of all existing loan transactions (newly - // created - // loan transactions would not have an Id before save) - final Set existingLoanTransactionIds = new HashSet(); - for (LoanTransaction loanTransaction : loan.getLoanTransactions()) { - if (!(loanTransaction.getId() == null)) { - existingLoanTransactionIds.add(loanTransaction.getId()); - } - } this.loanRepository.save(loan); if (StringUtils.isNotBlank(noteText)) { Note note = Note.loanNote(loan, noteText); this.noteRepository.save(note); } - - // make a call to accounting - if (loan.isAccountingEnabledOnLoanProduct()) { - /*** - * Variable holds list of all newly created loan transactions - * during this disbursal - **/ - List newLoanTransactions = new ArrayList(); - for (LoanTransaction loanTransaction : loan.getLoanTransactions()) { - if (!existingLoanTransactionIds.contains(loanTransaction.getId())) { - newLoanTransactions.add(loanTransaction); - } - } - LoanDTO loanDTO = populateLoanDTO(loan, newLoanTransactions); - journalEntryWritePlatformService.createJournalEntriesForLoan(loanDTO); - } + + final Map accountingBridgeData = loan.deriveDisbursementData(currency.toData()); + journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } return new CommandProcessingResultBuilder() // @@ -185,15 +162,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Loan loan = retrieveLoanBy(loanId); - final Map changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine()); + final List existingTransactionIds = new ArrayList(); + final Map changes = loan.undoDisbursal(defaultLoanLifecycleStateMachine(), existingTransactionIds); if (!changes.isEmpty()) { - this.loanRepository.save(loan); + this.loanRepository.saveAndFlush(loan); final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { Note note = Note.loanNote(loan, noteText); this.noteRepository.save(note); } + + final Loan loanRefetch = retrieveLoanBy(loanId); + + final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode()); + final Map accountingBridgeData = loanRefetch.deriveAccountingBridgeData(currency.toData(), existingTransactionIds); + journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } return new CommandProcessingResultBuilder() // diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index 2b12001b8..ebe19ab67 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanproduct.service; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; +import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionEnumData; import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType; import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType; @@ -129,11 +130,11 @@ public class LoanEnumerations { return optionData; } - public static EnumOptionData amortizationType(Integer id) { + public static EnumOptionData amortizationType(final Integer id) { return amortizationType(AmortizationMethod.fromInt(id)); } - public static EnumOptionData amortizationType(AmortizationMethod amortizationMethod) { + public static EnumOptionData amortizationType(final AmortizationMethod amortizationMethod) { EnumOptionData optionData = null; switch (amortizationMethod) { case EQUAL_INSTALLMENTS: @@ -152,11 +153,11 @@ public class LoanEnumerations { return optionData; } - public static EnumOptionData interestType(Integer id) { + public static EnumOptionData interestType(final Integer id) { return interestType(InterestMethod.fromInt(id)); } - public static EnumOptionData interestType(InterestMethod type) { + public static EnumOptionData interestType(final InterestMethod type) { EnumOptionData optionData = null; switch (type) { case FLAT: @@ -173,11 +174,11 @@ public class LoanEnumerations { return optionData; } - public static EnumOptionData interestCalculationPeriodType(Integer id) { + public static EnumOptionData interestCalculationPeriodType(final Integer id) { return interestCalculationPeriodType(InterestCalculationPeriodMethod.fromInt(id)); } - public static EnumOptionData interestCalculationPeriodType(InterestCalculationPeriodMethod type) { + public static EnumOptionData interestCalculationPeriodType(final InterestCalculationPeriodMethod type) { EnumOptionData optionData = null; switch (type) { case DAILY: @@ -196,51 +197,53 @@ public class LoanEnumerations { return optionData; } - public static EnumOptionData transactionType(final Integer id) { + public static LoanTransactionEnumData transactionType(final Integer id) { return transactionType(LoanTransactionType.fromInt(id)); } - public static EnumOptionData transactionType(final LoanTransactionType type) { - EnumOptionData optionData = null; + public static LoanTransactionEnumData transactionType(final LoanTransactionType type) { + LoanTransactionEnumData optionData = null; switch (type) { case INVALID: - optionData = new EnumOptionData(LoanTransactionType.INVALID.getValue().longValue(), LoanTransactionType.INVALID.getCode(), + optionData = new LoanTransactionEnumData(LoanTransactionType.INVALID.getValue().longValue(), + LoanTransactionType.INVALID.getCode(), "Invalid"); break; case DISBURSEMENT: - optionData = new EnumOptionData(LoanTransactionType.DISBURSEMENT.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.DISBURSEMENT.getValue().longValue(), LoanTransactionType.DISBURSEMENT.getCode(), "Dibursement"); break; case REPAYMENT: - optionData = new EnumOptionData(LoanTransactionType.REPAYMENT.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.REPAYMENT.getValue().longValue(), LoanTransactionType.REPAYMENT.getCode(), "Repayment"); break; case REPAYMENT_AT_DISBURSEMENT: - optionData = new EnumOptionData(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getValue().longValue(), LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.getCode(), "Repayment (at time of disbursement)"); break; case CONTRA: - optionData = new EnumOptionData(LoanTransactionType.CONTRA.getValue().longValue(), LoanTransactionType.CONTRA.getCode(), + optionData = new LoanTransactionEnumData(LoanTransactionType.CONTRA.getValue().longValue(), + LoanTransactionType.CONTRA.getCode(), "Reversal"); break; case WAIVE_INTEREST: - optionData = new EnumOptionData(LoanTransactionType.WAIVE_INTEREST.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.WAIVE_INTEREST.getValue().longValue(), LoanTransactionType.WAIVE_INTEREST.getCode(), "Waive interest"); break; case MARKED_FOR_RESCHEDULING: - optionData = new EnumOptionData(LoanTransactionType.MARKED_FOR_RESCHEDULING.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.MARKED_FOR_RESCHEDULING.getValue().longValue(), LoanTransactionType.MARKED_FOR_RESCHEDULING.getCode(), "Close (as rescheduled)"); break; case WRITEOFF: - optionData = new EnumOptionData(LoanTransactionType.WRITEOFF.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.WRITEOFF.getValue().longValue(), LoanTransactionType.WRITEOFF.getCode(), "Close (as written-off)"); break; case RECOVERY_REPAYMENT: - optionData = new EnumOptionData(LoanTransactionType.RECOVERY_REPAYMENT.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.RECOVERY_REPAYMENT.getValue().longValue(), LoanTransactionType.RECOVERY_REPAYMENT.getCode(), "Repayment (after write-off)"); break; case WAIVE_CHARGES: - optionData = new EnumOptionData(LoanTransactionType.WAIVE_CHARGES.getValue().longValue(), + optionData = new LoanTransactionEnumData(LoanTransactionType.WAIVE_CHARGES.getValue().longValue(), LoanTransactionType.WAIVE_CHARGES.getCode(), "Waive loan charges"); break; }