Mifosx 54, associating relations to staff entity

This commit is contained in:
Vishwas Babu AJ
2012-09-09 14:34:37 +01:00
committed by Keith Woodlock
parent 1585b33f42
commit fa6370d31a
22 changed files with 390 additions and 59 deletions
+1
View File
@@ -10,3 +10,4 @@ repos
*.jar *.jar
*.war *.war
*.ear *.ear
*.bak
+3
View File
@@ -0,0 +1,3 @@
ALTER TABLE `m_loan`
ADD COLUMN `loan_officer_id` BIGINT(20) NULL AFTER `fund_id`,
ADD CONSTRAINT `FK_m_loan_m_staff` FOREIGN KEY (`loan_officer_id`) REFERENCES `m_staff` (`id`);
+9
View File
@@ -0,0 +1,9 @@
ALTER TABLE `m_staff`
ADD COLUMN `office_id` BIGINT(20) NULL AFTER `id`,
ADD CONSTRAINT `FK_m_staff_m_office` FOREIGN KEY (`office_id`) REFERENCES `m_office` (`id`);
ALTER TABLE `m_staff`
ADD COLUMN `is_loan_officer` TINYINT(1) NOT NULL DEFAULT 0 AFTER `id`;
update m_staff set office_id=1;
@@ -40,6 +40,7 @@ import org.mifosng.platform.api.data.LoanRepaymentPeriodData;
import org.mifosng.platform.api.data.LoanRepaymentTransactionData; import org.mifosng.platform.api.data.LoanRepaymentTransactionData;
import org.mifosng.platform.api.data.LoanSchedule; import org.mifosng.platform.api.data.LoanSchedule;
import org.mifosng.platform.api.data.LoanTransactionData; import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.StaffData;
import org.mifosng.platform.api.data.TransactionProcessingStrategyData; import org.mifosng.platform.api.data.TransactionProcessingStrategyData;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService; import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService;
@@ -52,6 +53,7 @@ import org.mifosng.platform.loan.service.LoanReadPlatformService;
import org.mifosng.platform.loan.service.LoanWritePlatformService; import org.mifosng.platform.loan.service.LoanWritePlatformService;
import org.mifosng.platform.loanproduct.service.LoanDropdownReadPlatformService; import org.mifosng.platform.loanproduct.service.LoanDropdownReadPlatformService;
import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService; import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService;
import org.mifosng.platform.staff.service.StaffReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -88,6 +90,9 @@ public class LoansApiResource {
@Autowired @Autowired
private ApiJsonSerializerService apiJsonSerializerService; private ApiJsonSerializerService apiJsonSerializerService;
@Autowired
private StaffReadPlatformService staffReadPlatformService;
@GET @GET
@Path("template") @Path("template")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@@ -118,6 +123,9 @@ public class LoansApiResource {
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) { if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters); responseParameters.addAll(typicalResponseParameters);
}else if (responseParameters.contains("loanOfficerOptions") && (responseParameters.size() == 1)) {
// TODO Vishwas: check if response parameters should be additive
responseParameters.addAll(typicalResponseParameters);
} }
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
@@ -146,10 +154,19 @@ public class LoansApiResource {
final boolean convenienceDataRequired = false; final boolean convenienceDataRequired = false;
Collection<ChargeData> charges = loanBasicDetails.getCharges(); Collection<ChargeData> charges = loanBasicDetails.getCharges();
// populate loan officers if query param is passed in
Collection<StaffData> allowedLoanOfficers = null;
if (responseParameters.contains("loanOfficerOptions")) {
// get applicable loan officers
allowedLoanOfficers = this.staffReadPlatformService
.retrieveAllStaff(" office_id = "
+ loanBasicDetails.getClientOfficeId() + " and is_loan_officer = 1");
}
final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, null, null, charges, final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, null, null, charges,
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions); amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, allowedLoanOfficers);
return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, newLoanAccount); return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, newLoanAccount);
} }
@@ -176,6 +193,10 @@ public class LoansApiResource {
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) { if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters); responseParameters.addAll(typicalResponseParameters);
} else if ((responseParameters.contains("loanOfficerName") || responseParameters
.contains("loanOfficerId")) && (responseParameters.size() <= 2)) {
// TODO Vishwas: check if response parameters should be additive
responseParameters.addAll(typicalResponseParameters);
} }
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
@@ -241,11 +262,19 @@ public class LoansApiResource {
chargeOptions.removeAll(charges); chargeOptions.removeAll(charges);
} }
} }
Collection<StaffData> allowedLoanOfficers = null;
if (responseParameters.contains("loanOfficerOptions")) {
// get applicable loan officers
allowedLoanOfficers = this.staffReadPlatformService
.retrieveAllStaff(" office_id = "
+ loanBasicDetails.getClientOfficeId() + " and is_loan_officer = 1");
}
final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, summary, repaymentSchedule, loanRepayments, permissions, charges, final LoanAccountData loanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, summary, repaymentSchedule, loanRepayments, permissions, charges,
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions); amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, allowedLoanOfficers);
return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount); return this.apiJsonSerializerService.serialzieLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
} }
@@ -1,5 +1,6 @@
package org.mifosng.platform.api; package org.mifosng.platform.api;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.Set;
@@ -10,19 +11,25 @@ import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.StaffCommand; import org.mifosng.platform.api.commands.StaffCommand;
import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.OfficeLookup;
import org.mifosng.platform.api.data.StaffData; import org.mifosng.platform.api.data.StaffData;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService; import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService;
import org.mifosng.platform.api.infrastructure.ApiParameterHelper; import org.mifosng.platform.api.infrastructure.ApiParameterHelper;
import org.mifosng.platform.organisation.service.OfficeReadPlatformService;
import org.mifosng.platform.staff.service.StaffReadPlatformService; import org.mifosng.platform.staff.service.StaffReadPlatformService;
import org.mifosng.platform.staff.service.StaffWritePlatformService; import org.mifosng.platform.staff.service.StaffWritePlatformService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -44,10 +51,18 @@ public class StaffApiResource {
@Autowired @Autowired
private ApiJsonSerializerService apiJsonSerializerService; private ApiJsonSerializerService apiJsonSerializerService;
@Autowired
private OfficeReadPlatformService officeReadPlatformService;
private final static Logger logger = LoggerFactory
.getLogger(StaffApiResource.class);
@GET @GET
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveStaffs(@Context final UriInfo uriInfo) { public String retrieveStaff(@Context final UriInfo uriInfo,
@QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("officeId") final Integer officeId) {
Set<String> responseParameters = ApiParameterHelper Set<String> responseParameters = ApiParameterHelper
.extractFieldsForResponseIfProvided(uriInfo .extractFieldsForResponseIfProvided(uriInfo
@@ -55,8 +70,9 @@ public class StaffApiResource {
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters()); .getQueryParameters());
final String extraCriteria = getStaffCriteria(sqlSearch, officeId);
final Collection<StaffData> staff = this.readPlatformService final Collection<StaffData> staff = this.readPlatformService
.retrieveAllStaff(); .retrieveAllStaff(extraCriteria);
return this.apiJsonSerializerService.serializeStaffDataToJson( return this.apiJsonSerializerService.serializeStaffDataToJson(
prettyPrint, responseParameters, staff); prettyPrint, responseParameters, staff);
@@ -87,8 +103,14 @@ public class StaffApiResource {
.getQueryParameters()); .getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters()); .getQueryParameters());
boolean template = ApiParameterHelper.template(uriInfo
.getQueryParameters());
final StaffData staff = this.readPlatformService.retrieveStaff(staffId); final StaffData staff = this.readPlatformService.retrieveStaff(staffId);
if (template) {
staff.setAllowedOffices(new ArrayList<OfficeLookup>(
officeReadPlatformService.retrieveAllOfficesForLookup()));
}
return this.apiJsonSerializerService.serializeStaffDataToJson( return this.apiJsonSerializerService.serializeStaffDataToJson(
prettyPrint, responseParameters, staff); prettyPrint, responseParameters, staff);
@@ -108,4 +130,24 @@ public class StaffApiResource {
return Response.ok().entity(new EntityIdentifier(entityId)).build(); return Response.ok().entity(new EntityIdentifier(entityId)).build();
} }
private String getStaffCriteria(String sqlSearch, Integer officeId) {
String extraCriteria = "";
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
logger.info("extraCriteria; " + extraCriteria);
return extraCriteria;
}
} }
@@ -17,6 +17,7 @@ public class LoanApplicationCommand {
private final String externalId; private final String externalId;
private final Long fundId; private final Long fundId;
private final Long loanOfficerId;
private final Long transactionProcessingStrategyId; private final Long transactionProcessingStrategyId;
private final BigDecimal principal; private final BigDecimal principal;
@@ -63,13 +64,15 @@ public class LoanApplicationCommand {
final Integer interestCalculationPeriodMethod, final Integer interestCalculationPeriodMethod,
final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod, final Integer repaymentEvery, final Integer repaymentFrequency, final Integer numberOfRepayments, Integer amortizationMethod,
final Integer loanTermFrequency, final Integer loanTermFrequencyType, final Integer loanTermFrequency, final Integer loanTermFrequencyType,
final BigDecimal toleranceAmount, final LoanChargeCommand[] charges) { final BigDecimal toleranceAmount, final LoanChargeCommand[] charges,
final Long loanOfficerId) {
this.modifiedParameters = modifiedParameters; this.modifiedParameters = modifiedParameters;
this.loanId = loanId; this.loanId = loanId;
this.clientId = clientId; this.clientId = clientId;
this.productId = productId; this.productId = productId;
this.externalId = externalId; this.externalId = externalId;
this.fundId = fundId; this.fundId = fundId;
this.loanOfficerId = loanOfficerId;
this.transactionProcessingStrategyId = transactionProcessingStrategyId; this.transactionProcessingStrategyId = transactionProcessingStrategyId;
this.submittedOnDate = submittedOnDate; this.submittedOnDate = submittedOnDate;
@@ -231,6 +234,10 @@ public class LoanApplicationCommand {
public boolean isFundChanged() { public boolean isFundChanged() {
return this.modifiedParameters.contains("fundId"); return this.modifiedParameters.contains("fundId");
} }
public boolean isLoanOfficerChanged() {
return this.modifiedParameters.contains("loanOfficerId");
}
public boolean isTransactionStrategyChanged() { public boolean isTransactionStrategyChanged() {
return this.modifiedParameters.contains("transactionProcessingStrategyId"); return this.modifiedParameters.contains("transactionProcessingStrategyId");
@@ -259,4 +266,8 @@ public class LoanApplicationCommand {
public boolean isInterestChargedFromDateChanged() { public boolean isInterestChargedFromDateChanged() {
return this.modifiedParameters.contains("interestChargedFromDate"); return this.modifiedParameters.contains("interestChargedFromDate");
} }
public Long getLoanOfficerId() {
return loanOfficerId;
}
} }
@@ -10,16 +10,20 @@ public class StaffCommand {
private final Long id; private final Long id;
private final String firstName; private final String firstName;
private final String lastName; private final String lastName;
private final Long officeId;
private final boolean loanOfficerFlag;
private final Set<String> modifiedParameters; private final Set<String> modifiedParameters;
public StaffCommand(final Set<String> modifiedParameters, final Long id, public StaffCommand(final Set<String> modifiedParameters, final Long id,
final String firstName, final String lastName) { final Long officeId, final String firstName, final String lastName,
final boolean loanOfficerFlag) {
this.modifiedParameters = modifiedParameters; this.modifiedParameters = modifiedParameters;
this.id = id; this.id = id;
this.firstName = firstName; this.firstName = firstName;
this.lastName = lastName; this.lastName = lastName;
this.officeId = officeId;
this.loanOfficerFlag = loanOfficerFlag;
} }
public Long getId() { public Long getId() {
@@ -34,6 +38,14 @@ public class StaffCommand {
return lastName; return lastName;
} }
public Long getOfficeId() {
return officeId;
}
public boolean isLoanOfficerFlag() {
return loanOfficerFlag;
}
public boolean isFirstNameChanged() { public boolean isFirstNameChanged() {
return this.modifiedParameters.contains("firstname"); return this.modifiedParameters.contains("firstname");
} }
@@ -42,4 +54,12 @@ public class StaffCommand {
return this.modifiedParameters.contains("lastname"); return this.modifiedParameters.contains("lastname");
} }
public boolean isLoanOfficerFlagChanged() {
return this.modifiedParameters.contains("loanOfficerFlag");
}
public boolean isOfficeChanged() {
return this.modifiedParameters.contains("officeId");
}
} }
@@ -1,7 +1,9 @@
package org.mifosng.platform.api.data; package org.mifosng.platform.api.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
@@ -20,6 +22,8 @@ public class LoanAccountData {
private final EnumOptionData status; private final EnumOptionData status;
private final Long fundId; private final Long fundId;
private final String fundName; private final String fundName;
private Long loanOfficerId;
private String loanOfficerName;
private final CurrencyData currency; private final CurrencyData currency;
private final BigDecimal principal; private final BigDecimal principal;
private final BigDecimal inArrearsTolerance; private final BigDecimal inArrearsTolerance;
@@ -66,6 +70,7 @@ public class LoanAccountData {
private final Collection<EnumOptionData> interestCalculationPeriodTypeOptions; private final Collection<EnumOptionData> interestCalculationPeriodTypeOptions;
private final Collection<FundData> fundOptions; private final Collection<FundData> fundOptions;
private final Collection<ChargeData> chargeOptions; private final Collection<ChargeData> chargeOptions;
private final Collection<StaffData> loanOfficerOptions;
public LoanAccountData( public LoanAccountData(
final LoanBasicDetailsData basicDetails, final LoanBasicDetailsData basicDetails,
@@ -84,7 +89,8 @@ public class LoanAccountData {
final Collection<EnumOptionData> interestTypeOptions, final Collection<EnumOptionData> interestTypeOptions,
final Collection<EnumOptionData> interestCalculationPeriodTypeOptions, final Collection<EnumOptionData> interestCalculationPeriodTypeOptions,
final Collection<FundData> fundOptions, final Collection<FundData> fundOptions,
final Collection<ChargeData> chargeOptions) { final Collection<ChargeData> chargeOptions,
final Collection<StaffData> loanOfficerOptions) {
this.summary = summary; this.summary = summary;
this.repaymentSchedule = repaymentSchedule; this.repaymentSchedule = repaymentSchedule;
this.loanRepayments = loanRepayments; this.loanRepayments = loanRepayments;
@@ -100,6 +106,7 @@ public class LoanAccountData {
this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions; this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions;
this.fundOptions = fundOptions; this.fundOptions = fundOptions;
this.chargeOptions = chargeOptions; this.chargeOptions = chargeOptions;
this.loanOfficerOptions = loanOfficerOptions;
if (convenienceDataRequired) { if (convenienceDataRequired) {
int maxSubmittedOnOffsetFromToday = basicDetails int maxSubmittedOnOffsetFromToday = basicDetails
@@ -131,6 +138,9 @@ public class LoanAccountData {
this.loanProductDescription = basicDetails.getLoanProductDescription(); this.loanProductDescription = basicDetails.getLoanProductDescription();
this.fundId = basicDetails.getFundId(); this.fundId = basicDetails.getFundId();
this.fundName = basicDetails.getFundName(); this.fundName = basicDetails.getFundName();
this.loanOfficerId = basicDetails.getLoanOfficerId();
this.loanOfficerName = basicDetails.getLoanOfficerName();
this.submittedOnDate = basicDetails.getSubmittedOnDate(); this.submittedOnDate = basicDetails.getSubmittedOnDate();
this.approvedOnDate = basicDetails.getApprovedOnDate(); this.approvedOnDate = basicDetails.getApprovedOnDate();
@@ -364,4 +374,20 @@ public class LoanAccountData {
public Collection<ChargeData> getChargeOptions() { public Collection<ChargeData> getChargeOptions() {
return chargeOptions; return chargeOptions;
} }
public Long getLoanOfficerId() {
return loanOfficerId;
}
public void setLoanOfficerId(Long loanOfficerId) {
this.loanOfficerId = loanOfficerId;
}
public String getLoanOfficerName() {
return loanOfficerName;
}
public void setLoanOfficerName(String loanOfficerName) {
this.loanOfficerName = loanOfficerName;
}
} }
@@ -13,9 +13,14 @@ import org.joda.time.Months;
*/ */
public class LoanBasicDetailsData { public class LoanBasicDetailsData {
public Long getClientOfficeId() {
return clientOfficeId;
}
private final Long id; private final Long id;
private final String externalId; private final String externalId;
private final Long clientId; private final Long clientId;
private final Long clientOfficeId;
private final String clientName; private final String clientName;
private final Long loanProductId; private final Long loanProductId;
private final String loanProductName; private final String loanProductName;
@@ -23,6 +28,8 @@ public class LoanBasicDetailsData {
private final EnumOptionData status; private final EnumOptionData status;
private final Long fundId; private final Long fundId;
private final String fundName; private final String fundName;
private Long loanOfficerId;
private String loanOfficerName;
private final CurrencyData currency; private final CurrencyData currency;
private final BigDecimal principal; private final BigDecimal principal;
private final BigDecimal inArrearsTolerance; private final BigDecimal inArrearsTolerance;
@@ -52,8 +59,9 @@ public class LoanBasicDetailsData {
private final Collection<ChargeData> charges; private final Collection<ChargeData> charges;
public static LoanBasicDetailsData populateForNewLoanCreation(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate) { public static LoanBasicDetailsData populateForNewLoanCreation(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate,
return new LoanBasicDetailsData(clientId, clientName, expectedDisbursementDate); final Long clientOfficeId) {
return new LoanBasicDetailsData(clientId, clientName, expectedDisbursementDate, clientOfficeId);
} }
public static LoanBasicDetailsData populateForNewLoanCreation(final LoanBasicDetailsData loanAccount, final LoanProductData product) { public static LoanBasicDetailsData populateForNewLoanCreation(final LoanBasicDetailsData loanAccount, final LoanProductData product) {
@@ -61,7 +69,7 @@ public class LoanBasicDetailsData {
final Integer termFrequency = product.getNumberOfRepayments() * product.getRepaymentEvery(); final Integer termFrequency = product.getNumberOfRepayments() * product.getRepaymentEvery();
final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType(); final EnumOptionData termPeriodFrequencyType = product.getRepaymentFrequencyType();
return new LoanBasicDetailsData( return new LoanBasicDetailsData(
loanAccount.clientId, loanAccount.clientName, loanAccount.clientId, loanAccount.clientName, loanAccount.clientOfficeId,
product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(), product.getId(), product.getName(), product.getDescription(), product.getFundId(), product.getFundName(),
product.getCurrency(), product.getPrincipal(), product.getInArrearsTolerance(), product.getCurrency(), product.getPrincipal(), product.getInArrearsTolerance(),
termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), product.getRepaymentEvery(), product.getRepaymentFrequencyType(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), product.getRepaymentEvery(), product.getRepaymentFrequencyType(),
@@ -71,7 +79,7 @@ public class LoanBasicDetailsData {
} }
private LoanBasicDetailsData( private LoanBasicDetailsData(
final Long clientId, final String clientName, final Long clientId, final String clientName, final Long clientOfficeId,
final Long productId, final String productName, final String productDescription, final Long fundId, final String fundName, final Long productId, final String productName, final String productDescription, final Long fundId, final String fundName,
final CurrencyData currency, final BigDecimal principal, final BigDecimal inArrearsTolerance, final CurrencyData currency, final BigDecimal principal, final BigDecimal inArrearsTolerance,
final Integer termFrequency, final Integer termFrequency,
@@ -90,6 +98,7 @@ public class LoanBasicDetailsData {
this.externalId = null; this.externalId = null;
this.clientId = clientId; this.clientId = clientId;
this.clientName = clientName; this.clientName = clientName;
this.clientOfficeId = clientOfficeId;
this.loanProductId = productId; this.loanProductId = productId;
this.loanProductName = productName; this.loanProductName = productName;
this.loanProductDescription= productDescription; this.loanProductDescription= productDescription;
@@ -134,18 +143,20 @@ public class LoanBasicDetailsData {
this.charges = charges; this.charges = charges;
} }
private LoanBasicDetailsData(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate) { private LoanBasicDetailsData(final Long clientId, final String clientName, final LocalDate expectedDisbursementDate, final Long clientOfficeId) {
this.id = null; this.id = null;
this.externalId = null; this.externalId = null;
this.clientId = clientId; this.clientId = clientId;
this.clientName = clientName; this.clientName = clientName;
this.clientOfficeId = clientOfficeId;
this.loanProductId = null; this.loanProductId = null;
this.loanProductName = null; this.loanProductName = null;
this.loanProductDescription= null; this.loanProductDescription= null;
this.status = null; this.status = null;
this.fundId = null; this.fundId = null;
this.fundName = null; this.fundName = null;
this.loanOfficerId = null;
this.loanOfficerName = null;
this.currency = null; this.currency = null;
this.principal = null; this.principal = null;
this.inArrearsTolerance = null; this.inArrearsTolerance = null;
@@ -181,7 +192,7 @@ public class LoanBasicDetailsData {
final Long id, final Long id,
final String externalId, final String externalId,
final Long clientId, final String clientName, final Long clientId, final String clientName,
final Long loanProductId, final Long clientOfficeId, final Long loanProductId,
final String loanProductName, final String loanProductName,
final String loanProductDescription, final String loanProductDescription,
final Long fundId, String fundName, final Long fundId, String fundName,
@@ -210,16 +221,20 @@ public class LoanBasicDetailsData {
final Integer termFrequency, final Integer termFrequency,
final EnumOptionData termPeriodFrequencyType, final EnumOptionData termPeriodFrequencyType,
final Integer transactionStrategyId, final Integer transactionStrategyId,
final Collection<ChargeData> charges) { final Collection<ChargeData> charges,
final Long loanOfficerId, String loanOfficerName) {
this.id = id; this.id = id;
this.externalId = externalId; this.externalId = externalId;
this.clientId = clientId; this.clientId = clientId;
this.clientName = clientName; this.clientName = clientName;
this.clientOfficeId = clientOfficeId;
this.loanProductId = loanProductId; this.loanProductId = loanProductId;
this.loanProductName = loanProductName; this.loanProductName = loanProductName;
this.loanProductDescription = loanProductDescription; this.loanProductDescription = loanProductDescription;
this.fundId = fundId; this.fundId = fundId;
this.fundName = fundName; this.fundName = fundName;
this.loanOfficerId = loanOfficerId;
this.loanOfficerName = loanOfficerName;
this.closedOnDate = closedOnDate; this.closedOnDate = closedOnDate;
this.submittedOnDate = submittedOnDate; this.submittedOnDate = submittedOnDate;
this.approvedOnDate = approvedOnDate; this.approvedOnDate = approvedOnDate;
@@ -476,4 +491,20 @@ public class LoanBasicDetailsData {
public Collection<ChargeData> getCharges() { public Collection<ChargeData> getCharges() {
return charges; return charges;
} }
public Long getLoanOfficerId() {
return loanOfficerId;
}
public void setLoanOfficerId(Long loanOfficerId) {
this.loanOfficerId = loanOfficerId;
}
public String getLoanOfficerName() {
return loanOfficerName;
}
public void setLoanOfficerName(String loanOfficerName) {
this.loanOfficerName = loanOfficerName;
}
} }
@@ -1,6 +1,8 @@
package org.mifosng.platform.api.data; package org.mifosng.platform.api.data;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class StaffData implements Serializable { public class StaffData implements Serializable {
@@ -8,17 +10,23 @@ public class StaffData implements Serializable {
private String firstname; private String firstname;
private String lastname; private String lastname;
private String displayName; private String displayName;
private final Long officeId;
private final String officeName;
private final Boolean loanOfficerFlag;
public StaffData() { private List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>();
//
}
public StaffData(final Long id, final String firstname, public StaffData(final Long id, final String firstname,
final String lastname,final String displayName) { final String lastname, final String displayName,
final Long officeId, final String officeName,
final Boolean loanOfficerFlag) {
this.id = id; this.id = id;
this.firstname = firstname; this.firstname = firstname;
this.lastname = lastname; this.lastname = lastname;
this.displayName= displayName; this.displayName = displayName;
this.officeName = officeName;
this.loanOfficerFlag = loanOfficerFlag;
this.officeId = officeId;
} }
public Long getId() { public Long getId() {
@@ -53,5 +61,24 @@ public class StaffData implements Serializable {
this.displayName = displayName; this.displayName = displayName;
} }
public Long getOfficeId() {
return officeId;
}
public String getOfficeName() {
return officeName;
}
public Boolean getLoanOfficerFlag() {
return loanOfficerFlag;
}
public List<OfficeLookup> getAllowedOffices() {
return allowedOffices;
}
public void setAllowedOffices(List<OfficeLookup> allowedOffices) {
this.allowedOffices = allowedOffices;
}
} }
@@ -134,7 +134,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Set<String> supportedParams = new HashSet<String>( Set<String> supportedParams = new HashSet<String>(
Arrays.asList("firstname", "lastname") Arrays.asList("firstname", "lastname","officeId", "loanOfficerFlag")
); );
checkForUnsupportedParameters(requestMap, supportedParams); checkForUnsupportedParameters(requestMap, supportedParams);
@@ -143,8 +143,10 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
String firstname = extractStringParameter("firstname", requestMap, modifiedParameters); String firstname = extractStringParameter("firstname", requestMap, modifiedParameters);
String lastname = extractStringParameter("lastname", requestMap, modifiedParameters); String lastname = extractStringParameter("lastname", requestMap, modifiedParameters);
Boolean isLoanOfficer = extractBooleanParameter("loanOfficerFlag", requestMap, modifiedParameters);
Long officeId = extractLongParameter("officeId", requestMap, modifiedParameters);
return new StaffCommand(modifiedParameters, resourceIdentifier, firstname, lastname); return new StaffCommand(modifiedParameters, resourceIdentifier, officeId,firstname, lastname, isLoanOfficer);
} }
@Override @Override
@@ -445,7 +447,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
"loanTermFrequency", "loanTermFrequencyType", "charges", "loanTermFrequency", "loanTermFrequencyType", "charges",
"repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "repaymentFrequencyType", "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
"expectedDisbursementDate", "repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "expectedDisbursementDate", "repaymentsStartingFromDate", "interestChargedFromDate", "submittedOnDate", "submittedOnNote",
"locale", "dateFormat") "locale", "dateFormat", "loanOfficerId")
); );
checkForUnsupportedParameters(requestMap, supportedParams); checkForUnsupportedParameters(requestMap, supportedParams);
@@ -455,6 +457,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
Long clientId = extractLongParameter("clientId", requestMap, modifiedParameters); Long clientId = extractLongParameter("clientId", requestMap, modifiedParameters);
Long productId = extractLongParameter("productId", requestMap, modifiedParameters); Long productId = extractLongParameter("productId", requestMap, modifiedParameters);
Long fundId = extractLongParameter("fundId", requestMap, modifiedParameters); Long fundId = extractLongParameter("fundId", requestMap, modifiedParameters);
Long loanOfficerId = extractLongParameter("loanOfficerId", requestMap, modifiedParameters);
Long transactionProcessingStrategyId = extractLongParameter("transactionProcessingStrategyId", requestMap, modifiedParameters); Long transactionProcessingStrategyId = extractLongParameter("transactionProcessingStrategyId", requestMap, modifiedParameters);
String externalId = extractStringParameter("externalId", requestMap, modifiedParameters); String externalId = extractStringParameter("externalId", requestMap, modifiedParameters);
@@ -523,7 +526,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
principal, interestRatePerPeriod, interestRateFrequencyTypeValue, interestTypeValue, interestCalculationPeriodTypeValue, principal, interestRatePerPeriod, interestRateFrequencyTypeValue, interestTypeValue, interestCalculationPeriodTypeValue,
repaymentEvery, repaymentFrequencyType, numberOfRepayments, amortizationTypeValue, repaymentEvery, repaymentFrequencyType, numberOfRepayments, amortizationTypeValue,
loanTermFrequency, loanTermFrequencyType, loanTermFrequency, loanTermFrequencyType,
inArrearsToleranceValue, charges); inArrearsToleranceValue, charges,loanOfficerId);
} }
@Override @Override
@@ -63,7 +63,8 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
private static final Set<String> FUND_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> FUND_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "name", "externalId")); Arrays.asList("id", "name", "externalId"));
private static final Set<String> STAFF_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> STAFF_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "firstname", "lastname","displayName")); Arrays.asList("id", "firstname", "lastname","displayName", "officeId", "officeName",
"loanOfficerFlag","allowedOffices"));
private static final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> LOAN_PRODUCT_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "name", "description", "fundId", "fundName", Arrays.asList("id", "name", "description", "fundId", "fundName",
"transactionProcessingStrategyId", "transactionProcessingStrategyId",
@@ -149,7 +150,8 @@ public class GoogleGsonApiJsonSerializerService implements ApiJsonSerializerServ
"lifeCycleStatusDate", "summary", "repaymentSchedule", "lifeCycleStatusDate", "summary", "repaymentSchedule",
"loanRepayments", "permissions", "convenienceData", "charges", "loanRepayments", "permissions", "convenienceData", "charges",
"productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions", "chargeOptions")); "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions", "chargeOptions",
"loanOfficerId", "loanOfficerName", "loanOfficerOptions"));
private static final Set<String> LOAN_TRANSACTION_DATA_PARAMETERS = new HashSet<String>( private static final Set<String> LOAN_TRANSACTION_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "transactionType", "date", "principal", Arrays.asList("id", "transactionType", "date", "principal",
@@ -7,7 +7,7 @@ public class StaffNotFoundException extends
AbstractPlatformResourceNotFoundException { AbstractPlatformResourceNotFoundException {
public StaffNotFoundException(final Long id) { public StaffNotFoundException(final Long id) {
super("error.msg.fund.id.invalid", "Staff with identifier " + id super("error.msg.staff.id.invalid", "Staff with identifier " + id
+ " does not exist", id); + " does not exist", id);
} }
} }
@@ -0,0 +1,21 @@
package org.mifosng.platform.exceptions;
/**
* A {@link RuntimeException} thrown when staff resources are not found.
*/
public class StaffRoleException extends
AbstractPlatformResourceNotFoundException {
public static enum STAFF_ROLE {
LOAN_OFFICER, BRANCH_MANAGER;
@Override
public String toString() {
return name().toString().replaceAll("-", " ").toLowerCase();
}
}
public StaffRoleException(final Long id, STAFF_ROLE role) {
super("error.msg.staff.id.invalid.role", "Staff with identifier " + id
+ " is not a " + role.toString(), id);
}
}
@@ -38,6 +38,7 @@ import org.mifosng.platform.exceptions.InvalidLoanStateTransitionException;
import org.mifosng.platform.exceptions.InvalidLoanTransactionTypeException; import org.mifosng.platform.exceptions.InvalidLoanTransactionTypeException;
import org.mifosng.platform.fund.domain.Fund; import org.mifosng.platform.fund.domain.Fund;
import org.mifosng.platform.infrastructure.AbstractAuditableCustom; import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
import org.mifosng.platform.staff.domain.Staff;
import org.mifosng.platform.user.domain.AppUser; import org.mifosng.platform.user.domain.AppUser;
@Entity @Entity
@@ -57,6 +58,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@JoinColumn(name = "fund_id", nullable = true) @JoinColumn(name = "fund_id", nullable = true)
private Fund fund; private Fund fund;
@ManyToOne
@JoinColumn(name = "loan_officer_id", nullable = true)
private Staff loanofficer;
@ManyToOne @ManyToOne
@JoinColumn(name = "loan_transaction_strategy_id", nullable = true) @JoinColumn(name = "loan_transaction_strategy_id", nullable = true)
private LoanTransactionProcessingStrategy transactionProcessingStrategy; private LoanTransactionProcessingStrategy transactionProcessingStrategy;
@@ -157,10 +162,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@Transient @Transient
private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory(); private final LoanRepaymentScheduleTransactionProcessorFactory transactionProcessor = new LoanRepaymentScheduleTransactionProcessorFactory();
public static Loan createNew(final Fund fund, final LoanTransactionProcessingStrategy transactionProcessingStrategy, public static Loan createNew(final Fund fund,final Staff loanOfficer, final LoanTransactionProcessingStrategy transactionProcessingStrategy,
final LoanProduct loanProduct, final Client client, final LoanProduct loanProduct, final Client client,
final LoanProductRelatedDetail loanRepaymentScheduleDetail) { final LoanProductRelatedDetail loanRepaymentScheduleDetail) {
return new Loan(client, fund, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null); return new Loan(client, fund,loanOfficer, transactionProcessingStrategy, loanProduct, loanRepaymentScheduleDetail, null);
} }
protected Loan() { protected Loan() {
@@ -170,11 +175,12 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.charges = null; this.charges = null;
} }
public Loan(final Client client, Fund fund, LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct, public Loan(final Client client, Fund fund, Staff loanOfficer, LoanTransactionProcessingStrategy transactionProcessingStrategy, final LoanProduct loanProduct,
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final LoanProductRelatedDetail loanRepaymentScheduleDetail,
final LoanStatus loanStatus) { final LoanStatus loanStatus) {
this.client = client; this.client = client;
this.fund = fund; this.fund = fund;
this.loanofficer = loanOfficer;
this.transactionProcessingStrategy = transactionProcessingStrategy; this.transactionProcessingStrategy = transactionProcessingStrategy;
this.loanProduct = loanProduct; this.loanProduct = loanProduct;
this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail; this.loanRepaymentScheduleDetail = loanRepaymentScheduleDetail;
@@ -194,6 +200,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.loanProduct; return this.loanProduct;
} }
public Staff getLoanofficer() {
return loanofficer;
}
public LoanProductRelatedDetail repaymentScheduleDetail() { public LoanProductRelatedDetail repaymentScheduleDetail() {
return this.loanRepaymentScheduleDetail; return this.loanRepaymentScheduleDetail;
} }
@@ -23,6 +23,8 @@ import org.mifosng.platform.exceptions.FundNotFoundException;
import org.mifosng.platform.exceptions.InvalidCurrencyException; import org.mifosng.platform.exceptions.InvalidCurrencyException;
import org.mifosng.platform.exceptions.LoanProductNotFoundException; import org.mifosng.platform.exceptions.LoanProductNotFoundException;
import org.mifosng.platform.exceptions.LoanTransactionProcessingStrategyNotFoundException; import org.mifosng.platform.exceptions.LoanTransactionProcessingStrategyNotFoundException;
import org.mifosng.platform.exceptions.StaffNotFoundException;
import org.mifosng.platform.exceptions.StaffRoleException;
import org.mifosng.platform.fund.domain.Fund; import org.mifosng.platform.fund.domain.Fund;
import org.mifosng.platform.fund.domain.FundRepository; import org.mifosng.platform.fund.domain.FundRepository;
import org.mifosng.platform.loan.domain.AmortizationMethod; import org.mifosng.platform.loan.domain.AmortizationMethod;
@@ -41,6 +43,8 @@ import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategy;
import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository; import org.mifosng.platform.loan.domain.LoanTransactionProcessingStrategyRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType; import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanschedule.domain.AprCalculator; import org.mifosng.platform.loanschedule.domain.AprCalculator;
import org.mifosng.platform.staff.domain.Staff;
import org.mifosng.platform.staff.domain.StaffRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@@ -54,6 +58,7 @@ public class LoanAssembler {
private final FundRepository fundRepository; private final FundRepository fundRepository;
private final ChargeRepository chargeRepository; private final ChargeRepository chargeRepository;
private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository; private final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository;
private final StaffRepository staffRepository;
@Autowired @Autowired
public LoanAssembler( public LoanAssembler(
@@ -61,12 +66,14 @@ public class LoanAssembler {
final ClientRepository clientRepository, final ClientRepository clientRepository,
final FundRepository fundRepository, final FundRepository fundRepository,
final ChargeRepository chargeRepository, final ChargeRepository chargeRepository,
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository) { final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
final StaffRepository staffRepository) {
this.loanProductRepository = loanProductRepository; this.loanProductRepository = loanProductRepository;
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.fundRepository = fundRepository; this.fundRepository = fundRepository;
this.chargeRepository = chargeRepository; this.chargeRepository = chargeRepository;
this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository; this.loanTransactionProcessingStrategyRepository = loanTransactionProcessingStrategyRepository;
this.staffRepository = staffRepository;
} }
public Loan assembleFrom(final LoanApplicationCommand command) { public Loan assembleFrom(final LoanApplicationCommand command) {
@@ -94,7 +101,10 @@ public class LoanAssembler {
Fund fund = findFundByIdIfProvided(command.getFundId()); Fund fund = findFundByIdIfProvided(command.getFundId());
LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId()); LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(command.getTransactionProcessingStrategyId());
Loan loan = Loan.createNew(fund, loanTransactionProcessingStrategy, loanProduct, client, loanRepaymentScheduleDetail); //optionally associate a loan officer to the loan
Staff loanOfficer= findLoanOfficerByIdIfProvided(command.getLoanOfficerId());
Loan loan = Loan.createNew(fund,loanOfficer, loanTransactionProcessingStrategy, loanProduct, client, loanRepaymentScheduleDetail);
loan.setExternalId(command.getExternalId()); loan.setExternalId(command.getExternalId());
final Set<LoanCharge> charges = this.assembleSetOfCharges(command, loan, loanProduct, currency.getCode()); final Set<LoanCharge> charges = this.assembleSetOfCharges(command, loan, loanProduct, currency.getCode());
@@ -159,6 +169,20 @@ public class LoanAssembler {
return fund; return fund;
} }
private Staff findLoanOfficerByIdIfProvided(final Long loanOfficerId) {
Staff staff = null;
if (loanOfficerId != null) {
staff = this.staffRepository.findOne(loanOfficerId);
if (staff == null) {
throw new StaffNotFoundException(loanOfficerId);
} else if (!staff.getLoanOfficerFlag()) {
throw new StaffRoleException(loanOfficerId,
StaffRoleException.STAFF_ROLE.LOAN_OFFICER);
}
}
return staff;
}
public LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) { public LoanTransactionProcessingStrategy findStrategyByIdIfProvided(final Long transactionProcessingStrategyId) {
LoanTransactionProcessingStrategy strategy = null; LoanTransactionProcessingStrategy strategy = null;
if (transactionProcessingStrategyId != null) { if (transactionProcessingStrategyId != null) {
@@ -234,7 +234,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final LocalDate expectedDisbursementDate = new LocalDate(); final LocalDate expectedDisbursementDate = new LocalDate();
final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId); final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId);
LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(clientAccount.getId(), clientAccount.getDisplayName(), expectedDisbursementDate); LoanBasicDetailsData loanDetails = LoanBasicDetailsData.populateForNewLoanCreation(clientAccount.getId(), clientAccount.getDisplayName(), expectedDisbursementDate,
clientAccount.getOfficeId());
if (productId != null) { if (productId != null) {
LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
@@ -371,7 +372,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public String loanSchema() { public String loanSchema() {
return "l.id as id, l.external_id as externalId, l.fund_id as fundId, f.name as fundName, " return "l.id as id, l.external_id as externalId, l.fund_id as fundId, f.name as fundName, "
+ " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription, c.id as clientId, c.display_name as clientName, " + " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription, c.id as clientId, c.display_name as clientName, "
+ " l.submittedon_date as submittedOnDate," + " c.office_id as clientOfficeId,l.submittedon_date as submittedOnDate,"
+ " l.approvedon_date as approvedOnDate, l.expected_disbursedon_date as expectedDisbursementDate, l.disbursedon_date as actualDisbursementDate, l.expected_firstrepaymenton_date as expectedFirstRepaymentOnDate," + " 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.interest_calculated_from_date as interestChargedFromDate, l.closedon_date as closedOnDate, l.expected_maturedon_date as expectedMaturityDate, "
+ " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery," + " l.principal_amount as principal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
@@ -380,12 +381,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, " + " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType," + " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, " + " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode" + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ " l.loan_officer_id as loanOfficerId, s.display_name as loanOfficerName"
+ " from m_loan l" + " from m_loan l"
+ " join m_client c on c.id = l.client_id" + " join m_client c on c.id = l.client_id"
+ " join m_product_loan lp on lp.id = l.product_id" + " join m_product_loan lp on lp.id = l.product_id"
+ " join m_currency rc on rc.`code` = l.currency_code" + " join m_currency rc on rc.`code` = l.currency_code"
+ " left join m_fund f on f.id = l.fund_id"; + " left join m_fund f on f.id = l.fund_id"
+ " left join m_staff s on s.id = l.loan_officer_id";
} }
@Override @Override
@@ -404,9 +407,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
Long id = rs.getLong("id"); Long id = rs.getLong("id");
String externalId = rs.getString("externalId"); String externalId = rs.getString("externalId");
Long clientId = JdbcSupport.getLong(rs, "clientId"); Long clientId = JdbcSupport.getLong(rs, "clientId");
Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId");
String clientName = rs.getString("clientName"); String clientName = rs.getString("clientName");
Long fundId = JdbcSupport.getLong(rs, "fundId"); Long fundId = JdbcSupport.getLong(rs, "fundId");
String fundName = rs.getString("fundName"); String fundName = rs.getString("fundName");
Long loanOfficerId = JdbcSupport.getLong(rs, "loanOfficerId");
String loanOfficerName = rs.getString("loanOfficerName");
Long loanProductId = JdbcSupport.getLong(rs, "loanProductId"); Long loanProductId = JdbcSupport.getLong(rs, "loanProductId");
String loanProductName = rs.getString("loanProductName"); String loanProductName = rs.getString("loanProductName");
String loanProductDescription = rs.getString("loanProductDescription"); String loanProductDescription = rs.getString("loanProductDescription");
@@ -471,7 +477,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
} }
Collection<ChargeData> charges = null; Collection<ChargeData> charges = null;
return new LoanBasicDetailsData(id, externalId, clientId, clientName, return new LoanBasicDetailsData(id, externalId, clientId, clientName, clientOfficeId,
loanProductId, loanProductName, loanProductDescription, loanProductId, loanProductName, loanProductDescription,
fundId, fundName, fundId, fundName,
closedOnDate, closedOnDate,
@@ -485,7 +491,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
amortizationType, interestType, amortizationType, interestType,
interestCalculationPeriodType, interestCalculationPeriodType,
status, status,
lifeCycleStatusDate, termFrequency, termPeriodFrequencyType, transactionStrategyId, charges); lifeCycleStatusDate, termFrequency, termPeriodFrequencyType, transactionStrategyId, charges,
loanOfficerId, loanOfficerName);
} }
} }
@@ -2,17 +2,19 @@ package org.mifosng.platform.staff.domain;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.StaffCommand; import org.mifosng.platform.api.commands.StaffCommand;
import org.mifosng.platform.infrastructure.AbstractAuditableCustom; import org.mifosng.platform.infrastructure.AbstractAuditableCustom;
import org.mifosng.platform.organisation.domain.Office;
import org.mifosng.platform.user.domain.AppUser; import org.mifosng.platform.user.domain.AppUser;
@Entity @Entity
@Table(name = "m_staff", uniqueConstraints = { @Table(name = "m_staff", uniqueConstraints = { @UniqueConstraint(columnNames = { "display_name" }, name = "display_name") })
@UniqueConstraint(columnNames = { "display_name" }, name = "display_name")})
public class Staff extends AbstractAuditableCustom<AppUser, Long> { public class Staff extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "firstname", length = 50) @Column(name = "firstname", length = 50)
@@ -25,21 +27,39 @@ public class Staff extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "display_name", length = 100) @Column(name = "display_name", length = 100)
private String displayName; private String displayName;
public static Staff createNew(final String firstname, final String lastname) { // Office to which this employee belongs
return new Staff(firstname, lastname); @SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "office_id", nullable = false)
private Office office;
// Flag determines if employee is a loan Officer
@SuppressWarnings("unused")
@Column(name = "is_loan_officer ", nullable = false)
private Boolean loanOfficerFlag;
public static Staff createNew(Office staffOffice, final String firstname,
final String lastname, boolean isLoanOfficer) {
return new Staff(staffOffice, firstname, lastname, isLoanOfficer);
} }
protected Staff() { protected Staff() {
// //
} }
private Staff(final String firstname, final String lastname) { private Staff(final Office staffOffice, final String firstname,
final String lastname, final boolean isLoanOfficer) {
this.office = staffOffice;
this.firstname = StringUtils.defaultIfEmpty(firstname, null); this.firstname = StringUtils.defaultIfEmpty(firstname, null);
this.lastname = StringUtils.defaultIfEmpty(lastname, null); this.lastname = StringUtils.defaultIfEmpty(lastname, null);
this.loanOfficerFlag = isLoanOfficer;
deriveDisplayName(firstname); deriveDisplayName(firstname);
} }
public void update(final StaffCommand command) { public void update(final StaffCommand command, final Office staffOffice) {
if (command.isOfficeChanged()) {
this.office = staffOffice;
}
if (command.isFirstNameChanged()) { if (command.isFirstNameChanged()) {
this.firstname = StringUtils.defaultIfEmpty(command.getFirstName(), this.firstname = StringUtils.defaultIfEmpty(command.getFirstName(),
@@ -54,6 +74,10 @@ public class Staff extends AbstractAuditableCustom<AppUser, Long> {
if (command.isLastNameChanged() || command.isFirstNameChanged()) { if (command.isLastNameChanged() || command.isFirstNameChanged()) {
deriveDisplayName(firstname); deriveDisplayName(firstname);
} }
if (command.isLoanOfficerFlagChanged()) {
this.loanOfficerFlag = command.isLoanOfficerFlag();
}
} }
private void deriveDisplayName(final String firstname) { private void deriveDisplayName(final String firstname) {
@@ -64,4 +88,8 @@ public class Staff extends AbstractAuditableCustom<AppUser, Long> {
} }
} }
public Boolean getLoanOfficerFlag() {
return loanOfficerFlag;
}
} }
@@ -29,6 +29,10 @@ public class StaffCommandValidator {
baseDataValidator.reset().parameter("lastname") baseDataValidator.reset().parameter("lastname")
.value(command.getLastName()).notBlank() .value(command.getLastName()).notBlank()
.notExceedingLengthOf(50); .notExceedingLengthOf(50);
baseDataValidator.reset().parameter("officeId")
.value(command.getOfficeId()).notNull()
.integerGreaterThanZero();
if (!dataValidationErrors.isEmpty()) { if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException( throw new PlatformApiDataValidationException(
@@ -8,5 +8,5 @@ public interface StaffReadPlatformService {
StaffData retrieveStaff(Long staffId); StaffData retrieveStaff(Long staffId);
Collection<StaffData> retrieveAllStaff(); Collection<StaffData> retrieveAllStaff(final String extraCriteria);
} }
@@ -4,6 +4,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.data.StaffData; import org.mifosng.platform.api.data.StaffData;
import org.mifosng.platform.exceptions.StaffNotFoundException; import org.mifosng.platform.exceptions.StaffNotFoundException;
import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource;
@@ -30,7 +31,9 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
private static final class StaffMapper implements RowMapper<StaffData> { private static final class StaffMapper implements RowMapper<StaffData> {
public String schema() { public String schema() {
return " s.id as id, s.firstname as firstname, s.lastname as lastname, s.display_name as displayName from m_staff s "; return " s.id as id,s.office_id as officeId, o.name as officeName, s.firstname as firstname, s.lastname as lastname,"
+ " s.display_name as displayName, s.is_loan_officer as isLoanOfficer from m_staff s "
+ " join m_office o on o.id = s.office_id";
} }
@Override @Override
@@ -41,19 +44,27 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
String firstname = rs.getString("firstname"); String firstname = rs.getString("firstname");
String lastname = rs.getString("lastname"); String lastname = rs.getString("lastname");
String displayName = rs.getString("displayName"); String displayName = rs.getString("displayName");
Long officeId = rs.getLong("officeId");
return new StaffData(id, firstname, lastname,displayName); boolean isLoanOfficer = rs.getBoolean("isLoanOfficer");
String officeName = rs.getString("officeName");
return new StaffData(id, firstname, lastname, displayName,
officeId, officeName, isLoanOfficer);
} }
} }
@Override @Override
public Collection<StaffData> retrieveAllStaff() { public Collection<StaffData> retrieveAllStaff(final String extraCriteria) {
context.authenticatedUser(); context.authenticatedUser();
StaffMapper rm = new StaffMapper(); StaffMapper rm = new StaffMapper();
String sql = "select " + rm.schema() + " order by s.lastname"; String sql = "select " + rm.schema();
if (StringUtils.isNotBlank(extraCriteria)) {
sql += " where " + extraCriteria;
}
sql = sql + " order by s.lastname";
return this.jdbcTemplate.query(sql, rm, new Object[] {}); return this.jdbcTemplate.query(sql, rm, new Object[] {});
} }
@@ -2,11 +2,14 @@ package org.mifosng.platform.staff.service;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.StaffCommand; import org.mifosng.platform.api.commands.StaffCommand;
import org.mifosng.platform.exceptions.StaffNotFoundException; import org.mifosng.platform.exceptions.OfficeNotFoundException;
import org.mifosng.platform.exceptions.PlatformDataIntegrityException; import org.mifosng.platform.exceptions.PlatformDataIntegrityException;
import org.mifosng.platform.exceptions.StaffNotFoundException;
import org.mifosng.platform.organisation.domain.Office;
import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.staff.domain.Staff; import org.mifosng.platform.staff.domain.Staff;
import org.mifosng.platform.staff.domain.StaffRepository; import org.mifosng.platform.staff.domain.StaffRepository;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -23,13 +26,16 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final StaffRepository staffRepository; private final StaffRepository staffRepository;
private final OfficeRepository officeRepository;
@Autowired @Autowired
public StaffWritePlatformServiceJpaRepositoryImpl( public StaffWritePlatformServiceJpaRepositoryImpl(
final PlatformSecurityContext context, final PlatformSecurityContext context,
final StaffRepository staffRepository) { final StaffRepository staffRepository,
final OfficeRepository officeRepository) {
this.context = context; this.context = context;
this.staffRepository = staffRepository; this.staffRepository = staffRepository;
this.officeRepository = officeRepository;
} }
@Transactional @Transactional
@@ -42,8 +48,14 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements
StaffCommandValidator validator = new StaffCommandValidator(command); StaffCommandValidator validator = new StaffCommandValidator(command);
validator.validateForCreate(); validator.validateForCreate();
Staff staff = Staff.createNew(command.getFirstName(), Office staffOffice = this.officeRepository.findOne(command
command.getLastName()); .getOfficeId());
if (staffOffice == null) {
throw new OfficeNotFoundException(command.getOfficeId());
}
Staff staff = Staff.createNew(staffOffice, command.getFirstName(),
command.getLastName(), command.isLoanOfficerFlag());
this.staffRepository.saveAndFlush(staff); this.staffRepository.saveAndFlush(staff);
@@ -69,7 +81,17 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements
if (staff == null) { if (staff == null) {
throw new StaffNotFoundException(staffId); throw new StaffNotFoundException(staffId);
} }
staff.update(command);
Office staffOffice = null;
Long officeId = command.getOfficeId();
if (command.isOfficeChanged() && officeId != null) {
staffOffice = this.officeRepository.findOne(officeId);
if (staffOffice == null) {
throw new OfficeNotFoundException(command.getOfficeId());
}
}
staff.update(command, staffOffice);
this.staffRepository.saveAndFlush(staff); this.staffRepository.saveAndFlush(staff);