MIFOSX-1742 : added collection sheet for individuals

This commit is contained in:
Pramod Nuthakki
2015-01-16 10:24:26 +05:30
parent bc38cf4ff9
commit 2bd1332da7
28 changed files with 1080 additions and 85 deletions
+155 -6
View File
@@ -1183,7 +1183,7 @@
</div>
<div class="flybar-nav">
<h2 class="flybar-button">Group</h2>
<h2 class="flybar-button">Group & Collection Sheet</h2>
<div id="toc-menu-loan" class="flybar-menu">
<div class="tocMatrix">
<table class=matrixHeading>
@@ -1437,6 +1437,24 @@
<td></td>
<td></td>
</tr>
<tr>
<td><a href="#centers">Collection Sheet</a></td>
<td>collectionsheet?command=generateCollectionSheet</td>
<td><a href="#generate_individual_collection_sheet">Generate Collection Sheet</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>collectionsheet?command=saveCollectionSheet</td>
<td><a href="#save_individual_collection_sheet">Save Collection Sheet</a></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
@@ -5334,6 +5352,99 @@ Request Body:
</div>
</div>
<a id="generate_individual_collection_sheet" name="generate_individual_collection_sheet" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Generate Individual Collection Sheet</h4>
<p>This Api retrieves repayment details of all individual loans under a office as on a specified meeting date.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/collectionsheet?command=generateCollectionSheet</code>
<code class="method-request">POST collectionsheet?command=generateCollectionSheet
Content-Type: application/json
Request Body:
{
"dateFormat":"dd MMMM yyyy",
"locale":"en",
"transactionDate":"15 January 2015",
"officeId":3
}
</code>
<code class="method-response">
{
"dueDate": [
2015,
1,
15
],
"clients": [
{
"clientId": 74,
"clientName": "guarantee test",
"loans": [
{
"loanId": 307,
"accountId": "000000307",
"accountStatusId": 300,
"productShortName": "pr",
"productId": 60,
"currency": {
"code": "USD",
"name": "US Dollar",
"decimalPlaces": 2,
"inMultiplesOf": 0,
"displaySymbol": "$",
"nameCode": "currency.USD",
"displayLabel": "US Dollar ($)"
},
"principalDue": 1126.23,
"principalPaid": 8873.77,
"interestDue": 0,
"interestPaid": 504.95,
"totalDue": 1126.23
}
],
"savings": [
{
"savingsId": 213,
"accountId": "000000213",
"accountStatusId": 300,
"productName": "11",
"productId": 30,
"currency": {
"code": "USD",
"name": "US Dollar",
"decimalPlaces": 2,
"inMultiplesOf": 0,
"displaySymbol": "$",
"nameCode": "currency.USD",
"displayLabel": "US Dollar ($)"
},
"dueAmount": 2000
}
]
}
],
"paymentTypeOptions": [
{
"id": 19,
"name": "receipt",
"position": 1,
"description": "rec"
},
{
"id": 20,
"name": "check",
"position": 2,
"description": "che"
}
]
}
</code>
</div>
</div>
<a id="centers_save_collectionsheet" name="centers_save_collectionsheet" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
@@ -5364,17 +5475,55 @@ Request Body:
"changes": {
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"bulkTransations": {
"loanId": 10,
"transactionAmount": 1221.36,
"transactionDate": [2014,5,4]
}
"loanTransactions": [10],
"SavingsTransactions": []
}
}
</code>
</div>
</div>
<a id="save_individual_collection_sheet" name="save_individual_collection_sheet" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Save Collection Sheet</h4>
<p>This Api allows the loan officer to perform bulk repayments of individual loans and deposit of mandatory savings on a given meeting date.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/collectionsheet?command=saveCollectionSheet</code>
<code class="method-request">POST collectionsheet?command=saveCollectionSheet
{
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"transactionDate": "04 May 2014",
"actualDisbursementDate": "04 May 2014",
"bulkDisbursementTransactions": [],
"bulkRepaymentTransactions": [{
"loanId": 10,
"transactionAmount": 1221.36,
"paymentTypeId":19,
"receiptNumber":"1245356"
}],
"bulkSavingsDueTransactions":[]
}
</code>
<code class="method-response">
{
"groupId": 10,
"resourceId": 10,
"changes": {
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"loanTransactions": [15],
"SavingsTransactions": []
}
}
</code>
</div>
</div>
<a id="centers_update" name="centers_update" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
+1 -1
View File
@@ -192,7 +192,7 @@ body {
.flybar-nav {
display: block;
float: left;
width: 90px;
min-width: 90px;
position: relative;
}
@@ -697,6 +697,11 @@ public class CommandWrapper {
public boolean isCollectionSheetResource() {
return this.entityName.equals("COLLECTIONSHEET");
}
public boolean isSaveIndividualCollectionSheet() {
return isCollectionSheetResource() && this.actionName.equalsIgnoreCase("SAVE");
}
public boolean isCenterResource() {
return this.entityName.equalsIgnoreCase("CENTER");
@@ -1425,6 +1425,13 @@ public class CommandWrapperBuilder {
this.href = "/groups/" + groupId + "?command=saveCollectionSheet";
return this;
}
public CommandWrapperBuilder saveIndividualCollectionSheet() {
this.actionName = "SAVE";
this.entityName = "COLLECTIONSHEET";
this.href = "/collectionsheet?command=saveCollectionSheet";
return this;
}
public CommandWrapperBuilder deleteGroup(final Long groupId) {
this.actionName = "DELETE";
@@ -280,15 +280,15 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else if (wrapper.isDelete()) {
handler = this.applicationContext.getBean("deleteTellerCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isAllocateCashier()) {
handler = this.applicationContext.getBean("allocateCashierToTellerCommandHandler", NewCommandSourceHandler.class);
handler = this.applicationContext.getBean("allocateCashierToTellerCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdateCashierAllocation()) {
handler = this.applicationContext.getBean("updateCashierAllocationCommandHandler", NewCommandSourceHandler.class);
handler = this.applicationContext.getBean("updateCashierAllocationCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDeleteCashierAllocation()) {
handler = this.applicationContext.getBean("deleteCashierAllocationCommandHandler", NewCommandSourceHandler.class);
handler = this.applicationContext.getBean("deleteCashierAllocationCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isAllocateCashToCashier()) {
handler = this.applicationContext.getBean("allocateCashToCashierCommandHandler", NewCommandSourceHandler.class);
handler = this.applicationContext.getBean("allocateCashToCashierCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSettleCashFromCashier()) {
handler = this.applicationContext.getBean("settleCashFromCashierCommandHandler", NewCommandSourceHandler.class);
handler = this.applicationContext.getBean("settleCashFromCashierCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -755,6 +755,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else if (wrapper.isCollectionSheetResource()) {
if (wrapper.isUpdate()) {
handler = this.applicationContext.getBean("updateCollectionSheetCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSaveIndividualCollectionSheet()) {
handler = this.applicationContext.getBean("saveIndividualCollectionSheetCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -9,6 +9,8 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
public class CollectionSheetConstants {
public static final String COLLECTIONSHEET_RESOURCE_NAME = "collectionsheet";
@@ -23,6 +25,8 @@ public class CollectionSheetConstants {
public static final String bulkSavingsDueTransactionsParamName = "bulkSavingsDueTransactions";
public static final String noteParamName = "note";
public static final String calendarIdParamName = "calendarId";
public static final String officeIdParamName = "officeId";
public static final String staffIdParamName = "staffId";
// attendance parameters
public static final String clientsAttendanceParamName = "clientsAttendance";
@@ -35,5 +39,16 @@ public class CollectionSheetConstants {
public static final Set<String> COLLECTIONSHEET_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, transactionDateParamName, actualDisbursementDateParamName, bulkRepaymentTransactionsParamName,
bulkDisbursementTransactionsParamName, noteParamName, calendarIdParamName, clientsAttendanceParamName, bulkSavingsDueTransactionsParamName));
bulkDisbursementTransactionsParamName, noteParamName, calendarIdParamName, clientsAttendanceParamName,
bulkSavingsDueTransactionsParamName, PaymentDetailConstants.paymentTypeParamName,
PaymentDetailConstants.accountNumberParamName, PaymentDetailConstants.checkNumberParamName,
PaymentDetailConstants.routingCodeParamName, PaymentDetailConstants.receiptNumberParamName,
PaymentDetailConstants.bankNumberParamName));
public static final Set<String> INDIVIDUAL_COLLECTIONSHEET_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
dateFormatParamName, transactionDateParamName, actualDisbursementDateParamName, bulkRepaymentTransactionsParamName,
bulkDisbursementTransactionsParamName, noteParamName, bulkSavingsDueTransactionsParamName));
public static final Set<String> INDIVIDUAL_COLLECTIONSHEET_SUPPORTED_PARAMS = new HashSet<>(Arrays.asList(transactionDateParamName,
localeParamName, dateFormatParamName, officeIdParamName, staffIdParamName));
}
@@ -0,0 +1,89 @@
/**
* 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.api;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
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.JsonQuery;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants;
import org.mifosplatform.portfolio.collectionsheet.data.IndividualCollectionSheetData;
import org.mifosplatform.portfolio.collectionsheet.service.CollectionSheetReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
@Path("/collectionsheet")
@Component
@Scope("singleton")
public class CollectionSheetApiResourse {
private final CollectionSheetReadPlatformService collectionSheetReadPlatformService;
private final ToApiJsonSerializer<Object> toApiJsonSerializer;
private final FromJsonHelper fromJsonHelper;
private final ApiRequestParameterHelper apiRequestPrameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final PlatformSecurityContext context;
@Autowired
public CollectionSheetApiResourse(final CollectionSheetReadPlatformService collectionSheetReadPlatformService,
final ToApiJsonSerializer<Object> toApiJsonSerializer, final FromJsonHelper fromJsonHelper,
final ApiRequestParameterHelper apiRequestPrameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final PlatformSecurityContext context) {
this.collectionSheetReadPlatformService = collectionSheetReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.fromJsonHelper = fromJsonHelper;
this.apiRequestPrameterHelper = apiRequestPrameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.context = context;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String generateCollectionSheet(@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson,
@Context final UriInfo uriInfo) {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "generateCollectionSheet")) {
this.context.authenticatedUser().validateHasReadPermission(CollectionSheetConstants.COLLECTIONSHEET_RESOURCE_NAME);
final JsonElement parsedQuery = this.fromJsonHelper.parse(apiRequestBodyAsJson);
final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, this.fromJsonHelper);
final IndividualCollectionSheetData collectionSheet = this.collectionSheetReadPlatformService
.generateIndividualCollectionSheet(query);
final ApiRequestJsonSerializationSettings settings = this.apiRequestPrameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, collectionSheet);
} else if (is(commandParam, "saveCollectionSheet")) {
final CommandWrapper commandRequest = builder.saveIndividualCollectionSheet().build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
return null;
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
}
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.collectionsheet.command;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
/**
* Immutable command for Single loan repayment.
@@ -17,11 +18,14 @@ public class SingleRepaymentCommand {
private final Long loanId;
private final BigDecimal transactionAmount;
private final LocalDate transactionDate;
private final PaymentDetail paymentDetail;
public SingleRepaymentCommand(final Long loanId, final BigDecimal transactionAmount, final LocalDate transactionDate) {
public SingleRepaymentCommand(final Long loanId, final BigDecimal transactionAmount, final LocalDate transactionDate,
final PaymentDetail paymentDetail) {
this.loanId = loanId;
this.transactionAmount = transactionAmount;
this.transactionDate = transactionDate;
this.paymentDetail = paymentDetail;
}
public Long getLoanId() {
@@ -36,4 +40,7 @@ public class SingleRepaymentCommand {
return this.transactionDate;
}
public PaymentDetail getPaymentDetail() {
return this.paymentDetail;
}
}
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.collectionsheet.data;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.COLLECTIONSHEET_REQUEST_DATA_PARAMETERS;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.COLLECTIONSHEET_RESOURCE_NAME;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.INDIVIDUAL_COLLECTIONSHEET_REQUEST_DATA_PARAMETERS;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.attendanceTypeParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.bulkDisbursementTransactionsParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.bulkRepaymentTransactionsParamName;
@@ -15,8 +16,8 @@ import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstan
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.clientIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.clientsAttendanceParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.loanIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.savingsIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.noteParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.savingsIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionAmountParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName;
@@ -35,6 +36,7 @@ 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.FromJsonHelper;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -82,7 +84,39 @@ public class CollectionSheetTransactionDataValidator {
validateDisbursementTransactions(element, baseDataValidator);
validateRepaymentTransactions(element, baseDataValidator);
validateSavingsDueTransactions(element, baseDataValidator);
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
validatePaymentDetails(baseDataValidator, element, locale);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateIndividualCollectionSheet(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, INDIVIDUAL_COLLECTIONSHEET_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(COLLECTIONSHEET_RESOURCE_NAME);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
final String note = this.fromApiJsonHelper.extractStringNamed(noteParamName, element);
if (StringUtils.isNotBlank(note)) {
baseDataValidator.reset().parameter(noteParamName).value(note).notExceedingLengthOf(1000);
}
validateDisbursementTransactions(element, baseDataValidator);
validateRepaymentTransactions(element, baseDataValidator);
validateSavingsDueTransactions(element, baseDataValidator);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -147,11 +181,13 @@ public class CollectionSheetTransactionDataValidator {
.integerGreaterThanZero();
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].disbursement.amount").value(disbursementAmount)
.notNull().zeroOrPositiveAmount();
validatePaymentDetails(baseDataValidator, loanTransactionElement, locale);
}
}
}
}
private void validateSavingsDueTransactions(final JsonElement element, final DataValidatorBuilder baseDataValidator) {
final JsonObject topLevelJsonElement = element.getAsJsonObject();
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
@@ -168,13 +204,27 @@ public class CollectionSheetTransactionDataValidator {
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].savings.id").value(savingsId).notNull()
.integerGreaterThanZero();
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].due.amount").value(dueAmount)
.notNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].due.amount").value(dueAmount).notNull()
.zeroOrPositiveAmount();
validatePaymentDetails(baseDataValidator, savingsTransactionElement, locale);
}
}
}
}
private void validatePaymentDetails(final DataValidatorBuilder baseDataValidator, final JsonElement element, final Locale locale) {
// Validate all string payment detail fields for max length
final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerNamed(PaymentDetailConstants.paymentTypeParamName, element,
locale);
baseDataValidator.reset().parameter(PaymentDetailConstants.paymentTypeParamName).value(paymentTypeId).ignoreIfNull()
.integerGreaterThanZero();
for (final String paymentDetailParameterName : PaymentDetailConstants.PAYMENT_CREATE_REQUEST_DATA_PARAMETERS) {
final String paymentDetailParameterValue = this.fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element);
baseDataValidator.reset().parameter(paymentDetailParameterName).value(paymentDetailParameterValue).ignoreIfNull()
.notExceedingLengthOf(50);
}
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
@@ -0,0 +1,96 @@
/**
* 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.data;
import java.util.Collection;
/**
* Immutable data object for clients with loans due for disbursement or
* collection.
*/
public class IndividualClientData {
private final Long clientId;
private final String clientName;
private Collection<LoanDueData> loans;
private Collection<SavingsDueData> savings;
public static IndividualClientData instance(final Long clientId, final String clientName) {
final Collection<LoanDueData> loans = null;
final Collection<SavingsDueData> savings = null;
return new IndividualClientData(clientId, clientName, loans, savings);
}
public static IndividualClientData withSavings(final IndividualClientData client, final Collection<SavingsDueData> savings) {
return new IndividualClientData(client.clientId, client.clientName, client.loans, savings);
}
public static IndividualClientData withLoans(final IndividualClientData client, final Collection<LoanDueData> loans) {
return new IndividualClientData(client.clientId, client.clientName, loans, client.savings);
}
/**
* @param clientId
* @param clientName
* @param loans
* @param savings
*/
private IndividualClientData(Long clientId, String clientName, Collection<LoanDueData> loans, Collection<SavingsDueData> savings) {
this.clientId = clientId;
this.clientName = clientName;
this.loans = loans;
this.savings = savings;
}
public Long getClientId() {
return this.clientId;
}
public String getClientName() {
return this.clientName;
}
public Collection<LoanDueData> getLoans() {
return this.loans;
}
public void setLoans(final Collection<LoanDueData> loans) {
this.loans = loans;
}
public void addLoans(LoanDueData loans) {
if (this.loans != null) {
this.loans.add(loans);
}
}
public Collection<SavingsDueData> getSavings() {
return this.savings;
}
public void setSavings(Collection<SavingsDueData> savings) {
this.savings = savings;
}
public void addSavings(SavingsDueData savings) {
if (this.savings != null) {
this.savings.add(savings);
}
}
@Override
public boolean equals(final Object obj) {
final IndividualClientData clientData = (IndividualClientData) obj;
return clientData.clientId.compareTo(this.clientId) == 0;
}
@Override
public int hashCode() {
return this.clientId.hashCode();
}
}
@@ -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.data;
import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
/**
* Immutable data object for collection sheet.
*/
public class IndividualCollectionSheetData {
@SuppressWarnings("unused")
private final LocalDate dueDate;
@SuppressWarnings("unused")
private final Collection<IndividualClientData> clients;
@SuppressWarnings("unused")
private final Collection<CodeValueData> paymentTypeOptions;
public static IndividualCollectionSheetData instance(final LocalDate date, final Collection<IndividualClientData> clients,
final Collection<CodeValueData> paymentTypeOptions) {
return new IndividualCollectionSheetData(date, clients, paymentTypeOptions);
}
private IndividualCollectionSheetData(final LocalDate dueDate, final Collection<IndividualClientData> clients,
final Collection<CodeValueData> paymentTypeOptions) {
this.dueDate = dueDate;
this.clients = clients;
this.paymentTypeOptions = paymentTypeOptions;
}
}
@@ -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.data;
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.
*/
public class IndividualCollectionSheetLoanFlatData {
private final String clientName;
private final Long clientId;
private final Long loanId;
private final String accountId;
private final Integer accountStatusId;
private final String productShortName;
private final Long productId;
private final CurrencyData currency;
private BigDecimal disbursementAmount = BigDecimal.ZERO;
private BigDecimal principalDue = BigDecimal.ZERO;
private BigDecimal principalPaid = BigDecimal.ZERO;
private BigDecimal interestDue = BigDecimal.ZERO;
private BigDecimal interestPaid = BigDecimal.ZERO;
private BigDecimal chargesDue = BigDecimal.ZERO;
public IndividualCollectionSheetLoanFlatData(final String clientName, final Long clientId, final Long loanId, final String accountId,
final Integer accountStatusId, final String productShortName, final Long productId, final CurrencyData currency,
final BigDecimal disbursementAmount, final BigDecimal principalDue, final BigDecimal principalPaid,
final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue) {
this.clientName = clientName;
this.clientId = clientId;
this.loanId = loanId;
this.accountId = accountId;
this.accountStatusId = accountStatusId;
this.productShortName = productShortName;
this.productId = productId;
this.currency = currency;
this.disbursementAmount = disbursementAmount;
this.principalDue = principalDue;
this.principalPaid = principalPaid;
this.interestDue = interestDue;
this.interestPaid = interestPaid;
this.chargesDue = chargesDue;
}
public String getClientName() {
return this.clientName;
}
public Long getClientId() {
return this.clientId;
}
public Long getLoanId() {
return this.loanId;
}
public String getAccountId() {
return this.accountId;
}
public Integer getAccountStatusId() {
return this.accountStatusId;
}
public String getProductShortName() {
return this.productShortName;
}
public Long getProductId() {
return this.productId;
}
public CurrencyData getCurrency() {
return this.currency;
}
public BigDecimal getDisbursementAmount() {
return this.disbursementAmount;
}
public BigDecimal getPrincipalDue() {
return this.principalDue;
}
public BigDecimal getPrincipalPaid() {
return this.principalPaid;
}
public BigDecimal getInterestDue() {
return this.interestDue;
}
public BigDecimal getInterestPaid() {
return this.interestPaid;
}
public BigDecimal getChargesDue() {
return this.chargesDue;
}
public LoanDueData getLoanDueData() {
return new LoanDueData(this.loanId, this.accountId, this.accountStatusId, this.productShortName, this.productId, this.currency,
this.disbursementAmount, this.principalDue, this.principalPaid, this.interestDue, this.interestPaid, this.chargesDue);
}
public IndividualClientData getClientData() {
return IndividualClientData.instance(this.clientId, this.clientName);
}
}
@@ -9,6 +9,7 @@ import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
@@ -24,25 +25,30 @@ public class JLGCollectionSheetData {
private final Collection<SavingsProductData> savingsProducts;
private final Collection<JLGGroupData> groups;
private final List<EnumOptionData> attendanceTypeOptions;
private final Collection<CodeValueData> paymentTypeOptions;
public static JLGCollectionSheetData instance(final LocalDate date, final Collection<LoanProductData> loanProducts,
final Collection<JLGGroupData> groups, final List<EnumOptionData> attendanceTypeOptions) {
return new JLGCollectionSheetData(date, loanProducts, null, groups, attendanceTypeOptions);
final Collection<JLGGroupData> groups, final List<EnumOptionData> attendanceTypeOptions,
final Collection<CodeValueData> paymentTypeOptions) {
return new JLGCollectionSheetData(date, loanProducts, null, groups, attendanceTypeOptions, paymentTypeOptions);
}
public static JLGCollectionSheetData withSavingsProducts(final JLGCollectionSheetData data,
final Collection<SavingsProductData> savingsProducts) {
return new JLGCollectionSheetData(data.dueDate, data.loanProducts, savingsProducts, data.groups, data.attendanceTypeOptions);
return new JLGCollectionSheetData(data.dueDate, data.loanProducts, savingsProducts, data.groups, data.attendanceTypeOptions,
data.paymentTypeOptions);
}
private JLGCollectionSheetData(LocalDate dueDate, Collection<LoanProductData> loanProducts,
Collection<SavingsProductData> savingsProducts, Collection<JLGGroupData> groups, List<EnumOptionData> attendanceTypeOptions) {
Collection<SavingsProductData> savingsProducts, Collection<JLGGroupData> groups, List<EnumOptionData> attendanceTypeOptions,
final Collection<CodeValueData> paymentTypeOptions) {
this.dueDate = dueDate;
this.loanProducts = loanProducts;
this.savingsProducts = savingsProducts;
this.groups = groups;
this.attendanceTypeOptions = attendanceTypeOptions;
this.paymentTypeOptions = paymentTypeOptions;
}
public LocalDate getDate() {
@@ -0,0 +1,33 @@
/**
* 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.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 SaveIndividualCollectionSheetCommandHandler implements NewCommandSourceHandler {
private final CollectionSheetWritePlatformService collectionSheetWritePlatformService;
@Autowired
public SaveIndividualCollectionSheetCommandHandler(final CollectionSheetWritePlatformService collectionSheetWritePlatformService) {
this.collectionSheetWritePlatformService = collectionSheetWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.collectionSheetWritePlatformService.saveIndividualCollectionSheet(command);
}
}
@@ -16,6 +16,8 @@ import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializ
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.mifosplatform.portfolio.collectionsheet.command.SingleRepaymentCommand;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetailAssembler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -32,16 +34,28 @@ public final class CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer ex
AbstractFromApiJsonDeserializer<CollectionSheetBulkRepaymentCommand> {
private final FromJsonHelper fromApiJsonHelper;
private final PaymentDetailAssembler paymentDetailAssembler;
@Autowired
public CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
public CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper,
final PaymentDetailAssembler paymentDetailAssembler) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.paymentDetailAssembler = paymentDetailAssembler;
}
@Override
public CollectionSheetBulkRepaymentCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final JsonElement element = this.fromApiJsonHelper.parse(json);
final PaymentDetail paymentDetail = this.paymentDetailAssembler.fetchPaymentDetail(element.getAsJsonObject());
return commandFromApiJson(json, paymentDetail);
}
public CollectionSheetBulkRepaymentCommand commandFromApiJson(final String json, final PaymentDetail paymentDetail) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final JsonElement element = this.fromApiJsonHelper.parse(json);
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed("transactionDate", element);
@@ -63,7 +77,12 @@ public final class CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer ex
final Long loanId = this.fromApiJsonHelper.extractLongNamed("loanId", loanTransactionElement);
final BigDecimal transactionAmount = this.fromApiJsonHelper.extractBigDecimalNamed("transactionAmount",
loanTransactionElement, locale);
loanRepaymentTransactions[i] = new SingleRepaymentCommand(loanId, transactionAmount, transactionDate);
PaymentDetail detail = paymentDetail;
if (paymentDetail == null) {
detail = this.paymentDetailAssembler.fetchPaymentDetail(loanTransactionElement);
}
loanRepaymentTransactions[i] = new SingleRepaymentCommand(loanId, transactionAmount, transactionDate, detail);
}
}
}
@@ -5,9 +5,12 @@
*/
package org.mifosplatform.portfolio.collectionsheet.serialization;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.INDIVIDUAL_COLLECTIONSHEET_SUPPORTED_PARAMS;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.calendarIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.dateFormatParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.localeParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.officeIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.staffIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName;
import java.lang.reflect.Type;
@@ -37,8 +40,8 @@ public class CollectionSheetGenerateCommandFromApiJsonDeserializer {
/**
* The parameters supported for this command.
*/
final Set<String> supportedParameters = new HashSet<>(Arrays.asList(transactionDateParamName, localeParamName,
dateFormatParamName, calendarIdParamName));
final Set<String> supportedParameters = new HashSet<>(Arrays.asList(transactionDateParamName, localeParamName, dateFormatParamName,
calendarIdParamName));
private final FromJsonHelper fromApiJsonHelper;
@@ -74,4 +77,34 @@ public class CollectionSheetGenerateCommandFromApiJsonDeserializer {
"Validation errors exist.", dataValidationErrors); }
}
public void validateForGenerateCollectionSheetOfIndividuals(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, INDIVIDUAL_COLLECTIONSHEET_SUPPORTED_PARAMS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("collectionsheet");
final String transactionDateStr = this.fromApiJsonHelper.extractStringNamed(transactionDateParamName, element);
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDateStr).notBlank();
if (!StringUtils.isBlank(transactionDateStr)) {
final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
baseDataValidator.reset().parameter(transactionDateParamName).value(dueDate).notNull();
}
final Long officeId = this.fromApiJsonHelper.extractLongNamed(officeIdParamName, element);
baseDataValidator.reset().parameter(officeIdParamName).value(officeId).longGreaterThanZero();
final Long staffId = this.fromApiJsonHelper.extractLongNamed(staffIdParamName, element);
baseDataValidator.reset().parameter(staffIdParamName).value(staffId).longGreaterThanZero();
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -6,6 +6,7 @@
package org.mifosplatform.portfolio.collectionsheet.service;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.portfolio.collectionsheet.data.IndividualCollectionSheetData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
public interface CollectionSheetReadPlatformService {
@@ -14,4 +15,6 @@ public interface CollectionSheetReadPlatformService {
JLGCollectionSheetData generateCenterCollectionSheet(final Long groupId, final JsonQuery query);
IndividualCollectionSheetData generateIndividualCollectionSheet(final JsonQuery query);
}
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.collectionsheet.service;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.calendarIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.officeIdParamName;
import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.staffIdParamName;
import java.math.BigDecimal;
import java.sql.ResultSet;
@@ -20,6 +22,8 @@ import java.util.List;
import java.util.Set;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
@@ -30,6 +34,9 @@ import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException;
import org.mifosplatform.portfolio.collectionsheet.data.IndividualClientData;
import org.mifosplatform.portfolio.collectionsheet.data.IndividualCollectionSheetData;
import org.mifosplatform.portfolio.collectionsheet.data.IndividualCollectionSheetLoanFlatData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGClientData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData;
import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetFlatData;
@@ -44,6 +51,7 @@ import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.meeting.attendance.service.AttendanceDropdownReadPlatformService;
import org.mifosplatform.portfolio.meeting.attendance.service.AttendanceEnumerations;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -65,14 +73,16 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
private final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer;
private final CalendarRepositoryWrapper calendarRepositoryWrapper;
private final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService;
final MandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new MandatorySavingsCollectionsheetExtractor();
private final MandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new MandatorySavingsCollectionsheetExtractor();
private final CodeValueReadPlatformService codeValueReadPlatformService;
@Autowired
public CollectionSheetReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
final CenterReadPlatformService centerReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer,
final CalendarRepositoryWrapper calendarRepositoryWrapper,
final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService) {
final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context;
this.centerReadPlatformService = centerReadPlatformService;
this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
@@ -80,6 +90,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
this.groupReadPlatformService = groupReadPlatformService;
this.calendarRepositoryWrapper = calendarRepositoryWrapper;
this.attendanceDropdownReadPlatformService = attendanceDropdownReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
}
/*
@@ -94,6 +105,8 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
boolean firstTime = true;
Long prevGroupId = null;
Long prevClientId = null;
final Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
final List<JLGGroupData> jlgGroupsData = new ArrayList<>();
List<JLGClientData> clientsData = new ArrayList<>();
@@ -168,7 +181,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
}
jlgCollectionSheetData = JLGCollectionSheetData.instance(dueDate, loanProducts, jlgGroupsData,
this.attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions());
this.attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions(), paymentOptions);
}
return jlgCollectionSheetData;
@@ -613,4 +626,219 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
return SavingsDueData.instance(savingsId, accountId, accountStatusId, productName, productId, currency, dueAmount);
}
}
@Override
public IndividualCollectionSheetData generateIndividualCollectionSheet(final JsonQuery query) {
this.collectionSheetGenerateCommandFromApiJsonDeserializer.validateForGenerateCollectionSheetOfIndividuals(query.json());
final LocalDate transactionDate = query.localDateValueOfParameterNamed(transactionDateParamName);
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
final String transactionDateStr = df.format(transactionDate.toDate());
final AppUser currentUser = this.context.authenticatedUser();
final String hierarchy = currentUser.getOffice().getHierarchy();
final String officeHierarchy = hierarchy + "%";
final Long officeId = query.longValueOfParameterNamed(officeIdParamName);
final Long staffId = query.longValueOfParameterNamed(staffIdParamName);
final boolean checkForOfficeId = officeId != null;
final boolean checkForStaffId = staffId != null;
final IndividualCollectionSheetFaltDataMapper mapper = new IndividualCollectionSheetFaltDataMapper(checkForOfficeId,
checkForStaffId);
final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", transactionDateStr).addValue(
"officeHierarchy", officeHierarchy);
if (checkForOfficeId) {
((MapSqlParameterSource) namedParameters).addValue("officeId", officeId);
}
if (checkForStaffId) {
((MapSqlParameterSource) namedParameters).addValue("staffId", staffId);
}
final Collection<IndividualCollectionSheetLoanFlatData> collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(
mapper.sqlSchema(), namedParameters, mapper);
IndividualMandatorySavingsCollectionsheetExtractor mandatorySavingsExtractor = new IndividualMandatorySavingsCollectionsheetExtractor(
checkForOfficeId, checkForStaffId);
// mandatory savings data for collection sheet
Collection<IndividualClientData> clientData = this.namedParameterjdbcTemplate.query(
mandatorySavingsExtractor.collectionSheetSchema(), namedParameters, mandatorySavingsExtractor);
// merge savings data into loan data
mergeLoanData(collectionSheetFlatDatas, (List<IndividualClientData>) clientData);
Collection<CodeValueData> paymentOptions = this.codeValueReadPlatformService
.retrieveCodeValuesByCode(PaymentDetailConstants.paymentTypeCodeName);
return IndividualCollectionSheetData.instance(transactionDate, clientData, paymentOptions);
}
private static final class IndividualCollectionSheetFaltDataMapper implements RowMapper<IndividualCollectionSheetLoanFlatData> {
private final String sql;
public IndividualCollectionSheetFaltDataMapper(final boolean checkForOfficeId, final boolean checkforStaffId) {
StringBuilder sb = new StringBuilder();
sb.append("SELECT loandata.*, sum(lc.amount_outstanding_derived) as chargesDue ");
sb.append("from (SELECT cl.display_name As clientName, ");
sb.append("cl.id As clientId, ln.id As loanId, ln.account_no As accountId, ln.loan_status_id As accountStatusId,");
sb.append(" pl.short_name As productShortName, ln.product_id As productId, ");
sb.append("ln.currency_code as currencyCode, ln.currency_digits as currencyDigits, ln.currency_multiplesof as inMultiplesOf, ");
sb.append("rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("if(ln.loan_status_id = 200 , ln.principal_amount , null) As disbursementAmount, ");
sb.append("sum(ifnull(if(ln.loan_status_id = 300, ls.principal_amount, 0.0), 0.0) - ifnull(if(ln.loan_status_id = 300, ls.principal_completed_derived, 0.0), 0.0)) As principalDue, ");
sb.append("ln.principal_repaid_derived As principalPaid, ");
sb.append("sum(ifnull(if(ln.loan_status_id = 300, ls.interest_amount, 0.0), 0.0) - ifnull(if(ln.loan_status_id = 300, ls.interest_completed_derived, 0.0), 0.0)) As interestDue, ");
sb.append("ln.interest_repaid_derived As interestPaid ");
sb.append("FROM m_loan ln ");
sb.append("JOIN m_client cl ON cl.id = ln.client_id ");
sb.append("LEFT JOIN m_office of ON of.id = cl.office_id AND of.hierarchy like :officeHierarchy ");
sb.append("LEFT JOIN m_product_loan pl ON pl.id = ln.product_id ");
sb.append("LEFT JOIN m_currency rc on rc.`code` = ln.currency_code ");
sb.append("JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate ");
sb.append("where ");
if (checkForOfficeId) {
sb.append("of.id = :officeId and ");
}
if (checkforStaffId) {
sb.append("ln.loan_officer_id = :staffId and ");
}
sb.append("(ln.loan_status_id = 200 or ln.loan_status_id = 300) ");
sb.append("and ln.group_id is null GROUP BY cl.id , ln.id ORDER BY cl.id , ln.id ) loandata ");
sb.append("LEFT JOIN m_loan_charge lc ON lc.loan_id = loandata.loanId AND lc.is_paid_derived = 0 AND lc.is_active = 1 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) ");
sb.append("GROUP BY loandata.clientId, loandata.loanId ORDER BY loandata.clientId, loandata.loanId ");
sql = sb.toString();
}
public String sqlSchema() {
return sql;
}
@Override
public IndividualCollectionSheetLoanFlatData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
final String clientName = rs.getString("clientName");
final Long clientId = JdbcSupport.getLong(rs, "clientId");
final Long loanId = JdbcSupport.getLong(rs, "loanId");
final String accountId = rs.getString("accountId");
final Integer accountStatusId = JdbcSupport.getInteger(rs, "accountStatusId");
final String productShortName = rs.getString("productShortName");
final Long productId = JdbcSupport.getLong(rs, "productId");
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 inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
CurrencyData currencyData = null;
if (currencyCode != null) {
currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
currencyNameCode);
}
final BigDecimal disbursementAmount = rs.getBigDecimal("disbursementAmount");
final BigDecimal principalDue = rs.getBigDecimal("principalDue");
final BigDecimal principalPaid = rs.getBigDecimal("principalPaid");
final BigDecimal interestDue = rs.getBigDecimal("interestDue");
final BigDecimal interestPaid = rs.getBigDecimal("interestPaid");
final BigDecimal chargesDue = rs.getBigDecimal("chargesDue");
return new IndividualCollectionSheetLoanFlatData(clientName, clientId, loanId, accountId, accountStatusId, productShortName,
productId, currencyData, disbursementAmount, principalDue, principalPaid, interestDue, interestPaid, chargesDue);
}
}
private static final class IndividualMandatorySavingsCollectionsheetExtractor implements
ResultSetExtractor<Collection<IndividualClientData>> {
private final SavingsDueDataMapper savingsDueDataMapper = new SavingsDueDataMapper();
private final String sql;
public IndividualMandatorySavingsCollectionsheetExtractor(final boolean checkForOfficeId, final boolean checkforStaffId) {
final StringBuffer sb = new StringBuffer(400);
sb.append("SELECT cl.display_name As clientName, cl.id As clientId, ");
sb.append("sa.id As savingsId, sa.account_no As accountId, sa.status_enum As accountStatusId, ");
sb.append("sp.short_name As productShortName, sp.id As productId, ");
sb.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ");
sb.append("rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, ");
sb.append("sum(ifnull(mss.deposit_amount,0) - ifnull(mss.deposit_amount_completed_derived,0)) as dueAmount ");
sb.append("FROM m_savings_account sa ");
sb.append("JOIN m_client cl ON cl.id = sa.client_id ");
sb.append("JOIN m_savings_product sp ON sa.product_id=sp.id ");
sb.append("JOIN m_deposit_account_recurring_detail dard ON sa.id = dard.savings_account_id AND dard.is_mandatory = true AND dard.is_calendar_inherited = false ");
sb.append("JOIN m_mandatory_savings_schedule mss ON mss.savings_account_id=sa.id AND mss.completed_derived = 0 AND mss.duedate <= :dueDate ");
sb.append("LEFT JOIN m_office of ON of.id = cl.office_id AND of.hierarchy like :officeHierarchy ");
sb.append("LEFT JOIN m_currency rc on rc.`code` = sa.currency_code ");
sb.append("WHERE sa.status_enum=300 and sa.group_id is null ");
sb.append("and (cl.status_enum = 300 or (cl.status_enum = 600 and cl.closedon_date >= :dueDate)) ");
if (checkForOfficeId) {
sb.append("and of.id = :officeId ");
}
if (checkforStaffId) {
sb.append("and sa.field_officer_id = :staffId ");
}
sb.append("GROUP BY cl.id , sa.id ORDER BY cl.id , sa.id ");
this.sql = sb.toString();
}
public String collectionSheetSchema() {
return this.sql;
}
@SuppressWarnings("null")
@Override
public Collection<IndividualClientData> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<IndividualClientData> clientData = new ArrayList<>();
int rowNum = 0;
IndividualClientData client = null;
Long previousClientId = null;
while (rs.next()) {
final Long clientId = JdbcSupport.getLong(rs, "clientId");
if (previousClientId == null || clientId.compareTo(previousClientId) != 0) {
final String clientName = rs.getString("clientName");
client = IndividualClientData.instance(clientId, clientName);
client = IndividualClientData.withSavings(client, new ArrayList<SavingsDueData>());
clientData.add(client);
previousClientId = clientId;
}
SavingsDueData saving = savingsDueDataMapper.mapRow(rs, rowNum);
client.addSavings(saving);
rowNum++;
}
return clientData;
}
}
private void mergeLoanData(final Collection<IndividualCollectionSheetLoanFlatData> loanFlatDatas, List<IndividualClientData> clientDatas) {
IndividualClientData clientSavingsData = null;
for (IndividualCollectionSheetLoanFlatData loanFlatData : loanFlatDatas) {
IndividualClientData clientData = loanFlatData.getClientData();
if (clientSavingsData == null || !clientSavingsData.equals(clientData)) {
if (clientDatas.contains(clientData)) {
final int index = clientDatas.indexOf(clientData);
if (index < 0) return;
clientSavingsData = clientDatas.get(index);
clientSavingsData.setLoans(new ArrayList<LoanDueData>());
} else {
clientSavingsData = clientData;
clientSavingsData.setLoans(new ArrayList<LoanDueData>());
clientDatas.add(clientSavingsData);
}
}
clientSavingsData.addLoans(loanFlatData.getLoanDueData());
}
}
}
@@ -11,4 +11,6 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface CollectionSheetWritePlatformService {
CommandProcessingResult updateCollectionSheet(JsonCommand command);
CommandProcessingResult saveIndividualCollectionSheet(JsonCommand command);
}
@@ -5,8 +5,10 @@
*/
package org.mifosplatform.portfolio.collectionsheet.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
@@ -20,8 +22,11 @@ import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheet
import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetailAssembler;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.mifosplatform.portfolio.savings.domain.DepositAccountAssembler;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
import org.mifosplatform.portfolio.savings.service.DepositAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -36,6 +41,7 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
private final MeetingWritePlatformService meetingWritePlatformService;
private final DepositAccountAssembler accountAssembler;
private final DepositAccountWritePlatformService accountWritePlatformService;
private final PaymentDetailAssembler paymentDetailAssembler;
@Autowired
public CollectionSheetWritePlatformServiceJpaRepositoryImpl(final LoanWritePlatformService loanWritePlatformService,
@@ -43,7 +49,7 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
final CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer,
final CollectionSheetTransactionDataValidator transactionDataValidator,
final MeetingWritePlatformService meetingWritePlatformService, final DepositAccountAssembler accountAssembler,
final DepositAccountWritePlatformService accountWritePlatformService) {
final DepositAccountWritePlatformService accountWritePlatformService, final PaymentDetailAssembler paymentDetailAssembler) {
this.loanWritePlatformService = loanWritePlatformService;
this.bulkRepaymentCommandFromApiJsonDeserializer = bulkRepaymentCommandFromApiJsonDeserializer;
this.bulkDisbursalCommandFromApiJsonDeserializer = bulkDisbursalCommandFromApiJsonDeserializer;
@@ -51,6 +57,7 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
this.meetingWritePlatformService = meetingWritePlatformService;
this.accountAssembler = accountAssembler;
this.accountWritePlatformService = accountWritePlatformService;
this.paymentDetailAssembler = paymentDetailAssembler;
}
@Override
@@ -67,11 +74,12 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
changes.put("note", noteText);
}
changes.putAll(updateBulkReapayments(command));
final PaymentDetail paymentDetail = this.paymentDetailAssembler.fetchPaymentDetail(command.parsedJson().getAsJsonObject());
changes.putAll(updateBulkReapayments(command, paymentDetail));
changes.putAll(updateBulkDisbursals(command));
changes.putAll(updateBulkMandatorySavingsDuePayments(command));
changes.putAll(updateBulkMandatorySavingsDuePayments(command, paymentDetail));
this.meetingWritePlatformService.updateCollectionSheetAttendance(command);
@@ -82,10 +90,39 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
.with(changes).with(changes).build();
}
private Map<String, Object> updateBulkReapayments(final JsonCommand command) {
@Override
public CommandProcessingResult saveIndividualCollectionSheet(final JsonCommand command) {
this.transactionDataValidator.validateIndividualCollectionSheet(command);
final Map<String, Object> changes = new HashMap<>();
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
changes.put("note", noteText);
}
final PaymentDetail paymentDetail = null;
changes.putAll(updateBulkReapayments(command, paymentDetail));
changes.putAll(updateBulkDisbursals(command));
changes.putAll(updateBulkMandatorySavingsDuePayments(command, paymentDetail));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(command.entityId()) //
.withGroupId(command.entityId()) //
.with(changes).with(changes).build();
}
private Map<String, Object> updateBulkReapayments(final JsonCommand command, final PaymentDetail paymentDetail) {
final Map<String, Object> changes = new HashMap<>();
final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand = this.bulkRepaymentCommandFromApiJsonDeserializer
.commandFromApiJson(command.json());
.commandFromApiJson(command.json(), paymentDetail);
changes.putAll(this.loanWritePlatformService.makeLoanBulkRepayment(bulkRepaymentCommand));
return changes;
}
@@ -98,20 +135,21 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col
return changes;
}
private Map<String, Object> updateBulkMandatorySavingsDuePayments(final JsonCommand command) {
private Map<String, Object> updateBulkMandatorySavingsDuePayments(final JsonCommand command, final PaymentDetail paymentDetail) {
final Map<String, Object> changes = new HashMap<>();
final Collection<SavingsAccountTransactionDTO> savingsTransactions = this.accountAssembler.assembleBulkMandatorySavingsAccountTransactionDTOs(command);
final Collection<SavingsAccountTransactionDTO> savingsTransactions = this.accountAssembler
.assembleBulkMandatorySavingsAccountTransactionDTOs(command, paymentDetail);
List<Long> depositTransactionIds = new ArrayList<>();
for (SavingsAccountTransactionDTO savingsAccountTransactionDTO : savingsTransactions) {
try {
this.accountWritePlatformService.mandatorySavingsAccountDeposit(savingsAccountTransactionDTO);
changes.put("savingsAccountId", savingsAccountTransactionDTO.getSavingsAccountId());
changes.put("transationAmount", savingsAccountTransactionDTO.getTransactionAmount());
SavingsAccountTransaction savingsAccountTransaction = this.accountWritePlatformService.mandatorySavingsAccountDeposit(savingsAccountTransactionDTO);
depositTransactionIds.add(savingsAccountTransaction.getId());
} catch (Exception e) {
// TODO: handle exception
}
}
changes.put("SavingsTransactions", depositTransactionIds);
return changes;
}
}
@@ -9,7 +9,6 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -124,7 +123,6 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidRefundDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanDisbursalException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentException;
@@ -761,21 +759,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final boolean isRecoveryRepayment = false;
if (repaymentCommand == null) { return changes; }
List<Long> transactionIds = new ArrayList<>();
boolean isAccountTransfer = false;
for (final SingleRepaymentCommand singleLoanRepaymentCommand : repaymentCommand) {
/****
* TODO Vishwas, have a re-look at this implementation, defaulting
* it to null for now
***/
final Loan loan = this.loanAssembler.assembleFrom(singleLoanRepaymentCommand.getLoanId());
final PaymentDetail paymentDetail = null;
final PaymentDetail paymentDetail = singleLoanRepaymentCommand.getPaymentDetail();
if (paymentDetail != null && paymentDetail.getId() == null) {
this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
final CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder();
this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(),
LoanTransaction loanTransaction = this.loanAccountDomainService.makeRepayment(loan, commandProcessingResultBuilder, bulkRepaymentCommand.getTransactionDate(),
singleLoanRepaymentCommand.getTransactionAmount(), paymentDetail, bulkRepaymentCommand.getNote(), null,
isRecoveryRepayment, isAccountTransfer);
transactionIds.add(loanTransaction.getId());
changes.put("bulkTransactions", singleLoanRepaymentCommand);
}
changes.put("loanTransactions", transactionIds);
return changes;
}
@@ -1971,19 +1970,18 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
@Transactional
@Override
public void applyMeetingDateChanges(final Calendar calendar, final Collection<CalendarInstance> loanCalendarInstances) {
final Boolean reschedulebasedOnMeetingDates = null;
final Boolean reschedulebasedOnMeetingDates = null;
final LocalDate presentMeetingDate = null;
final LocalDate newMeetingDate = null;
applyMeetingDateChanges(calendar, loanCalendarInstances, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
}
@Transactional
@Override
@@ -2011,16 +2009,15 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
throw new CalendarParameterUpdateNotSupportedException("jlg.loan.recalculation", defaultUserMessage);
}
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate().toDate());
if(reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates ){
if (reschedulebasedOnMeetingDates != null && reschedulebasedOnMeetingDates) {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
holidays, workingDays, reschedulebasedOnMeetingDates, presentMeetingDate, newMeetingDate);
}else{
} else {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
holidays, workingDays);
holidays, workingDays);
}
saveLoanWithDataIntegrityViolationChecks(loan);
}
}
@@ -2708,7 +2705,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
return installments;
}
@Override
@Transactional
public CommandProcessingResult makeLoanRefund(Long loanId, JsonCommand command) {
@@ -2718,11 +2715,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
//checkRefundDateIsAfterAtLeastOneRepayment(loanId, transactionDate);
// checkRefundDateIsAfterAtLeastOneRepayment(loanId, transactionDate);
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
checkIfLoanIsPaidInAdvance(loanId, transactionAmount);
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
@@ -2748,15 +2745,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
private void checkIfLoanIsPaidInAdvance(final Long loanId,final BigDecimal transactionAmount) {
private void checkIfLoanIsPaidInAdvance(final Long loanId, final BigDecimal transactionAmount) {
BigDecimal overpaid = this.loanReadPlatformService.retrieveTotalPaidInAdvance(loanId).getPaidInAdvance();
if(overpaid == null || overpaid.equals(new BigDecimal(0)) || transactionAmount.floatValue() > overpaid.floatValue()) {
if(overpaid == null)
overpaid = BigDecimal.ZERO;
if (overpaid == null || overpaid.equals(new BigDecimal(0)) || transactionAmount.floatValue() > overpaid.floatValue()) {
if (overpaid == null) overpaid = BigDecimal.ZERO;
throw new InvalidPaidInAdvanceAmountException(overpaid.toPlainString());
}
}
}
private AppUser getAppUserIfPresent() {
AppUser user = null;
@@ -76,6 +76,11 @@ public final class PaymentDetail extends AbstractPersistable<Long> {
return paymentDetail;
}
public static PaymentDetail instance(final CodeValue paymentType, final String accountNumber, final String checkNumber,
final String routingCode, final String receiptNumber, final String bankNumber) {
return new PaymentDetail(paymentType, accountNumber, checkNumber, routingCode, receiptNumber, bankNumber);
}
private PaymentDetail(final CodeValue paymentType, final String accountNumber, final String checkNumber, final String routingCode,
final String receiptNumber, final String bankNumber) {
this.paymentType = paymentType;
@@ -0,0 +1,43 @@
/**
* 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.paymentdetail.domain;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.JsonObject;
@Service
public class PaymentDetailAssembler {
private final FromJsonHelper fromApiJsonHelper;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
@Autowired
public PaymentDetailAssembler(final FromJsonHelper fromApiJsonHelper, final CodeValueRepositoryWrapper codeValueRepositoryWrapper) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
}
public PaymentDetail fetchPaymentDetail(final JsonObject json) {
final Long paymentTypeId = this.fromApiJsonHelper.extractLongNamed(PaymentDetailConstants.paymentTypeParamName, json);
if (paymentTypeId == null) { return null; }
final CodeValue paymentType = this.codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(
PaymentDetailConstants.paymentTypeCodeName, paymentTypeId);
final String accountNumber = this.fromApiJsonHelper.extractStringNamed(PaymentDetailConstants.accountNumberParamName, json);
final String checkNumber = this.fromApiJsonHelper.extractStringNamed(PaymentDetailConstants.checkNumberParamName, json);
final String routingCode = this.fromApiJsonHelper.extractStringNamed(PaymentDetailConstants.routingCodeParamName, json);
final String receiptNumber = this.fromApiJsonHelper.extractStringNamed(PaymentDetailConstants.receiptNumberParamName, json);
final String bankNumber = this.fromApiJsonHelper.extractStringNamed(PaymentDetailConstants.bankNumberParamName, json);
return PaymentDetail.instance(paymentType, accountNumber, checkNumber, routingCode, receiptNumber, bankNumber);
}
}
@@ -31,7 +31,6 @@ public class PaymentDetailWritePlatformServiceJpaRepositoryImpl implements Payme
}
@Override
@Transactional
public PaymentDetail createPaymentDetail(final JsonCommand command, final Map<String, Object> changes) {
final Long paymentTypeId = command.longValueOfParameterNamed(PaymentDetailConstants.paymentTypeParamName);
if (paymentTypeId == null) { return null; }
@@ -24,8 +24,7 @@ public class SavingsAccountTransactionDTO {
private final AppUser appUser;
public SavingsAccountTransactionDTO(final DateTimeFormatter formatter, final LocalDate transactionDate,
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final Date createdDate,
final AppUser appUser) {
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final Date createdDate, final AppUser appUser) {
this.formatter = formatter;
this.transactionDate = transactionDate;
this.transactionAmount = transactionAmount;
@@ -79,9 +78,8 @@ public class SavingsAccountTransactionDTO {
public Long getSavingsAccountId() {
return this.savingsAccountId;
}
public AppUser getAppUser() {
return this.appUser;
}
public AppUser getAppUser() {
return this.appUser;
}
}
@@ -48,6 +48,8 @@ import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
@@ -66,7 +68,9 @@ import org.mifosplatform.portfolio.group.exception.CenterNotActiveException;
import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException;
import org.mifosplatform.portfolio.group.exception.GroupNotActiveException;
import org.mifosplatform.portfolio.interestratechart.domain.InterestRateChart;
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetailAssembler;
import org.mifosplatform.portfolio.savings.DepositAccountOnClosureType;
import org.mifosplatform.portfolio.savings.DepositAccountType;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
@@ -101,6 +105,7 @@ public class DepositAccountAssembler {
private final SavingsAccountChargeAssembler savingsAccountChargeAssembler;
private final FromJsonHelper fromApiJsonHelper;
private final DepositProductAssembler depositProductAssembler;
private final PaymentDetailAssembler paymentDetailAssembler;
@Autowired
public DepositAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
@@ -110,7 +115,8 @@ public class DepositAccountAssembler {
final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper,
final DepositProductAssembler depositProductAssembler,
final RecurringDepositProductRepository recurringDepositProductRepository,
final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final PlatformSecurityContext context) {
final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final PlatformSecurityContext context,
final PaymentDetailAssembler paymentDetailAssembler) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
this.clientRepository = clientRepository;
@@ -124,6 +130,7 @@ public class DepositAccountAssembler {
this.recurringDepositProductRepository = recurringDepositProductRepository;
this.savingsHelper = new SavingsHelper(accountTransfersReadPlatformService);
this.context = context;
this.paymentDetailAssembler = paymentDetailAssembler;
}
/**
@@ -392,13 +399,12 @@ public class DepositAccountAssembler {
return depositAccountRecurringDetail;
}
public Collection<SavingsAccountTransactionDTO> assembleBulkMandatorySavingsAccountTransactionDTOs(final JsonCommand command) {
public Collection<SavingsAccountTransactionDTO> assembleBulkMandatorySavingsAccountTransactionDTOs(final JsonCommand command,final PaymentDetail paymentDetail) {
AppUser user = getAppUserIfPresent();
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Collection<SavingsAccountTransactionDTO> savingsAccountTransactions = new ArrayList<>();
final PaymentDetail paymentDetail = null;
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(element.getAsJsonObject());
final JsonObject topLevelJsonElement = element.getAsJsonObject();
@@ -415,8 +421,12 @@ public class DepositAccountAssembler {
final Long savingsId = this.fromApiJsonHelper.extractLongNamed(savingsIdParamName, savingsTransactionElement);
final BigDecimal dueAmount = this.fromApiJsonHelper.extractBigDecimalNamed(transactionAmountParamName,
savingsTransactionElement, locale);
PaymentDetail detail = paymentDetail;
if (paymentDetail == null) {
detail = this.paymentDetailAssembler.fetchPaymentDetail(savingsTransactionElement);
}
final SavingsAccountTransactionDTO savingsAccountTransactionDTO = new SavingsAccountTransactionDTO(formatter,
transactionDate, dueAmount, paymentDetail, new Date(), savingsId, user);
transactionDate, dueAmount, detail, new Date(), savingsId, user);
savingsAccountTransactions.add(savingsAccountTransactionDTO);
}
}
@@ -1286,9 +1286,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
boolean isRegularTransaction = false;
final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom(
accountTransactionDTO.getSavingsAccountId(), DepositAccountType.RECURRING_DEPOSIT);
final PaymentDetail paymentDetail = accountTransactionDTO.getPaymentDetail();
if (paymentDetail != null && paymentDetail.getId() == null) {
this.paymentDetailWritePlatformService.persistPaymentDetail(paymentDetail);
}
return this.depositAccountDomainService.handleRDDeposit(account, accountTransactionDTO.getFormatter(),
accountTransactionDTO.getTransactionDate(), accountTransactionDTO.getTransactionAmount(),
accountTransactionDTO.getPaymentDetail(), isRegularTransaction);
accountTransactionDTO.getTransactionDate(), accountTransactionDTO.getTransactionAmount(), paymentDetail,
isRegularTransaction);
}
private AppUser getAppUserIfPresent() {
@@ -0,0 +1,2 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('collection_sheet', 'READ_COLLECTIONSHEET', 'COLLECTIONSHEET', 'READ', 0);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('collection_sheet', 'SAVE_COLLECTIONSHEET', 'COLLECTIONSHEET', 'SAVE', 0);