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; }