MIFOSX-583 wip
This commit is contained in:
+9
@@ -2448,4 +2448,13 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder undoClientTransaction(final Long clientId, final Long transactionId) {
|
||||
this.actionName = ClientApiConstants.CLIENT_TRANSACTION_ACTION_UNDO;
|
||||
this.entityName = ClientApiConstants.CLIENT_RESOURCE_NAME;
|
||||
this.entityId = transactionId;
|
||||
this.clientId = clientId;
|
||||
this.href = "/clients/" + clientId + "/transactions/" + transactionId + "?command=undo";
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-6
@@ -5,16 +5,11 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.api;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
|
||||
public class ClientApiConstants {
|
||||
|
||||
@@ -28,10 +23,22 @@ public class ClientApiConstants {
|
||||
public static final String CLIENT_CHARGE_ACTION_PAY = "PAY";
|
||||
public static final String CLIENT_CHARGE_ACTION_INACTIVATE = "INACTIVATE";
|
||||
|
||||
// Client charge associations and query parameters
|
||||
public static final String CLIENT_CHARGE_QUERY_PARAM_STATUS = "chargeStatus";
|
||||
public static final String CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL = "all";
|
||||
public static final String CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE = "active";
|
||||
public static final String CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE = "inactive";
|
||||
public static final String CLIENT_CHARGE_ASSOCIATIONS_TRANSACTIONS = "transactions";
|
||||
|
||||
// Client transaction action names
|
||||
public static final String CLIENT_TRANSACTION_ACTION_READ = "READTRANSACTION";
|
||||
public static final String CLIENT_TRANSACTION_ACTION_UNDO = "UNDOTRANSACTION";
|
||||
|
||||
// Commands
|
||||
public static final String CLIENT_CHARGE_COMMAND_WAIVE_CHARGE = "waive";
|
||||
public static final String CLIENT_CHARGE_COMMAND_PAY_CHARGE = "paycharge";
|
||||
public static final String CLIENT_CHARGE_COMMAND_INACTIVATE_CHARGE = "inactivate";
|
||||
public static final String CLIENT_TRANSACTION_COMMAND_UNDO = "undo";
|
||||
|
||||
public static final String CLIENT_CLOSURE_REASON = "ClientClosureReason";
|
||||
public static final String CLIENT_ACTION_REASON = "ClientActionReason";
|
||||
@@ -119,6 +126,7 @@ public class ClientApiConstants {
|
||||
public static final String amountParamName = "amount";
|
||||
public static final String amountPaidParamName = "amountPaid";
|
||||
public static final String chargeOptionsParamName = "chargeOptions";
|
||||
public static final String transactionsParamName = "transactions";
|
||||
|
||||
// client transactions response parameters
|
||||
public static final String transactionAmountParamName = "transactionAmount";
|
||||
@@ -176,7 +184,7 @@ public class ClientApiConstants {
|
||||
public static final Set<String> CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(chargeIdParamName,
|
||||
clientIdParamName, chargeNameParamName, penaltyParamName, chargeTimeTypeParamName, dueAsOfDateParamName,
|
||||
chargeCalculationTypeParamName, currencyParamName, amountWaivedParamName, amountWrittenOffParamName, amountOutstandingParamName,
|
||||
amountOrPercentageParamName, amountParamName, amountPaidParamName, chargeOptionsParamName));
|
||||
amountOrPercentageParamName, amountParamName, amountPaidParamName, chargeOptionsParamName, transactionsParamName));
|
||||
|
||||
public static final Set<String> CLIENT_CHARGES_ADD_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName));
|
||||
|
||||
+40
-8
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.api;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
@@ -24,6 +26,7 @@ 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.ApiParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
@@ -33,9 +36,12 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.data.ClientChargeData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientTransactionData;
|
||||
import org.mifosplatform.portfolio.client.service.ClientChargeReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.service.ClientTransactionReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Path("/clients/{clientId}/charges")
|
||||
@Component
|
||||
@@ -44,6 +50,7 @@ public class ClientChargesApiResource {
|
||||
private final PlatformSecurityContext context;
|
||||
private final ChargeReadPlatformService chargeReadPlatformService;
|
||||
private final ClientChargeReadPlatformService clientChargeReadPlatformService;
|
||||
private final ClientTransactionReadPlatformService clientTransactionReadPlatformService;
|
||||
private final DefaultToApiJsonSerializer<ClientChargeData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
@@ -53,28 +60,36 @@ public class ClientChargesApiResource {
|
||||
final ClientChargeReadPlatformService clientChargeReadPlatformService,
|
||||
final DefaultToApiJsonSerializer<ClientChargeData> toApiJsonSerializer,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final ClientTransactionReadPlatformService clientTransactionReadPlatformService) {
|
||||
this.context = context;
|
||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||
this.clientChargeReadPlatformService = clientChargeReadPlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.clientTransactionReadPlatformService = clientTransactionReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllClientCharges(@PathParam("clientId") final Long clientId,
|
||||
@DefaultValue("all") @QueryParam("chargeStatus") final String chargeStatus, @Context final UriInfo uriInfo) {
|
||||
@DefaultValue(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL) @QueryParam(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS) final String chargeStatus,
|
||||
@QueryParam("paid") final Boolean paid, @Context final UriInfo uriInfo) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME);
|
||||
|
||||
if (!(is(chargeStatus, "all") || is(chargeStatus, "active")
|
||||
|| is(chargeStatus, "inactive"))) { throw new UnrecognizedQueryParamException("status", chargeStatus,
|
||||
new Object[] { "all", "active", "inactive" }); }
|
||||
if (!(is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL)
|
||||
|| is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE)
|
||||
|| is(chargeStatus,
|
||||
ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE))) { throw new UnrecognizedQueryParamException(
|
||||
ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS, chargeStatus,
|
||||
new Object[] { ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL,
|
||||
ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE,
|
||||
ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE }); }
|
||||
|
||||
final Collection<ClientChargeData> clientCharges = this.clientChargeReadPlatformService.retrieveClientCharges(clientId,
|
||||
chargeStatus);
|
||||
chargeStatus, paid);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, clientCharges, ClientApiConstants.CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS);
|
||||
@@ -109,7 +124,24 @@ public class ClientChargesApiResource {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME);
|
||||
|
||||
final ClientChargeData clientCharge = this.clientChargeReadPlatformService.retrieveClientCharge(clientId, chargeId);
|
||||
ClientChargeData clientCharge = this.clientChargeReadPlatformService.retrieveClientCharge(clientId, chargeId);
|
||||
|
||||
// extract associations
|
||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
if (!associationParameters.isEmpty()) {
|
||||
if (associationParameters.contains("all")) {
|
||||
associationParameters.addAll(Arrays.asList(ClientApiConstants.CLIENT_CHARGE_ASSOCIATIONS_TRANSACTIONS));
|
||||
}
|
||||
ApiParameterHelper.excludeAssociationsForResponseIfProvided(uriInfo.getQueryParameters(), associationParameters);
|
||||
if (associationParameters.contains(ClientApiConstants.CLIENT_CHARGE_ASSOCIATIONS_TRANSACTIONS)) {
|
||||
Collection<ClientTransactionData> clientTransactionDatas = this.clientTransactionReadPlatformService
|
||||
.retrieveAllTransactions(clientId, chargeId);
|
||||
if (CollectionUtils.isEmpty(clientTransactionDatas)) {
|
||||
clientTransactionDatas = null;
|
||||
}
|
||||
clientCharge = ClientChargeData.addAssociations(clientCharge, clientTransactionDatas);
|
||||
}
|
||||
}
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, clientCharge, ClientApiConstants.CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS);
|
||||
@@ -132,7 +164,7 @@ public class ClientChargesApiResource {
|
||||
@Path("{chargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String payOrWaiveSavingsAccountCharge(@PathParam("clientId") final Long clientId, @PathParam("chargeId") final Long chargeId,
|
||||
public String payOrWaiveClientCharge(@PathParam("clientId") final Long clientId, @PathParam("chargeId") final Long chargeId,
|
||||
@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
|
||||
|
||||
String json = "";
|
||||
|
||||
+33
@@ -9,15 +9,22 @@ import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
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.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
@@ -80,4 +87,30 @@ public class ClientTransactionsApiResource {
|
||||
ClientApiConstants.CLIENT_TRANSACTION_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{transactionId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String undoClientTransaction(@PathParam("clientId") final Long clientId, @PathParam("transactionId") final Long transactionId,
|
||||
@QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
|
||||
|
||||
String json = "";
|
||||
if (is(commandParam, ClientApiConstants.CLIENT_TRANSACTION_COMMAND_UNDO)) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().undoClientTransaction(clientId, transactionId)
|
||||
.withJson(apiRequestBodyAsJson).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
json = this.toApiJsonSerializer.serialize(result);
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException("command", commandParam, ClientApiConstants.CLIENT_TRANSACTION_COMMAND_UNDO);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-7
@@ -46,17 +46,31 @@ public class ClientChargeData {
|
||||
|
||||
private final Boolean isActive;
|
||||
|
||||
private final Boolean isPaid;
|
||||
|
||||
private final LocalDate inactivationDate;
|
||||
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
|
||||
private final Collection<ClientTransactionData> clientTransactionDatas;
|
||||
|
||||
public static ClientChargeData instance(Long id, Long clientId, Long chargeId, String name, EnumOptionData chargeTimeType,
|
||||
LocalDate dueDate, EnumOptionData chargeCalculationType, CurrencyData currency, BigDecimal amount, BigDecimal amountPaid,
|
||||
BigDecimal amountWaived, BigDecimal amountWrittenOff, BigDecimal amountOutstanding, boolean penalty, Boolean isActive,
|
||||
LocalDate inactivationDate, Collection<ChargeData> chargeOptions) {
|
||||
|
||||
BigDecimal amountWaived, BigDecimal amountWrittenOff, BigDecimal amountOutstanding, boolean penalty, Boolean isPaid,
|
||||
Boolean isActive, LocalDate inactivationDate, Collection<ChargeData> chargeOptions) {
|
||||
Collection<ClientTransactionData> clientTransactionDatas = null;
|
||||
return new ClientChargeData(id, clientId, chargeId, name, chargeTimeType, dueDate, chargeCalculationType, currency, amount,
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isActive, inactivationDate, chargeOptions);
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isPaid, isActive, inactivationDate, chargeOptions,
|
||||
clientTransactionDatas);
|
||||
}
|
||||
|
||||
public static ClientChargeData addAssociations(ClientChargeData clientChargeData,
|
||||
Collection<ClientTransactionData> clientTransactionDatas) {
|
||||
return new ClientChargeData(clientChargeData.id, clientChargeData.clientId, clientChargeData.chargeId, clientChargeData.name,
|
||||
clientChargeData.chargeTimeType, clientChargeData.dueDate, clientChargeData.chargeCalculationType,
|
||||
clientChargeData.currency, clientChargeData.amount, clientChargeData.amountPaid, clientChargeData.amountWaived,
|
||||
clientChargeData.amountWrittenOff, clientChargeData.amountOutstanding, clientChargeData.penalty, clientChargeData.isPaid,
|
||||
clientChargeData.isActive, clientChargeData.inactivationDate, clientChargeData.chargeOptions, clientTransactionDatas);
|
||||
}
|
||||
|
||||
public static ClientChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||
@@ -74,17 +88,20 @@ public class ClientChargeData {
|
||||
final BigDecimal amountWrittenOff = null;
|
||||
final BigDecimal amountOutstanding = null;
|
||||
final Boolean penalty = false;
|
||||
final Boolean isPaid = null;
|
||||
final Boolean isActive = null;
|
||||
final LocalDate inactivationDate = null;
|
||||
final Collection<ClientTransactionData> clientTransactionDatas = null;
|
||||
|
||||
return new ClientChargeData(id, clientId, chargeId, name, chargeTimeType, dueDate, chargeCalculationType, currency, amount,
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isActive, inactivationDate, chargeOptions);
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isPaid, isActive, inactivationDate, chargeOptions,
|
||||
clientTransactionDatas);
|
||||
}
|
||||
|
||||
private ClientChargeData(Long id, Long clientId, Long chargeId, String name, EnumOptionData chargeTimeType, LocalDate dueDate,
|
||||
EnumOptionData chargeCalculationType, CurrencyData currency, BigDecimal amount, BigDecimal amountPaid, BigDecimal amountWaived,
|
||||
BigDecimal amountWrittenOff, BigDecimal amountOutstanding, boolean penalty, Boolean isActive, LocalDate inactivationDate,
|
||||
Collection<ChargeData> chargeOptions) {
|
||||
BigDecimal amountWrittenOff, BigDecimal amountOutstanding, boolean penalty, Boolean isPaid, Boolean isActive,
|
||||
LocalDate inactivationDate, Collection<ChargeData> chargeOptions, Collection<ClientTransactionData> clientTransactionDatas) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.clientId = clientId;
|
||||
@@ -100,11 +117,15 @@ public class ClientChargeData {
|
||||
this.amountWrittenOff = amountWrittenOff;
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.penalty = penalty;
|
||||
this.isPaid = isPaid;
|
||||
this.isActive = isActive;
|
||||
this.inactivationDate = inactivationDate;
|
||||
|
||||
// template related fields
|
||||
this.chargeOptions = chargeOptions;
|
||||
|
||||
/// associations
|
||||
this.clientTransactionDatas = clientTransactionDatas;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
-17
@@ -83,7 +83,7 @@ public class ClientCharge extends AbstractPersistable<Long> {
|
||||
|
||||
@Transient
|
||||
private OrganisationCurrency currency;
|
||||
|
||||
|
||||
protected ClientCharge() {
|
||||
//
|
||||
}
|
||||
@@ -117,15 +117,43 @@ public class ClientCharge extends AbstractPersistable<Long> {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
public Money pay(final Money amountPaid) {
|
||||
Money amountPaidToDate = Money.of(this.getCurrency(), this.amountPaid);
|
||||
Money amountOutstanding = Money.of(this.getCurrency(), this.amountOutstanding);
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
return Money.of(this.getCurrency(), this.amountOutstanding);
|
||||
}
|
||||
|
||||
public void undoPayment(final Money transactionAmount) {
|
||||
Money amountPaid = getAmountPaid();
|
||||
amountPaid = amountPaid.minus(transactionAmount);
|
||||
this.amountPaid = amountPaid.getAmount();
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
this.paid = false;
|
||||
this.status = true;
|
||||
}
|
||||
|
||||
public Money waive() {
|
||||
Money amountWaivedToDate = getAmountWaived();
|
||||
Money amountOutstanding = getAmountOutstanding();
|
||||
Money totalAmountWaived = amountWaivedToDate.plus(amountOutstanding);
|
||||
this.amountWaived = totalAmountWaived.getAmount();
|
||||
this.amountOutstanding = BigDecimal.ZERO;
|
||||
this.waived = true;
|
||||
return totalAmountWaived;
|
||||
}
|
||||
|
||||
public void undoWaiver(final Money transactionAmount) {
|
||||
Money amountWaived = getAmountWaived();
|
||||
amountWaived = amountWaived.minus(transactionAmount);
|
||||
this.amountWaived = amountWaived.getAmount();
|
||||
this.amountOutstanding = calculateOutstanding();
|
||||
this.waived = false;
|
||||
this.status = true;
|
||||
}
|
||||
|
||||
private void populateDerivedFields(final BigDecimal amount) {
|
||||
@@ -158,7 +186,6 @@ public class ClientCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
private BigDecimal calculateOutstanding() {
|
||||
|
||||
BigDecimal amountPaidLocal = BigDecimal.ZERO;
|
||||
if (this.amountPaid != null) {
|
||||
amountPaidLocal = this.amountPaid;
|
||||
@@ -248,28 +275,28 @@ public class ClientCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) {
|
||||
final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency));
|
||||
final Money amountWaivedOrWrittenOff = getAmountWaived().plus(getAmountWrittenOff());
|
||||
return Money.of(currency, this.amountPaid).plus(amountWaivedOrWrittenOff).isGreaterThanZero();
|
||||
}
|
||||
|
||||
public Money getAmount(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amount);
|
||||
public Money getAmount() {
|
||||
return Money.of(getCurrency(), this.amount);
|
||||
}
|
||||
|
||||
public Money getAmountPaid(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountPaid);
|
||||
public Money getAmountPaid() {
|
||||
return Money.of(getCurrency(), this.amountPaid);
|
||||
}
|
||||
|
||||
public Money getAmountWaived(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWaived);
|
||||
public Money getAmountWaived() {
|
||||
return Money.of(getCurrency(), this.amountWaived);
|
||||
}
|
||||
|
||||
public Money getAmountWrittenOff(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
public Money getAmountWrittenOff() {
|
||||
return Money.of(getCurrency(), this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public Money getAmountOutstanding(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
public Money getAmountOutstanding() {
|
||||
return Money.of(getCurrency(), this.amountOutstanding);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
@@ -45,4 +45,20 @@ public class ClientChargePaidBy extends AbstractPersistable<Long> {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public ClientTransaction getClientTransaction() {
|
||||
return this.clientTransaction;
|
||||
}
|
||||
|
||||
public void setClientTransaction(ClientTransaction clientTransaction) {
|
||||
this.clientTransaction = clientTransaction;
|
||||
}
|
||||
|
||||
public ClientCharge getClientCharge() {
|
||||
return this.clientCharge;
|
||||
}
|
||||
|
||||
public void setClientCharge(ClientCharge clientCharge) {
|
||||
this.clientCharge = clientCharge;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -8,7 +8,6 @@ package org.mifosplatform.portfolio.client.domain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.accounting.glaccount.domain.GLAccountType;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public class ClientEnumerations {
|
||||
|
||||
+45
-1
@@ -19,14 +19,17 @@ import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrency;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@@ -78,6 +81,11 @@ public class ClientTransaction extends AbstractPersistable<Long> {
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "clientTransaction", orphanRemoval = true)
|
||||
private Set<ClientChargePaidBy> clientChargePaidByCollection = new HashSet<>();
|
||||
|
||||
@Transient
|
||||
private OrganisationCurrency currency;
|
||||
|
||||
protected ClientTransaction() {}
|
||||
|
||||
public static ClientTransaction payCharge(final Client client, final Office office, PaymentDetail paymentDetail, final LocalDate date,
|
||||
final Money amount, final String currencyCode, final AppUser appUser) {
|
||||
final boolean isReversed = false;
|
||||
@@ -91,7 +99,7 @@ public class ClientTransaction extends AbstractPersistable<Long> {
|
||||
final boolean isReversed = false;
|
||||
final String externalId = null;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.PAY_CHARGE.getValue(), date, amount, isReversed,
|
||||
return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.WAIVE_CHARGE.getValue(), date, amount, isReversed,
|
||||
externalId, DateUtils.getDateOfTenant(), currencyCode, appUser);
|
||||
}
|
||||
|
||||
@@ -111,8 +119,44 @@ public class ClientTransaction extends AbstractPersistable<Long> {
|
||||
this.appUser = appUser;
|
||||
}
|
||||
|
||||
public void reverse() {
|
||||
this.reversed = true;
|
||||
}
|
||||
|
||||
public boolean isPayChargeTransaction() {
|
||||
return ClientTransactionType.PAY_CHARGE.getValue().equals(this.typeOf);
|
||||
}
|
||||
|
||||
public boolean isWaiveChargeTransaction() {
|
||||
return ClientTransactionType.WAIVE_CHARGE.getValue().equals(this.typeOf);
|
||||
}
|
||||
|
||||
public Set<ClientChargePaidBy> getClientChargePaidByCollection() {
|
||||
return this.clientChargePaidByCollection;
|
||||
}
|
||||
|
||||
public Long getClientId() {
|
||||
return client.getId();
|
||||
}
|
||||
|
||||
public Money getAmount() {
|
||||
return Money.of(getCurrency(), this.amount);
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
return this.currency.toMonetaryCurrency();
|
||||
}
|
||||
|
||||
public void setCurrency(OrganisationCurrency currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return this.currencyCode;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.client.domain;
|
||||
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientTransactionNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class ClientTransactionRepositoryWrapper {
|
||||
|
||||
private final ClientTransactionRepository repository;
|
||||
private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository;
|
||||
|
||||
@Autowired
|
||||
public ClientTransactionRepositoryWrapper(final ClientTransactionRepository repository,
|
||||
final OrganisationCurrencyRepositoryWrapper currencyRepositoryWrapper) {
|
||||
this.repository = repository;
|
||||
this.organisationCurrencyRepository = currencyRepositoryWrapper;
|
||||
}
|
||||
|
||||
public ClientTransaction findOneWithNotFoundDetection(final Long clientId, final Long transactionId) {
|
||||
final ClientTransaction clientTransaction = this.repository.findOne(transactionId);
|
||||
if (clientTransaction == null
|
||||
|| clientTransaction.getClientId() != clientId) { throw new ClientTransactionNotFoundException(clientId, transactionId); }
|
||||
// enrich Client charge with details of Organizational currency
|
||||
clientTransaction.setCurrency(organisationCurrencyRepository.findOneWithNotFoundDetection(clientTransaction.getCurrencyCode()));
|
||||
return clientTransaction;
|
||||
}
|
||||
|
||||
public void save(final ClientTransaction clientTransaction) {
|
||||
this.repository.save(clientTransaction);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final ClientTransaction clientTransaction) {
|
||||
this.repository.saveAndFlush(clientTransaction);
|
||||
}
|
||||
|
||||
public void delete(final ClientTransaction clientTransaction) {
|
||||
this.repository.delete(clientTransaction);
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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.client.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when attempting to delete clients
|
||||
*/
|
||||
public class ClientTransactionCannotBeUndoneException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public ClientTransactionCannotBeUndoneException(final long clientId, final Long transactionId) {
|
||||
super("error.msg.clients.transaction.cannot.be.undone", "Client transaction with identifier " + transactionId
|
||||
+ " for client with identifier " + clientId + " has already been reversed", transactionId);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.client.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class ClientTransactionNotFoundException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public ClientTransactionNotFoundException(final Long clientId, final Long transactionId) {
|
||||
super("error.msg.client.transaction.not.found.exception",
|
||||
"The Transaction with id `" + transactionId + "` does not exist for a Client with id `" + clientId, transactionId,
|
||||
clientId);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -29,6 +29,6 @@ public class DeleteClientChargeCommandHandler implements NewCommandSourceHandler
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.writePlatformService.deleteCharge(command.getClientId(), command.entityId(), command);
|
||||
return this.writePlatformService.deleteCharge(command.getClientId(), command.entityId());
|
||||
}
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.client.handler;
|
||||
|
||||
import org.mifosplatform.commands.annotation.CommandType;
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
|
||||
import org.mifosplatform.portfolio.client.service.ClientTransactionWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@CommandType(entity = ClientApiConstants.CLIENT_RESOURCE_NAME, action = ClientApiConstants.CLIENT_TRANSACTION_ACTION_UNDO)
|
||||
public class UndoClientTransactionCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final ClientTransactionWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UndoClientTransactionCommandHandler(final ClientTransactionWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.writePlatformService.undo(command.getClientId(), command.entityId());
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -7,14 +7,11 @@ package org.mifosplatform.portfolio.client.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientChargeData;
|
||||
|
||||
public interface ClientChargeReadPlatformService {
|
||||
|
||||
ChargeData retrieveClientChargeTemplate();
|
||||
|
||||
Collection<ClientChargeData> retrieveClientCharges(Long clientId, String status);
|
||||
Collection<ClientChargeData> retrieveClientCharges(Long clientId, String status, Boolean isPaid);
|
||||
|
||||
ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId);
|
||||
|
||||
|
||||
+19
-20
@@ -17,11 +17,10 @@ import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeDropdownReadPlatformService;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
|
||||
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
|
||||
import org.mifosplatform.portfolio.client.data.ClientChargeData;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientChargeNotFoundException;
|
||||
import org.mifosplatform.portfolio.common.service.DropdownReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -33,17 +32,11 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final PlatformSecurityContext context;
|
||||
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
|
||||
private final DropdownReadPlatformService dropdownReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
|
||||
final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource,
|
||||
final DropdownReadPlatformService dropdownReadPlatformService) {
|
||||
public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) {
|
||||
this.context = context;
|
||||
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||
}
|
||||
|
||||
public static final class ClientChargeMapper implements RowMapper<ClientChargeData> {
|
||||
@@ -76,13 +69,15 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
|
||||
final int chargeCalculation = rs.getInt("chargeCalculation");
|
||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||
final boolean penalty = rs.getBoolean("penalty");
|
||||
final Boolean isPaid = rs.getBoolean("isPaid");
|
||||
final Boolean isActive = rs.getBoolean("isActive");
|
||||
final LocalDate inactivationDate = JdbcSupport.getLocalDate(rs, "inactivationDate");
|
||||
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
return ClientChargeData.instance(id, clientId, chargeId, name, chargeTimeType, dueDate, chargeCalculationType, currency, amount,
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isActive, inactivationDate, chargeOptions);
|
||||
amountPaid, amountWaived, amountWrittenOff, amountOutstanding, penalty, isPaid, isActive, inactivationDate,
|
||||
chargeOptions);
|
||||
|
||||
}
|
||||
|
||||
@@ -91,7 +86,7 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
|
||||
+ "cc.amount_paid_derived as amountPaid, cc.amount_waived_derived as amountWaived, "
|
||||
+ "cc.amount_writtenoff_derived as amountWrittenOff, cc.amount_outstanding_derived as amountOutstanding, "
|
||||
+ "cc.charge_time_enum as chargeTime, cc.is_penalty as penalty, cc.charge_due_date as dueAsOfDate, "
|
||||
+ "cc.charge_calculation_enum as chargeCalculation, "
|
||||
+ "cc.charge_calculation_enum as chargeCalculation, cc.is_paid_derived as isPaid, cc.waived as waived, "
|
||||
+ "cc.is_active as isActive, cc.inactivated_on_date as inactivationDate, "
|
||||
+ "c.currency_code as currencyCode, oc.name as currencyName, "
|
||||
+ "oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, "
|
||||
@@ -102,15 +97,25 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientChargeData> retrieveClientCharges(Long clientId, String status) {
|
||||
public Collection<ClientChargeData> retrieveClientCharges(Long clientId, String status, Boolean isPaid) {
|
||||
final ClientChargeMapper rm = new ClientChargeMapper();
|
||||
final StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("select ").append(rm.schema()).append(" where cc.client_id=? ");
|
||||
if (status.equalsIgnoreCase("active")) {
|
||||
|
||||
// filter for active charges
|
||||
if (status.equalsIgnoreCase(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE)) {
|
||||
sqlBuilder.append(" and cc.is_active = 1 ");
|
||||
} else if (status.equalsIgnoreCase("inactive")) {
|
||||
} else if (status.equalsIgnoreCase(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE)) {
|
||||
sqlBuilder.append(" and cc.is_active = 0 ");
|
||||
}
|
||||
|
||||
// filter for paid charges
|
||||
if (isPaid != null && isPaid) {
|
||||
sqlBuilder.append(" and ( cc.is_paid_derived = 1 or cc.waived = 1) ");
|
||||
} else if (isPaid != null && !isPaid) {
|
||||
sqlBuilder.append(" and (cc.is_paid_derived = 0 and cc.waived = 0) ");
|
||||
}
|
||||
|
||||
sqlBuilder.append(" order by cc.charge_time_enum ASC, cc.charge_due_date ASC, cc.is_penalty ASC");
|
||||
|
||||
return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { clientId });
|
||||
@@ -131,10 +136,4 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChargeData retrieveClientChargeTemplate() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ public interface ClientChargeWritePlatformService {
|
||||
CommandProcessingResult updateCharge(Long clientId, JsonCommand command);
|
||||
|
||||
@Transactional
|
||||
CommandProcessingResult deleteCharge(Long clientId, Long clientChargeId, JsonCommand command);
|
||||
CommandProcessingResult deleteCharge(Long clientId, Long clientChargeId);
|
||||
|
||||
@Transactional
|
||||
CommandProcessingResult waiveCharge(Long clientId, Long clientChargeId);
|
||||
|
||||
+105
-33
@@ -120,11 +120,13 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed(ClientApiConstants.transactionDateParamName);
|
||||
final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(ClientApiConstants.amountParamName);
|
||||
final Money chargePaid = Money.of(clientCharge.getCurrency(), amountPaid);
|
||||
|
||||
final Money chargePaid = validatePaymentDateAndAmount(client, clientCharge, fmt, transactionDate, amountPaid);
|
||||
// Validate business rules for payment
|
||||
validatePaymentTransaction(client, clientCharge, fmt, transactionDate, amountPaid);
|
||||
|
||||
// pay the charge
|
||||
clientCharge.pay(clientCharge.getCurrency(), chargePaid);
|
||||
clientCharge.pay(chargePaid);
|
||||
|
||||
// create Payment Transaction
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
@@ -146,6 +148,52 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult waiveCharge(Long clientId, Long clientChargeId) {
|
||||
final Client client = this.clientRepository.getActiveClient(clientId);
|
||||
final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId);
|
||||
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
// Validate business rules for payment
|
||||
validateWaiverTransaction(client, clientCharge);
|
||||
|
||||
// waive the charge
|
||||
Money waivedAmount = clientCharge.waive();
|
||||
|
||||
// create Waiver Transaction
|
||||
ClientTransaction clientTransaction = ClientTransaction.waiver(client, client.getOffice(), transactionDate, waivedAmount,
|
||||
clientCharge.getCurrency().getCode(), getAppUserIfPresent());
|
||||
this.clientTransactionRepository.save(clientTransaction);
|
||||
|
||||
// update charge paid by associations
|
||||
final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, waivedAmount.getAmount());
|
||||
clientTransaction.getClientChargePaidByCollection().add(chargePaidBy);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(clientCharge.getId()) //
|
||||
.withOfficeId(clientCharge.getClient().getOffice().getId()) //
|
||||
.withClientId(clientCharge.getClient().getId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult deleteCharge(Long clientId, Long clientChargeId) {
|
||||
final Client client = this.clientRepository.getActiveClient(clientId);
|
||||
final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId);
|
||||
|
||||
// Validate business rules for charge deletion
|
||||
validateChargeDeletion(client, clientCharge);
|
||||
|
||||
// delete the charge
|
||||
clientChargeRepository.delete(clientCharge);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(clientCharge.getId()) //
|
||||
.withOfficeId(clientCharge.getClient().getOffice().getId()) //
|
||||
.withClientId(clientCharge.getClient().getId()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates transaction to ensure that <br>
|
||||
* charge is active <br>
|
||||
@@ -159,31 +207,39 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
* @param fmt
|
||||
* @param transactionDate
|
||||
* @param amountPaid
|
||||
* @param requiresTransactionDateValidation
|
||||
* if set to false, transaction date specific validation is
|
||||
* skipped
|
||||
* @param requiresTransactionAmountValidation
|
||||
* if set to false transaction amount validation is skipped
|
||||
* @return
|
||||
*/
|
||||
private Money validatePaymentDateAndAmount(final Client client, final ClientCharge clientCharge, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal amountPaid) {
|
||||
private void validatePaymentDateAndAmount(final Client client, final ClientCharge clientCharge, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal amountPaid, final boolean requiresTransactionDateValidation,
|
||||
final boolean requiresTransactionAmountValidation) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME);
|
||||
|
||||
validateTransactionDateOnWorkingDay(transactionDate, clientCharge, fmt);
|
||||
|
||||
if (clientCharge.isNotActive()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("charge.is.not.active");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (client.getActivationLocalDate() != null && transactionDate.isBefore(client.getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.transactionDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
if (requiresTransactionDateValidation) {
|
||||
validateTransactionDateOnWorkingDay(transactionDate, clientCharge, fmt);
|
||||
|
||||
if (DateUtils.isDateInTheFuture(transactionDate)) {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.transactionDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
if (client.getActivationLocalDate() != null && transactionDate.isBefore(client.getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.transactionDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (DateUtils.isDateInTheFuture(transactionDate)) {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.transactionDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// validate charge is not already paid or waived
|
||||
@@ -195,12 +251,41 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final Money chargePaid = Money.of(clientCharge.getCurrency(), amountPaid);
|
||||
if (!clientCharge.getAmountOutstanding(clientCharge.getCurrency()).isGreaterThanOrEqualTo(chargePaid)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
if (requiresTransactionAmountValidation) {
|
||||
final Money chargePaid = Money.of(clientCharge.getCurrency(), amountPaid);
|
||||
if (!clientCharge.getAmountOutstanding().isGreaterThanOrEqualTo(chargePaid)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
return chargePaid;
|
||||
}
|
||||
|
||||
public void validateWaiverTransaction(final Client client, final ClientCharge clientCharge) {
|
||||
DateTimeFormatter fmt = null;
|
||||
LocalDate transactionDate = null;
|
||||
BigDecimal amountPaid = null;
|
||||
boolean requiresTransactionDateValidation = false;
|
||||
boolean requiresTransactionAmountValidation = false;
|
||||
validatePaymentDateAndAmount(client, clientCharge, fmt, transactionDate, amountPaid, requiresTransactionDateValidation,
|
||||
requiresTransactionAmountValidation);
|
||||
}
|
||||
|
||||
public void validatePaymentTransaction(final Client client, final ClientCharge clientCharge, final DateTimeFormatter fmt,
|
||||
final LocalDate transactionDate, final BigDecimal amountPaid) {
|
||||
boolean requiresTransactionDateValidation = true;
|
||||
boolean requiresTransactionAmountValidation = true;
|
||||
validatePaymentDateAndAmount(client, clientCharge, fmt, transactionDate, amountPaid, requiresTransactionDateValidation,
|
||||
requiresTransactionAmountValidation);
|
||||
}
|
||||
|
||||
public void validateChargeDeletion(final Client client, final ClientCharge clientCharge) {
|
||||
DateTimeFormatter fmt = null;
|
||||
LocalDate transactionDate = null;
|
||||
BigDecimal amountPaid = null;
|
||||
boolean requiresTransactionDateValidation = false;
|
||||
boolean requiresTransactionAmountValidation = false;
|
||||
validatePaymentDateAndAmount(client, clientCharge, fmt, transactionDate, amountPaid, requiresTransactionDateValidation,
|
||||
requiresTransactionAmountValidation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,19 +295,6 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
|
||||
@Override
|
||||
public CommandProcessingResult updateCharge(Long clientId, JsonCommand command) {
|
||||
this.clientChargeDataValidator.validateAdd(command.json());
|
||||
final Client client = clientRepository.getActiveClient(clientId);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult deleteCharge(Long clientId, Long clientChargeId, JsonCommand command) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult waiveCharge(Long clientId, Long clientChargeId) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -13,7 +13,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public interface ClientTransactionReadPlatformService {
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<ClientTransactionData> retrieveAllTransactions(final Long clientId);
|
||||
public Collection<ClientTransactionData> retrieveAllTransactions(Long clientId);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<ClientTransactionData> retrieveAllTransactions(final Long clientId, final Long chargeId);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public ClientTransactionData retrieveTransaction(Long clientId, Long transactionId);
|
||||
|
||||
+26
-6
@@ -18,9 +18,11 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientTransactionData;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransactionType;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientTransactionNotFoundException;
|
||||
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -49,7 +51,7 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti
|
||||
sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount, ");
|
||||
sqlBuilder.append("tr.created_date as submittedOnDate, tr.is_reversed as reversed, ");
|
||||
sqlBuilder.append("tr.external_id as externalId, o.name as officeName, o.id as officeId, ");
|
||||
sqlBuilder.append("c.id as clientId, c.account_no as accountNo, ");
|
||||
sqlBuilder.append("c.id as clientId, c.account_no as accountNo, ccpb.client_charge_id as clientChargeId, ");
|
||||
sqlBuilder.append("pd.payment_type_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, ");
|
||||
sqlBuilder.append("pd.receipt_number as receiptNumber, pd.bank_number as bankNumber,pd.routing_code as routingCode, ");
|
||||
sqlBuilder.append(
|
||||
@@ -63,6 +65,7 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti
|
||||
sqlBuilder.append("left join m_payment_detail pd on tr.payment_detail_id = pd.id ");
|
||||
sqlBuilder.append("left join m_payment_type pt on pd.payment_type_id = pt.id ");
|
||||
sqlBuilder.append("left join m_office o on o.id = tr.office_id ");
|
||||
sqlBuilder.append("left join m_client_charge_paid_by ccpb on ccpb.client_transaction_id = tr.id ");
|
||||
this.schemaSql = sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -116,15 +119,32 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti
|
||||
|
||||
@Override
|
||||
public Collection<ClientTransactionData> retrieveAllTransactions(Long clientId) {
|
||||
final String sql = "select " + this.clientTransactionMapper.schema()
|
||||
+ " where c.id = ? order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC";
|
||||
return this.jdbcTemplate.query(sql, this.clientTransactionMapper, new Object[] { clientId });
|
||||
Long chargeId = null;
|
||||
return retrieveAllTransactions(clientId, chargeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClientTransactionData> retrieveAllTransactions(Long clientId, Long chargeId) {
|
||||
Object[] parameters = new Object[1];
|
||||
String sql = "select " + this.clientTransactionMapper.schema() + " where c.id = ? ";
|
||||
if (chargeId != null) {
|
||||
parameters = new Object[2];
|
||||
parameters[1] = chargeId;
|
||||
sql = sql + " and ccpb.client_charge_id = ?";
|
||||
}
|
||||
parameters[0] = clientId;
|
||||
sql = sql + " order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC";
|
||||
return this.jdbcTemplate.query(sql, this.clientTransactionMapper, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTransactionData retrieveTransaction(Long clientId, Long transactionId) {
|
||||
final String sql = "select " + this.clientTransactionMapper.schema() + " where c.id = ? and tr.id= ?";
|
||||
return this.jdbcTemplate.queryForObject(sql, this.clientTransactionMapper, new Object[] { clientId, transactionId });
|
||||
try {
|
||||
final String sql = "select " + this.clientTransactionMapper.schema() + " where c.id = ? and tr.id= ?";
|
||||
return this.jdbcTemplate.queryForObject(sql, this.clientTransactionMapper, new Object[] { clientId, transactionId });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new ClientTransactionNotFoundException(clientId, transactionId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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.client.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public interface ClientTransactionWritePlatformService {
|
||||
|
||||
@Transactional
|
||||
CommandProcessingResult undo(Long clientId, Long transactionId);
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.client.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientCharge;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientChargePaidBy;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransaction;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientTransactionRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientTransactionCannotBeUndoneException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ClientTransactionWritePlatformServiceJpaRepositoryImpl implements ClientTransactionWritePlatformService {
|
||||
|
||||
private final ClientTransactionRepositoryWrapper clientTransactionRepository;
|
||||
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository;
|
||||
|
||||
@Autowired
|
||||
public ClientTransactionWritePlatformServiceJpaRepositoryImpl(final ClientTransactionRepositoryWrapper clientTransactionRepository,
|
||||
final ClientRepositoryWrapper clientRepositoryWrapper,
|
||||
final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepositoryWrapper) {
|
||||
this.clientTransactionRepository = clientTransactionRepository;
|
||||
this.clientRepository = clientRepositoryWrapper;
|
||||
this.organisationCurrencyRepository = organisationCurrencyRepositoryWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult undo(Long clientId, Long transactionId) {
|
||||
|
||||
final Client client = this.clientRepository.getActiveClient(clientId);
|
||||
|
||||
final ClientTransaction clientTransaction = this.clientTransactionRepository.findOneWithNotFoundDetection(clientId, transactionId);
|
||||
|
||||
// validate that transaction can be undone
|
||||
if (clientTransaction.isReversed()) { throw new ClientTransactionCannotBeUndoneException(clientId, transactionId); }
|
||||
|
||||
// mark transaction as reversed
|
||||
clientTransaction.reverse();
|
||||
|
||||
// revert any charges paid back to their original state
|
||||
if (clientTransaction.isPayChargeTransaction() || clientTransaction.isWaiveChargeTransaction()) {
|
||||
// undo charge
|
||||
final Set<ClientChargePaidBy> chargesPaidBy = clientTransaction.getClientChargePaidByCollection();
|
||||
for (final ClientChargePaidBy clientChargePaidBy : chargesPaidBy) {
|
||||
final ClientCharge clientCharge = clientChargePaidBy.getClientCharge();
|
||||
clientCharge.setCurrency(
|
||||
organisationCurrencyRepository.findOneWithNotFoundDetection(clientCharge.getCharge().getCurrencyCode()));
|
||||
if (clientTransaction.isPayChargeTransaction()) {
|
||||
clientCharge.undoPayment(clientTransaction.getAmount());
|
||||
} else if (clientTransaction.isWaiveChargeTransaction()) {
|
||||
clientCharge.undoWaiver(clientTransaction.getAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(transactionId) //
|
||||
.withOfficeId(client.officeId()) //
|
||||
.withClientId(clientId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('transaction_client', 'READTRANSACTION_CLIENT', 'CLIENT', 'READTRANSACTION', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('transaction_client', 'UNDOTRANSACTION_CLIENT', 'CLIENT', 'UNDOTRANSACTION', 0);
|
||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('transaction_client', 'UNDOTRANSACTION_CLIENT_CHECKER', 'CLIENT', 'UNDOTRANSACTION_CHECKER', 0);
|
||||
Reference in New Issue
Block a user