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,
`fund_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,
`currency_code` varchar(3) 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',
`term_frequency` smallint(5) NOT NULL DEFAULT '0',
`term_period_frequency_enum` smallint(5) NOT NULL DEFAULT '2',
`number_of_repayments` smallint(5) NOT NULL,
`repay_every` 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,
`total_charges_due_at_disbursement_derived` decimal(19,6) DEFAULT NULL,
`submittedon_date` datetime DEFAULT NULL,
`approvedon_date` datetime DEFAULT NULL,
`interest_calculated_from_date` date DEFAULT NULL,
`expected_disbursedon_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,
`maturedon_date` date DEFAULT NULL,
`closedon_date` datetime DEFAULT NULL,
`rejectedon_date` datetime DEFAULT NULL,
`rescheduledon_date` datetime DEFAULT NULL,
`withdrawnon_date` datetime DEFAULT NULL,
`writtenoffon_date` datetime DEFAULT NULL,
`submittedon_date` date DEFAULT NULL,
`submittedon_userid` bigint(20) DEFAULT NULL,
`approvedon_date` date DEFAULT NULL,
`approvedon_userid` bigint(20) 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,
`created_date` datetime DEFAULT NULL,
`lastmodified_date` datetime DEFAULT NULL,
`lastmodifiedby_id` bigint(20) DEFAULT NULL,
`loan_transaction_strategy_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `loan_account_no_UNIQUE` (`account_no`),
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_loanpurpose_codevalue` (`loanpurpose_cv_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 `m_loan_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`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_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 `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;
CREATE TABLE `m_guarantor` (
@@ -576,11 +594,9 @@ CREATE TABLE `m_guarantor` (
PRIMARY KEY (`id`),
INDEX `FK_m_guarantor_m_loan` (`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`
ADD CONSTRAINT `FK_m_loan_guarantor` FOREIGN KEY (`guarantor_id`) REFERENCES `m_guarantor` (`id`);
-- ALTER TABLE `m_loan` ADD CONSTRAINT `FK_m_loan_guarantor` FOREIGN KEY (`guarantor_id`) REFERENCES `m_guarantor` (`id`);
CREATE TABLE `m_loan_charge` (
`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;
}
public CommandWrapperBuilder deleteCodeValue(Long codeId, final Long codeValueId) {
public CommandWrapperBuilder deleteCodeValue(final Long codeId, final Long codeValueId) {
this.actionName = "DELETE";
this.entityName = "CODEVALUE";
this.entityId = codeValueId;
this.codeId = codeId;
this.href = "/codes/" + codeId + "/codevalues/" + codeValueId;
return this;
}
@@ -12,13 +12,12 @@ import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
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.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -33,9 +32,7 @@ public class Code extends AbstractPersistable<Long> {
@Column(name = "is_system_defined")
private final boolean systemDefined;
@SuppressWarnings("unused")
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
private Set<CodeValue> values;
public static Code fromJson(final JsonCommand command) {
@@ -72,7 +69,11 @@ public class Code extends AbstractPersistable<Long> {
actualChanges.put(firstnameParamName, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null);
}
return actualChanges;
}
public boolean remove(final CodeValue codeValueToDelete) {
return this.values.remove(codeValueToDelete);
}
}
@@ -27,6 +27,6 @@ public class DeleteCodeValueCommandHandler implements NewCommandSourceHandler {
@Override
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 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.CodeValue;
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.core.api.JsonCommand;
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 PlatformSecurityContext context;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
private final CodeValueRepository codeValueRepository;
private final CodeRepository codeRepository;
private final CodeValueCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@Autowired
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.codeRepository = codeRepository;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
this.codeValueRepository = codeValueRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
}
@@ -58,7 +62,10 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
final CodeValue codeValue = CodeValue.fromJson(code, command);
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) {
handleCodeValueDataIntegrityIssues(command, dve);
return new CommandProcessingResultBuilder() //
@@ -93,7 +100,7 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
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);
if (!changes.isEmpty()) {
@@ -116,26 +123,28 @@ public class CodeValueWritePlatformServiceJpaRepositoryImpl implements CodeValue
@Transactional
@Override
public CommandProcessingResult deleteCodeValue(final Long codeValueId) {
public CommandProcessingResult deleteCodeValue(final Long codeId, final Long codeValueId) {
try {
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) {
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.code.value.unknown.data.integrity.issue",
"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.fund.data.FundData;
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.LoanBasicDetailsData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
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.service.GuarantorReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
@@ -153,53 +152,63 @@ public class LoansApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup();
Collection<EnumOptionData> loanTermFrequencyTypeOptions = dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
Collection<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions();
Collection<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService
// template
final Collection<LoanProductData> productOptions = this.loanProductReadPlatformService.retrieveAllLoanProductsForLookup();
final Collection<EnumOptionData> loanTermFrequencyTypeOptions = dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
final Collection<EnumOptionData> repaymentFrequencyTypeOptions = dropdownReadPlatformService
.retrieveRepaymentFrequencyTypeOptions();
final Collection<EnumOptionData> interestRateFrequencyTypeOptions = dropdownReadPlatformService
.retrieveInterestRateFrequencyTypeOptions();
Collection<EnumOptionData> amortizationTypeOptions = dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
Collection<EnumOptionData> interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
Collection<EnumOptionData> interestCalculationPeriodTypeOptions = dropdownReadPlatformService
final Collection<EnumOptionData> amortizationTypeOptions = dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
final Collection<EnumOptionData> interestTypeOptions = dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions = dropdownReadPlatformService
.retrieveLoanInterestRateCalculatedInPeriodOptions();
Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = this.dropdownReadPlatformService
final Collection<FundData> fundOptions = this.fundReadPlatformService.retrieveAllFunds();
final Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = this.dropdownReadPlatformService
.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> loanCollateralOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode("LoanCollateral");
final boolean convenienceDataRequired = false;
final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, charges,
collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
loanCollateralOptions);
final boolean feeChargesOnly = false;
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
final ChargeData chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
// associations
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());
return this.toApiJsonSerializer.serialize(settings, newLoanAccount, LOAN_DATA_PARAMETERS);
@@ -213,7 +222,7 @@ public class LoansApiResource {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final LoanBasicDetailsData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
final LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveLoanAccountDetails(loanId);
Collection<LoanTransactionData> loanRepayments = null;
LoanScheduleData repaymentSchedule = null;
@@ -222,13 +231,12 @@ public class LoansApiResource {
Collection<LoanCollateralData> collateral = null;
final Set<String> mandatoryResponseParameters = new HashSet<String>();
boolean convenienceDataRequired = false;
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) {
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "convenienceData",
"charges", "guarantor", "collateral"));
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "charges", "guarantor",
"collateral"));
}
if (associationParameters.contains("guarantor")) {
@@ -253,11 +261,8 @@ public class LoansApiResource {
mandatoryResponseParameters.add("repaymentSchedule");
}
DisbursementData singleDisbursement = loanBasicDetails.toDisburementData();
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, loanBasicDetails.getCurrency(),
singleDisbursement, loanBasicDetails.getTotalDisbursementCharges(), loanBasicDetails.getInArrearsTolerance());
convenienceDataRequired = true;
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData = loanBasicDetails.repaymentScheduleRelatedData();
repaymentSchedule = this.loanReadPlatformService.retrieveRepaymentSchedule(loanId, repaymentScheduleRelatedData);
}
if (associationParameters.contains("charges")) {
@@ -308,16 +313,16 @@ public class LoansApiResource {
final boolean feeChargesOnly = false;
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.getOfficeId());
allowedLoanOfficers = this.staffReadPlatformService.retrieveAllLoanOfficersByOffice(loanBasicDetails.officeId());
loanPurposeOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanPurpose");
loanCollateralOptions = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
}
final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, repaymentSchedule,
loanRepayments, charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions,
repaymentFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions,
interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers,
loanPurposeOptions, loanCollateralOptions);
final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
charges, collateral, guarantors, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
loanCollateralOptions);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
mandatoryResponseParameters);
@@ -431,11 +436,15 @@ public class LoansApiResource {
@Produces({ MediaType.APPLICATION_JSON })
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
.getOfficeId());
final Long fromLoanOfficerId = loanBasicDetails.getLoanOfficerId();
.officeId());
final Long fromLoanOfficerId = loanBasicDetails.loanOfficerId();
final BulkTransferLoanOfficerData loanReassignmentData = BulkTransferLoanOfficerData.template(fromLoanOfficerId,
allowedLoanOfficers, new LocalDate());
@@ -446,5 +455,4 @@ public class LoansApiResource {
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.loanOfficeTransferToApiJsonSerializer.serialize(settings, loanReassignmentData, RESPONSE_DATA_PARAMETERS);
}
}
@@ -14,29 +14,30 @@ import org.joda.time.LocalDate;
*/
public class DisbursementData {
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final BigDecimal principalDisbursed;
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final BigDecimal principal;
public DisbursementData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, final BigDecimal principalDisbursed) {
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
this.principalDisbursed = principalDisbursed;
}
public DisbursementData(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate,
final BigDecimal principalDisbursed) {
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
this.principal = principalDisbursed;
}
public LocalDate disbursementDate() {
LocalDate disbursementDate = this.expectedDisbursementDate;
if (actualDisbursementDate != null) {
disbursementDate = actualDisbursementDate;
}
return disbursementDate;
}
public LocalDate disbursementDate() {
LocalDate disbursementDate = this.expectedDisbursementDate;
if (actualDisbursementDate != null) {
disbursementDate = actualDisbursementDate;
}
return disbursementDate;
}
public BigDecimal amount() {
return this.principalDisbursed;
}
public boolean isDisbursed() {
return this.actualDisbursementDate != null;
}
public BigDecimal amount() {
return this.principal;
}
public boolean isDisbursed() {
return this.actualDisbursementDate != null;
}
}
@@ -1,11 +1,12 @@
/**
* 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/.
* License, v. .0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/.0/.
*/
package org.mifosplatform.portfolio.loanaccount.data;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import org.joda.time.LocalDate;
@@ -29,15 +30,17 @@ public class LoanAccountData {
// basic loan details
private final Long id;
private final String accountNo;
private final LoanStatusEnumData status;
private final String externalId;
private final Long clientId;
private final String clientName;
private final Long clientOfficeId;
private final Long groupId;
private final String groupName;
private final Long groupOfficeId;
private final Long loanProductId;
private final String loanProductName;
private final String loanProductDescription;
private final LoanStatusEnumData status;
private final Long fundId;
private final String fundName;
private final Long loanPurposeId;
@@ -47,7 +50,6 @@ public class LoanAccountData {
private final CurrencyData currency;
private final BigDecimal principal;
private final BigDecimal inArrearsTolerance;
private final Integer termFrequency;
private final EnumOptionData termPeriodFrequencyType;
private final Integer numberOfRepayments;
@@ -61,14 +63,13 @@ public class LoanAccountData {
private final EnumOptionData interestType;
private final EnumOptionData interestCalculationPeriodType;
private final LocalDate submittedOnDate;
private final LocalDate approvedOnDate;
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
private final LocalDate repaymentsStartingFromDate;
// settings
private final LocalDate expectedFirstRepaymentOnDate;
private final LocalDate interestChargedFromDate;
private final LocalDate closedOnDate;
private final LocalDate expectedMaturityDate;
// timeline
private final LoanApplicationTimelineData timeline;
// totals
private final BigDecimal totalFeeChargesAtDisbursement;
// associations
private final LoanScheduleData repaymentSchedule;
@@ -76,7 +77,6 @@ public class LoanAccountData {
private final Collection<LoanChargeData> charges;
private final Collection<LoanCollateralData> collateral;
private final Collection<GuarantorData> guarantors;
private final LoanConvenienceData convenienceData;
// template
private final Collection<StaffData> loanOfficerOptions;
@@ -94,7 +94,389 @@ public class LoanAccountData {
private final Collection<CodeValueData> loanPurposeOptions;
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 Collection<LoanChargeData> charges, final Collection<LoanCollateralData> collateral,
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<StaffData> loanOfficerOptions, final Collection<CodeValueData> loanPurposeOptions,
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.transactions = transactions;
this.charges = charges;
this.collateral = collateral;
this.guarantors = guarantors;
// template
this.productOptions = productOptions;
this.termFrequencyTypeOptions = termFrequencyTypeOptions;
this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
@@ -124,114 +550,28 @@ public class LoanAccountData {
this.loanOfficerOptions = loanOfficerOptions;
this.loanPurposeOptions = loanPurposeOptions;
this.loanCollateralOptions = loanCollateralOptions;
}
if (convenienceDataRequired) {
int maxSubmittedOnOffsetFromToday = basicDetails.getMaxSubmittedOnOffsetFromToday();
int maxApprovedOnOffsetFromToday = basicDetails.getMaxApprovedOnOffsetFromToday();
int maxDisbursedOnOffsetFromToday = basicDetails.getMaxDisbursedOnOffsetFromToday();
int expectedLoanTermInDays = basicDetails.getLoanTermInDays();
int expectedLoanTermInMonths = basicDetails.getLoanTermInMonths();
int actualLoanTermInDays = basicDetails.getActualLoanTermInDays();
int actualLoanTermInMonths = basicDetails.getActualLoanTermInMonths();
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
return this.timeline.repaymentScheduleRelatedData(this.currency, this.principal, this.inArrearsTolerance,
this.totalFeeChargesAtDisbursement);
}
this.convenienceData = new LoanConvenienceData(maxSubmittedOnOffsetFromToday, maxApprovedOnOffsetFromToday,
maxDisbursedOnOffsetFromToday, expectedLoanTermInDays, actualLoanTermInDays, expectedLoanTermInMonths,
actualLoanTermInMonths);
} else {
this.convenienceData = null;
public Long officeId() {
Long officeId = this.clientOfficeId;
if (officeId == null) {
officeId = this.groupOfficeId;
}
if (basicDetails != null) {
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();
return officeId;
}
this.submittedOnDate = basicDetails.getSubmittedOnDate();
this.approvedOnDate = basicDetails.getApprovedOnDate();
this.expectedDisbursementDate = basicDetails.getExpectedDisbursementDate();
this.actualDisbursementDate = basicDetails.getActualDisbursementDate();
this.closedOnDate = basicDetails.getClosedOnDate();
this.expectedMaturityDate = basicDetails.getExpectedMaturityDate();
this.repaymentsStartingFromDate = basicDetails.getRepaymentsStartingFromDate();
this.interestChargedFromDate = basicDetails.getInterestChargedFromDate();
public Long loanOfficerId() {
return this.loanOfficerId;
}
this.currency = basicDetails.getCurrency();
this.principal = basicDetails.getPrincipal();
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;
}
public Collection<LoanChargeData> charges() {
return this.charges;
}
}
@@ -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 LocalDate submittedOnDate;
private final String submittedByUsername;
private final String submittedByFirstname;
private final String submittedByLastname;
private final LocalDate approvedOnDate;
private final LocalDate expectedDisbursementDate;
private final LocalDate actualDisbursementDate;
@@ -149,6 +152,9 @@ public class LoanBasicDetailsData {
this.interestCalculationPeriodType = interestCalculationPeriodType;
this.submittedOnDate = null;
this.submittedByUsername = null;
this.submittedByFirstname = null;
this.submittedByLastname = null;
this.approvedOnDate = null;
this.expectedDisbursementDate = expectedDisbursementDate;
@@ -200,6 +206,9 @@ public class LoanBasicDetailsData {
this.interestCalculationPeriodType = null;
this.submittedOnDate = null;
this.submittedByUsername = null;
this.submittedByFirstname = null;
this.submittedByLastname = null;
this.approvedOnDate = null;
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 Long loanProductId, final String loanProductName, final String loanProductDescription, final Long fundId,
final String fundName, final Long loanPurposeId, final String loanPurposeName, final LocalDate closedOnDate,
final LocalDate submittedOnDate, final 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 interestChargedFromDate, final CurrencyData currency, final BigDecimal principal,
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 interestCalculationPeriodType, final LoanStatusEnumData status, final Integer termFrequency,
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.accountNo = accountNo;
this.externalId = externalId;
@@ -246,6 +256,9 @@ public class LoanBasicDetailsData {
this.loanOfficerName = loanOfficerName;
this.closedOnDate = closedOnDate;
this.submittedOnDate = submittedOnDate;
this.submittedByUsername = submittedByUsername;
this.submittedByFirstname = submittedByFirstname;
this.submittedByLastname = submittedByLastname;
this.approvedOnDate = approvedOnDate;
this.expectedDisbursementDate = expectedDisbursementDate;
this.actualDisbursementDate = actualDisbursementDate;
@@ -430,6 +443,18 @@ public class LoanBasicDetailsData {
return submittedOnDate;
}
public String getSubmittedByUsername() {
return this.submittedByUsername;
}
public String getSubmittedByFirstname() {
return this.submittedByFirstname;
}
public String getSubmittedByLastname() {
return this.submittedByLastname;
}
public LocalDate getApprovedOnDate() {
return approvedOnDate;
}
@@ -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;
@ManyToOne(optional = true)
@JoinColumn(name = "client_id")
@JoinColumn(name = "client_id", nullable = true)
private Client client;
@ManyToOne(optional = true)
@JoinColumn(name = "group_id")
@JoinColumn(name = "group_id", nullable = true)
private Group group;
@ManyToOne
@JoinColumn(name = "product_id")
@JoinColumn(name = "product_id", nullable = false)
private LoanProduct loanProduct;
@ManyToOne
@ManyToOne(optional = true)
@JoinColumn(name = "fund_id", nullable = true)
private Fund fund;
@@ -123,48 +123,71 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "loan_status_id", nullable = false)
private Integer loanStatus;
@Temporal(TemporalType.TIMESTAMP)
// loan application states
@Temporal(TemporalType.DATE)
@Column(name = "submittedon_date")
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")
private Date rejectedOnDate;
@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")
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")
private Date approvedOnDate;
@SuppressWarnings("unused")
@ManyToOne(optional = true)
@JoinColumn(name = "approvedon_userid", nullable = true)
private AppUser approvedBy;
@Temporal(TemporalType.DATE)
@Column(name = "expected_disbursedon_date")
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)
@Column(name = "disbursedon_date")
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")
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")
private Date writtenOffOnDate;
@Temporal(TemporalType.TIMESTAMP)
@Temporal(TemporalType.DATE)
@Column(name = "rescheduledon_date")
private Date rescheduledOnDate;
@@ -176,6 +199,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "maturedon_date")
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)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
private Set<LoanCharge> charges = new HashSet<LoanCharge>();
@@ -320,7 +351,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.accountNumberRequiresAutoGeneration;
}
public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) {
public void setAccountNumberRequiresAutoGeneration(final boolean accountNumberRequiresAutoGeneration) {
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
}
@@ -830,7 +861,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return existingLoanCollateral;
}
private LoanChargeCommand[] getLoanCharges(Set<LoanCharge> setOfLoanCharges) {
private LoanChargeCommand[] getLoanCharges(final Set<LoanCharge> setOfLoanCharges) {
LoanChargeCommand[] existingLoanCharges = null;
@@ -853,8 +884,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
}
public void loanApplicationSubmittal(final LoanSchedule loanSchedule, final LoanLifecycleStateMachine lifecycleStateMachine,
final LocalDate submittedOn, final String externalId) {
public void loanApplicationSubmittal(final AppUser currentUser, final LoanSchedule loanSchedule,
final LoanLifecycleStateMachine lifecycleStateMachine, final LocalDate submittedOn, final String externalId) {
final LoanScheduleData loanScheduleData = loanSchedule.generate();
@@ -880,6 +911,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.termPeriodFrequencyType = loanSchedule.getLoanTermPeriodFrequencyType().getValue();
this.submittedOnDate = submittedOn.toDate();
this.submittedBy = currentUser;
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
if (loanSchedule.getRepaymentStartFromDate() != null) {
@@ -890,7 +922,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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.";
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();
}
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>();
@@ -931,7 +964,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
this.rejectedOnDate = rejectedOn.toDate();
this.rejectedBy = currentUser;
this.closedOnDate = rejectedOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
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,
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.";
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
}
@@ -952,7 +988,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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 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);
this.withdrawnOnDate = withdrawnOn.toDate();
this.withdrawnBy = currentUser;
this.closedOnDate = withdrawnOn.toDate();
this.closedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
actualChanges.put("withdrawnOnDate", withdrawnOn.toString(fmt));
@@ -984,7 +1023,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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.";
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, command);
}
@@ -993,7 +1032,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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>();
@@ -1011,6 +1051,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
this.approvedOnDate = approvedOn.toDate();
this.approvedBy = currentUser;
actualChanges.put("locale", command.locale());
actualChanges.put("dateFormat", command.dateFormat());
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,
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.";
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));
this.approvedOnDate = null;
this.approvedBy = null;
actualChanges.put("approvedOnDate", "");
this.loanOfficerHistory.clear();
@@ -1062,7 +1104,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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 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);
this.disbursedOnDate = disbursedOn.toDate();
this.disbursedBy = currentUser;
this.expectedMaturityDate = determineExpectedMaturityDate().toDate();
actualChanges.put("locale", command.locale());
@@ -1190,6 +1234,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
this.disbursedOnDate = null;
this.disbursedBy = null;
actualChanges.put("disbursedOnDate", "");
updateLoanToPreDisbursalState();
@@ -1906,7 +1951,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return charges;
}
public void setCharges(Set<LoanCharge> charges) {
public void setCharges(final Set<LoanCharge> charges) {
this.charges = charges;
}
@@ -1964,7 +2009,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
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());
}
@@ -201,9 +201,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.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 Long transactionProcessingStrategyId = fromApiJsonHelper.extractLongNamed(transactionProcessingStrategyIdParameterName,
element);
@@ -118,11 +118,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Override
public CommandProcessingResult submitLoanApplication(final JsonCommand command) {
context.authenticatedUser();
AppUser currentUser = context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json());
final Loan newLoanApplication = loanAssembler.assembleFrom(command);
final Loan newLoanApplication = loanAssembler.assembleFrom(command, currentUser);
this.loanRepository.save(newLoanApplication);
@@ -317,7 +317,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
@Override
public CommandProcessingResult approveLoanApplication(final Long loanId, final JsonCommand command) {
AppUser currentUser = context.authenticatedUser();
final AppUser currentUser = context.authenticatedUser();
final LoanStateTransitionCommand approveLoanApplication = this.loanStateTransitionCommandFromApiJsonDeserializer
.commandFromApiJson(command.json());
@@ -329,7 +329,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (this.isBeforeToday(approvedOnLocalDate) && currentUser.canNotApproveLoanInPast()) { throw new NoAuthorizationException(
"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()) {
this.loanRepository.save(loan);
@@ -398,7 +398,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
if (this.isBeforeToday(eventDate) && currentUser.canNotRejectLoanInPast()) { throw new NoAuthorizationException(
"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()) {
this.loanRepository.save(loan);
@@ -436,7 +436,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
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."); }
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(command, defaultLoanLifecycleStateMachine());
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command,
defaultLoanLifecycleStateMachine());
if (!changes.isEmpty()) {
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.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -82,16 +83,16 @@ public class LoanAssembler {
this.loanCollateralAssembler = loanCollateralAssembler;
}
public Loan assembleFrom(final JsonCommand command) {
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) {
final JsonElement element = command.parsedJson();
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", 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 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)."); }
loanApplication.loanApplicationSubmittal(loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId);
loanApplication.loanApplicationSubmittal(currentUser, loanSchedule, defaultLoanLifecycleStateMachine(), submittedOnDate, externalId);
return loanApplication;
}
@@ -5,27 +5,24 @@
*/
package org.mifosplatform.portfolio.loanaccount.service;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
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.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
public interface LoanReadPlatformService {
LoanBasicDetailsData retrieveLoanAccountDetails(Long loanId);
LoanAccountData retrieveLoanAccountDetails(Long loanId);
LoanScheduleData retrieveRepaymentSchedule(Long loanId, CurrencyData currency, DisbursementData disbursement,
BigDecimal totalChargesAtDisbursement, BigDecimal inArrearsTolerance);
LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData);
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);
@@ -14,6 +14,7 @@ import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
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.security.service.PlatformSecurityContext;
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.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.LoanBasicDetailsData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanApplicationTimelineData;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
@@ -77,7 +79,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanBasicDetailsData retrieveLoanAccountDetails(final Long loanId) {
public LoanAccountData retrieveLoanAccountDetails(final Long loanId) {
try {
context.authenticatedUser();
@@ -95,17 +97,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId, final CurrencyData currency, final DisbursementData disbursement,
final BigDecimal totalFeeChargesAtDisbursement, final BigDecimal inArrearsTolerance) {
public LoanScheduleData retrieveRepaymentSchedule(final Long loanId,
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData) {
try {
context.authenticatedUser();
final DisbursementData disbursement = repaymentScheduleRelatedLoanData.disbursementData();
final LoanScheduleMapper rm = new LoanScheduleMapper(disbursement);
final String sql = "select " + rm.loanScheduleSchema() + " where l.id = ? order by ls.loan_id, ls.installment";
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 });
@@ -157,8 +162,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final BigDecimal totalOverdue = wrapper.deriveCumulativeTotalOverdue();
final CurrencyData currency = repaymentScheduleRelatedLoanData.getCurrency();
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);
boolean isWaiveAllowed = totalOverdueMoney.isGreaterThanZero()
&& (tolerance.isGreaterThan(totalOverdueMoney) || tolerance.isEqualTo(totalOverdueMoney));
@@ -201,38 +207,36 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
@Override
public LoanBasicDetailsData retrieveClientAndProductDetails(final Long clientId, final Long productId) {
public LoanAccountData retrieveClientAndProductDetails(final Long clientId, final Long productId) {
context.authenticatedUser();
final LocalDate expectedDisbursementDate = new LocalDate();
final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId);
LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewIndividualClientLoanCreation(clientAccount.id(),
clientAccount.displayName(), expectedDisbursementDate, clientAccount.officeId());
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.displayName(),
clientAccount.officeId(), expectedDisbursementDate);
if (productId != null) {
LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(loanDetails, selectedProduct);
final LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
loanTemplateDetails = LoanAccountData.populateLoanProductDefaults(loanTemplateDetails, selectedProduct);
}
return loanDetails;
return loanTemplateDetails;
}
@Override
public LoanBasicDetailsData retrieveGroupAndProductDetails(Long groupId, Long productId) {
public LoanAccountData retrieveGroupAndProductDetails(final Long groupId, final Long productId) {
context.authenticatedUser();
final LocalDate expectedDisbursementDate = new LocalDate();
final GroupData groupAccount = this.groupReadPlatformService.retrieveGroup(groupId);
LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewGroupLoanCreation(groupAccount.getId(),
groupAccount.getName(), expectedDisbursementDate, groupAccount.getOfficeId());
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanAccountData loanDetails = LoanAccountData.groupDefaults(groupAccount.getId(), groupAccount.getName(),
groupAccount.getOfficeId(), expectedDisbursementDate);
if (productId != null) {
LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(loanDetails, selectedProduct);
loanDetails = LoanAccountData.populateLoanProductDefaults(loanDetails, selectedProduct);
}
return loanDetails;
@@ -322,7 +326,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
return transaction.toData(currencyData);
}
private static final class LoanMapper implements RowMapper<LoanBasicDetailsData> {
private static final class LoanMapper implements RowMapper<LoanAccountData> {
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,"
@@ -330,10 +334,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " 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,"
+ " 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.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.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, "
@@ -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"
+ " 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_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";
}
@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 currencyName = rs.getString("currencyName");
@@ -385,17 +400,48 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final String loanProductDescription = rs.getString("loanProductDescription");
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 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 actualDisbursementDate = JdbcSupport.getLocalDate(rs, "actualDisbursementDate");
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
final String disbursedByUsername = rs.getString("disbursedByUsername");
final String disbursedByFirstname = rs.getString("disbursedByFirstname");
final String disbursedByLastname = rs.getString("disbursedByLastname");
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 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 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 repaymentEvery = JdbcSupport.getInteger(rs, "repaymentEvery");
@@ -426,15 +472,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId);
Collection<LoanChargeData> charges = null;
return new LoanBasicDetailsData(id, accountNo, externalId, clientId, clientName, clientOfficeId, groupId, groupName,
groupOfficeId, loanProductId, loanProductName, loanProductDescription, fundId, fundName, loanPurposeId,
loanPurposeName, closedOnDate, submittedOnDate, approvedOnDate, expectedDisbursementDate, actualDisbursementDate,
expectedMaturityDate, expectedFirstRepaymentOnDate, interestChargedFromDate, currencyData, principal,
inArrearsTolerance, numberOfRepayments, repaymentEvery, interestRatePerPeriod, annualInterestRate,
repaymentFrequencyType, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType,
status, termFrequency, termPeriodFrequencyType, transactionStrategyId, charges, loanOfficerId, loanOfficerName,
totalDisbursementCharges);
// settings
final LocalDate expectedFirstRepaymentOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstRepaymentOnDate");
final LocalDate interestChargedFromDate = JdbcSupport.getLocalDate(rs, "interestChargedFromDate");
return LoanAccountData.basicLoanDetails(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);
}
}
@@ -131,7 +131,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
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()) {
// variable stores Id's of all existing loan transactions (newly
// created
@@ -740,7 +740,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.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>();
for (LoanTransaction loanTransaction : loanTransactions) {
LoanTransactionDTO loanTransactionDTO = new LoanTransactionDTO(loanTransaction.getId().toString(), loanTransaction.getDateOf(),
@@ -754,7 +754,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
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>();
loanTransactions.add(loanTransaction);
return populateLoanDTO(loan, loanTransactions);