support for tracking what user took action on loan and being able to provide that data as part of api.

This commit is contained in:
Keith Woodlock
2013-02-14 23:13:38 +00:00
parent 0ec56c32f8
commit 285594e125
25 changed files with 1308 additions and 493 deletions
@@ -501,7 +501,8 @@ CREATE TABLE `m_loan` (
`product_id` bigint(20) DEFAULT NULL, `product_id` bigint(20) DEFAULT NULL,
`fund_id` bigint(20) DEFAULT NULL, `fund_id` bigint(20) DEFAULT NULL,
`loan_officer_id` bigint(20) DEFAULT NULL, `loan_officer_id` bigint(20) DEFAULT NULL,
`loanpurpose_cv_id` INT(11) DEFAULT NULL, `loanpurpose_cv_id` int(11) DEFAULT NULL,
`loan_transaction_strategy_id` bigint(20) DEFAULT NULL,
`loan_status_id` smallint(5) NOT NULL, `loan_status_id` smallint(5) NOT NULL,
`currency_code` varchar(3) NOT NULL, `currency_code` varchar(3) NOT NULL,
`currency_digits` smallint(5) NOT NULL, `currency_digits` smallint(5) NOT NULL,
@@ -514,29 +515,34 @@ CREATE TABLE `m_loan` (
`interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT '1', `interest_calculated_in_period_enum` smallint(5) NOT NULL DEFAULT '1',
`term_frequency` smallint(5) NOT NULL DEFAULT '0', `term_frequency` smallint(5) NOT NULL DEFAULT '0',
`term_period_frequency_enum` smallint(5) NOT NULL DEFAULT '2', `term_period_frequency_enum` smallint(5) NOT NULL DEFAULT '2',
`number_of_repayments` smallint(5) NOT NULL,
`repay_every` smallint(5) NOT NULL, `repay_every` smallint(5) NOT NULL,
`repayment_period_frequency_enum` smallint(5) NOT NULL, `repayment_period_frequency_enum` smallint(5) NOT NULL,
`number_of_repayments` smallint(5) NOT NULL,
`amortization_method_enum` smallint(5) NOT NULL, `amortization_method_enum` smallint(5) NOT NULL,
`total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL, `total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL,
`submittedon_date` datetime DEFAULT NULL, `interest_calculated_from_date` date DEFAULT NULL,
`approvedon_date` datetime DEFAULT NULL,
`expected_disbursedon_date` date DEFAULT NULL, `expected_disbursedon_date` date DEFAULT NULL,
`expected_firstrepaymenton_date` date DEFAULT NULL, `expected_firstrepaymenton_date` date DEFAULT NULL,
`interest_calculated_from_date` date DEFAULT NULL,
`disbursedon_date` date DEFAULT NULL,
`expected_maturedon_date` date DEFAULT NULL, `expected_maturedon_date` date DEFAULT NULL,
`maturedon_date` date DEFAULT NULL, `maturedon_date` date DEFAULT NULL,
`closedon_date` datetime DEFAULT NULL, `submittedon_date` date DEFAULT NULL,
`rejectedon_date` datetime DEFAULT NULL, `submittedon_userid` bigint(20) DEFAULT NULL,
`rescheduledon_date` datetime DEFAULT NULL, `approvedon_date` date DEFAULT NULL,
`withdrawnon_date` datetime DEFAULT NULL, `approvedon_userid` bigint(20) DEFAULT NULL,
`writtenoffon_date` datetime DEFAULT NULL, `rejectedon_date` date DEFAULT NULL,
`rejectedon_userid` bigint(20) DEFAULT NULL,
`withdrawnon_date` date DEFAULT NULL,
`withdrawnon_userid` bigint(20) DEFAULT NULL,
`disbursedon_date` date DEFAULT NULL,
`disbursedon_userid` bigint(20) DEFAULT NULL,
`rescheduledon_date` date DEFAULT NULL,
`writtenoffon_date` date DEFAULT NULL,
`closedon_date` date DEFAULT NULL,
`closedon_userid` bigint(20) DEFAULT NULL,
`createdby_id` bigint(20) DEFAULT NULL, `createdby_id` bigint(20) DEFAULT NULL,
`created_date` datetime DEFAULT NULL, `created_date` datetime DEFAULT NULL,
`lastmodified_date` datetime DEFAULT NULL, `lastmodified_date` datetime DEFAULT NULL,
`lastmodifiedby_id` bigint(20) DEFAULT NULL, `lastmodifiedby_id` bigint(20) DEFAULT NULL,
`loan_transaction_strategy_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `loan_account_no_UNIQUE` (`account_no`), UNIQUE KEY `loan_account_no_UNIQUE` (`account_no`),
UNIQUE KEY `loan_externalid_UNIQUE` (`external_id`), UNIQUE KEY `loan_externalid_UNIQUE` (`external_id`),
@@ -547,13 +553,25 @@ CREATE TABLE `m_loan` (
KEY `FK_m_loan_m_staff` (`loan_officer_id`), KEY `FK_m_loan_m_staff` (`loan_officer_id`),
KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`), KEY `FK_m_loanpurpose_codevalue` (`loanpurpose_cv_id`),
KEY `group_id` (`group_id`), KEY `group_id` (`group_id`),
CONSTRAINT `FK7C885877240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`), KEY `FK_submittedon_userid` (`submittedon_userid`),
KEY `FK_approvedon_userid` (`approvedon_userid`),
KEY `FK_rejectedon_userid` (`rejectedon_userid`),
KEY `FK_withdrawnon_userid` (`withdrawnon_userid`),
KEY `FK_closedon_userid` (`closedon_userid`),
KEY `FK_disbursedon_userid` (`disbursedon_userid`),
CONSTRAINT `FKB6F935D87179A0CB` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`), CONSTRAINT `FKB6F935D87179A0CB` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`),
CONSTRAINT `m_loan_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`),
CONSTRAINT `FKB6F935D8C8D4B434` FOREIGN KEY (`product_id`) REFERENCES `m_product_loan` (`id`), CONSTRAINT `FKB6F935D8C8D4B434` FOREIGN KEY (`product_id`) REFERENCES `m_product_loan` (`id`),
CONSTRAINT `FK7C885877240145` FOREIGN KEY (`fund_id`) REFERENCES `m_fund` (`id`),
CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`), CONSTRAINT `FK_loan_ltp_strategy` FOREIGN KEY (`loan_transaction_strategy_id`) REFERENCES `ref_loan_transaction_processing_strategy` (`id`),
CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`),
CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`), CONSTRAINT `FK_m_loanpurpose_codevalue` FOREIGN KEY (`loanpurpose_cv_id`) REFERENCES `m_code_value` (`id`),
CONSTRAINT `m_loan_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`) CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`),
CONSTRAINT `FK_submittedon_userid` FOREIGN KEY (`submittedon_userid`) REFERENCES `m_appuser` (`id`),
CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`),
CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`),
CONSTRAINT `FK_withdrawnon_userid` FOREIGN KEY (`withdrawnon_userid`) REFERENCES `m_appuser` (`id`),
CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`),
CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `m_guarantor` ( CREATE TABLE `m_guarantor` (
@@ -576,11 +594,9 @@ CREATE TABLE `m_guarantor` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
INDEX `FK_m_guarantor_m_loan` (`loan_id`), INDEX `FK_m_guarantor_m_loan` (`loan_id`),
CONSTRAINT `FK_m_guarantor_m_loan` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`) CONSTRAINT `FK_m_guarantor_m_loan` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`)
) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `m_loan` -- ALTER TABLE `m_loan` ADD CONSTRAINT `FK_m_loan_guarantor` FOREIGN KEY (`guarantor_id`) REFERENCES `m_guarantor` (`id`);
ADD CONSTRAINT `FK_m_loan_guarantor` FOREIGN KEY (`guarantor_id`) REFERENCES `m_guarantor` (`id`);
CREATE TABLE `m_loan_charge` ( CREATE TABLE `m_loan_charge` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, `id` bigint(20) NOT NULL AUTO_INCREMENT,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,51 @@
ALTER TABLE `m_loan`
DROP FOREIGN KEY `FK_m_loan_guarantor`;
ALTER TABLE `m_loan`
DROP COLUMN `guarantor_id`,
DROP INDEX `FK_m_loan_guarantor`;
ALTER TABLE `m_loan`
CHANGE COLUMN `submittedon_date` `submittedon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `approvedon_date` `approvedon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `closedon_date` `closedon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `rejectedon_date` `rejectedon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `rescheduledon_date` `rescheduledon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `withdrawnon_date` `withdrawnon_date` DATE NULL DEFAULT NULL,
CHANGE COLUMN `writtenoffon_date` `writtenoffon_date` DATE NULL DEFAULT NULL;
ALTER TABLE `m_loan`
ADD COLUMN `submittedon_userid` BIGINT(20) DEFAULT NULL AFTER `submittedon_date`,
ADD KEY `FK_submittedon_userid` (`submittedon_userid`),
ADD CONSTRAINT `FK_submittedon_userid` FOREIGN KEY (`submittedon_userid`) REFERENCES `m_appuser` (`id`);
ALTER TABLE `m_loan`
ADD COLUMN `approvedon_userid` BIGINT(20) DEFAULT NULL AFTER `approvedon_date`,
ADD KEY `FK_approvedon_userid` (`approvedon_userid`),
ADD CONSTRAINT `FK_approvedon_userid` FOREIGN KEY (`approvedon_userid`) REFERENCES `m_appuser` (`id`);
ALTER TABLE `m_loan`
ADD COLUMN `rejectedon_userid` BIGINT(20) DEFAULT NULL AFTER `rejectedon_date`,
ADD KEY `FK_rejectedon_userid` (`rejectedon_userid`),
ADD CONSTRAINT `FK_rejectedon_userid` FOREIGN KEY (`rejectedon_userid`) REFERENCES `m_appuser` (`id`);
ALTER TABLE `m_loan`
ADD COLUMN `withdrawnon_userid` BIGINT(20) DEFAULT NULL AFTER `withdrawnon_date`,
ADD KEY `FK_withdrawnon_userid` (`withdrawnon_userid`),
ADD CONSTRAINT `FK_withdrawnon_userid` FOREIGN KEY (`withdrawnon_userid`) REFERENCES `m_appuser` (`id`);
ALTER TABLE `m_loan`
ADD COLUMN `disbursedon_userid` BIGINT(20) DEFAULT NULL AFTER `disbursedon_date`,
ADD KEY `FK_disbursedon_userid` (`disbursedon_userid`),
ADD CONSTRAINT `FK_disbursedon_userid` FOREIGN KEY (`disbursedon_userid`) REFERENCES `m_appuser` (`id`);
ALTER TABLE `m_loan`
ADD COLUMN `closedon_userid` BIGINT(20) DEFAULT NULL AFTER `closedon_date`,
ADD KEY `FK_closedon_userid` (`closedon_userid`),
ADD CONSTRAINT `FK_closedon_userid` FOREIGN KEY (`closedon_userid`) REFERENCES `m_appuser` (`id`);
@@ -591,10 +591,11 @@ public class CommandWrapperBuilder {
return this; return this;
} }
public CommandWrapperBuilder deleteCodeValue(Long codeId, final Long codeValueId) { public CommandWrapperBuilder deleteCodeValue(final Long codeId, final Long codeValueId) {
this.actionName = "DELETE"; this.actionName = "DELETE";
this.entityName = "CODEVALUE"; this.entityName = "CODEVALUE";
this.entityId = codeValueId; this.entityId = codeValueId;
this.codeId = codeId;
this.href = "/codes/" + codeId + "/codevalues/" + codeValueId; this.href = "/codes/" + codeId + "/codevalues/" + codeValueId;
return this; return this;
} }
@@ -12,13 +12,12 @@ import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException; import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -33,9 +32,7 @@ public class Code extends AbstractPersistable<Long> {
@Column(name = "is_system_defined") @Column(name = "is_system_defined")
private final boolean systemDefined; private final boolean systemDefined;
@SuppressWarnings("unused") @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
private Set<CodeValue> values; private Set<CodeValue> values;
public static Code fromJson(final JsonCommand command) { public static Code fromJson(final JsonCommand command) {
@@ -72,7 +69,11 @@ public class Code extends AbstractPersistable<Long> {
actualChanges.put(firstnameParamName, newValue); actualChanges.put(firstnameParamName, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null); this.name = StringUtils.defaultIfEmpty(newValue, null);
} }
return actualChanges; return actualChanges;
} }
public boolean remove(final CodeValue codeValueToDelete) {
return this.values.remove(codeValueToDelete);
}
} }
@@ -27,6 +27,6 @@ public class DeleteCodeValueCommandHandler implements NewCommandSourceHandler {
@Override @Override
public CommandProcessingResult processCommand(final JsonCommand command) { public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.deleteCodeValue(command.entityId()); return this.writePlatformService.deleteCodeValue(command.getCodeId(), command.entityId());
} }
} }
@@ -14,5 +14,5 @@ public interface CodeValueWritePlatformService {
CommandProcessingResult updateCodeValue(Long codeValueId, JsonCommand command); CommandProcessingResult updateCodeValue(Long codeValueId, JsonCommand command);
CommandProcessingResult deleteCodeValue(Long codeValueId); CommandProcessingResult deleteCodeValue(Long codeId, Long codeValueId);
} }
@@ -11,7 +11,8 @@ import org.mifosplatform.infrastructure.codes.domain.Code;
import org.mifosplatform.infrastructure.codes.domain.CodeRepository; import org.mifosplatform.infrastructure.codes.domain.CodeRepository;
import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository; import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository;
import org.mifosplatform.infrastructure.codes.exception.CodeValueNotFoundException; import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.codes.exception.CodeNotFoundException;
import org.mifosplatform.infrastructure.codes.serialization.CodeValueCommandFromApiJsonDeserializer; import org.mifosplatform.infrastructure.codes.serialization.CodeValueCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -31,15 +32,18 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
private final static Logger logger = LoggerFactory.getLogger(CodeValueWritePlatformServiceJpaRepositoryImpl.class); private final static Logger logger = LoggerFactory.getLogger(CodeValueWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
private final CodeValueRepository codeValueRepository; private final CodeValueRepository codeValueRepository;
private final CodeRepository codeRepository; private final CodeRepository codeRepository;
private final CodeValueCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final CodeValueCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@Autowired @Autowired
public CodeValueWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final CodeRepository codeRepository, public CodeValueWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final CodeRepository codeRepository,
final CodeValueRepository codeValueRepository, final CodeValueCommandFromApiJsonDeserializer fromApiJsonDeserializer) { final CodeValueRepositoryWrapper codeValueRepositoryWrapper, final CodeValueRepository codeValueRepository,
final CodeValueCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
this.context = context; this.context = context;
this.codeRepository = codeRepository; this.codeRepository = codeRepository;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
this.codeValueRepository = codeValueRepository; this.codeValueRepository = codeValueRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
} }
@@ -58,7 +62,10 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
final CodeValue codeValue = CodeValue.fromJson(code, command); final CodeValue codeValue = CodeValue.fromJson(code, command);
this.codeValueRepository.save(codeValue); this.codeValueRepository.save(codeValue);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(codeValue.getId()).build(); return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(codeValue.getId()) //
.build();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleCodeValueDataIntegrityIssues(command, dve); handleCodeValueDataIntegrityIssues(command, dve);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -93,7 +100,7 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
this.fromApiJsonDeserializer.validateForUpdate(command.json()); this.fromApiJsonDeserializer.validateForUpdate(command.json());
final CodeValue codeValue = retrieveCodeValueBy(codeValueId); final CodeValue codeValue = this.codeValueRepositoryWrapper.findOneWithNotFoundDetection(codeValueId);
final Map<String, Object> changes = codeValue.update(command); final Map<String, Object> changes = codeValue.update(command);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
@@ -116,26 +123,28 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
@Transactional @Transactional
@Override @Override
public CommandProcessingResult deleteCodeValue(final Long codeValueId) { public CommandProcessingResult deleteCodeValue(final Long codeId, final Long codeValueId) {
try { try {
this.context.authenticatedUser(); this.context.authenticatedUser();
CodeValue codeValue = retrieveCodeValueBy(codeValueId); final Code code = this.codeRepository.findOne(codeId);
if (code == null) { throw new CodeNotFoundException(codeId); }
this.codeValueRepository.delete(codeValue); final CodeValue codeValueToDelete = this.codeValueRepositoryWrapper.findOneWithNotFoundDetection(codeValueId);
return new CommandProcessingResultBuilder().withEntityId(codeValueId).build(); boolean removed = code.remove(codeValueToDelete);
if (removed) {
this.codeRepository.save(code);
}
return new CommandProcessingResultBuilder() //
.withEntityId(codeValueId) //
.build();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve); logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.code.value.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.code.value.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + dve.getMostSpecificCause().getMessage()); "Unknown data integrity issue with resource: " + dve.getMostSpecificCause().getMessage());
} }
} }
private CodeValue retrieveCodeValueBy(final Long codeValueId) {
final CodeValue codeValue = this.codeValueRepository.findOne(codeValueId);
if (codeValue == null) { throw new CodeValueNotFoundException(codeValueId); }
return codeValue;
}
} }
@@ -47,12 +47,11 @@ import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.fund.data.FundData; import org.mifosplatform.portfolio.fund.data.FundData;
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService; import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData; import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanBasicDetailsData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData; import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData; import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData; import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
import org.mifosplatform.portfolio.loanaccount.guarantor.service.GuarantorReadPlatformService; import org.mifosplatform.portfolio.loanaccount.guarantor.service.GuarantorReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
@@ -153,53 +152,63 @@ public class LoansApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup(); // template
Collection<EnumOptionData> loanTermFrequencyTypeOptions = dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions(); final Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup();
Collection<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions(); final Collection<EnumOptionData> loanTermFrequencyTypeOptions = dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
Collection<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService final Collection<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService
.retrieveRepaymentFrequencyTypeOptions();
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService
.retrieveInterestRateFrequencyTypeOptions(); .retrieveInterestRateFrequencyTypeOptions();
Collection<EnumOptionData> amortizationTypeOptions = dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions(); final Collection<EnumOptionData> amortizationTypeOptions = dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
Collection<EnumOptionData> interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions(); final Collection<EnumOptionData> interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
Collection<EnumOptionData> interestCalculationPeriodTypeOptions = dropdownReadPlatformService final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = dropdownReadPlatformService
.retrieveLoanInterestRateCalculatedInPeriodOptions(); .retrieveLoanInterestRateCalculatedInPeriodOptions();
Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds(); final Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = this.dropdownReadPlatformService final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = this.dropdownReadPlatformService
.retreiveTransactionProcessingStrategies(); .retreiveTransactionProcessingStrategies();
final boolean feeChargesOnly = false;
Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
ChargeData chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
LoanBasicDetailsData loanBasicDetails = null;
Collection<LoanChargeData> charges = null;
Collection<LoanCollateralData> collateral = null;
Collection<GuarantorData> guarantors = null;
Collection<StaffData> allowedLoanOfficers = null;
if (clientId != null) {
loanBasicDetails = this.loanReadPlatformService.retrieveClientAndProductDetails(clientId, productId);
charges = loanBasicDetails.getCharges();
final Long officeId = loanBasicDetails.getClientOfficeId();
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId);
} else if (groupId != null) {
loanBasicDetails = this.loanReadPlatformService.retrieveGroupAndProductDetails(groupId, productId);
charges = loanBasicDetails.getCharges();
final Long officeId = loanBasicDetails.getGroupOfficeId();
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(officeId);
}
final Collection<CodeValueData> loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose"); final Collection<CodeValueData> loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
final Collection<CodeValueData> loanCollateralOptions = this.codeValueReadPlatformService final Collection<CodeValueData> loanCollateralOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode("LoanCollateral"); .retrieveCodeValuesByCode("LoanCollateral");
final boolean convenienceDataRequired = false; final boolean feeChargesOnly = false;
final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, charges, final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, final ChargeData chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions, // associations
loanCollateralOptions); final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> loanRepayments = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
LoanAccountData newLoanAccount = null;
if (clientId != null) {
final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveClientAndProductDetails(clientId, productId);
final Collection<LoanChargeData> charges = loanBasicDetails.charges();
final Long officeId = loanBasicDetails.officeId();
final Collection<StaffData> 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);
} else if (groupId != null) {
final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveGroupAndProductDetails(groupId, productId);
final Collection<LoanChargeData> charges = loanBasicDetails.charges();
final Long officeId = loanBasicDetails.officeId();
final Collection<StaffData>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);
} else {
newLoanAccount = LoanAccountData.collateralTemplate(loanCollateralOptions);
}
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS);
@@ -213,7 +222,7 @@ public class LoansApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId); final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
Collection<LoanTransactionData> loanRepayments = null; Collection<LoanTransactionData> loanRepayments = null;
LoanScheduleData repaymentSchedule = null; LoanScheduleData repaymentSchedule = null;
@@ -222,13 +231,12 @@ public class LoansApiResource {
Collection<LoanCollateralData> collateral = null; Collection<LoanCollateralData> collateral = null;
final Set<String> mandatoryResponseParameters = new HashSet<String>(); final Set<String> mandatoryResponseParameters = new HashSet<String>();
boolean convenienceDataRequired = false;
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) { if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) { if (associationParameters.contains("all")) {
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "convenienceData", associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "charges", "guarantor",
"charges", "guarantor", "collateral")); "collateral"));
} }
if (associationParameters.contains("guarantor")) { if (associationParameters.contains("guarantor")) {
@@ -253,11 +261,8 @@ public class LoansApiResource {
mandatoryResponseParameters.add("repaymentSchedule"); mandatoryResponseParameters.add("repaymentSchedule");
} }
DisbursementData singleDisbursement = loanBasicDetails.toDisburementData(); final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(), repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData);
singleDisbursement, loanBasicDetails.getTotalDisbursementCharges(), loanBasicDetails.getInArrearsTolerance());
convenienceDataRequired = true;
} }
if (associationParameters.contains("charges")) { if (associationParameters.contains("charges")) {
@@ -308,16 +313,16 @@ public class LoansApiResource {
final boolean feeChargesOnly = false; final boolean feeChargesOnly = false;
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate(); chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getOfficeId()); allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.officeId());
loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose"); loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral"); loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
} }
final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, repaymentSchedule, final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
loanRepayments, charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
loanPurposeOptions, loanCollateralOptions); loanCollateralOptions);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(), final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
mandatoryResponseParameters); mandatoryResponseParameters);
@@ -431,11 +436,15 @@ public class LoansApiResource {
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String assignLoanOfficerTemplate(@PathParam("loanId") final Long loanId, @Context final UriInfo uriInfo) { public String assignLoanOfficerTemplate(@PathParam("loanId") final Long loanId, @Context final UriInfo uriInfo) {
final LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId); // TODO - KW - review if this template method can be put back into
// normal
// template method to avoid 'assign' on api. and avoid needing to query
// for officeId and loanOfficerId in current way!
final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
final Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails final Collection<StaffData> allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails
.getOfficeId()); .officeId());
final Long fromLoanOfficerId = loanBasicDetails.getLoanOfficerId(); final Long fromLoanOfficerId = loanBasicDetails.loanOfficerId();
final BulkTransferLoanOfficerData loanReassignmentData = BulkTransferLoanOfficerData.template(fromLoanOfficerId, final BulkTransferLoanOfficerData loanReassignmentData = BulkTransferLoanOfficerData.template(fromLoanOfficerId,
allowedLoanOfficers, new LocalDate()); allowedLoanOfficers, new LocalDate());
@@ -446,5 +455,4 @@ public class LoansApiResource {
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.loanOfficeTransferToApiJsonSerializer.serialize(settings, loanReassignmentData, RESPONSE_DATA_PARAMETERS); return this.loanOfficeTransferToApiJsonSerializer.serialize(settings, loanReassignmentData, RESPONSE_DATA_PARAMETERS);
} }
} }
@@ -14,29 +14,30 @@ import org.joda.time.LocalDate;
*/ */
public class DisbursementData { public class DisbursementData {
private final LocalDate expectedDisbursementDate; private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate; private final LocalDate actualDisbursementDate;
private final BigDecimal principalDisbursed; private final BigDecimal principal;
public DisbursementData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, final BigDecimal principalDisbursed) { public DisbursementData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
this.expectedDisbursementDate = expectedDisbursementDate; final BigDecimal principalDisbursed) {
this.actualDisbursementDate = actualDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
this.principalDisbursed = principalDisbursed; this.actualDisbursementDate = actualDisbursementDate;
} this.principal = principalDisbursed;
}
public LocalDate disbursementDate() { public LocalDate disbursementDate() {
LocalDate disbursementDate = this.expectedDisbursementDate; LocalDate disbursementDate = this.expectedDisbursementDate;
if (actualDisbursementDate != null) { if (actualDisbursementDate != null) {
disbursementDate = actualDisbursementDate; disbursementDate = actualDisbursementDate;
} }
return disbursementDate; return disbursementDate;
} }
public BigDecimal amount() { public BigDecimal amount() {
return this.principalDisbursed; return this.principal;
} }
public boolean isDisbursed() { public boolean isDisbursed() {
return this.actualDisbursementDate != null; return this.actualDisbursementDate != null;
} }
} }
@@ -1,11 +1,12 @@
/** /**
* This Source Code Form is subject to the terms of the Mozilla Public * 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, * License, v. .0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. * You can obtain one at http://mozilla.org/MPL/.0/.
*/ */
package org.mifosplatform.portfolio.loanaccount.data; package org.mifosplatform.portfolio.loanaccount.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@@ -29,15 +30,17 @@ public class LoanAccountData {
// basic loan details // basic loan details
private final Long id; private final Long id;
private final String accountNo; private final String accountNo;
private final LoanStatusEnumData status;
private final String externalId; private final String externalId;
private final Long clientId; private final Long clientId;
private final String clientName; private final String clientName;
private final Long clientOfficeId;
private final Long groupId; private final Long groupId;
private final String groupName; private final String groupName;
private final Long groupOfficeId;
private final Long loanProductId; private final Long loanProductId;
private final String loanProductName; private final String loanProductName;
private final String loanProductDescription; private final String loanProductDescription;
private final LoanStatusEnumData status;
private final Long fundId; private final Long fundId;
private final String fundName; private final String fundName;
private final Long loanPurposeId; private final Long loanPurposeId;
@@ -47,7 +50,6 @@ public class LoanAccountData {
private final CurrencyData currency; private final CurrencyData currency;
private final BigDecimal principal; private final BigDecimal principal;
private final BigDecimal inArrearsTolerance; private final BigDecimal inArrearsTolerance;
private final Integer termFrequency; private final Integer termFrequency;
private final EnumOptionData termPeriodFrequencyType; private final EnumOptionData termPeriodFrequencyType;
private final Integer numberOfRepayments; private final Integer numberOfRepayments;
@@ -61,14 +63,13 @@ public class LoanAccountData {
private final EnumOptionData interestType; private final EnumOptionData interestType;
private final EnumOptionData interestCalculationPeriodType; private final EnumOptionData interestCalculationPeriodType;
private final LocalDate submittedOnDate; // settings
private final LocalDate approvedOnDate; private final LocalDate expectedFirstRepaymentOnDate;
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final LocalDate repaymentsStartingFromDate;
private final LocalDate interestChargedFromDate; private final LocalDate interestChargedFromDate;
private final LocalDate closedOnDate; // timeline
private final LocalDate expectedMaturityDate; private final LoanApplicationTimelineData timeline;
// totals
private final BigDecimal totalFeeChargesAtDisbursement;
// associations // associations
private final LoanScheduleData repaymentSchedule; private final LoanScheduleData repaymentSchedule;
@@ -76,7 +77,6 @@ public class LoanAccountData {
private final Collection<LoanChargeData> charges; private final Collection<LoanChargeData> charges;
private final Collection<LoanCollateralData> collateral; private final Collection<LoanCollateralData> collateral;
private final Collection<GuarantorData> guarantors; private final Collection<GuarantorData> guarantors;
private final LoanConvenienceData convenienceData;
// template // template
private final Collection<StaffData> loanOfficerOptions; private final Collection<StaffData> loanOfficerOptions;
@@ -94,7 +94,389 @@ public class LoanAccountData {
private final Collection<CodeValueData> loanPurposeOptions; private final Collection<CodeValueData> loanPurposeOptions;
private final Collection<CodeValueData> loanCollateralOptions; private final Collection<CodeValueData> loanCollateralOptions;
public LoanAccountData(final LoanBasicDetailsData basicDetails, final boolean convenienceDataRequired, /**
* Used to produce a {@link LoanAccountData} with only collateral options
* for now.
*/
public static LoanAccountData collateralTemplate(final Collection<CodeValueData> loanCollateralOptions) {
final Long id = null;
final String accountNo = null;
final LoanStatusEnumData status = null;
final String externalId = null;
final Long clientId = null;
final String clientName = null;
final Long clientOfficeId = null;
final Long groupId = null;
final String groupName = null;
final Long groupOfficeId = null;
final Long loanProductId = null;
final String loanProductName = null;
final String loanProductDescription = null;
final Long fundId = null;
final String fundName = null;
final Long loanPurposeId = null;
final String loanPurposeName = null;
final Long loanOfficerId = null;
final String loanOfficerName = null;
final CurrencyData currencyData = null;
final BigDecimal principal = null;
final BigDecimal inArrearsTolerance = null;
final Integer termFrequency = null;
final EnumOptionData termPeriodFrequencyType = null;
final Integer numberOfRepayments = null;
final Integer repaymentEvery = null;
final EnumOptionData repaymentFrequencyType = null;
final Long transactionProcessingStrategyId = null;
final EnumOptionData amortizationType = null;
final BigDecimal interestRatePerPeriod = null;
final EnumOptionData interestRateFrequencyType = null;
final BigDecimal annualInterestRate = null;
final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null;
final LocalDate expectedFirstRepaymentOnDate = null;
final LocalDate interestChargedFromDate = null;
final LoanApplicationTimelineData timeline = null;
final BigDecimal totalFeeChargesAtDisbursement = null;
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
final Collection<EnumOptionData> amortizationTypeOptions = null;
final Collection<EnumOptionData> interestTypeOptions = null;
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
final Collection<FundData> fundOptions = null;
final Collection<ChargeData> chargeOptions = null;
final ChargeData chargeTemplate = null;
final Collection<StaffData> loanOfficerOptions = null;
final Collection<CodeValueData> loanPurposeOptions = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
loanCollateralOptions);
}
/**
* Used to produce a {@link LoanAccountData} with only client information
* defaulted.
*/
public static LoanAccountData clientDefaults(final Long clientId, final String clientName, final Long clientOfficeId,
final LocalDate expectedDisbursementDate) {
final Long id = null;
final String accountNo = null;
final LoanStatusEnumData status = null;
final String externalId = null;
final Long groupId = null;
final String groupName = null;
final Long groupOfficeId = null;
final Long loanProductId = null;
final String loanProductName = null;
final String loanProductDescription = null;
final Long fundId = null;
final String fundName = null;
final Long loanPurposeId = null;
final String loanPurposeName = null;
final Long loanOfficerId = null;
final String loanOfficerName = null;
final CurrencyData currencyData = null;
final BigDecimal principal = null;
final BigDecimal inArrearsTolerance = null;
final Integer termFrequency = null;
final EnumOptionData termPeriodFrequencyType = null;
final Integer numberOfRepayments = null;
final Integer repaymentEvery = null;
final EnumOptionData repaymentFrequencyType = null;
final Long transactionProcessingStrategyId = null;
final EnumOptionData amortizationType = null;
final BigDecimal interestRatePerPeriod = null;
final EnumOptionData interestRateFrequencyType = null;
final BigDecimal annualInterestRate = null;
final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null;
final LocalDate expectedFirstRepaymentOnDate = null;
final LocalDate interestChargedFromDate = null;
final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate);
final BigDecimal totalFeeChargesAtDisbursement = null;
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
final Collection<EnumOptionData> amortizationTypeOptions = null;
final Collection<EnumOptionData> interestTypeOptions = null;
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
final Collection<FundData> fundOptions = null;
final Collection<ChargeData> chargeOptions = null;
final ChargeData chargeTemplate = null;
final Collection<StaffData> loanOfficerOptions = null;
final Collection<CodeValueData> loanPurposeOptions = null;
final Collection<CodeValueData> loanCollateralOptions = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
loanCollateralOptions);
}
/**
* Used to produce a {@link LoanAccountData} with only group information
* defaulted.
*/
public static LoanAccountData groupDefaults(final Long groupId, final String groupName, final Long groupOfficeId,
final LocalDate expectedDisbursementDate) {
final Long id = null;
final String accountNo = null;
final LoanStatusEnumData status = null;
final String externalId = null;
final Long clientId = null;
final String clientName = null;
final Long clientOfficeId = null;
final Long loanProductId = null;
final String loanProductName = null;
final String loanProductDescription = null;
final Long fundId = null;
final String fundName = null;
final Long loanPurposeId = null;
final String loanPurposeName = null;
final Long loanOfficerId = null;
final String loanOfficerName = null;
final CurrencyData currencyData = null;
final BigDecimal principal = null;
final BigDecimal inArrearsTolerance = null;
final Integer termFrequency = null;
final EnumOptionData termPeriodFrequencyType = null;
final Integer numberOfRepayments = null;
final Integer repaymentEvery = null;
final EnumOptionData repaymentFrequencyType = null;
final Long transactionProcessingStrategyId = null;
final EnumOptionData amortizationType = null;
final BigDecimal interestRatePerPeriod = null;
final EnumOptionData interestRateFrequencyType = null;
final BigDecimal annualInterestRate = null;
final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null;
final LocalDate expectedFirstRepaymentOnDate = null;
final LocalDate interestChargedFromDate = null;
final LoanApplicationTimelineData timeline = LoanApplicationTimelineData.templateDefault(expectedDisbursementDate);
final BigDecimal totalFeeChargesAtDisbursement = null;
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
final Collection<EnumOptionData> amortizationTypeOptions = null;
final Collection<EnumOptionData> interestTypeOptions = null;
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
final Collection<FundData> fundOptions = null;
final Collection<ChargeData> chargeOptions = null;
final ChargeData chargeTemplate = null;
final Collection<StaffData> loanOfficerOptions = null;
final Collection<CodeValueData> loanPurposeOptions = null;
final Collection<CodeValueData> loanCollateralOptions = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionProcessingStrategyId, amortizationType,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType,
expectedFirstRepaymentOnDate, interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule,
transactions, charges, collateral, guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
loanCollateralOptions);
}
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
final Collection<EnumOptionData> amortizationTypeOptions = null;
final Collection<EnumOptionData> interestTypeOptions = null;
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
final Collection<FundData> fundOptions = null;
final Collection<ChargeData> chargeOptions = null;
final ChargeData chargeTemplate = null;
final Collection<StaffData> loanOfficerOptions = null;
final Collection<CodeValueData> loanPurposeOptions = null;
final Collection<CodeValueData> loanCollateralOptions = null;
final Integer termFrequency = product.getNumberOfRepayments() * product.getRepaymentEvery();
final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType();
final Collection<LoanChargeData> charges = new ArrayList<LoanChargeData>();
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 LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
acc.groupId, acc.groupName, acc.groupOfficeId, product.getId(), product.getName(), product.getDescription(),
product.getFundId(), product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName,
product.getCurrency(), product.getPrincipal(), product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType,
product.getNumberOfRepayments(), product.getRepaymentEvery(), product.getRepaymentFrequencyType(),
product.getTransactionProcessingStrategyId(), product.getAmortizationType(), product.getInterestRatePerPeriod(),
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, acc.interestChargedFromDate, acc.timeline,
acc.totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral, guarantors, productOptions,
termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
}
/*
* Used to send back loan account data with the basic details coming from
* query.
*/
public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status,
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 Long loanOfficerId, final String loanOfficerName, final CurrencyData currencyData,
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 BigDecimal annualInterestRate,
final EnumOptionData interestType, final EnumOptionData interestCalculationPeriodType,
final LocalDate expectedFirstRepaymentOnDate, final LocalDate interestChargedFromDate,
final LoanApplicationTimelineData timeline, final BigDecimal totalFeeChargesAtDisbursement) {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
final Collection<EnumOptionData> amortizationTypeOptions = null;
final Collection<EnumOptionData> interestTypeOptions = null;
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = null;
final Collection<FundData> fundOptions = null;
final Collection<ChargeData> chargeOptions = null;
final ChargeData chargeTemplate = null;
final Collection<StaffData> loanOfficerOptions = null;
final Collection<CodeValueData> loanPurposeOptions = null;
final Collection<CodeValueData> loanCollateralOptions = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, loanPurposeName,
loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency, termPeriodFrequencyType,
numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId, amortizationType, interestRatePerPeriod,
interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType, expectedFirstRepaymentOnDate,
interestChargedFromDate, timeline, totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral,
guarantors, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
}
/*
* Used to combine the associations and template data on top of exist loan
* account data
*/
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final LoanScheduleData repaymentSchedule,
final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges,
final Collection<LoanCollateralData> collateral, final Collection<GuarantorData> guarantors,
final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions,
final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions,
final Collection<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<EnumOptionData> amortizationTypeOptions,
final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
final Collection<CodeValueData> loanCollateralOptions) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
acc.groupId, acc.groupName, acc.groupOfficeId, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency,
acc.principal, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments,
acc.repaymentEvery, acc.repaymentFrequencyType, acc.transactionProcessingStrategyId, acc.amortizationType,
acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.interestChargedFromDate, acc.timeline,
acc.totalFeeChargesAtDisbursement, repaymentSchedule, transactions, charges, collateral, guarantors, productOptions,
termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions);
}
private LoanAccountData(
final Long id, //
final String accountNo, //
final LoanStatusEnumData status, //
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 Long loanOfficerId,
final String loanOfficerName, //
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 transactionProcessingStrategyId,
final EnumOptionData amortizationType,
final BigDecimal interestRatePerPeriod,
final EnumOptionData interestRateFrequencyType,
final BigDecimal annualInterestRate,
final EnumOptionData interestType,
final EnumOptionData interestCalculationPeriodType,
final LocalDate expectedFirstRepaymentOnDate,
final LocalDate interestChargedFromDate,
final LoanApplicationTimelineData timeline,
final BigDecimal totalFeeChargesAtDisbursement, //
final LoanScheduleData repaymentSchedule, final Collection<LoanTransactionData> transactions, final LoanScheduleData repaymentSchedule, final Collection<LoanTransactionData> transactions,
final Collection<LoanChargeData> charges, final Collection<LoanCollateralData> collateral, final Collection<LoanChargeData> charges, final Collection<LoanCollateralData> collateral,
final Collection<GuarantorData> guarantors, final Collection<LoanProductData> productOptions, final Collection<GuarantorData> guarantors, final Collection<LoanProductData> productOptions,
@@ -105,11 +487,55 @@ public class LoanAccountData {
final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate, final Collection<FundData> fundOptions, final Collection<ChargeData> chargeOptions, final ChargeData chargeTemplate,
final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions, final Collection<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
final Collection<CodeValueData> loanCollateralOptions) { final Collection<CodeValueData> loanCollateralOptions) {
this.id = id;
this.accountNo = accountNo;
this.status = status;
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.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 = transactionProcessingStrategyId;
this.amortizationType = amortizationType;
this.interestRatePerPeriod = interestRatePerPeriod;
this.interestRateFrequencyType = interestRateFrequencyType;
this.annualInterestRate = annualInterestRate;
this.interestType = interestType;
this.interestCalculationPeriodType = interestCalculationPeriodType;
this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate;
this.interestChargedFromDate = interestChargedFromDate;
this.timeline = timeline;
// totals
this.totalFeeChargesAtDisbursement = totalFeeChargesAtDisbursement;
// associations
this.repaymentSchedule = repaymentSchedule; this.repaymentSchedule = repaymentSchedule;
this.transactions = transactions; this.transactions = transactions;
this.charges = charges; this.charges = charges;
this.collateral = collateral; this.collateral = collateral;
this.guarantors = guarantors; this.guarantors = guarantors;
// template
this.productOptions = productOptions; this.productOptions = productOptions;
this.termFrequencyTypeOptions = termFrequencyTypeOptions; this.termFrequencyTypeOptions = termFrequencyTypeOptions;
this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions; this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
@@ -124,114 +550,28 @@ public class LoanAccountData {
this.loanOfficerOptions = loanOfficerOptions; this.loanOfficerOptions = loanOfficerOptions;
this.loanPurposeOptions = loanPurposeOptions; this.loanPurposeOptions = loanPurposeOptions;
this.loanCollateralOptions = loanCollateralOptions; this.loanCollateralOptions = loanCollateralOptions;
}
if (convenienceDataRequired) { public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
int maxSubmittedOnOffsetFromToday = basicDetails.getMaxSubmittedOnOffsetFromToday(); return this.timeline.repaymentScheduleRelatedData(this.currency, this.principal, this.inArrearsTolerance,
int maxApprovedOnOffsetFromToday = basicDetails.getMaxApprovedOnOffsetFromToday(); this.totalFeeChargesAtDisbursement);
int maxDisbursedOnOffsetFromToday = basicDetails.getMaxDisbursedOnOffsetFromToday(); }
int expectedLoanTermInDays = basicDetails.getLoanTermInDays();
int expectedLoanTermInMonths = basicDetails.getLoanTermInMonths();
int actualLoanTermInDays = basicDetails.getActualLoanTermInDays();
int actualLoanTermInMonths = basicDetails.getActualLoanTermInMonths();
this.convenienceData = new LoanConvenienceData(maxSubmittedOnOffsetFromToday, maxApprovedOnOffsetFromToday, public Long officeId() {
maxDisbursedOnOffsetFromToday, expectedLoanTermInDays, actualLoanTermInDays, expectedLoanTermInMonths, Long officeId = this.clientOfficeId;
actualLoanTermInMonths);
} else { if (officeId == null) {
this.convenienceData = null; officeId = this.groupOfficeId;
} }
if (basicDetails != null) { return officeId;
this.id = basicDetails.getId(); }
this.accountNo = basicDetails.getAccountNo();
this.externalId = basicDetails.getExternalId();
this.clientId = basicDetails.getClientId();
this.clientName = basicDetails.getClientName();
this.groupId = basicDetails.getGroupId();
this.groupName = basicDetails.getGroupName();
this.loanProductId = basicDetails.getLoanProductId();
this.loanProductName = basicDetails.getLoanProductName();
this.loanProductDescription = basicDetails.getLoanProductDescription();
this.fundId = basicDetails.getFundId();
this.fundName = basicDetails.getFundName();
this.loanPurposeId = basicDetails.getLoanPurposeId();
this.loanPurposeName = basicDetails.getLoanPurposeName();
this.loanOfficerId = basicDetails.getLoanOfficerId();
this.loanOfficerName = basicDetails.getLoanOfficerName();
this.submittedOnDate = basicDetails.getSubmittedOnDate(); public Long loanOfficerId() {
this.approvedOnDate = basicDetails.getApprovedOnDate(); return this.loanOfficerId;
this.expectedDisbursementDate = basicDetails.getExpectedDisbursementDate(); }
this.actualDisbursementDate = basicDetails.getActualDisbursementDate();
this.closedOnDate = basicDetails.getClosedOnDate();
this.expectedMaturityDate = basicDetails.getExpectedMaturityDate();
this.repaymentsStartingFromDate = basicDetails.getRepaymentsStartingFromDate();
this.interestChargedFromDate = basicDetails.getInterestChargedFromDate();
this.currency = basicDetails.getCurrency(); public Collection<LoanChargeData> charges() {
this.principal = basicDetails.getPrincipal(); return this.charges;
this.inArrearsTolerance = basicDetails.getInArrearsTolerance();
this.termFrequency = basicDetails.getTermFrequency();
this.termPeriodFrequencyType = basicDetails.getTermPeriodFrequencyType();
this.numberOfRepayments = basicDetails.getNumberOfRepayments();
this.repaymentEvery = basicDetails.getRepaymentEvery();
this.transactionProcessingStrategyId = basicDetails.getTransactionStrategyId();
this.interestRatePerPeriod = basicDetails.getInterestRatePerPeriod();
this.annualInterestRate = basicDetails.getAnnualInterestRate();
this.repaymentFrequencyType = basicDetails.getRepaymentFrequencyType();
this.interestRateFrequencyType = basicDetails.getInterestRateFrequencyType();
this.amortizationType = basicDetails.getAmortizationType();
this.interestType = basicDetails.getInterestType();
this.interestCalculationPeriodType = basicDetails.getInterestCalculationPeriodType();
this.status = basicDetails.getStatus();
} else {
this.id = null;
this.accountNo = null;
this.externalId = null;
this.clientId = null;
this.clientName = null;
this.groupId = null;
this.groupName = null;
this.loanProductId = null;
this.loanProductName = null;
this.loanProductDescription = null;
this.fundId = null;
this.fundName = null;
this.loanPurposeId = null;
this.loanPurposeName = null;
this.loanOfficerId = null;
this.loanOfficerName = null;
this.submittedOnDate = null;
this.approvedOnDate = null;
this.expectedDisbursementDate = null;
this.actualDisbursementDate = null;
this.closedOnDate = null;
this.expectedMaturityDate = null;
this.repaymentsStartingFromDate = null;
this.interestChargedFromDate = 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.status = null;
}
} }
} }
@@ -0,0 +1,111 @@
package org.mifosplatform.portfolio.loanaccount.data;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object represent the important time-line events of a loan
* application and loan.
*/
@SuppressWarnings("unused")
public class LoanApplicationTimelineData {
private final LocalDate submittedOnDate;
private final String submittedByUsername;
private final String submittedByFirstname;
private final String submittedByLastname;
private final LocalDate rejectedOnDate;
private final String rejectedByUsername;
private final String rejectedByFirstname;
private final String rejectedByLastname;
private final LocalDate withdrawnOnDate;
private final String withdrawnByUsername;
private final String withdrawnByFirstname;
private final String withdrawnByLastname;
private final LocalDate approvedOnDate;
private final String approvedByUsername;
private final String approvedByFirstname;
private final String approvedByLastname;
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final String disbursedByUsername;
private final String disbursedByFirstname;
private final String disbursedByLastname;
private final LocalDate expectedMaturityDate;
public static LoanApplicationTimelineData templateDefault(final LocalDate expectedDisbursementDate) {
final LocalDate submittedOnDate = null;
final String submittedByUsername = null;
final String submittedByFirstname = null;
final String submittedByLastname = null;
final LocalDate rejectedOnDate = null;
final String rejectedByUsername = null;
final String rejectedByFirstname = null;
final String rejectedByLastname = null;
final LocalDate withdrawnOnDate = null;
final String withdrawnByUsername = null;
final String withdrawnByFirstname = null;
final String withdrawnByLastname = null;
final LocalDate approvedOnDate = null;
final String approvedByUsername = null;
final String approvedByFirstname = null;
final String approvedByLastname = null;
final LocalDate actualDisbursementDate = null;
final String disbursedByUsername = null;
final String disbursedByFirstname = null;
final String disbursedByLastname = null;
final LocalDate closedOnDate = null;
final String closedByUsername = null;
final String closedByFirstname = null;
final String closedByLastname = null;
final LocalDate expectedMaturityDate = null;
return new LoanApplicationTimelineData(submittedOnDate, submittedByUsername, submittedByFirstname, submittedByLastname,
rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname, withdrawnOnDate, withdrawnByUsername,
withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname,
expectedDisbursementDate, actualDisbursementDate, disbursedByUsername, disbursedByFirstname, disbursedByLastname,
closedOnDate, closedByUsername, closedByFirstname, closedByLastname, expectedMaturityDate);
}
public LoanApplicationTimelineData(final LocalDate submittedOnDate, final String submittedByUsername,
final String submittedByFirstname, final String submittedByLastname, final LocalDate rejectedOnDate,
final String rejectedByUsername, final String rejectedByFirstname, final String rejectedByLastname,
final LocalDate withdrawnOnDate, final String withdrawnByUsername, final String withdrawnByFirstname,
final String withdrawnByLastname, final LocalDate approvedOnDate, final String approvedByUsername,
final String approvedByFirstname, final String approvedByLastname, final LocalDate expectedDisbursementDate,
final LocalDate actualDisbursementDate, final String disbursedByUsername, final String disbursedByFirstname,
final String disbursedByLastname, final LocalDate closedOnDate, final String closedByUsername, final String closedByFirstname,
final String closedByLastname, final LocalDate expectedMaturityDate) {
this.submittedOnDate = submittedOnDate;
this.submittedByUsername = submittedByUsername;
this.submittedByFirstname = submittedByFirstname;
this.submittedByLastname = submittedByLastname;
this.rejectedOnDate = rejectedOnDate;
this.rejectedByUsername = rejectedByUsername;
this.rejectedByFirstname = rejectedByFirstname;
this.rejectedByLastname = rejectedByLastname;
this.withdrawnOnDate = withdrawnOnDate;
this.withdrawnByUsername = withdrawnByUsername;
this.withdrawnByFirstname = withdrawnByFirstname;
this.withdrawnByLastname = withdrawnByLastname;
this.approvedOnDate = approvedOnDate;
this.approvedByUsername = approvedByUsername;
this.approvedByFirstname = approvedByFirstname;
this.approvedByLastname = approvedByLastname;
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
this.disbursedByUsername = disbursedByUsername;
this.disbursedByFirstname = disbursedByFirstname;
this.disbursedByLastname = disbursedByLastname;
this.expectedMaturityDate = expectedMaturityDate;
}
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData(final CurrencyData currency, final BigDecimal principal,
final BigDecimal inArrearsTolerance, final BigDecimal totalFeeChargesAtDisbursement) {
return new RepaymentScheduleRelatedLoanData(this.expectedDisbursementDate, this.actualDisbursementDate, currency, principal,
inArrearsTolerance, totalFeeChargesAtDisbursement);
}
}
@@ -61,6 +61,9 @@ public class LoanBasicDetailsData {
private final EnumOptionData interestCalculationPeriodType; private final EnumOptionData interestCalculationPeriodType;
private final LocalDate submittedOnDate; private final LocalDate submittedOnDate;
private final String submittedByUsername;
private final String submittedByFirstname;
private final String submittedByLastname;
private final LocalDate approvedOnDate; private final LocalDate approvedOnDate;
private final LocalDate expectedDisbursementDate; private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate; private final LocalDate actualDisbursementDate;
@@ -149,6 +152,9 @@ public class LoanBasicDetailsData {
this.interestCalculationPeriodType = interestCalculationPeriodType; this.interestCalculationPeriodType = interestCalculationPeriodType;
this.submittedOnDate = null; this.submittedOnDate = null;
this.submittedByUsername = null;
this.submittedByFirstname = null;
this.submittedByLastname = null;
this.approvedOnDate = null; this.approvedOnDate = null;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
@@ -200,6 +206,9 @@ public class LoanBasicDetailsData {
this.interestCalculationPeriodType = null; this.interestCalculationPeriodType = null;
this.submittedOnDate = null; this.submittedOnDate = null;
this.submittedByUsername = null;
this.submittedByFirstname = null;
this.submittedByLastname = null;
this.approvedOnDate = null; this.approvedOnDate = null;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
@@ -217,7 +226,8 @@ public class LoanBasicDetailsData {
final String clientName, final Long clientOfficeId, final Long groupId, final String groupName, final Long groupOfficeId, 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 Long loanProductId, final String loanProductName, final String loanProductDescription, final Long fundId,
final String fundName, final Long loanPurposeId, final String loanPurposeName, final LocalDate closedOnDate, final String fundName, final Long loanPurposeId, final String loanPurposeName, final LocalDate closedOnDate,
final LocalDate submittedOnDate, final LocalDate approvedOnDate, final LocalDate expectedDisbursementDate, 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 actualDisbursementDate, final LocalDate expectedMaturityDate, final LocalDate repaymentsStartingFromDate,
final LocalDate interestChargedFromDate, final CurrencyData currency, final BigDecimal principal, final LocalDate interestChargedFromDate, final CurrencyData currency, final BigDecimal principal,
final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery, final BigDecimal inArrearsTolerance, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -225,7 +235,7 @@ public class LoanBasicDetailsData {
final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType,
final EnumOptionData interestCalculationPeriodType, final LoanStatusEnumData status, final Integer termFrequency, final EnumOptionData interestCalculationPeriodType, final LoanStatusEnumData status, final Integer termFrequency,
final EnumOptionData termPeriodFrequencyType, final Long transactionStrategyId, final Collection<LoanChargeData> charges, final EnumOptionData termPeriodFrequencyType, final Long transactionStrategyId, final Collection<LoanChargeData> charges,
final Long loanOfficerId, String loanOfficerName, final BigDecimal totalDisbursementCharges) { final Long loanOfficerId, final String loanOfficerName, final BigDecimal totalDisbursementCharges) {
this.id = id; this.id = id;
this.accountNo = accountNo; this.accountNo = accountNo;
this.externalId = externalId; this.externalId = externalId;
@@ -246,6 +256,9 @@ public class LoanBasicDetailsData {
this.loanOfficerName = loanOfficerName; this.loanOfficerName = loanOfficerName;
this.closedOnDate = closedOnDate; this.closedOnDate = closedOnDate;
this.submittedOnDate = submittedOnDate; this.submittedOnDate = submittedOnDate;
this.submittedByUsername = submittedByUsername;
this.submittedByFirstname = submittedByFirstname;
this.submittedByLastname = submittedByLastname;
this.approvedOnDate = approvedOnDate; this.approvedOnDate = approvedOnDate;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate; this.actualDisbursementDate = actualDisbursementDate;
@@ -430,6 +443,18 @@ public class LoanBasicDetailsData {
return submittedOnDate; return submittedOnDate;
} }
public String getSubmittedByUsername() {
return this.submittedByUsername;
}
public String getSubmittedByFirstname() {
return this.submittedByFirstname;
}
public String getSubmittedByLastname() {
return this.submittedByLastname;
}
public LocalDate getApprovedOnDate() { public LocalDate getApprovedOnDate() {
return approvedOnDate; return approvedOnDate;
} }
@@ -0,0 +1,67 @@
/**
* 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 org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object representing repayment schedule related information.
*/
public class RepaymentScheduleRelatedLoanData {
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final CurrencyData currency;
private final BigDecimal principal;
private final BigDecimal inArrearsTolerance;
private final BigDecimal totalFeeChargesAtDisbursement;
public RepaymentScheduleRelatedLoanData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
final CurrencyData currency, final BigDecimal principal, final BigDecimal inArrearsTolerance,
final BigDecimal totalFeeChargesAtDisbursement) {
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
this.currency = currency;
this.principal = principal;
this.inArrearsTolerance = inArrearsTolerance;
this.totalFeeChargesAtDisbursement = totalFeeChargesAtDisbursement;
}
public LocalDate disbursementDate() {
LocalDate disbursementDate = this.expectedDisbursementDate;
if (actualDisbursementDate != null) {
disbursementDate = actualDisbursementDate;
}
return disbursementDate;
}
public BigDecimal amount() {
return this.principal;
}
public boolean isDisbursed() {
return this.actualDisbursementDate != null;
}
public CurrencyData getCurrency() {
return this.currency;
}
public BigDecimal getInArrearsTolerance() {
return this.inArrearsTolerance;
}
public BigDecimal getTotalFeeChargesAtDisbursement() {
return this.totalFeeChargesAtDisbursement;
}
public DisbursementData disbursementData() {
return new DisbursementData(this.expectedDisbursementDate, this.actualDisbursementDate, this.principal);
}
}
@@ -84,18 +84,18 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
private String externalId; private String externalId;
@ManyToOne(optional = true) @ManyToOne(optional = true)
@JoinColumn(name = "client_id") @JoinColumn(name = "client_id", nullable = true)
private Client client; private Client client;
@ManyToOne(optional = true) @ManyToOne(optional = true)
@JoinColumn(name = "group_id") @JoinColumn(name = "group_id", nullable = true)
private Group group; private Group group;
@ManyToOne @ManyToOne
@JoinColumn(name = "product_id") @JoinColumn(name = "product_id", nullable = false)
private LoanProduct loanProduct; private LoanProduct loanProduct;
@ManyToOne @ManyToOne(optional = true)
@JoinColumn(name = "fund_id", nullable = true) @JoinColumn(name = "fund_id", nullable = true)
private Fund fund; private Fund fund;
@@ -123,48 +123,71 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "loan_status_id", nullable = false) @Column(name = "loan_status_id", nullable = false)
private Integer loanStatus; private Integer loanStatus;
@Temporal(TemporalType.TIMESTAMP) // loan application states
@Temporal(TemporalType.DATE)
@Column(name = "submittedon_date") @Column(name = "submittedon_date")
private Date submittedOnDate; private Date submittedOnDate;
@Temporal(TemporalType.TIMESTAMP) @SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "submittedon_userid", nullable = true)
private AppUser submittedBy;
@Temporal(TemporalType.DATE)
@Column(name = "rejectedon_date") @Column(name = "rejectedon_date")
private Date rejectedOnDate; private Date rejectedOnDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Temporal(TemporalType.TIMESTAMP) @ManyToOne(optional = true)
@JoinColumn(name = "rejectedon_userid", nullable = true)
private AppUser rejectedBy;
@SuppressWarnings("unused")
@Temporal(TemporalType.DATE)
@Column(name = "withdrawnon_date") @Column(name = "withdrawnon_date")
private Date withdrawnOnDate; private Date withdrawnOnDate;
@Temporal(TemporalType.TIMESTAMP) @SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "withdrawnon_userid", nullable = true)
private AppUser withdrawnBy;
@Temporal(TemporalType.DATE)
@Column(name = "approvedon_date") @Column(name = "approvedon_date")
private Date approvedOnDate; private Date approvedOnDate;
@SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "approvedon_userid", nullable = true)
private AppUser approvedBy;
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "expected_disbursedon_date") @Column(name = "expected_disbursedon_date")
private Date expectedDisbursedOnDate; private Date expectedDisbursedOnDate;
@Temporal(TemporalType.DATE)
@Column(name = "expected_firstrepaymenton_date")
private Date expectedFirstRepaymentOnDate;
@Temporal(TemporalType.DATE)
@Column(name = "interest_calculated_from_date")
private Date interestChargedFromDate;
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "disbursedon_date") @Column(name = "disbursedon_date")
private Date disbursedOnDate; private Date disbursedOnDate;
@Temporal(TemporalType.TIMESTAMP) @SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "disbursedon_userid", nullable = true)
private AppUser disbursedBy;
@Temporal(TemporalType.DATE)
@Column(name = "closedon_date") @Column(name = "closedon_date")
private Date closedOnDate; private Date closedOnDate;
@Temporal(TemporalType.TIMESTAMP) @SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "closedon_userid", nullable = true)
private AppUser closedBy;
@Temporal(TemporalType.DATE)
@Column(name = "writtenoffon_date") @Column(name = "writtenoffon_date")
private Date writtenOffOnDate; private Date writtenOffOnDate;
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.DATE)
@Column(name = "rescheduledon_date") @Column(name = "rescheduledon_date")
private Date rescheduledOnDate; private Date rescheduledOnDate;
@@ -176,6 +199,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "maturedon_date") @Column(name = "maturedon_date")
private Date maturedOnDate; private Date maturedOnDate;
@Temporal(TemporalType.DATE)
@Column(name = "expected_firstrepaymenton_date")
private Date expectedFirstRepaymentOnDate;
@Temporal(TemporalType.DATE)
@Column(name = "interest_calculated_from_date")
private Date interestChargedFromDate;
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
private Set<LoanCharge> charges = new HashSet<LoanCharge>(); private Set<LoanCharge> charges = new HashSet<LoanCharge>();
@@ -320,7 +351,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.accountNumberRequiresAutoGeneration; return this.accountNumberRequiresAutoGeneration;
} }
public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) { public void setAccountNumberRequiresAutoGeneration(final boolean accountNumberRequiresAutoGeneration) {
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration; this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
} }
@@ -830,7 +861,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return existingLoanCollateral; return existingLoanCollateral;
} }
private LoanChargeCommand[] getLoanCharges(Set<LoanCharge> setOfLoanCharges) { private LoanChargeCommand[] getLoanCharges(final Set<LoanCharge> setOfLoanCharges) {
LoanChargeCommand[] existingLoanCharges = null; LoanChargeCommand[] existingLoanCharges = null;
@@ -853,8 +884,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
} }
public void loanApplicationSubmittal(final LoanSchedule loanSchedule, final LoanLifecycleStateMachine lifecycleStateMachine, public void loanApplicationSubmittal(final AppUser currentUser, final LoanSchedule loanSchedule,
final LocalDate submittedOn, final String externalId) { final LoanLifecycleStateMachine lifecycleStateMachine, final LocalDate submittedOn, final String externalId) {
final LoanScheduleData loanScheduleData = loanSchedule.generate(); final LoanScheduleData loanScheduleData = loanSchedule.generate();
@@ -880,6 +911,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue(); this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue();
this.submittedOnDate = submittedOn.toDate(); this.submittedOnDate = submittedOn.toDate();
this.submittedBy = currentUser;
this.expectedMaturityDate = determineExpectedMaturityDate().toDate(); this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
if (loanSchedule.getRepaymentStartFromDate() != null) { if (loanSchedule.getRepaymentStartFromDate() != null) {
@@ -890,7 +922,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.interestChargedFromDate = loanSchedule.getInterestChargedFromDate().toDate(); this.interestChargedFromDate = loanSchedule.getInterestChargedFromDate().toDate();
} }
if (submittedOn.isAfter(new LocalDate())) { if (submittedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is submitted cannot be in the future."; final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn); throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn);
} }
@@ -913,7 +945,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.repaymentScheduleInstallments.get(numberOfInstallments - 1).getDueDate(); return this.repaymentScheduleInstallments.get(numberOfInstallments - 1).getDueDate();
} }
public Map<String, Object> loanApplicationRejection(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine) { public Map<String, Object> loanApplicationRejection(final AppUser currentUser, final JsonCommand command,
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
@@ -931,7 +964,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
this.rejectedOnDate = rejectedOn.toDate(); this.rejectedOnDate = rejectedOn.toDate();
this.rejectedBy = currentUser;
this.closedOnDate = rejectedOn.toDate(); this.closedOnDate = rejectedOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale()); actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat()); actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("rejectedOnDate", rejectedOn.toString(fmt)); actualChanges.put("rejectedOnDate", rejectedOn.toString(fmt));
@@ -943,7 +979,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn, throw new InvalidLoanStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn,
getSubmittedOnDate()); getSubmittedOnDate());
} }
if (rejectedOn.isAfter(new LocalDate())) { if (rejectedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is rejected cannot be in the future."; final String errorMessage = "The date on which a loan is rejected cannot be in the future.";
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn); throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
} }
@@ -952,7 +988,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return actualChanges; return actualChanges;
} }
public Map<String, Object> loanApplicationWithdrawnByApplicant(final JsonCommand command, public Map<String, Object> loanApplicationWithdrawnByApplicant(final AppUser currentUser, final JsonCommand command,
final LoanLifecycleStateMachine loanLifecycleStateMachine) { final LoanLifecycleStateMachine loanLifecycleStateMachine) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
@@ -971,7 +1007,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
this.withdrawnOnDate = withdrawnOn.toDate(); this.withdrawnOnDate = withdrawnOn.toDate();
this.withdrawnBy = currentUser;
this.closedOnDate = withdrawnOn.toDate(); this.closedOnDate = withdrawnOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale()); actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat()); actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt)); actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt));
@@ -984,7 +1023,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
getSubmittedOnDate()); getSubmittedOnDate());
} }
if (withdrawnOn.isAfter(new LocalDate())) { if (withdrawnOn.isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future."; final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, command); throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, command);
} }
@@ -993,7 +1032,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return actualChanges; return actualChanges;
} }
public Map<String, Object> loanApplicationApproval(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine) { public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
@@ -1011,6 +1051,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
} }
this.approvedOnDate = approvedOn.toDate(); this.approvedOnDate = approvedOn.toDate();
this.approvedBy = currentUser;
actualChanges.put("locale", command.locale()); actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat()); actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("approvedOnDate", approvedOnDateChange); actualChanges.put("approvedOnDate", approvedOnDateChange);
@@ -1022,7 +1063,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage, throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage,
getApprovedOnDate(), submittalDate); getApprovedOnDate(), submittalDate);
} }
if (approvedOn.isAfter(new LocalDate())) { if (approvedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is approved cannot be in the future."; final String errorMessage = "The date on which a loan is approved cannot be in the future.";
throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate()); throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate());
} }
@@ -1048,6 +1089,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
actualChanges.put("status", LoanEnumerations.status(this.loanStatus)); actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
this.approvedOnDate = null; this.approvedOnDate = null;
this.approvedBy = null;
actualChanges.put("approvedOnDate", ""); actualChanges.put("approvedOnDate", "");
this.loanOfficerHistory.clear(); this.loanOfficerHistory.clear();
@@ -1062,7 +1104,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
handleDisbursementTransaction(expectedDisbursedOnLocalDate); handleDisbursementTransaction(expectedDisbursedOnLocalDate);
} }
public Map<String, Object> disburse(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, public Map<String, Object> disburse(final AppUser currentUser, final JsonCommand command,
final LoanLifecycleStateMachine loanLifecycleStateMachine,
final ApplicationCurrency currency) { final ApplicationCurrency currency) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(); final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>();
@@ -1083,6 +1126,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
this.disbursedOnDate = disbursedOn.toDate(); this.disbursedOnDate = disbursedOn.toDate();
this.disbursedBy = currentUser;
this.expectedMaturityDate = determineExpectedMaturityDate().toDate(); this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
actualChanges.put("locale", command.locale()); actualChanges.put("locale", command.locale());
@@ -1190,6 +1234,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
actualChanges.put("status", LoanEnumerations.status(this.loanStatus)); actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
this.disbursedOnDate = null; this.disbursedOnDate = null;
this.disbursedBy = null;
actualChanges.put("disbursedOnDate", ""); actualChanges.put("disbursedOnDate", "");
updateLoanToPreDisbursalState(); updateLoanToPreDisbursalState();
@@ -1906,7 +1951,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return charges; return charges;
} }
public void setCharges(Set<LoanCharge> charges) { public void setCharges(final Set<LoanCharge> charges) {
this.charges = charges; this.charges = charges;
} }
@@ -1964,7 +2009,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.loanRepaymentScheduleDetail.getInArrearsTolerance(); return this.loanRepaymentScheduleDetail.getInArrearsTolerance();
} }
public boolean identifiedBy(String identifier) { public boolean identifiedBy(final String identifier) {
return identifier.equalsIgnoreCase(this.externalId) || identifier.equalsIgnoreCase(this.getId().toString()); return identifier.equalsIgnoreCase(this.externalId) || identifier.equalsIgnoreCase(this.getId().toString());
} }
@@ -201,9 +201,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.notExceedingLengthOf(500); .notExceedingLengthOf(500);
} }
// not optional at present but might make it so to allow it to pick up
// on only available strategy
// by default which would probably be the norm.
final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId"; final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId";
final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed(transactionProcessingStrategyIdParameterName, final Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed(transactionProcessingStrategyIdParameterName,
element); element);
@@ -118,11 +118,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Override @Override
public CommandProcessingResult submitLoanApplication(final JsonCommand command) { public CommandProcessingResult submitLoanApplication(final JsonCommand command) {
context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json()); this.fromApiJsonDeserializer.validateForCreate(command.json());
final Loan newLoanApplication = loanAssembler.assembleFrom(command); final Loan newLoanApplication = loanAssembler.assembleFrom(command, currentUser);
this.loanRepository.save(newLoanApplication); this.loanRepository.save(newLoanApplication);
@@ -317,7 +317,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Override @Override
public CommandProcessingResult approveLoanApplication(final Long loanId, final JsonCommand command) { public CommandProcessingResult approveLoanApplication(final Long loanId, final JsonCommand command) {
AppUser currentUser = context.authenticatedUser(); final AppUser currentUser = context.authenticatedUser();
final LoanStateTransitionCommand approveLoanApplication = this.loanStateTransitionCommandFromApiJsonDeserializer final LoanStateTransitionCommand approveLoanApplication = this.loanStateTransitionCommandFromApiJsonDeserializer
.commandFromApiJson(command.json()); .commandFromApiJson(command.json());
@@ -329,7 +329,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (this.isBeforeToday(approvedOnLocalDate) && currentUser.canNotApproveLoanInPast()) { throw new NoAuthorizationException( if (this.isBeforeToday(approvedOnLocalDate) && currentUser.canNotApproveLoanInPast()) { throw new NoAuthorizationException(
"User has no authority to approve loan with a date in the past."); } "User has no authority to approve loan with a date in the past."); }
final Map<String, Object> changes = loan.loanApplicationApproval(command, defaultLoanLifecycleStateMachine()); final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -398,7 +398,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (this.isBeforeToday(eventDate) && currentUser.canNotRejectLoanInPast()) { throw new NoAuthorizationException( if (this.isBeforeToday(eventDate) && currentUser.canNotRejectLoanInPast()) { throw new NoAuthorizationException(
"User has no authority to reject loan with a date in the past."); } "User has no authority to reject loan with a date in the past."); }
final Map<String, Object> changes = loan.loanApplicationRejection(command, defaultLoanLifecycleStateMachine()); final Map<String, Object> changes = loan.loanApplicationRejection(currentUser, command, defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -436,7 +436,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (this.isBeforeToday(eventDate) && currentUser.canNotWithdrawByClientLoanInPast()) { throw new NoAuthorizationException( if (this.isBeforeToday(eventDate) && currentUser.canNotWithdrawByClientLoanInPast()) { throw new NoAuthorizationException(
"User has no authority to mark loan as withdrawn by applicant with a date in the past."); } "User has no authority to mark loan as withdrawn by applicant with a date in the past."); }
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(command, defaultLoanLifecycleStateMachine()); final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command,
defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -43,6 +43,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository; import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -82,16 +83,16 @@ public class LoanAssembler {
this.loanCollateralAssembler = loanCollateralAssembler; this.loanCollateralAssembler = loanCollateralAssembler;
} }
public Loan assembleFrom(final JsonCommand command) { public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
final JsonElement element = command.parsedJson(); final JsonElement element = command.parsedJson();
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element); final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
final Long groupId = fromApiJsonHelper.extractLongNamed("groupId", element); final Long groupId = fromApiJsonHelper.extractLongNamed("groupId", element);
return assembleApplication(element, clientId, groupId); return assembleApplication(element, clientId, groupId, currentUser);
} }
private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId) { private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId, final AppUser currentUser) {
final String accountNo = fromApiJsonHelper.extractStringNamed("accountNo", element); final String accountNo = fromApiJsonHelper.extractStringNamed("accountNo", element);
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element); final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
@@ -148,7 +149,7 @@ public class LoanAssembler {
if (loanApplication == null) { throw new IllegalStateException("No loan application exists for either a client or group (or both)."); } if (loanApplication == null) { throw new IllegalStateException("No loan application exists for either a client or group (or both)."); }
loanApplication.loanApplicationSubmittal(loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId); loanApplication.loanApplicationSubmittal(currentUser, loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId);
return loanApplication; return loanApplication;
} }
@@ -5,27 +5,24 @@
*/ */
package org.mifosplatform.portfolio.loanaccount.service; package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.Collection; import java.util.Collection;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanBasicDetailsData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData; import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
public interface LoanReadPlatformService { public interface LoanReadPlatformService {
LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId); LoanAccountData retrieveLoanAccountDetails(Long loanId);
LoanScheduleData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement, LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData);
BigDecimal totalChargesAtDisbursement, BigDecimal inArrearsTolerance);
Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId); Collection<LoanTransactionData> retrieveLoanTransactions(Long loanId);
LoanBasicDetailsData retrieveClientAndProductDetails(Long clientId, Long productId); LoanAccountData retrieveClientAndProductDetails(Long clientId, Long productId);
LoanBasicDetailsData retrieveGroupAndProductDetails(Long groupId, Long productId); LoanAccountData retrieveGroupAndProductDetails(Long groupId, Long productId);
LoanTransactionData retrieveLoanTransactionTemplate(Long loanId); LoanTransactionData retrieveLoanTransactionTemplate(Long loanId);
@@ -14,6 +14,7 @@ import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.data.CurrencyData;
@@ -27,10 +28,11 @@ import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.group.data.GroupData; import org.mifosplatform.portfolio.group.data.GroupData;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService; import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData; import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanBasicDetailsData; import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData; import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData; import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData; import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction; import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
@@ -77,7 +79,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public LoanBasicDetailsData retrieveLoanAccountDetails(final Long loanId) { public LoanAccountData retrieveLoanAccountDetails(final Long loanId) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
@@ -95,17 +97,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId, final CurrencyData currency, final DisbursementData disbursement, public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
final BigDecimal totalFeeChargesAtDisbursement, final BigDecimal inArrearsTolerance) { final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
final DisbursementData disbursement = repaymentScheduleRelatedLoanData.disbursementData();
final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement); final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement);
final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment"; final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment";
final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod( final LoanSchedulePeriodData disbursementPeriod = LoanSchedulePeriodData.disbursementOnlyPeriod(
disbursement.disbursementDate(), disbursement.amount(), totalFeeChargesAtDisbursement, disbursement.isDisbursed()); disbursement.disbursementDate(), disbursement.amount(),
repaymentScheduleRelatedLoanData.getTotalFeeChargesAtDisbursement(), disbursement.isDisbursed());
final Collection<LoanSchedulePeriodData> repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId }); final Collection<LoanSchedulePeriodData> repaymentSchedulePeriods = this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
@@ -157,8 +162,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue(); final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue();
final CurrencyData currency = repaymentScheduleRelatedLoanData.getCurrency();
final MonetaryCurrency monetaryCurrency = new MonetaryCurrency(currency.code(), currency.decimalPlaces()); final MonetaryCurrency monetaryCurrency = new MonetaryCurrency(currency.code(), currency.decimalPlaces());
final Money tolerance = Money.of(monetaryCurrency, inArrearsTolerance); final Money tolerance = Money.of(monetaryCurrency, repaymentScheduleRelatedLoanData.getInArrearsTolerance());
final Money totalOverdueMoney = Money.of(monetaryCurrency, totalOverdue); final Money totalOverdueMoney = Money.of(monetaryCurrency, totalOverdue);
boolean isWaiveAllowed = totalOverdueMoney.isGreaterThanZero() boolean isWaiveAllowed = totalOverdueMoney.isGreaterThanZero()
&& (tolerance.isGreaterThan(totalOverdueMoney) || tolerance.isEqualTo(totalOverdueMoney)); && (tolerance.isGreaterThan(totalOverdueMoney) || tolerance.isEqualTo(totalOverdueMoney));
@@ -201,38 +207,36 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
@Override @Override
public LoanBasicDetailsData retrieveClientAndProductDetails(final Long clientId, final Long productId) { public LoanAccountData retrieveClientAndProductDetails(final Long clientId, final Long productId) {
context.authenticatedUser(); context.authenticatedUser();
final LocalDate expectedDisbursementDate = new LocalDate();
final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId); final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewIndividualClientLoanCreation(clientAccount.id(), LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.displayName(),
clientAccount.displayName(), expectedDisbursementDate, clientAccount.officeId()); clientAccount.officeId(), expectedDisbursementDate);
if (productId != null) { if (productId != null) {
LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); final LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(loanDetails, selectedProduct); loanTemplateDetails = LoanAccountData.populateLoanProductDefaults(loanTemplateDetails, selectedProduct);
} }
return loanDetails; return loanTemplateDetails;
} }
@Override @Override
public LoanBasicDetailsData retrieveGroupAndProductDetails(Long groupId, Long productId) { public LoanAccountData retrieveGroupAndProductDetails(final Long groupId, final Long productId) {
context.authenticatedUser(); context.authenticatedUser();
final LocalDate expectedDisbursementDate = new LocalDate();
final GroupData groupAccount = this.groupReadPlatformService.retrieveGroup(groupId); final GroupData groupAccount = this.groupReadPlatformService.retrieveGroup(groupId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewGroupLoanCreation(groupAccount.getId(), LoanAccountData loanDetails = LoanAccountData.groupDefaults(groupAccount.getId(), groupAccount.getName(),
groupAccount.getName(), expectedDisbursementDate, groupAccount.getOfficeId()); groupAccount.getOfficeId(), expectedDisbursementDate);
if (productId != null) { if (productId != null) {
LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(loanDetails, selectedProduct); loanDetails = LoanAccountData.populateLoanProductDefaults(loanDetails, selectedProduct);
} }
return loanDetails; return loanDetails;
@@ -322,7 +326,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
return transaction.toData(currencyData); return transaction.toData(currencyData);
} }
private static final class LoanMapper implements RowMapper<LoanBasicDetailsData> { private static final class LoanMapper implements RowMapper<LoanAccountData> {
public String loanSchema() { public String loanSchema() {
return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName," return "l.id as id, l.account_no as accountNo, l.external_id as externalId, l.fund_id as fundId, f.name as fundName,"
@@ -330,10 +334,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription," + " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription,"
+ " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId," + " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId,"
+ " g.id as groupId, g.name as groupName, g.office_id as groupOfficeId," + " g.id as groupId, g.name as groupName, g.office_id as groupOfficeId,"
+ " l.submittedon_date as submittedOnDate," + " l.submittedon_date as submittedOnDate, sbu.username as submittedByUsername, sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,"
+ " l.rejectedon_date as rejectedOnDate, rbu.username as rejectedByUsername, rbu.firstname as rejectedByFirstname, rbu.lastname as rejectedByLastname,"
+ " l.withdrawnon_date as withdrawnOnDate, wbu.username as withdrawnByUsername, wbu.firstname as withdrawnByFirstname, wbu.lastname as withdrawnByLastname,"
+ " l.approvedon_date as approvedOnDate, abu.username as approvedByUsername, abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname,"
+ " l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, dbu.username as disbursedByUsername, dbu.firstname as disbursedByFirstname, dbu.lastname as disbursedByLastname,"
+ " l.closedon_date as closedOnDate, cbu.username as closedByUsername, cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,"
+ " l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate, l.interest_calculated_from_date as interestChargedFromDate, l.expected_maturedon_date as expectedMaturityDate, "
+ " l.total_charges_due_at_disbursement_derived as totalDisbursementCharges," + " l.total_charges_due_at_disbursement_derived as totalDisbursementCharges,"
+ " l.approvedon_date as approvedOnDate, l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate,"
+ " l.interest_calculated_from_date as interestChargedFromDate, l.closedon_date as closedOnDate, l.expected_maturedon_date as expectedMaturityDate, "
+ " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery," + " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, " + " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, " + " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
@@ -345,11 +354,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " left join m_client c on c.id = l.client_id" + " left join m_group g on g.id = l.group_id" + " left join m_client c on c.id = l.client_id" + " left join m_group g on g.id = l.group_id"
+ " join m_product_loan lp on lp.id = l.product_id" + " join m_currency rc on rc.`code` = l.currency_code" + " join m_product_loan lp on lp.id = l.product_id" + " join m_currency rc on rc.`code` = l.currency_code"
+ " left join m_fund f on f.id = l.fund_id" + " left join m_staff s on s.id = l.loan_officer_id" + " left join m_fund f on f.id = l.fund_id" + " left join m_staff s on s.id = l.loan_officer_id"
+ " left join m_appuser sbu on sbu.id = l.submittedon_userid"
+ " left join m_appuser rbu on rbu.id = l.rejectedon_userid"
+ " left join m_appuser wbu on wbu.id = l.withdrawnon_userid"
+ " left join m_appuser abu on abu.id = l.approvedon_userid"
+ " left join m_appuser dbu on dbu.id = l.disbursedon_userid"
+ " left join m_appuser cbu on cbu.id = l.closedon_userid"
+ " left join m_code_value cv on cv.id = l.loanpurpose_cv_id"; + " left join m_code_value cv on cv.id = l.loanpurpose_cv_id";
} }
@Override @Override
public LoanBasicDetailsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { public LoanAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final String currencyCode = rs.getString("currencyCode"); final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName"); final String currencyName = rs.getString("currencyName");
@@ -385,17 +400,48 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String loanProductDescription = rs.getString("loanProductDescription"); final String loanProductDescription = rs.getString("loanProductDescription");
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
final String submittedByUsername = rs.getString("submittedByUsername");
final String submittedByFirstname = rs.getString("submittedByFirstname");
final String submittedByLastname = rs.getString("submittedByLastname");
final LocalDate rejectedOnDate = JdbcSupport.getLocalDate(rs, "rejectedOnDate");
final String rejectedByUsername = rs.getString("rejectedByUsername");
final String rejectedByFirstname = rs.getString("rejectedByFirstname");
final String rejectedByLastname = rs.getString("rejectedByLastname");
final LocalDate withdrawnOnDate = JdbcSupport.getLocalDate(rs, "withdrawnOnDate");
final String withdrawnByUsername = rs.getString("withdrawnByUsername");
final String withdrawnByFirstname = rs.getString("withdrawnByFirstname");
final String withdrawnByLastname = rs.getString("withdrawnByLastname");
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate"); final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
final String approvedByUsername = rs.getString("approvedByUsername");
final String approvedByFirstname = rs.getString("approvedByFirstname");
final String approvedByLastname = rs.getString("approvedByLastname");
final LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate"); final LocalDate expectedDisbursementDate = JdbcSupport.getLocalDate(rs, "expectedDisbursementDate");
final LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate"); final LocalDate actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate"); final String disbursedByUsername = rs.getString("disbursedByUsername");
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate"); final String disbursedByFirstname = rs.getString("disbursedByFirstname");
final String disbursedByLastname = rs.getString("disbursedByLastname");
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate"); final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
final String closedByUsername = rs.getString("closedByUsername");
final String closedByFirstname = rs.getString("closedByFirstname");
final String closedByLastname = rs.getString("closedByLastname");
final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate"); final LocalDate expectedMaturityDate = JdbcSupport.getLocalDate(rs, "expectedMaturityDate");
final LoanApplicationTimelineData timeline = new LoanApplicationTimelineData(submittedOnDate, submittedByUsername,
submittedByFirstname, submittedByLastname, rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname,
withdrawnOnDate, withdrawnByUsername, withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername,
approvedByFirstname, approvedByLastname, expectedDisbursementDate, actualDisbursementDate, disbursedByUsername,
disbursedByFirstname, disbursedByLastname, closedOnDate, closedByUsername, closedByFirstname, closedByLastname,
expectedMaturityDate);
final BigDecimal principal = rs.getBigDecimal("principal"); final BigDecimal principal = rs.getBigDecimal("principal");
final BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance"); final BigDecimal inArrearsTolerance = rs.getBigDecimal("inArrearsTolerance");
final BigDecimal totalDisbursementCharges = rs.getBigDecimal("totalDisbursementCharges"); final BigDecimal totalFeeChargesAtDisbursement = rs.getBigDecimal("totalDisbursementCharges");
final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments"); final Integer numberOfRepayments = JdbcSupport.getInteger(rs, "numberOfRepayments");
final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery"); final Integer repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
@@ -426,15 +472,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId"); final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId); final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId);
Collection<LoanChargeData> charges = null; // settings
return new LoanBasicDetailsData(id, accountNo, externalId, clientId, clientName, clientOfficeId, groupId, groupName, final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId, final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
loanPurposeName, closedOnDate, submittedOnDate, approvedOnDate, expectedDisbursementDate, actualDisbursementDate,
expectedMaturityDate, expectedFirstRepaymentOnDate, interestChargedFromDate, currencyData, principal, return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupId,
inArrearsTolerance, numberOfRepayments, repaymentEvery, interestRatePerPeriod, annualInterestRate, groupName, groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId,
repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, principal, inArrearsTolerance, termFrequency,
status, termFrequency, termPeriodFrequencyType, transactionStrategyId, charges, loanOfficerId, loanOfficerName, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, transactionStrategyId,
totalDisbursementCharges); amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType,
interestCalculationPeriodType, expectedFirstRepaymentOnDate, interestChargedFromDate, timeline,
totalFeeChargesAtDisbursement);
} }
} }
@@ -131,7 +131,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode()); final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getPrincpal().getCurrencyCode());
final Map<String, Object> changes = loan.disburse(command, defaultLoanLifecycleStateMachine(), currency); final Map<String, Object> changes = loan.disburse(currentUser, command, defaultLoanLifecycleStateMachine(), currency);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
// variable stores Id's of all existing loan transactions (newly // variable stores Id's of all existing loan transactions (newly
// created // created
@@ -740,7 +740,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build(); .build();
} }
private LoanDTO populateLoanDTO(Loan loan, List<LoanTransaction> loanTransactions) { private LoanDTO populateLoanDTO(final Loan loan, final List<LoanTransaction> loanTransactions) {
List<LoanTransactionDTO> loanTransactionDTOs = new ArrayList<LoanTransactionDTO>(); List<LoanTransactionDTO> loanTransactionDTOs = new ArrayList<LoanTransactionDTO>();
for (LoanTransaction loanTransaction : loanTransactions) { for (LoanTransaction loanTransaction : loanTransactions) {
LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(), LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(),
@@ -754,7 +754,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.isAccrualBasedAccountingEnabledOnLoanProduct(), loanTransactionDTOs); loan.isAccrualBasedAccountingEnabledOnLoanProduct(), loanTransactionDTOs);
} }
private LoanDTO populateLoanData(Loan loan, LoanTransaction loanTransaction) { private LoanDTO populateLoanData(final Loan loan, final LoanTransaction loanTransaction) {
List<LoanTransaction> loanTransactions = new ArrayList<LoanTransaction>(); List<LoanTransaction> loanTransactions = new ArrayList<LoanTransaction>();
loanTransactions.add(loanTransaction); loanTransactions.add(loanTransaction);
return populateLoanDTO(loan, loanTransactions); return populateLoanDTO(loan, loanTransactions);