MIFOSX-109: vishwas work on gaurantor squashed into one commit.

This commit is contained in:
Vishwas Babu AJ
2012-11-21 16:40:01 +00:00
committed by Keith Woodlock
parent 9aa9b870f0
commit e874efc3ac
22 changed files with 1121 additions and 15 deletions
@@ -0,0 +1,25 @@
CREATE TABLE `m_guarantor_external` (
`loan_id` BIGINT(20) NOT NULL,
`firstname` VARCHAR(50) NOT NULL,
`lastname` VARCHAR(50) NOT NULL,
`dob` DATE NULL,
`address_line_1` VARCHAR(500) NULL,
`address_line_2` VARCHAR(500) NULL,
`city` VARCHAR(50) NULL,
`state` VARCHAR(50) NULL,
`country` VARCHAR(50) NULL,
`zip` VARCHAR(20) NULL,
`house_phone_number` VARCHAR(20) NULL,
`mobile_number` VARCHAR(20) NULL,
`comment` VARCHAR(20) NULL,
PRIMARY KEY (`loan_id`),
CONSTRAINT `FK_m_guarantor_m_loan` FOREIGN KEY (`loan_id`) REFERENCES `m_loan` (`id`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `m_loan`
ADD COLUMN `guarantor_id` BIGINT(20) NULL DEFAULT NULL AFTER `loan_officer_id`,
ADD CONSTRAINT `FK_m_loan_guarantor` FOREIGN KEY (`guarantor_id`) REFERENCES `m_client` (`id`);
insert into x_registered_table values ('m_guarantor_external','m_loan');
@@ -0,0 +1,118 @@
package org.mifosng.platform.api;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.GuarantorData;
import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService;
import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService;
import org.mifosng.platform.guarantor.GuarantorReadPlatformService;
import org.mifosng.platform.guarantor.GuarantorWritePlatformService;
import org.mifosng.platform.infrastructure.api.ApiParameterHelper;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/loans/{loanId}/guarantor")
@Component
@Scope("singleton")
public class GuarantorsApiResource {
@Autowired
private GuarantorWritePlatformService guarantorWritePlatformService;
@Autowired
private GuarantorReadPlatformService guarantorReadPlatformService;
@Autowired
private PortfolioApiDataConversionService apiDataConversionService;
@Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService;
private static final Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("externalGuarantor", "existingClientId", "firstname",
"lastname", "addressLine1", "addressLine2", "city",
"state", "zip", "country", "mobileNumber",
"housePhoneNumber", "comment", "dob"));
private final String SystemEntityType = "m_guarantor_external";
@Autowired
private PlatformSecurityContext context;
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveGuarantorDetails(@Context final UriInfo uriInfo,
@PathParam("loanId") final Long loanId) {
context.authenticatedUser().validateHasReadPermission(SystemEntityType);
Set<String> responseParameters = ApiParameterHelper
.extractFieldsForResponseIfProvided(uriInfo
.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo
.getQueryParameters());
GuarantorData guarantorData = guarantorReadPlatformService
.retrieveGuarantor(loanId);
return this.apiJsonSerializerService.serializeGuarantorDataToJson(
prettyPrint, responseParameters, guarantorData);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response createGuarantor(@PathParam("loanId") final Long loanId,
final String jsonRequestBody) {
final GuarantorCommand command = this.apiDataConversionService
.convertJsonToGuarantorCommand(null, loanId, jsonRequestBody);
this.guarantorWritePlatformService.createGuarantor(loanId, command);
// returns the loan Identifier for which the guarantor was associated
return Response.ok().entity(new EntityIdentifier(loanId)).build();
}
@PUT
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateGuarantor(@PathParam("loanId") final Long loanId,
final String jsonRequestBody) {
final GuarantorCommand command = this.apiDataConversionService
.convertJsonToGuarantorCommand(null, loanId, jsonRequestBody);
this.guarantorWritePlatformService.updateGuarantor(loanId, command);
return Response.ok().entity(new EntityIdentifier(loanId)).build();
}
@DELETE
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response deleteGuarantor(@PathParam("loanId") final Long loanId) {
this.guarantorWritePlatformService.removeGuarantor(loanId);
return Response.ok(new EntityIdentifier(loanId)).build();
}
}
@@ -33,6 +33,7 @@ import org.mifosng.platform.api.data.DisbursementData;
import org.mifosng.platform.api.data.EntityIdentifier;
import org.mifosng.platform.api.data.EnumOptionData;
import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.GuarantorData;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanBasicDetailsData;
import org.mifosng.platform.api.data.LoanChargeData;
@@ -50,6 +51,7 @@ import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.mifosng.platform.exceptions.UnrecognizedQueryParamException;
import org.mifosng.platform.fund.service.FundReadPlatformService;
import org.mifosng.platform.guarantor.GuarantorReadPlatformService;
import org.mifosng.platform.infrastructure.api.ApiParameterHelper;
import org.mifosng.platform.loan.service.CalculationPlatformService;
import org.mifosng.platform.loan.service.LoanReadPlatformService;
@@ -100,7 +102,10 @@ public class LoansApiResource {
@Autowired
private PlatformSecurityContext context;
@Autowired
private GuarantorReadPlatformService guarantorReadPlatformService;
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -152,7 +157,7 @@ public class LoansApiResource {
final LoanAccountData newLoanAccount = new LoanAccountData(loanBasicDetails, convenienceDataRequired, null, null, null, charges,
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers);
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers,null);
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, newLoanAccount);
}
@@ -177,13 +182,22 @@ public class LoansApiResource {
LoanScheduleData repaymentSchedule = null;
LoanPermissionData permissions = null;
Collection<LoanChargeData> charges = null;
GuarantorData guarantorData = null;
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"));
associationParameters.addAll(Arrays.asList("repaymentSchedule", "transactions", "permissions", "convenienceData", "charges", "guarantor"));
}
boolean existsGuarantor = false;
if (associationParameters.contains("guarantor")) {
if(guarantorReadPlatformService.existsGuarantor(loanId)){
guarantorData = this.guarantorReadPlatformService.retrieveGuarantor(loanId);
existsGuarantor = true;
}
}
if (associationParameters.contains("transactions")) {
@@ -208,7 +222,7 @@ public class LoansApiResource {
if (associationParameters.contains("permissions")) {
loanRepaymentsCount = retrieveNonDisbursementTransactions(loanRepayments);
permissions = this.loanReadPlatformService.retrieveLoanPermissions(loanBasicDetails, isWaiveAllowed, loanRepaymentsCount);
permissions = this.loanReadPlatformService.retrieveLoanPermissions(loanBasicDetails, isWaiveAllowed, loanRepaymentsCount, existsGuarantor);
}
convenienceDataRequired = true;
}
@@ -256,7 +270,7 @@ public class LoansApiResource {
productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
repaymentStrategyOptions, interestRateFrequencyTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
fundOptions, chargeOptions, chargeTemplate, null);
fundOptions, chargeOptions, chargeTemplate, null, guarantorData);
return this.apiJsonSerializerService.serializeLoanAccountDataToJson(prettyPrint, responseParameters, loanAccount);
}
@@ -0,0 +1,141 @@
package org.mifosng.platform.api.commands;
import java.util.Set;
/**
* Immutable command for creating or updating details of a Guarantor.
*/
public class GuarantorCommand {
private final boolean externalGuarantor;
/*** Fields for current customers serving as guarantors **/
private final Long existingClientId;
/*** Fields for external persons serving as guarantors ***/
private final String firstname;
private final String lastname;
private final String addressLine1;
private final String addressLine2;
private final String city;
private final String state;
private final String zip;
private final String country;
private final String mobileNumber;
private final String housePhoneNumber;
private final String comment;
private final String dob;
/**Feilds for passing Locale info to generic data service api**/
private String dateFormat;
private String locale;
private final Set<String> modifiedParameters;
public GuarantorCommand(final Set<String> modifiedParameters,
final Long existingClientId, final String firstname,
final String lastname, final Boolean externalGuarantor,
final String addressLine1, final String addressLine2,
final String city, final String state, final String zip,
final String country, final String mobileNumber,
final String housePhoneNumber, final String comment,
final String dob) {
this.modifiedParameters = modifiedParameters;
this.externalGuarantor = externalGuarantor;
/*** Fields for current customers serving as guarantors **/
this.existingClientId = existingClientId;
/*** Fields for external persons serving as guarantors ***/
this.firstname = firstname;
this.lastname = lastname;
this.addressLine1 = addressLine1;
this.addressLine2 = addressLine2;
this.city = city;
this.state = state;
this.zip = zip;
this.country = country;
this.mobileNumber = mobileNumber;
this.housePhoneNumber = housePhoneNumber;
this.comment = comment;
this.dob = dob;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public Boolean isExternalGuarantor() {
return externalGuarantor;
}
public Long getExistingClientId() {
return existingClientId;
}
public String getAddressLine1() {
return addressLine1;
}
public String getAddressLine2() {
return addressLine2;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public String getZip() {
return zip;
}
public String getCountry() {
return country;
}
public String getMobileNumber() {
return mobileNumber;
}
public String getHousePhoneNumber() {
return housePhoneNumber;
}
public String getComment() {
return comment;
}
public Set<String> getModifiedParameters() {
return modifiedParameters;
}
public String getDob() {
return dob;
}
public String getDateFormat() {
return dateFormat;
}
public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
}
@@ -0,0 +1,196 @@
package org.mifosng.platform.api.data;
import org.joda.time.LocalDate;
public class GuarantorData {
private String firstname;
private String lastname;
private boolean externalGuarantor;
/*** Fields for current customers serving as guarantors **/
private Long existingClientId;
private String externalId;
private String officeName;
private LocalDate joinedDate;
/*** Fields for external persons serving as guarantors ***/
private String addressLine1;
private String addressLine2;
private String city;
private String state;
private String zip;
private String country;
private String mobileNumber;
private String housePhoneNumber;
private String comment;
private LocalDate dob;
public GuarantorData(final Long existingClientId, final String firstname,
final String lastname, final String externalId,
final String officeName, final LocalDate joinedDate) {
this.existingClientId = existingClientId;
this.firstname = firstname;
this.lastname = lastname;
this.externalId = externalId;
this.officeName = officeName;
this.joinedDate = joinedDate;
this.externalGuarantor = false;
}
public GuarantorData(final String firstname, final String lastname,
final LocalDate dob, final String addressLine1,
final String addressLine2, final String city, final String state,
final String zip, final String country, final String mobileNumber,
final String housePhoneNumber, final String comment) {
this.firstname = firstname;
this.lastname = lastname;
this.dob = dob;
this.addressLine1 = addressLine1;
this.addressLine2 = addressLine2;
this.city = city;
this.state = state;
this.zip = zip;
this.country = country;
this.mobileNumber = mobileNumber;
this.housePhoneNumber = housePhoneNumber;
this.comment = comment;
this.externalGuarantor = true;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public Long getExistingClientId() {
return existingClientId;
}
public void setExistingClientId(Long existingClientId) {
this.existingClientId = existingClientId;
}
public String getExternalId() {
return externalId;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public String getOfficeName() {
return officeName;
}
public void setOfficeName(String officeName) {
this.officeName = officeName;
}
public LocalDate getJoinedDate() {
return joinedDate;
}
public void setJoinedDate(LocalDate joinedDate) {
this.joinedDate = joinedDate;
}
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getAddressLine2() {
return addressLine2;
}
public void setAddressLine2(String addressLine2) {
this.addressLine2 = addressLine2;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public String getHousePhoneNumber() {
return housePhoneNumber;
}
public void setHousePhoneNumber(String housePhoneNumber) {
this.housePhoneNumber = housePhoneNumber;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public boolean getExternalGuarantor() {
return externalGuarantor;
}
public void setExternalGuarantor(boolean externalGuarantor) {
this.externalGuarantor = externalGuarantor;
}
public LocalDate getDob() {
return dob;
}
public void setDob(LocalDate dob) {
this.dob = dob;
}
}
@@ -59,6 +59,7 @@ public class LoanAccountData {
private final Collection<LoanChargeData> charges;
private final LoanPermissionData permissions;
private final LoanConvenienceData convenienceData;
private final GuarantorData guarantorData;
// template
private final Collection<StaffData> loanOfficerOptions;
@@ -92,7 +93,8 @@ public class LoanAccountData {
final Collection<FundData> fundOptions,
final Collection<ChargeData> chargeOptions,
final ChargeData chargeTemplate,
final Collection<StaffData> loanOfficerOptions) {
final Collection<StaffData> loanOfficerOptions,
final GuarantorData guarantorData) {
this.repaymentSchedule = repaymentSchedule;
this.transactions = transactions;
this.permissions = permissions;
@@ -109,6 +111,7 @@ public class LoanAccountData {
this.chargeOptions = chargeOptions;
this.chargeTemplate = chargeTemplate;
this.loanOfficerOptions = loanOfficerOptions;
this.guarantorData = guarantorData;
if (convenienceDataRequired) {
int maxSubmittedOnOffsetFromToday = basicDetails
@@ -19,6 +19,10 @@ public class LoanPermissionData {
private final boolean undoDisbursalAllowed;
private final boolean anyActionOnLoanAllowed;
//permissions for setting/removing guarantors for Loans
private final boolean setGuarantorAllowed;
private final boolean editGuarantorAllowed;
// status of loan
private final boolean pendingApproval;
private final boolean waitingForDisbursal;
@@ -35,6 +39,8 @@ public class LoanPermissionData {
final boolean undoApprovalAllowed,
final boolean undoDisbursalAllowed,
final boolean disbursalAllowed,
final boolean setGuarantorAllowed,
final boolean editGuarantorAllowed,
final boolean pendingApproval,
final boolean waitingForDisbursal,
final boolean closedObligationsMet) {
@@ -49,6 +55,8 @@ public class LoanPermissionData {
this.undoDisbursalAllowed = undoDisbursalAllowed;
this.disbursalAllowed = disbursalAllowed;
this.pendingApproval = pendingApproval;
this.setGuarantorAllowed = setGuarantorAllowed;
this.editGuarantorAllowed = editGuarantorAllowed;
this.waitingForDisbursal = waitingForDisbursal;
this.closedObligationsMet = closedObligationsMet;
this.anyActionOnLoanAllowed = closeLoanAllowed || closeLoanAsRescheduledAllowed || rejectAllowed || withdrawnByApplicantAllowed || pendingApproval || undoDisbursalAllowed || makeRepaymentAllowed;
@@ -25,6 +25,7 @@ import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.GroupAccountSummaryCollectionData;
import org.mifosng.platform.api.data.GroupData;
import org.mifosng.platform.api.data.GuarantorData;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanChargeData;
import org.mifosng.platform.api.data.LoanProductData;
@@ -165,6 +166,13 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
"projectedInterestAccuredOnMaturity", "actualInterestAccured", "projectedMaturityAmount", "actualMaturityAmount",
"preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "isLockinPeriodAllowed",
"lockinPeriod", "lockinPeriodType"));
//guarantors
private static final Set<String> GUARANTOR_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("externalGuarantor", "existingClientId",
"firstname", "lastname", "addressLine1",
"addressLine2", "city", "state", "zip", "country",
"mobileNumber", "housePhoneNumber", "comment", "dob"));
// accounting
private static final Set<String> CHART_OF_ACCOUNTS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name"));
@@ -584,4 +592,13 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
CHART_OF_ACCOUNTS_DATA_PARAMETERS, prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, chartOfAccounts);
}
@Override
public String serializeGuarantorDataToJson(boolean prettyPrint,
Set<String> responseParameters, GuarantorData guarantorData) {
final Gson gsonDeserializer = helper
.createGsonBuilderWithParameterExclusionSerializationStrategy(
GUARANTOR_DATA_PARAMETERS, prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, guarantorData);
}
}
@@ -15,6 +15,7 @@ import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand;
import org.mifosng.platform.api.commands.DepositStateTransitionCommand;
import org.mifosng.platform.api.commands.FundCommand;
import org.mifosng.platform.api.commands.GroupCommand;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanProductCommand;
@@ -94,5 +95,7 @@ public interface PortfolioApiDataConversionService {
CodeCommand convertJsonToCodeCommand(Long resourceIdentifier, String json);
SavingAccountCommand convertJsonToSavingAccountCommand(Long resourceIdentifier, String json);
SavingAccountCommand convertJsonToSavingAccountCommand(Long resourceIdentifier,String json);
GuarantorCommand convertJsonToGuarantorCommand(Long resourceIdentifier, Long loanId, String json);
}
@@ -31,6 +31,7 @@ import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand;
import org.mifosng.platform.api.commands.DepositStateTransitionCommand;
import org.mifosng.platform.api.commands.FundCommand;
import org.mifosng.platform.api.commands.GroupCommand;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.mifosng.platform.api.commands.LoanApplicationCommand;
import org.mifosng.platform.api.commands.LoanChargeCommand;
import org.mifosng.platform.api.commands.LoanProductCommand;
@@ -1628,4 +1629,68 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
savingProductType, tenureType, frequency, interestType, minimumBalanceForWithdrawal, interestCalculationMethod,
isLockinPeriodAllowed, isPartialDepositAllowed, lockinPeriod, lockinPeriodType);
}
@Override
public GuarantorCommand convertJsonToGuarantorCommand(
Long resourceIdentifier, Long loanId, String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
Type typeOfMap = new TypeToken<Map<String, String>>() {
}.getType();
Map<String, String> requestMap = gsonConverter
.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(Arrays.asList(
"externalGuarantor", "existingClientId", "firstname",
"lastname", "addressLine1", "addressLine2", "city", "state",
"zip", "country", "mobileNumber", "housePhoneNumber",
"comment", "dob", "locale", "dateFormat"));
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
boolean externalGuarantor = extractBooleanParameter(
"externalGuarantor", requestMap, modifiedParameters);
Long existingClientId = extractLongParameter("existingClientId",
requestMap, modifiedParameters);
String firstname = extractStringParameter("firstname", requestMap,
modifiedParameters);
String lastname = extractStringParameter("lastname", requestMap,
modifiedParameters);
String addressLine1 = extractStringParameter("addressLine1",
requestMap, modifiedParameters);
String addressLine2 = extractStringParameter("addressLine2",
requestMap, modifiedParameters);
String city = extractStringParameter("city", requestMap,
modifiedParameters);
String state = extractStringParameter("state", requestMap,
modifiedParameters);
String zip = extractStringParameter("zip", requestMap,
modifiedParameters);
String country = extractStringParameter("country", requestMap,
modifiedParameters);
String mobileNumber = extractStringParameter("mobileNumber",
requestMap, modifiedParameters);
String housePhoneNumber = extractStringParameter("housePhoneNumber",
requestMap, modifiedParameters);
String comment = extractStringParameter("comment", requestMap,
modifiedParameters);
String dob = extractStringParameter("dob", requestMap,
modifiedParameters);
// workaround for passing locale info to data table api
final String dateFormat = (String) requestMap.get("dateFormat");
final String locale = (String) requestMap.get("locale");
GuarantorCommand command = new GuarantorCommand(modifiedParameters,
existingClientId, firstname, lastname, externalGuarantor,
addressLine1, addressLine2, city, state, zip, country,
mobileNumber, housePhoneNumber, comment, dob);
command.setDateFormat(dateFormat);
command.setLocale(locale);
return command;
}
}
@@ -23,6 +23,7 @@ import org.mifosng.platform.api.data.FundData;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.GroupAccountSummaryCollectionData;
import org.mifosng.platform.api.data.GroupData;
import org.mifosng.platform.api.data.GuarantorData;
import org.mifosng.platform.api.data.LoanAccountData;
import org.mifosng.platform.api.data.LoanChargeData;
import org.mifosng.platform.api.data.LoanProductData;
@@ -156,7 +157,9 @@ public interface PortfolioApiJsonSerializerService {
String serializeSavingAccountsDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<SavingAccountData> accounts);
// TODO - KW - might devide serialize up into portfolio and account to
// reduce interface
String serializeChartOfAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, ChartOfAccountsData chartOfAccounts);
// TODO - KW - might devide serialize up into portfolio and account to reduce interface
String serializeChartOfAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, ChartOfAccountsData chartOfAccounts);
String serializeGuarantorDataToJson(boolean prettyPrint,Set<String> responseParameters, GuarantorData guarantorData);
}
@@ -7,14 +7,15 @@ import org.mifosng.platform.api.data.EntityIdentifier;
import org.springframework.security.access.prepost.PreAuthorize;
public interface DocumentWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_DOCUMENT')")
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_m_guarantor_external')")
Long createDocument(DocumentCommand documentCommand, InputStream inputStream);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_DOCUMENT')")
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_m_guarantor_external')")
EntityIdentifier updateDocument(DocumentCommand documentCommand,
InputStream inputStream);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_DOCUMENT')")
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_m_guarantor_external')")
EntityIdentifier deleteDocument(DocumentCommand documentCommand);
}
@@ -0,0 +1,13 @@
package org.mifosng.platform.exceptions;
/**
* A {@link RuntimeException} thrown when guarantor resources are not found.
*/
public class GuarantorNotFoundException extends
AbstractPlatformResourceNotFoundException {
public GuarantorNotFoundException(Long id) {
super("error.msg.loan.guarantor.", "Loan with identifier " + id
+ " does not have a guarantor associated with it", id);
}
}
@@ -0,0 +1,17 @@
package org.mifosng.platform.exceptions;
/**
* {@link AbstractPlatformDomainRuleException} thrown when a Client is set as a
* guarantor for his/her own loans
*/
public class InvalidGuarantorException extends
AbstractPlatformDomainRuleException {
public InvalidGuarantorException(Long clientId, Long loanId) {
super("error.msg.invalid.guarantor", "Tried to set Client with id "
+ clientId
+ " as a guarantor to his/her own loan with loan identifier ="
+ loanId, clientId, loanId);
}
}
@@ -0,0 +1,119 @@
package org.mifosng.platform.guarantor;
import java.util.ArrayList;
import java.util.List;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
public class GuarantorCommandValidator {
private final GuarantorCommand command;
public GuarantorCommandValidator(GuarantorCommand command) {
this.command = command;
}
public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
dataValidationErrors).resource("Guarantor");
// validate for existing Client
if (command.isExternalGuarantor() == null
|| command.isExternalGuarantor() == false) {
baseDataValidator.reset().parameter("existingClientId")
.value(command.getExistingClientId()).notNull()
.integerGreaterThanZero();
} else {
// validate for an external guarantor
baseDataValidator.reset().parameter("firstname")
.value(command.getFirstname()).notBlank()
.notExceedingLengthOf(50);
baseDataValidator.reset().parameter("lastname")
.value(command.getLastname()).notBlank()
.notExceedingLengthOf(50);
validateNonMandatoryFieldsForMaxLength(baseDataValidator);
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
}
public void validateForUpdate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
dataValidationErrors).resource("Guarantor");
// validate for existing Client
if (command.isExternalGuarantor() == null
|| command.isExternalGuarantor() == false) {
baseDataValidator.reset().parameter("existingClientId")
.value(command.getExistingClientId()).notNull()
.integerGreaterThanZero();
} else {
// validate for an external guarantor
baseDataValidator.reset().parameter("firstname")
.value(command.getFirstname()).notBlank()
.notExceedingLengthOf(50);
baseDataValidator.reset().parameter("lastname")
.value(command.getLastname()).notBlank()
.notExceedingLengthOf(50);
validateNonMandatoryFieldsForMaxLength(baseDataValidator);
}
baseDataValidator.reset().anyOfNotNull(command.getExistingClientId(),
command.getAddressLine1(), command.getAddressLine2(),
command.getCity(), command.getComment(), command.getCountry(),
command.getFirstname(), command.getHousePhoneNumber(),
command.getLastname(), command.getMobileNumber(),
command.getState(), command.getZip());
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
}
/**
* @param baseDataValidator
*/
private void validateNonMandatoryFieldsForMaxLength(
DataValidatorBuilder baseDataValidator) {
// validate non mandatory fields for length
baseDataValidator.reset().parameter("addressLine1")
.value(command.getAddressLine1()).ignoreIfNull()
.notExceedingLengthOf(50);
baseDataValidator.reset().parameter("addressLine2")
.value(command.getAddressLine2()).ignoreIfNull()
.notExceedingLengthOf(50);
baseDataValidator.reset().parameter("city").value(command.getCity())
.ignoreIfNull().notExceedingLengthOf(50);
baseDataValidator.reset().parameter("state").value(command.getState())
.ignoreIfNull().notExceedingLengthOf(50);
baseDataValidator.reset().parameter("zip").value(command.getZip())
.ignoreIfNull().notExceedingLengthOf(50);
baseDataValidator.reset().parameter("country")
.value(command.getCountry()).ignoreIfNull()
.notExceedingLengthOf(50);
baseDataValidator.reset().parameter("mobileNumber")
.value(command.getMobileNumber()).ignoreIfNull()
.notExceedingLengthOf(20);
baseDataValidator.reset().parameter("housePhoneNumber")
.value(command.getHousePhoneNumber()).ignoreIfNull()
.notExceedingLengthOf(20);
baseDataValidator.reset().parameter("comment")
.value(command.getComment()).ignoreIfNull()
.notExceedingLengthOf(500);
}
}
@@ -0,0 +1,13 @@
package org.mifosng.platform.guarantor;
import org.mifosng.platform.api.data.GuarantorData;
public interface GuarantorReadPlatformService {
GuarantorData retrieveGuarantor(Long loanId);
boolean existsGuarantor(Long loanId);
GuarantorData getExternalGuarantor(Long loanId);
}
@@ -0,0 +1,122 @@
package org.mifosng.platform.guarantor;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.data.GenericResultsetData;
import org.mifosng.platform.api.data.GuarantorData;
import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.exceptions.GuarantorNotFoundException;
import org.mifosng.platform.exceptions.LoanNotFoundException;
import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.noncore.ReadWriteNonCoreDataService;
import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GuarantorReadPlatformServiceImpl implements
GuarantorReadPlatformService {
private final LoanRepository loanRepository;
private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
// Table for storing external Guarantor Details
public static final String EXTERNAL_GUARANTOR_TABLE_NAME = "m_guarantor_external";
@Autowired
public GuarantorReadPlatformServiceImpl(
final LoanRepository loanRepository,
final ReadWriteNonCoreDataService readWriteNonCoreDataService,
final OfficeRepository officeRepository) {
this.loanRepository = loanRepository;
this.readWriteNonCoreDataService = readWriteNonCoreDataService;
}
@Override
public boolean existsGuarantor(Long loanId) {
Loan loan = validateLoanExists(loanId);
// return if internal guarantor exists
if (loan.getGuarantor() != null) {
return true;
}
// return if an external guarantor exists
if (null != getExternalGuarantor(loanId)) {
return true;
}
// else no guarantor exists
return false;
}
@Override
public GuarantorData retrieveGuarantor(Long loanId) {
GuarantorData guarantorData = null;
Loan loan = validateLoanExists(loanId);
// does an internal guarantor exist
if (loan.getGuarantor() != null) {
Client guarantor = loan.getGuarantor();
LocalDate localDate = new LocalDate(guarantor.getJoiningDate());
guarantorData = new GuarantorData(guarantor.getId(),
guarantor.getFirstName(), guarantor.getLastName(),
guarantor.getExternalId(), guarantor.getOffice().getName(),
localDate);
} else {
guarantorData = getExternalGuarantor(loanId);
}
// throw error if guarantor does not exist
if (guarantorData == null) {
throw new GuarantorNotFoundException(loanId);
}
return guarantorData;
}
/**
* @param loanId
* @return
*/
private Loan validateLoanExists(Long loanId) {
Loan loan = loanRepository.findOne(loanId);
if (loan == null) {
throw new LoanNotFoundException(loanId);
}
return loan;
}
/**
* @param loanId
* @return
*/
public GuarantorData getExternalGuarantor(Long loanId) {
GenericResultsetData genericResultDataSet = readWriteNonCoreDataService
.retrieveDataTableGenericResultSet(
EXTERNAL_GUARANTOR_TABLE_NAME, loanId, null, null);
if (genericResultDataSet.getData().size() == 1) {
List<String> guarantorRow = genericResultDataSet.getData().get(0)
.getRow();
String firstname = guarantorRow.get(1);
String lastname = guarantorRow.get(2);
LocalDate dateOfBirth = null;
if (!StringUtils.isBlank(guarantorRow.get(3))) {
dateOfBirth = new LocalDate(guarantorRow.get(3));
}
String addressLine1 = guarantorRow.get(4);
String addressLine2 = guarantorRow.get(5);
String city = guarantorRow.get(6);
String state = guarantorRow.get(7);
String country = guarantorRow.get(8);
String zip = guarantorRow.get(9);
String housePhoneNumber = guarantorRow.get(10);
String mobileNumber = guarantorRow.get(11);
String comment = guarantorRow.get(12);
GuarantorData guarantorData = new GuarantorData(firstname,
lastname, dateOfBirth, addressLine1, addressLine2, city,
state, zip, country, mobileNumber, housePhoneNumber,
comment);
return guarantorData;
}
return null;
}
}
@@ -0,0 +1,17 @@
package org.mifosng.platform.guarantor;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.springframework.security.access.prepost.PreAuthorize;
public interface GuarantorWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS','PORTFOLIO_MANAGEMENT_SUPER_USER')")
void createGuarantor(final Long loanId, final GuarantorCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS','PORTFOLIO_MANAGEMENT_SUPER_USER')")
void updateGuarantor(final Long loanId, final GuarantorCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS','PORTFOLIO_MANAGEMENT_SUPER_USER')")
void removeGuarantor(final Long loanId);
}
@@ -0,0 +1,182 @@
package org.mifosng.platform.guarantor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.GuarantorCommand;
import org.mifosng.platform.api.data.ApiParameterError;
import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.client.domain.ClientRepository;
import org.mifosng.platform.exceptions.ClientNotFoundException;
import org.mifosng.platform.exceptions.InvalidGuarantorException;
import org.mifosng.platform.exceptions.LoanNotFoundException;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.loan.domain.Loan;
import org.mifosng.platform.loan.domain.LoanRepository;
import org.mifosng.platform.noncore.ReadWriteNonCoreDataService;
import org.mifosng.platform.organisation.domain.OfficeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GuarantorWritePlatformServiceImpl implements
GuarantorWritePlatformService {
private final LoanRepository loanRepository;
private final ClientRepository clientRepository;
private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
private final GuarantorReadPlatformService guarantorReadPlatformService;
// Table for storing external Guarantor Details
public static final String EXTERNAL_GUARANTOR_TABLE_NAME = "m_guarantor_external";
@Autowired
public GuarantorWritePlatformServiceImpl(
final LoanRepository loanRepository,
final ReadWriteNonCoreDataService readWriteNonCoreDataService,
final OfficeRepository officeRepository,
final ClientRepository clientRepository,
final GuarantorReadPlatformService guarantorReadPlatformService) {
this.loanRepository = loanRepository;
this.readWriteNonCoreDataService = readWriteNonCoreDataService;
this.clientRepository = clientRepository;
this.guarantorReadPlatformService = guarantorReadPlatformService;
}
@Override
@Transactional
public void createGuarantor(Long loanId, GuarantorCommand command) {
GuarantorCommandValidator validator = new GuarantorCommandValidator(
command);
validator.validateForCreate();
saveOrUpdateGuarantor(loanId, command);
}
@Override
@Transactional
public void updateGuarantor(Long loanId, GuarantorCommand command) {
GuarantorCommandValidator validator = new GuarantorCommandValidator(
command);
validator.validateForUpdate();
saveOrUpdateGuarantor(loanId, command);
}
@Override
@Transactional
public void removeGuarantor(Long loanId) {
Loan loan = validateLoanExists(loanId);
// remove internal guarantor, if any
if (loan.getGuarantor() != null) {
loan.setGuarantor(null);
loanRepository.saveAndFlush(loan);
}
// remove external guarantor, if any
readWriteNonCoreDataService.deleteDatatableEntries(
EXTERNAL_GUARANTOR_TABLE_NAME, loanId);
}
/**
* @param loanId
* @param command
*/
private void saveOrUpdateGuarantor(Long loanId, GuarantorCommand command) {
Loan loan = validateLoanExists(loanId);
// mark an existing client as a guarantor
if (command.isExternalGuarantor() == null
|| !command.isExternalGuarantor()) {
// can't set client as a guarantor to himself
if (loan.getClient().getId().equals(command.getExistingClientId())) {
throw new InvalidGuarantorException(
command.getExistingClientId(), loanId);
}
Client guarantor = clientRepository.findOne(command
.getExistingClientId());
if (guarantor == null) {
throw new ClientNotFoundException(command.getExistingClientId());
}
loan.setGuarantor(guarantor);
this.loanRepository.saveAndFlush(loan);
// also delete any existing External Guarantors
readWriteNonCoreDataService.deleteDatatableEntries(
EXTERNAL_GUARANTOR_TABLE_NAME, loanId);
}// or create an external guarantor
else {
Set<String> modifiedParameters = command.getModifiedParameters();
Map<String, String> modifiedParametersMap = new HashMap<String, String>();
/***
* TODO Vishwas: Check with JW/KW if using reflection here is a good
* idea
**/
Class<? extends GuarantorCommand> guarantorCommandClass = command
.getClass();
for (String modifiedParameter : modifiedParameters) {
Method method;
try {
if (modifiedParameter.equalsIgnoreCase("externalGuarantor")
|| modifiedParameter
.equalsIgnoreCase("existingClientId")) {
continue;
} else {
method = guarantorCommandClass.getMethod("get"
+ StringUtils.capitalize(modifiedParameter));
}
String columnName = StringUtils.join(StringUtils
.splitByCharacterTypeCamelCase(modifiedParameter),
'_');
modifiedParametersMap.put(columnName.toLowerCase(), method
.invoke(command).toString());
} catch (Exception e) {
// TODO: This block would ideally never be reached, could
// use an
// empty catch block instead?
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError apiParameterError = ApiParameterError
.parameterError(
"validation.msg.validation.errors.exist",
"", modifiedParameter);
dataValidationErrors.add(apiParameterError);
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Invalid parameter passed for Creating updating Guarantor",
dataValidationErrors);
}
}
/*** update or create a new external Guarantor entry ***/
modifiedParametersMap.put("locale", command.getLocale());
modifiedParametersMap.put("dateFormat", command.getDateFormat());
if (guarantorReadPlatformService.getExternalGuarantor(loanId) != null) {
readWriteNonCoreDataService.updateDatatableEntryOnetoOne(
EXTERNAL_GUARANTOR_TABLE_NAME, loanId,
modifiedParametersMap);
} else {
readWriteNonCoreDataService.newDatatableEntry(
EXTERNAL_GUARANTOR_TABLE_NAME, loanId,
modifiedParametersMap);
}
// finally unset any existing internal guarantors
if (loan.getGuarantor() != null) {
loan.setGuarantor(null);
this.loanRepository.saveAndFlush(loan);
}
}
}
/**
* @param loanId
* @return
*/
private Loan validateLoanExists(Long loanId) {
Loan loan = loanRepository.findOne(loanId);
if (loan == null) {
throw new LoanNotFoundException(loanId);
}
return loan;
}
}
@@ -50,6 +50,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
@ManyToOne(optional = true)
@JoinColumn(name = "client_id")
private Client client;
@ManyToOne(optional = true)
@JoinColumn(name = "guarantor_id")
private Client guarantor;
@SuppressWarnings("unused")
@ManyToOne(optional = true)
@@ -1629,4 +1633,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
return latestRecordWithNoEndDate;
}
public Client getGuarantor() {
return guarantor;
}
public void setGuarantor(Client guarantor) {
this.guarantor = guarantor;
}
public Client getClient() {
return client;
}
}
@@ -20,7 +20,7 @@ public interface LoanReadPlatformService {
LoanPermissionData retrieveLoanPermissions(
LoanBasicDetailsData loanBasicDetails, boolean isWaiverAllowed,
int repaymentAndWaiveCount);
int repaymentAndWaiveCount, boolean existsGuarantor);
LoanBasicDetailsData retrieveClientAndProductDetails(Long clientId, Long productId);
@@ -197,7 +197,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public LoanPermissionData retrieveLoanPermissions(
final LoanBasicDetailsData loanBasicDetails,
final boolean isWaiverAllowed,
final int repaymentAndWaiveCount) {
final int repaymentAndWaiveCount,
final boolean existsGuarantor) {
final boolean pendingApproval = (loanBasicDetails.getStatus().getId().equals(100L));
final boolean waitingForDisbursal = (loanBasicDetails.getStatus().getId().equals(200L));
@@ -210,8 +211,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final boolean isOverpaid = (loanBasicDetails.getStatus().getId().equals(700L));
boolean addLoanChargeAllowed = true;
boolean setGuarantorAllowed = true;
boolean editGuarantorAllowed = true;
if (closed || isOverpaid) {
addLoanChargeAllowed = false;
setGuarantorAllowed = false;
editGuarantorAllowed = false;
}
if(existsGuarantor){
setGuarantorAllowed = false;
}else{
editGuarantorAllowed = false;
}
final boolean waiveAllowed = isWaiverAllowed && isActive;
@@ -234,6 +245,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
addLoanChargeAllowed, waiveAllowed, makeRepaymentAllowed,
rejectAllowed, withdrawnByApplicantAllowed,
undoApprovalAllowed, undoDisbursalAllowed, disbursalAllowed,
setGuarantorAllowed,editGuarantorAllowed,
pendingApproval, waitingForDisbursal, closedObligationsMet);
}