Collection sheet UI and bulk update

This commit is contained in:
ashok-conflux
2013-03-27 16:30:45 +05:30
parent 69d228a502
commit c77f3e15f1
20 changed files with 719 additions and 50 deletions
@@ -463,4 +463,9 @@ public class CommandWrapper {
public boolean isGroupResource() { public boolean isGroupResource() {
return this.entityName.equalsIgnoreCase("GROUP"); return this.entityName.equalsIgnoreCase("GROUP");
} }
public boolean isCollectionSheetResource(){
return this.entityName.equals("COLLECTIONSHEET");
}
} }
@@ -827,4 +827,12 @@ public class CommandWrapperBuilder {
this.href = "/loans/" + loanId + "/collaterals/" + collateralId; this.href = "/loans/" + loanId + "/collaterals/" + collateralId;
return this; return this;
} }
public CommandWrapperBuilder updateCollectionSheet(final Long groupId) {
this.actionName = "UPDATE";
this.entityName = "COLLECTIONSHEET";
this.entityId = groupId;
this.href = "/groups/" + groupId + "/collectionsheet";
return this;
}
} }
@@ -394,6 +394,14 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
throw new UnsupportedCommandException(wrapper.commandName()); throw new UnsupportedCommandException(wrapper.commandName());
} }
} else if (wrapper.isCollectionSheetResource()) {
if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateCollectionSheetCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else { } else {
throw new UnsupportedCommandException(wrapper.commandName()); throw new UnsupportedCommandException(wrapper.commandName());
} }
@@ -6,6 +6,7 @@ import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST;
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;
@@ -15,7 +16,11 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.core.service.DateUtils;
@@ -37,7 +42,7 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class CollectionSheetApiResource { public class CollectionSheetApiResource {
private final Set<String> COLLECTIONSHEET_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("dueDate", "groups")); private final Set<String> COLLECTIONSHEET_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("dueDate", "loanProducts", "groups"));
/* /*
* dueDate format is ISO 8601 Calendar Date (YYYYMMDD) * dueDate format is ISO 8601 Calendar Date (YYYYMMDD)
*/ */
@@ -46,17 +51,18 @@ public class CollectionSheetApiResource {
private final CollectionSheetReadPlatformService collectionSheetReadPlatformService; private final CollectionSheetReadPlatformService collectionSheetReadPlatformService;
private final ToApiJsonSerializer<JLGCollectionSheetData> toApiJsonSerializer; private final ToApiJsonSerializer<JLGCollectionSheetData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper; private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired @Autowired
public CollectionSheetApiResource(final PlatformSecurityContext context, public CollectionSheetApiResource(final PlatformSecurityContext context,
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final CollectionSheetReadPlatformService collectionSheetReadPlatformService,
final ToApiJsonSerializer<JLGCollectionSheetData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper) { final ToApiJsonSerializer<JLGCollectionSheetData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context; this.context = context;
this.collectionSheetReadPlatformService = collectionSheetReadPlatformService; this.collectionSheetReadPlatformService = collectionSheetReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper; this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
} }
@GET @GET
@@ -72,4 +78,16 @@ public class CollectionSheetApiResource {
return this.toApiJsonSerializer.serialize(settings, collectionSheet, this.COLLECTIONSHEET_DATA_PARAMETERS); return this.toApiJsonSerializer.serialize(settings, collectionSheet, this.COLLECTIONSHEET_DATA_PARAMETERS);
} }
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateCalendar(@PathParam("groupId") final Long groupId, final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCollectionSheet(groupId).withJson(jsonRequestBody).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
} }
@@ -0,0 +1,38 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.command;
import org.joda.time.LocalDate;
/**
* Immutable command for loan bulk disburse.
*/
public class CollectionSheetBulkDisbursalCommand {
private final String note;
private final LocalDate transactionDate;
private final SingleDisbursalCommand[] disburseTransactions;
public CollectionSheetBulkDisbursalCommand(String note, final LocalDate transactionDate, SingleDisbursalCommand[] disburseTransactions) {
this.note = note;
this.transactionDate = transactionDate;
this.disburseTransactions = disburseTransactions;
}
public String getNote() {
return this.note;
}
public SingleDisbursalCommand[] getDisburseTransactions() {
return this.disburseTransactions;
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
}
@@ -0,0 +1,39 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.command;
import org.joda.time.LocalDate;
/**
* Immutable command for loan bulk repayment.
*/
public class CollectionSheetBulkRepaymentCommand {
private final String note;
private final LocalDate transactionDate;
private final SingleRepaymentCommand[] repaymentTransactions;
public CollectionSheetBulkRepaymentCommand(String note, final LocalDate transactionDate, SingleRepaymentCommand[] repaymentTransactions) {
this.note = note;
this.transactionDate = transactionDate;
this.repaymentTransactions = repaymentTransactions;
}
public String getNote() {
return this.note;
}
public SingleRepaymentCommand[] getLoanTransactions() {
return this.repaymentTransactions;
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
}
@@ -0,0 +1,39 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.command;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
/**
* Immutable command for Single loan repayment.
*/
public class SingleDisbursalCommand {
private final Long loanId;
private final BigDecimal transactionAmount;
private final LocalDate transactionDate;
public SingleDisbursalCommand(Long loanId, BigDecimal transactionAmount, LocalDate transactionDate) {
this.loanId = loanId;
this.transactionAmount = transactionAmount;
this.transactionDate = transactionDate;
}
public Long getLoanId() {
return this.loanId;
}
public BigDecimal getTransactionAmount() {
return this.transactionAmount;
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
}
@@ -0,0 +1,39 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.command;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
/**
* Immutable command for Single loan repayment.
*/
public class SingleRepaymentCommand {
private final Long loanId;
private final BigDecimal transactionAmount;
private final LocalDate transactionDate;
public SingleRepaymentCommand(Long loanId, BigDecimal transactionAmount, LocalDate transactionDate) {
this.loanId = loanId;
this.transactionAmount = transactionAmount;
this.transactionDate = transactionDate;
}
public Long getLoanId() {
return this.loanId;
}
public BigDecimal getTransactionAmount() {
return this.transactionAmount;
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
}
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.collectionsheet.data;
import java.util.Collection; import java.util.Collection;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
/** /**
* Immutable data object for join liability group's collection sheet. * Immutable data object for join liability group's collection sheet.
@@ -15,10 +16,12 @@ import org.joda.time.LocalDate;
public class JLGCollectionSheetData { public class JLGCollectionSheetData {
private final LocalDate dueDate; private final LocalDate dueDate;
private final Collection<LoanProductData> loanProducts;
private final Collection<JLGClientsData> groups; private final Collection<JLGClientsData> groups;
public JLGCollectionSheetData(final LocalDate date, final Collection<JLGClientsData> groups) { public JLGCollectionSheetData(final LocalDate date, final Collection<LoanProductData> loanProducts, final Collection<JLGClientsData> groups) {
this.dueDate = date; this.dueDate = date;
this.loanProducts = loanProducts;
this.groups = groups; this.groups = groups;
} }
@@ -30,4 +33,7 @@ public class JLGCollectionSheetData {
return this.groups; return this.groups;
} }
public Collection<LoanProductData> getLoanProducts() {
return this.loanProducts;
}
} }
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.collectionsheet.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/** /**
* Immutable data object for extracting flat data for joint liability group's collection sheet. * Immutable data object for extracting flat data for joint liability group's collection sheet.
*/ */
@@ -25,8 +27,7 @@ public class JLGCollectionSheetFlatData {
private final Integer accountStatusId; private final Integer accountStatusId;
private final String productShortName; private final String productShortName;
private final Long productId; private final Long productId;
private final String currencyCode; private final CurrencyData currency;
private final Integer currencyDigits;
private BigDecimal disbursementAmount = BigDecimal.ZERO; private BigDecimal disbursementAmount = BigDecimal.ZERO;
private BigDecimal principalDue = BigDecimal.ZERO; private BigDecimal principalDue = BigDecimal.ZERO;
private BigDecimal principalPaid = BigDecimal.ZERO; private BigDecimal principalPaid = BigDecimal.ZERO;
@@ -37,7 +38,7 @@ public class JLGCollectionSheetFlatData {
public JLGCollectionSheetFlatData(final String groupName, final Long groupId, final Long staffId, final String staffName, public JLGCollectionSheetFlatData(final String groupName, final Long groupId, final Long staffId, final String staffName,
final Long levelId, final String levelName, final String clientName, final Long clientId, final Long loanId, final Long levelId, final String levelName, final String clientName, final Long clientId, final Long loanId,
final String accountId, final Integer accountStatusId, final String productShortName, final Long productId, final String accountId, final Integer accountStatusId, final String productShortName, final Long productId,
final String currencyCode, final Integer currencyDigits, final BigDecimal disbursementAmount, final BigDecimal principalDue, final CurrencyData currency, final BigDecimal disbursementAmount, final BigDecimal principalDue,
final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue) { final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue) {
this.groupName = groupName; this.groupName = groupName;
this.groupId = groupId; this.groupId = groupId;
@@ -52,8 +53,7 @@ public class JLGCollectionSheetFlatData {
this.accountStatusId = accountStatusId; this.accountStatusId = accountStatusId;
this.productShortName = productShortName; this.productShortName = productShortName;
this.productId = productId; this.productId = productId;
this.currencyCode = currencyCode; this.currency = currency;
this.currencyDigits = currencyDigits;
this.disbursementAmount = disbursementAmount; this.disbursementAmount = disbursementAmount;
this.principalDue = principalDue; this.principalDue = principalDue;
this.principalPaid = principalPaid; this.principalPaid = principalPaid;
@@ -114,12 +114,8 @@ public class JLGCollectionSheetFlatData {
return this.productId; return this.productId;
} }
public String getCurrencyCode() { public CurrencyData getCurrency() {
return this.currencyCode; return this.currency;
}
public Integer getCurrencyDigits() {
return this.currencyDigits;
} }
public BigDecimal getDisbursementAmount() { public BigDecimal getDisbursementAmount() {
@@ -147,9 +143,8 @@ public class JLGCollectionSheetFlatData {
} }
public LoanDueData getLoanDueData() { public LoanDueData getLoanDueData() {
return new LoanDueData(this.loanId, this.accountId, this.accountStatusId, this.productShortName, this.productId, this.currencyCode, return new LoanDueData(this.loanId, this.accountId, this.accountStatusId, this.productShortName, this.productId, this.currency,
this.currencyDigits, this.disbursementAmount, this.principalDue, this.principalPaid, this.interestDue, this.interestPaid, this.disbursementAmount, this.principalDue, this.principalPaid, this.interestDue, this.interestPaid, this.chargesDue);
this.chargesDue);
} }
public ClientLoansData getClientLoansData() { public ClientLoansData getClientLoansData() {
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.collectionsheet.data;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/** /**
* Immutable data object for representing loan with dues (example: loan is due for disbursement, repayments). * Immutable data object for representing loan with dues (example: loan is due for disbursement, repayments).
*/ */
@@ -17,17 +19,17 @@ public class LoanDueData {
private final Integer accountStatusId; private final Integer accountStatusId;
private final String productShortName; private final String productShortName;
private final Long productId; private final Long productId;
private final String currencyCode; private final CurrencyData currency;
private final Integer currencyDigits;
private BigDecimal disbursementAmount = BigDecimal.ZERO; private BigDecimal disbursementAmount = BigDecimal.ZERO;
private BigDecimal principalDue = BigDecimal.ZERO; private BigDecimal principalDue = BigDecimal.ZERO;
private BigDecimal principalPaid = BigDecimal.ZERO; private BigDecimal principalPaid = BigDecimal.ZERO;
private BigDecimal interestDue = BigDecimal.ZERO; private BigDecimal interestDue = BigDecimal.ZERO;
private BigDecimal interestPaid = BigDecimal.ZERO; private BigDecimal interestPaid = BigDecimal.ZERO;
private BigDecimal chargesDue = BigDecimal.ZERO; private BigDecimal chargesDue = BigDecimal.ZERO;
private BigDecimal totalDue = BigDecimal.ZERO;
public LoanDueData(final Long loanId, final String accountId, final Integer accountStatusId, final String productShortName, public LoanDueData(final Long loanId, final String accountId, final Integer accountStatusId, final String productShortName,
final Long productId, final String currencyCode, final Integer currencyDigits, final BigDecimal disbursementAmount, final Long productId, final CurrencyData currency, final BigDecimal disbursementAmount,
final BigDecimal principalDue, final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal principalDue, final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid,
final BigDecimal chargesDue) { final BigDecimal chargesDue) {
this.loanId = loanId; this.loanId = loanId;
@@ -35,14 +37,14 @@ public class LoanDueData {
this.accountStatusId = accountStatusId; this.accountStatusId = accountStatusId;
this.productShortName = productShortName; this.productShortName = productShortName;
this.productId = productId; this.productId = productId;
this.currencyCode = currencyCode; this.currency = currency;
this.currencyDigits = currencyDigits;
this.disbursementAmount = disbursementAmount; this.disbursementAmount = disbursementAmount;
this.principalDue = principalDue; this.principalDue = principalDue;
this.principalPaid = principalPaid; this.principalPaid = principalPaid;
this.interestDue = interestDue; this.interestDue = interestDue;
this.interestPaid = interestPaid; this.interestPaid = interestPaid;
this.chargesDue = chargesDue; this.chargesDue = chargesDue;
this.totalDue = this.totalDue.add(principalDue).add(interestDue);
} }
public Long getLoanId() { public Long getLoanId() {
@@ -65,12 +67,8 @@ public class LoanDueData {
return this.productId; return this.productId;
} }
public String getCurrencyCode() { public CurrencyData getCurrency() {
return this.currencyCode; return this.currency;
}
public Integer getCurrencyDigits() {
return this.currencyDigits;
} }
public BigDecimal getDisbursementAmount() { public BigDecimal getDisbursementAmount() {
@@ -0,0 +1,28 @@
package org.mifosplatform.portfolio.collectionsheet.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.collectionsheet.service.CollectionSheetWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateCollectionSheetCommandHandler implements NewCommandSourceHandler {
private final CollectionSheetWritePlatformService collectionSheetWritePlatformService;
@Autowired
public UpdateCollectionSheetCommandHandler(final CollectionSheetWritePlatformService collectionSheetWritePlatformService) {
this.collectionSheetWritePlatformService = collectionSheetWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.collectionSheetWritePlatformService.updateCollectionSheet(command);
}
}
@@ -0,0 +1,118 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for
* {@link CollectionSheetBulkDisbursalCommand}'s.
*/
@Component
public final class CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<CollectionSheetBulkDisbursalCommand> {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer(FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public CollectionSheetBulkDisbursalCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
//TODO: AA need to refactor transactionDate and actualDisbursementDate
//actualDisbursementDate used in Loan.disburse()
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("transactionDate", "actualDisbursementDate", "bulkRepaymentTransactions", "bulkDisbursementTransactions", "note",
"locale", "dateFormat"));
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element);
final String note = fromApiJsonHelper.extractStringNamed("note", element);
final JsonObject topLevelJsonElement = element.getAsJsonObject();
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
SingleDisbursalCommand[] loanDisbursementTransactions = null;
if (element.isJsonObject()) {
if (topLevelJsonElement.has("bulkDisbursementTransactions")
&& topLevelJsonElement.get("bulkDisbursementTransactions").isJsonArray()) {
final JsonArray array = topLevelJsonElement.get("bulkDisbursementTransactions").getAsJsonArray();
loanDisbursementTransactions = new SingleDisbursalCommand[array.size()];
for (int i = 0; i < array.size(); i++) {
final JsonObject loanTransactionElement = array.get(i).getAsJsonObject();
final Long loanId = this.fromApiJsonHelper.extractLongNamed("loanId", loanTransactionElement);
final BigDecimal disbursementAmount = this.fromApiJsonHelper.extractBigDecimalNamed("transactionAmount", loanTransactionElement, locale);
loanDisbursementTransactions[i] = new SingleDisbursalCommand(loanId, disbursementAmount, transactionDate);
}
}
}
return new CollectionSheetBulkDisbursalCommand(note, transactionDate, loanDisbursementTransactions);
}
public void validateBulkDisbursalTransaction(final CollectionSheetBulkDisbursalCommand bulkDisburseCommand) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.bulk.disbursement.transaction");
baseDataValidator.reset().parameter("transactionDate").value(bulkDisburseCommand.getTransactionDate()).notNull();
if (StringUtils.isNotBlank(bulkDisburseCommand.getNote())) {
baseDataValidator.reset().parameter("note").value(bulkDisburseCommand.getNote()).notExceedingLengthOf(1000);
}
final SingleDisbursalCommand[] loanDisbursements = bulkDisburseCommand.getDisburseTransactions();
if (loanDisbursements != null) {
for (int i = 0; i < loanDisbursements.length; i++) {
SingleDisbursalCommand singleLoanDisburseCommand = loanDisbursements[i];
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id").value(singleLoanDisburseCommand.getLoanId())
.notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].disbursement.amount")
.value(singleLoanDisburseCommand.getTransactionAmount()).notNull().zeroOrPositiveAmount();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -0,0 +1,116 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for
* {@link CollectionSheetBulkRepaymentCommand}'s.
*/
@Component
public final class CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<CollectionSheetBulkRepaymentCommand> {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer(FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public CollectionSheetBulkRepaymentCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("transactionDate", "actualDisbursementDate", "bulkRepaymentTransactions", "bulkDisbursementTransactions", "note",
"locale", "dateFormat"));
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element);
final String note = fromApiJsonHelper.extractStringNamed("note", element);
final JsonObject topLevelJsonElement = element.getAsJsonObject();
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
SingleRepaymentCommand[] loanRepaymentTransactions = null;
if (element.isJsonObject()) {
if (topLevelJsonElement.has("bulkRepaymentTransactions")
&& topLevelJsonElement.get("bulkRepaymentTransactions").isJsonArray()) {
final JsonArray array = topLevelJsonElement.get("bulkRepaymentTransactions").getAsJsonArray();
loanRepaymentTransactions = new SingleRepaymentCommand[array.size()];
for (int i = 0; i < array.size(); i++) {
final JsonObject loanTransactionElement = array.get(i).getAsJsonObject();
final Long loanId = this.fromApiJsonHelper.extractLongNamed("loanId", loanTransactionElement);
final BigDecimal transactionAmount = this.fromApiJsonHelper.extractBigDecimalNamed("transactionAmount", loanTransactionElement, locale);
loanRepaymentTransactions[i] = new SingleRepaymentCommand(loanId, transactionAmount, transactionDate);
}
}
}
return new CollectionSheetBulkRepaymentCommand(note, transactionDate, loanRepaymentTransactions);
}
public void validateBulkRepaymentTransaction(final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.bulk.repayment.transaction");
baseDataValidator.reset().parameter("transactionDate").value(bulkRepaymentCommand.getTransactionDate()).notNull();
if (StringUtils.isNotBlank(bulkRepaymentCommand.getNote())) {
baseDataValidator.reset().parameter("note").value(bulkRepaymentCommand.getNote()).notExceedingLengthOf(1000);
}
final SingleRepaymentCommand[] loanRepayments = bulkRepaymentCommand.getLoanTransactions();
if (loanRepayments != null) {
for (int i = 0; i < loanRepayments.length; i++) {
SingleRepaymentCommand singleLoanRepaymentCommand = loanRepayments[i];
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id")
.value(singleLoanRepaymentCommand.getLoanId()).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].transaction.amount")
.value(singleLoanRepaymentCommand.getTransactionAmount()).notNull().zeroOrPositiveAmount();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -5,12 +5,15 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.collectionsheet.data.ClientLoansData; import org.mifosplatform.portfolio.collectionsheet.data.ClientLoansData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGClientsData; import org.mifosplatform.portfolio.collectionsheet.data.JLGClientsData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData; import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
@@ -19,6 +22,7 @@ import org.mifosplatform.portfolio.collectionsheet.data.LoanDueData;
import org.mifosplatform.portfolio.group.data.GroupData; import org.mifosplatform.portfolio.group.data.GroupData;
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException; import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformServiceImpl; import org.mifosplatform.portfolio.group.service.GroupReadPlatformServiceImpl;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
@@ -88,11 +92,12 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
JLGCollectionSheetData jlgCollectionSheetData = null; JLGCollectionSheetData jlgCollectionSheetData = null;
JLGCollectionSheetFlatData prevCollectioSheetFlatData = null; JLGCollectionSheetFlatData prevCollectioSheetFlatData = null;
JLGCollectionSheetFlatData corrCollectioSheetFlatData = null; JLGCollectionSheetFlatData corrCollectioSheetFlatData = null;
Set<LoanProductData> loanProducts = new HashSet<LoanProductData>();
if (jlgCollectionSheetFlatData != null) { if (jlgCollectionSheetFlatData != null) {
for (final JLGCollectionSheetFlatData collectionSheetFlatData : jlgCollectionSheetFlatData) { for (final JLGCollectionSheetFlatData collectionSheetFlatData : jlgCollectionSheetFlatData) {
loanProducts.add(LoanProductData.lookupWithCurrency(collectionSheetFlatData.getProductId(), collectionSheetFlatData.getProductShortName(), collectionSheetFlatData.getCurrency()));
corrCollectioSheetFlatData = collectionSheetFlatData; corrCollectioSheetFlatData = collectionSheetFlatData;
if (firstTime || collectionSheetFlatData.getGroupId().equals(prevGroupId)) { if (firstTime || collectionSheetFlatData.getGroupId().equals(prevGroupId)) {
@@ -149,7 +154,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
jlgClientsDatas.add(jlgClientsData); jlgClientsDatas.add(jlgClientsData);
jlgCollectionSheetData = new JLGCollectionSheetData(dueDate, jlgClientsDatas); jlgCollectionSheetData = new JLGCollectionSheetData(dueDate, loanProducts, jlgClientsDatas);
} }
return jlgCollectionSheetData; return jlgCollectionSheetData;
@@ -184,12 +189,11 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
+ "ln.loan_status_id As accountStatusId, " + "ln.loan_status_id As accountStatusId, "
+ "pl.name As productShortName, " + "pl.name As productShortName, "
+ "ln.product_id As productId, " + "ln.product_id As productId, "
+ "ln.currency_code As currencyCode, " + "ln.currency_code as currencyCode, ln.currency_digits as currencyDigits, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
+ "ln.currency_digits As currencyDigits, "
+ "if(ln.loan_status_id = 200 , ln.principal_amount , null) As disbursementAmount, " + "if(ln.loan_status_id = 200 , ln.principal_amount , null) As disbursementAmount, "
+ "sum(ls.principal_amount - ls.principal_completed_derived) As principalDue, " + "sum(ifnull(ls.principal_amount, 0.0) - ifnull(ls.principal_completed_derived, 0.0)) As principalDue, "
+ "ln.principal_repaid_derived As principalPaid, " + "ln.principal_repaid_derived As principalPaid, "
+ "sum(ls.interest_amount - ls.interest_completed_derived) As interestDue, " + "sum(ifnull(ls.interest_amount, 0.0) - ifnull(ls.interest_completed_derived, 0.0)) As interestDue, "
+ "ln.interest_repaid_derived As interestPaid, " + "ln.interest_repaid_derived As interestPaid, "
+ "sum(lc.amount_outstanding_derived) as chargesDue " + "sum(lc.amount_outstanding_derived) as chargesDue "
+ "FROM m_group gp " + "FROM m_group gp "
@@ -200,6 +204,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
+ "JOIN m_client cl ON cl.id = gc.client_id " + "JOIN m_client cl ON cl.id = gc.client_id "
+ "LEFT JOIN m_loan ln ON cl.id = ln.client_id AND ln.group_id is not null AND ( ln.loan_status_id = 300 OR ( ln.loan_status_id =200 AND ln.expected_disbursedon_date <= :dueDate )) " + "LEFT JOIN m_loan ln ON cl.id = ln.client_id AND ln.group_id is not null AND ( ln.loan_status_id = 300 OR ( ln.loan_status_id =200 AND ln.expected_disbursedon_date <= :dueDate )) "
+ "LEFT JOIN m_product_loan pl ON pl.id = ln.product_id " + "LEFT JOIN m_product_loan pl ON pl.id = ln.product_id "
+ "JOIN m_currency rc on rc.`code` = ln.currency_code "
+ "LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate " + "LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate "
+ "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) " + "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) "
+ "WHERE gp.hierarchy like :hierarchy " + "GROUP BY gp.id ,cl.id , ln.id " + "ORDER BY gp.id , cl.id , ln.id "; + "WHERE gp.hierarchy like :hierarchy " + "GROUP BY gp.id ,cl.id , ln.id " + "ORDER BY gp.id , cl.id , ln.id ";
@@ -221,8 +226,15 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final Integer accountStatusId = JdbcSupport.getInteger(rs, "accountStatusId"); final Integer accountStatusId = JdbcSupport.getInteger(rs, "accountStatusId");
final String productShortName = rs.getString("productShortName"); final String productShortName = rs.getString("productShortName");
final Long productId = JdbcSupport.getLong(rs, "productId"); final Long productId = JdbcSupport.getLong(rs, "productId");
final String currencyCode = rs.getString("currencyCode"); final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode);
final BigDecimal disbursementAmount = rs.getBigDecimal("disbursementAmount"); final BigDecimal disbursementAmount = rs.getBigDecimal("disbursementAmount");
final BigDecimal principalDue = rs.getBigDecimal("principalDue"); final BigDecimal principalDue = rs.getBigDecimal("principalDue");
final BigDecimal principalPaid = rs.getBigDecimal("principalPaid"); final BigDecimal principalPaid = rs.getBigDecimal("principalPaid");
@@ -231,7 +243,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
final BigDecimal chargesDue = rs.getBigDecimal("chargesDue"); final BigDecimal chargesDue = rs.getBigDecimal("chargesDue");
return new JLGCollectionSheetFlatData(groupName, groupId, staffId, staffName, levelId, levelName, clientName, clientId, loanId, return new JLGCollectionSheetFlatData(groupName, groupId, staffId, staffName, levelId, levelName, clientName, clientId, loanId,
accountId, accountStatusId, productShortName, productId, currencyCode, currencyDigits, disbursementAmount, accountId, accountStatusId, productShortName, productId, currencyData, disbursementAmount,
principalDue, principalPaid, interestDue, interestPaid, chargesDue); principalDue, principalPaid, interestDue, interestPaid, chargesDue);
} }
@@ -0,0 +1,9 @@
package org.mifosplatform.portfolio.collectionsheet.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface CollectionSheetWritePlatformService {
CommandProcessingResult updateCollectionSheet(JsonCommand command);
}
@@ -0,0 +1,79 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collectionsheet.service;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements CollectionSheetWritePlatformService {
private final LoanWritePlatformService loanWritePlatformService;
private final CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer bulkRepaymentCommandFromApiJsonDeserializer;
private final CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer;
@Autowired
public CollectionSheetWritePlatformServiceJpaRepositoryImpl(LoanWritePlatformService loanWritePlatformService,
CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer bulkRepaymentCommandFromApiJsonDeserializer,
CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer) {
this.loanWritePlatformService = loanWritePlatformService;
this.bulkRepaymentCommandFromApiJsonDeserializer = bulkRepaymentCommandFromApiJsonDeserializer;
this.bulkDisbursalCommandFromApiJsonDeserializer = bulkDisbursalCommandFromApiJsonDeserializer;
}
@Override
public CommandProcessingResult updateCollectionSheet(JsonCommand command) {
Map<String, Object> changes = new HashMap<String, Object>();
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
}
changes.putAll(updateBulkReapayments(command));
changes.putAll(updateBulkDisbursals(command));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(command.entityId()) //
.withGroupId(command.entityId()) //
.with(changes)
.with(changes).build();
}
private Map<String, Object> updateBulkReapayments(JsonCommand command) {
Map<String, Object> changes = new HashMap<String, Object>();
final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand = this.bulkRepaymentCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
this.bulkRepaymentCommandFromApiJsonDeserializer.validateBulkRepaymentTransaction(bulkRepaymentCommand);
changes.putAll(this.loanWritePlatformService.makeLoanBulkRepayment(bulkRepaymentCommand));
return changes;
}
private Map<String, Object> updateBulkDisbursals(JsonCommand command) {
Map<String, Object> changes = new HashMap<String, Object>();
final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand = this.bulkDisbursalCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
this.bulkDisbursalCommandFromApiJsonDeserializer.validateBulkDisbursalTransaction(bulkDisbursalCommand);
changes.putAll(this.loanWritePlatformService.bulkLoanDisbursal(command, bulkDisbursalCommand));
return changes;
}
}
@@ -5,17 +5,25 @@
*/ */
package org.mifosplatform.portfolio.loanaccount.service; package org.mifosplatform.portfolio.loanaccount.service;
import java.util.Map;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
public interface LoanWritePlatformService { public interface LoanWritePlatformService {
CommandProcessingResult disburseLoan(Long loanId, JsonCommand command); CommandProcessingResult disburseLoan(Long loanId, JsonCommand command);
Map<String, Object> bulkLoanDisbursal(JsonCommand command, CollectionSheetBulkDisbursalCommand bulkDisbursalCommand);
CommandProcessingResult undoLoanDisbursal(Long loanId, JsonCommand command); CommandProcessingResult undoLoanDisbursal(Long loanId, JsonCommand command);
CommandProcessingResult makeLoanRepayment(Long loanId, JsonCommand command); CommandProcessingResult makeLoanRepayment(Long loanId, JsonCommand command);
Map<String, Object> makeLoanBulkRepayment(CollectionSheetBulkRepaymentCommand bulkRepaymentCommand);
CommandProcessingResult adjustLoanTransaction(Long loanId, Long transactionId, JsonCommand command); CommandProcessingResult adjustLoanTransaction(Long loanId, Long transactionId, JsonCommand command);
CommandProcessingResult waiveInterestOnLoan(Long loanId, JsonCommand command); CommandProcessingResult waiveInterestOnLoan(Long loanId, JsonCommand command);
@@ -32,6 +32,10 @@ import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedExc
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException; import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON; import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException; import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleDisbursalCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand; import org.mifosplatform.portfolio.loanaccount.command.LoanUpdateCommand;
import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail; import org.mifosplatform.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
@@ -144,6 +148,44 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.build(); .build();
} }
@Transactional
@Override
public Map<String, Object> bulkLoanDisbursal(JsonCommand command, CollectionSheetBulkDisbursalCommand bulkDisbursalCommand) {
final AppUser currentUser = context.authenticatedUser();
SingleDisbursalCommand[] disbursalCommand = bulkDisbursalCommand.getDisburseTransactions();
Map<String, Object> changes = new LinkedHashMap<String, Object>();
if(disbursalCommand == null){
return changes;
}
for (int i = 0; i < disbursalCommand.length; i++) {
SingleDisbursalCommand singleLoanDisbursalCommand = disbursalCommand[i];
final Loan loan = retrieveLoanBy(singleLoanDisbursalCommand.getLoanId());
final ApplicationCurrency currency = this.applicationCurrencyRepository.findOneByCode(loan.getCurrencyCode());
final List<Long> existingTransactionIds = new ArrayList<Long>();
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
changes.putAll(loan.disburse(currentUser, command, currency, existingTransactionIds,
existingReversedTransactionIds));
if (!changes.isEmpty()) {
this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.loanNote(loan, noteText);
this.noteRepository.save(note);
}
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
}
return changes;
}
@Transactional @Transactional
@Override @Override
public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) { public CommandProcessingResult undoLoanDisbursal(final Long loanId, final JsonCommand command) {
@@ -204,6 +246,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
}
CommandProcessingResultBuilder commandProcessingResultBuilder = saveLoanRepayment(loanId, transactionAmount, transactionDate, noteText);
return commandProcessingResultBuilder
.withCommandId(command.commandId()) //
.withLoanId(loanId) //
.with(changes) //
.build();
}
private CommandProcessingResultBuilder saveLoanRepayment(final Long loanId, final BigDecimal transactionAmount,
final LocalDate transactionDate, final String noteText) {
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final List<Long> existingTransactionIds = new ArrayList<Long>(); final List<Long> existingTransactionIds = new ArrayList<Long>();
@@ -230,9 +288,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
this.loanRepository.save(loan); this.loanRepository.save(loan);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) { if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText); Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
@@ -240,14 +297,27 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withEntityId(newRepaymentTransaction.getId()) //
.withEntityId(newRepaymentTransaction.getId()) // .withOfficeId(loan.getOfficeId()) //
.withOfficeId(loan.getOfficeId()) // .withClientId(loan.getClientId()) //
.withClientId(loan.getClientId()) // .withGroupId(loan.getGroupId()); //
.withGroupId(loan.getGroupId()) // }
.withLoanId(loanId) //
.with(changes) // @Transactional
.build(); @Override
public Map<String, Object> makeLoanBulkRepayment(final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand) {
context.authenticatedUser();
final SingleRepaymentCommand[] repaymentCommand = bulkRepaymentCommand.getLoanTransactions();
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
if(repaymentCommand == null) return changes;
for (SingleRepaymentCommand singleLoanRepaymentCommand : repaymentCommand) {
saveLoanRepayment(singleLoanRepaymentCommand.getLoanId(), singleLoanRepaymentCommand.getTransactionAmount(), bulkRepaymentCommand.getTransactionDate(), bulkRepaymentCommand.getNote());
changes.put("bulkTransations", singleLoanRepaymentCommand);
}
return changes;
} }
@Transactional @Transactional
@@ -103,6 +103,32 @@ public class LoanProductData {
transactionProcessingStrategyName, charges, accountingType); transactionProcessingStrategyName, charges, accountingType);
} }
public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) {
final String description = null;
final BigDecimal principal = null;
final BigDecimal tolerance = null;
final Integer numberOfRepayments = null;
final Integer repaymentEvery = null;
final BigDecimal interestRatePerPeriod = null;
final BigDecimal annualInterestRate = null;
final EnumOptionData repaymentFrequencyType = null;
final EnumOptionData interestRateFrequencyType = null;
final EnumOptionData amortizationType = null;
final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null;
final Long fundId = null;
final String fundName = null;
final Long transactionProcessingStrategyId = null;
final String transactionProcessingStrategyName = null;
final Collection<ChargeData> charges = null;
final EnumOptionData accountingType = null;
return new LoanProductData(id, name, description, currency, principal, tolerance, numberOfRepayments, repaymentEvery,
interestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, amortizationType,
interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId,
transactionProcessingStrategyName, charges, accountingType);
}
public static LoanProductData sensibleDefaultsForNewLoanProductCreation() { public static LoanProductData sensibleDefaultsForNewLoanProductCreation() {
final Long id = null; final Long id = null;
final String name = null; final String name = null;
@@ -378,4 +404,14 @@ public class LoanProductData {
public Collection<ChargeData> getChargeOptions() { public Collection<ChargeData> getChargeOptions() {
return chargeOptions; return chargeOptions;
} }
@Override
public boolean equals(Object obj) {
LoanProductData loanProductData = (LoanProductData) obj;
return loanProductData.id.equals(this.id);
}
@Override
public int hashCode() {
return this.id.hashCode();
}
} }