From b6626b0b832bd095d7a3afd076ee756e465d8e60 Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Wed, 19 Aug 2015 00:49:48 +0530 Subject: [PATCH] wip:changes for client fees --- .../office/domain/OrganisationCurrency.java | 9 +- ...WritePlatformServiceJpaRepositoryImpl.java | 1 - .../client/api/ClientApiConstants.java | 30 ++- .../client/api/ClientChargesApiResource.java | 2 + .../client/api/ClientPaymentsApiResource.java | 17 -- .../api/ClientTransactionsApiResource.java | 78 +++++++ .../client/data/ClientTransactionData.java | 56 +++++ .../portfolio/client/domain/ClientCharge.java | 95 ++++++-- .../client/domain/ClientChargePaidBy.java | 5 + .../domain/ClientChargeRepositoryWrapper.java | 39 ++++ .../client/domain/ClientEnumerations.java | 26 ++- .../domain/ClientRepositoryWrapper.java | 7 + .../client/domain/ClientTransaction.java | 62 ++++- .../domain/ClientTransactionRepository.java | 8 + .../client/domain/ClientTransactionType.java | 66 ++++++ .../ClientChargeReadPlatformServiceImpl.java | 2 + ...WritePlatformServiceJpaRepositoryImpl.java | 213 ++++++++++++++---- .../ClientTransactionReadPlatformService.java | 16 ++ ...entTransactionReadPlatformServiceImpl.java | 123 ++++++++++ .../savings/domain/SavingsAccount.java | 2 +- ...WritePlatformServiceJpaRepositoryImpl.java | 93 ++++---- ...WritePlatformServiceJpaRepositoryImpl.java | 114 +++++----- .../migrations/core_db/V266__client_fees.sql | 9 + 23 files changed, 877 insertions(+), 196 deletions(-) delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientPaymentsApiResource.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientTransactionData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargeRepositoryWrapper.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionRepository.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionType.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V266__client_fees.sql diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OrganisationCurrency.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OrganisationCurrency.java index 53f36b1ba..efe77e2e4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OrganisationCurrency.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/domain/OrganisationCurrency.java @@ -9,6 +9,7 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.springframework.data.jpa.domain.AbstractPersistable; /** @@ -54,8 +55,12 @@ public class OrganisationCurrency extends AbstractPersistable { this.nameCode = nameCode; this.displaySymbol = displaySymbol; } - + public final String getCode() { - return code; + return code; + } + + public final MonetaryCurrency toMonetaryCurrency() { + return new MonetaryCurrency(this.code, this.decimalPlaces, this.inMultiplesOf); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java index d65b0275d..48018856d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/charge/service/ChargeWritePlatformServiceJpaRepositoryImpl.java @@ -121,7 +121,6 @@ public class ChargeWritePlatformServiceJpaRepositoryImpl implements ChargeWriteP } if (!changes.isEmpty()) { - this.chargeRepository.save(chargeForUpdate); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java index 676ea6972..6ff9fb5cc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java @@ -5,11 +5,16 @@ */ 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 { @@ -74,6 +79,14 @@ public class ClientApiConstants { public static final String clientTypeParamName = "clientType"; public static final String clientClassificationIdParamName = "clientClassificationId"; public static final String clientClassificationParamName = "clientClassification"; + // request parameters for payment details + public static final String paymentTypeIdParamName = "paymentTypeId"; + public static final String transactionAccountNumberParamName = "accountNumber"; + public static final String checkNumberParamName = "checkNumber"; + public static final String routingCodeParamName = "routingCode"; + public static final String receiptNumberParamName = "receiptNumber"; + public static final String bankNumberParamName = "bankNumber"; + // response parameters public static final String statusParamName = "status"; public static final String hierarchyParamName = "hierarchy"; @@ -107,6 +120,14 @@ public class ClientApiConstants { public static final String amountPaidParamName = "amountPaid"; public static final String chargeOptionsParamName = "chargeOptions"; + // client transactions response parameters + public static final String transactionAmountParamName = "transactionAmount"; + public static final String paymentDetailDataParamName = "paymentDetailData"; + public static final String reversedParamName = "reversed"; + public static final String dateParamName = "date"; + private static final String transactionTypeParamName = "type"; + private static final String transactionCurrencyParamName = "currency"; + // associations related part of response public static final String groupsParamName = "groups"; @@ -160,7 +181,12 @@ public class ClientApiConstants { public static final Set CLIENT_CHARGES_ADD_REQUEST_DATA_PARAMETERS = new HashSet<>( Arrays.asList(chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName)); - public static final Set CLIENT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS = new HashSet<>( - Arrays.asList(amountParamName, transactionDateParamName, dateFormatParamName, localeParamName)); + public static final Set CLIENT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(amountParamName, + transactionDateParamName, dateFormatParamName, localeParamName, paymentTypeIdParamName, transactionAccountNumberParamName, + checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName)); + + public static final Set CLIENT_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, + transactionAmountParamName, paymentDetailDataParamName, reversedParamName, dateParamName, officeIdParamName, + officeNameParamName, transactionTypeParamName, transactionCurrencyParamName, externalIdParamName, submittedOnDateParamName)); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java index 4330f5f4d..a2f9c5bde 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java @@ -28,6 +28,7 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; import org.mifosplatform.portfolio.client.data.ClientChargeData; import org.mifosplatform.portfolio.client.service.ClientChargeReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Path("/clients/{clientId}/charges") @@ -41,6 +42,7 @@ public class ClientChargesApiResource { private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + @Autowired public ClientChargesApiResource(final PlatformSecurityContext context, final ChargeReadPlatformService chargeReadPlatformService, final ClientChargeReadPlatformService clientChargeReadPlatformService, final DefaultToApiJsonSerializer toApiJsonSerializer, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientPaymentsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientPaymentsApiResource.java deleted file mode 100644 index e7dbfa6ac..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientPaymentsApiResource.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.mifosplatform.portfolio.client.api; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -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; - -public class ClientPaymentsApiResource { - - - -} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java new file mode 100644 index 000000000..2963129ca --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java @@ -0,0 +1,78 @@ +package org.mifosplatform.portfolio.client.api; + +import java.util.Collection; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; + +import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; +import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.portfolio.client.data.ClientTransactionData; +import org.mifosplatform.portfolio.client.service.ClientTransactionReadPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Path("/clients/{clientId}/transactions") +@Component +public class ClientTransactionsApiResource { + + private final PlatformSecurityContext context; + private final ClientTransactionReadPlatformService clientTransactionReadPlatformService; + private final DefaultToApiJsonSerializer toApiJsonSerializer; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + + @Autowired + public ClientTransactionsApiResource(final PlatformSecurityContext context, + final ClientTransactionReadPlatformService clientTransactionReadPlatformService, + final DefaultToApiJsonSerializer toApiJsonSerializer, + final ApiRequestParameterHelper apiRequestParameterHelper, + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + this.context = context; + this.clientTransactionReadPlatformService = clientTransactionReadPlatformService; + this.toApiJsonSerializer = toApiJsonSerializer; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllClientTransactions(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); + + final Collection clientTransactions = this.clientTransactionReadPlatformService + .retrieveAllTransactions(clientId); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, clientTransactions, + ClientApiConstants.CLIENT_TRANSACTION_RESPONSE_DATA_PARAMETERS); + } + + @GET + @Path("{transactionId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveClientTransaction(@PathParam("clientId") final Long clientId, + @PathParam("transactionId") final Long transactionId, @Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); + + final ClientTransactionData clientTransaction = this.clientTransactionReadPlatformService.retrieveTransaction(clientId, + transactionId); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, clientTransaction, + ClientApiConstants.CLIENT_TRANSACTION_RESPONSE_DATA_PARAMETERS); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientTransactionData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientTransactionData.java new file mode 100644 index 000000000..2e1ba852a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientTransactionData.java @@ -0,0 +1,56 @@ +package org.mifosplatform.portfolio.client.data; + +import java.math.BigDecimal; +import java.util.Collection; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.organisation.monetary.data.CurrencyData; +import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData; +import org.mifosplatform.portfolio.paymenttype.data.PaymentTypeData; + +@SuppressWarnings("unused") +public class ClientTransactionData { + + private final Long id; + private final Long officeId; + private final String officeName; + private final EnumOptionData type; + private final LocalDate date; + private final CurrencyData currency; + private final PaymentDetailData paymentDetailData; + private final BigDecimal amount; + private final String externalId; + private final LocalDate submittedOnDate; + private final boolean reversed; + + // templates + final Collection paymentTypeOptions; + + public static ClientTransactionData create(Long id, Long officeId, String officeName, EnumOptionData type, LocalDate date, + CurrencyData currency, PaymentDetailData paymentDetailData, BigDecimal amount, String externalId, LocalDate submittedOnDate, + boolean reversed) { + final Collection paymentTypeOptions = null; + return new ClientTransactionData(id, officeId, officeName, type, date, currency, paymentDetailData, amount, externalId, + submittedOnDate, reversed, paymentTypeOptions); + } + + private ClientTransactionData(Long id, Long officeId, String officeName, EnumOptionData type, LocalDate date, CurrencyData currency, + PaymentDetailData paymentDetailData, BigDecimal amount, String externalId, LocalDate submittedOnDate, boolean reversed, + Collection paymentTypeOptions) { + super(); + this.id = id; + this.officeId = officeId; + this.officeName = officeName; + this.type = type; + this.date = date; + this.currency = currency; + this.paymentDetailData = paymentDetailData; + this.amount = amount; + this.externalId = externalId; + this.submittedOnDate = submittedOnDate; + this.reversed = reversed; + this.paymentTypeOptions = paymentTypeOptions; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientCharge.java index 4e4e942a2..d8cd52479 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientCharge.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientCharge.java @@ -1,7 +1,12 @@ package org.mifosplatform.portfolio.client.domain; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName; + import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; @@ -12,11 +17,21 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +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.OrganisationCurrency; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType; import org.mifosplatform.portfolio.charge.domain.ChargeTimeType; import org.mifosplatform.portfolio.client.api.ClientApiConstants; +import org.mifosplatform.portfolio.savings.domain.SavingsAccountCharge; +import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.data.jpa.domain.AbstractPersistable; @Entity @@ -72,6 +87,8 @@ public class ClientCharge extends AbstractPersistable { @Column(name = "inactivated_on_date") private Date inactivationDate; + private OrganisationCurrency currency; + public static ClientCharge createNew(final Client client, final Charge charge, final JsonCommand command) { BigDecimal amount = command.bigDecimalValueOfParameterNamed(ClientApiConstants.amountParamName); final LocalDate dueDate = command.localDateValueOfParameterNamed(ClientApiConstants.dueAsOfDateParamName); @@ -101,6 +118,17 @@ public class ClientCharge extends AbstractPersistable { 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); + 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); + } + private void populateDerivedFields(final BigDecimal amount) { switch (ChargeCalculationType.fromInt(this.chargeCalculation)) { case INVALID: @@ -152,6 +180,14 @@ public class ClientCharge extends AbstractPersistable { return this.amount.subtract(totalAccountedFor); } + public LocalDate getDueLocalDate() { + LocalDate dueDate = null; + if (this.dueDate != null) { + dueDate = new LocalDate(this.dueDate); + } + return dueDate; + } + public Client getClient() { return this.client; } @@ -172,26 +208,6 @@ public class ClientCharge extends AbstractPersistable { return this.chargeCalculation; } - public BigDecimal getAmount() { - return this.amount; - } - - public BigDecimal getAmountPaid() { - return this.amountPaid; - } - - public BigDecimal getAmountWaived() { - return this.amountWaived; - } - - public BigDecimal getAmountWrittenOff() { - return this.amountWrittenOff; - } - - public BigDecimal getAmountOutstanding() { - return this.amountOutstanding; - } - public boolean isPenaltyCharge() { return this.penaltyCharge; } @@ -204,10 +220,14 @@ public class ClientCharge extends AbstractPersistable { return this.waived; } - public boolean isStatus() { + public boolean isActive() { return this.status; } + public boolean isNotActive() { + return !this.status; + } + public Date getInactivationDate() { return this.inactivationDate; } @@ -220,4 +240,37 @@ public class ClientCharge extends AbstractPersistable { return this.client.getOffice().getId(); } + public void setCurrency(OrganisationCurrency currency) { + this.currency = currency; + } + + public MonetaryCurrency getCurrency() { + return this.currency.toMonetaryCurrency(); + } + + public boolean isPaidOrPartiallyPaid(final MonetaryCurrency currency) { + final Money amountWaivedOrWrittenOff = getAmountWaived(currency).plus(getAmountWrittenOff(currency)); + return Money.of(currency, this.amountPaid).plus(amountWaivedOrWrittenOff).isGreaterThanZero(); + } + + public Money getAmount(final MonetaryCurrency currency) { + return Money.of(currency, this.amount); + } + + public Money getAmountPaid(final MonetaryCurrency currency) { + return Money.of(currency, this.amountPaid); + } + + public Money getAmountWaived(final MonetaryCurrency currency) { + return Money.of(currency, this.amountWaived); + } + + public Money getAmountWrittenOff(final MonetaryCurrency currency) { + return Money.of(currency, this.amountWrittenOff); + } + + public Money getAmountOutstanding(final MonetaryCurrency currency) { + return Money.of(currency, this.amountOutstanding); + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargePaidBy.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargePaidBy.java index 367371dd1..7f6b05abe 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargePaidBy.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargePaidBy.java @@ -29,6 +29,11 @@ public class ClientChargePaidBy extends AbstractPersistable { } + public static ClientChargePaidBy instance(final ClientTransaction clientTransaction, final ClientCharge clientCharge, + final BigDecimal amount) { + return new ClientChargePaidBy(clientTransaction, clientCharge, amount); + } + public ClientChargePaidBy(final ClientTransaction clientTransaction, final ClientCharge clientCharge, final BigDecimal amount) { this.clientTransaction = clientTransaction; this.clientCharge = clientCharge; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargeRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargeRepositoryWrapper.java new file mode 100644 index 000000000..78441088a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientChargeRepositoryWrapper.java @@ -0,0 +1,39 @@ +package org.mifosplatform.portfolio.client.domain; + +import org.mifosplatform.organisation.office.domain.OrganisationCurrencyRepositoryWrapper; +import org.mifosplatform.portfolio.charge.exception.ChargeNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; + +public class ClientChargeRepositoryWrapper { + + private final ClientChargeRepository repository; + private final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepository; + + @Autowired + public ClientChargeRepositoryWrapper(final ClientChargeRepository repository, + final OrganisationCurrencyRepositoryWrapper organisationCurrencyRepositoryWrapper) { + this.repository = repository; + this.organisationCurrencyRepository = organisationCurrencyRepositoryWrapper; + } + + public ClientCharge findOneWithNotFoundDetection(final Long id) { + final ClientCharge clientCharge = this.repository.findOne(id); + if (clientCharge == null) { throw new ChargeNotFoundException(id); } + // enrich Client charge with details of Organizational currency + clientCharge.setCurrency(organisationCurrencyRepository.findOneWithNotFoundDetection(clientCharge.getCharge().getCurrencyCode())); + return clientCharge; + } + + public void save(final ClientCharge clientCharge) { + this.repository.save(clientCharge); + } + + public void saveAndFlush(final ClientCharge clientCharge) { + this.repository.saveAndFlush(clientCharge); + } + + public void delete(final ClientCharge clientCharge) { + this.repository.delete(clientCharge); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java index 86b4866c7..8f256070d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java @@ -5,6 +5,10 @@ */ 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 { @@ -33,7 +37,8 @@ public class ClientEnumerations { optionData = new EnumOptionData(ClientStatus.REJECTED.getValue().longValue(), ClientStatus.REJECTED.getCode(), "Rejected"); break; case WITHDRAWN: - optionData = new EnumOptionData(ClientStatus.WITHDRAWN.getValue().longValue(), ClientStatus.WITHDRAWN.getCode(), "Withdrawn"); + optionData = new EnumOptionData(ClientStatus.WITHDRAWN.getValue().longValue(), ClientStatus.WITHDRAWN.getCode(), + "Withdrawn"); break; case TRANSFER_IN_PROGRESS: optionData = new EnumOptionData(ClientStatus.TRANSFER_IN_PROGRESS.getValue().longValue(), @@ -49,4 +54,23 @@ public class ClientEnumerations { return optionData; } + + public static EnumOptionData clientTransactionType(final int id) { + return clientTransactionType(ClientTransactionType.fromInt(id)); + } + + public static EnumOptionData clientTransactionType(final ClientTransactionType clientTransactionType) { + final EnumOptionData optionData = new EnumOptionData(clientTransactionType.getValue().longValue(), clientTransactionType.getCode(), + clientTransactionType.toString()); + return optionData; + } + + public static List clientTransactionType(final ClientTransactionType[] clientTransactionTypes) { + final List optionDatas = new ArrayList<>(); + for (final ClientTransactionType clientTransaction : clientTransactionTypes) { + optionDatas.add(clientTransactionType(clientTransaction)); + } + return optionDatas; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java index 5c26af704..9ca9acbd1 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.portfolio.client.domain; +import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -42,4 +43,10 @@ public class ClientRepositoryWrapper { public void delete(final Client client) { this.repository.delete(client); } + + public Client getActiveClient(Long clientId) { + final Client client = this.findOneWithNotFoundDetection(clientId); + if (client.isNotActive()) { throw new ClientNotActiveException(client.getId()); } + return client; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransaction.java index 251291e33..46105543f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransaction.java @@ -18,9 +18,10 @@ 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.Money; import org.mifosplatform.organisation.office.domain.Office; -import org.mifosplatform.portfolio.loanaccount.domain.Loan; -import org.mifosplatform.portfolio.loanaccount.domain.LoanChargePaidBy; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -41,16 +42,15 @@ public class ClientTransaction extends AbstractPersistable { @JoinColumn(name = "payment_detail_id", nullable = true) private PaymentDetail paymentDetail; + @Column(name = "currency_code", length = 3) + private String currencyCode; + @Column(name = "transaction_type_enum", nullable = false) - private final Integer typeOf; + private Integer typeOf; @Temporal(TemporalType.DATE) @Column(name = "transaction_date", nullable = false) - private final Date dateOf; - - @Temporal(TemporalType.DATE) - @Column(name = "submitted_on_date", nullable = false) - private final Date submittedOnDate; + private Date dateOf; @Column(name = "amount", scale = 6, precision = 19, nullable = false) private BigDecimal amount; @@ -63,13 +63,51 @@ public class ClientTransaction extends AbstractPersistable { @Temporal(TemporalType.TIMESTAMP) @Column(name = "created_date", nullable = false) - private final Date createdDate; + private Date createdDate; @ManyToOne @JoinColumn(name = "appuser_id", nullable = true) - private final AppUser appUser; + private AppUser appUser; @LazyCollection(LazyCollectionOption.FALSE) - @OneToMany(cascade = CascadeType.ALL, mappedBy = "loanTransaction", orphanRemoval = true) - private Set loanChargesPaid = new HashSet<>(); + @OneToMany(cascade = CascadeType.ALL, mappedBy = "clientTransaction", orphanRemoval = true) + private Set clientChargePaidByCollection = new HashSet<>(); + + 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; + final String externalId = null; + return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.PAY_CHARGE.getValue(), date, amount, isReversed, + externalId, DateUtils.getDateOfTenant(), currencyCode, appUser); + } + + public static ClientTransaction waiver(final Client client, final Office office, final LocalDate date, final Money amount, + final String currencyCode, final AppUser appUser) { + 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, + externalId, DateUtils.getDateOfTenant(), currencyCode, appUser); + } + + public ClientTransaction(Client client, Office office, PaymentDetail paymentDetail, Integer typeOf, LocalDate transactionLocalDate, + Money amount, boolean reversed, String externalId, Date createdDate, String currencyCode, AppUser appUser) { + super(); + this.client = client; + this.office = office; + this.paymentDetail = paymentDetail; + this.typeOf = typeOf; + this.dateOf = transactionLocalDate.toDate(); + this.amount = amount.getAmount(); + this.reversed = reversed; + this.externalId = externalId; + this.createdDate = createdDate; + this.currencyCode = currencyCode; + this.appUser = appUser; + } + + public Set getClientChargePaidByCollection() { + return this.clientChargePaidByCollection; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionRepository.java new file mode 100644 index 000000000..a2077d7d7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionRepository.java @@ -0,0 +1,8 @@ +package org.mifosplatform.portfolio.client.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface ClientTransactionRepository extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionType.java new file mode 100644 index 000000000..91a7b971a --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientTransactionType.java @@ -0,0 +1,66 @@ +package org.mifosplatform.portfolio.client.domain; + +import java.util.HashMap; +import java.util.Map; + +public enum ClientTransactionType { + + PAY_CHARGE(1, "clientTransactionType.payCharge"), // + WAIVE_CHARGE(2, "clientTransactionType.waiveCharge"); + + private final Integer value; + private final String code; + + private ClientTransactionType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + private static final Map intToEnumMap = new HashMap<>(); + private static int minValue; + private static int maxValue; + + static { + int i = 0; + for (final ClientTransactionType type : ClientTransactionType.values()) { + if (i == 0) { + minValue = type.value; + } + intToEnumMap.put(type.value, type); + if (minValue >= type.value) { + minValue = type.value; + } + if (maxValue < type.value) { + maxValue = type.value; + } + i = i + 1; + } + } + + public static ClientTransactionType fromInt(final int i) { + final ClientTransactionType type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } + + public static int getMinValue() { + return minValue; + } + + public static int getMaxValue() { + return maxValue; + } + + @Override + public String toString() { + return name().toString(); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java index fa03aaf39..1bd8be483 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java @@ -17,6 +17,7 @@ import org.mifosplatform.portfolio.charge.service.ChargeEnumerations; 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; import org.springframework.jdbc.core.RowMapper; @@ -30,6 +31,7 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService; private final DropdownReadPlatformService dropdownReadPlatformService; + @Autowired public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context, final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService, final RoutingDataSource dataSource, final DropdownReadPlatformService dropdownReadPlatformService) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java index b7572c3f0..211d0991b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java @@ -1,9 +1,13 @@ package org.mifosplatform.portfolio.client.service; +import java.math.BigDecimal; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; @@ -13,9 +17,10 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; -import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepository; +import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; @@ -23,13 +28,14 @@ import org.mifosplatform.portfolio.client.api.ClientApiConstants; import org.mifosplatform.portfolio.client.data.ClientChargeDataValidator; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientCharge; -import org.mifosplatform.portfolio.client.domain.ClientChargeRepository; -import org.mifosplatform.portfolio.client.domain.ClientRepository; +import org.mifosplatform.portfolio.client.domain.ClientChargePaidBy; +import org.mifosplatform.portfolio.client.domain.ClientChargeRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; -import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; -import org.mifosplatform.portfolio.savings.data.SavingsAccountDataValidator; -import org.mifosplatform.portfolio.savings.domain.SavingsAccount; -import org.mifosplatform.portfolio.savings.domain.SavingsAccountCharge; +import org.mifosplatform.portfolio.client.domain.ClientTransaction; +import org.mifosplatform.portfolio.client.domain.ClientTransactionRepository; +import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; +import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; +import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -43,14 +49,17 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client private final ConfigurationDomainService configurationDomainService; private final HolidayRepositoryWrapper holidayRepository; private final WorkingDaysRepositoryWrapper workingDaysRepository; - private final ClientChargeRepository clientChargeRepository; + private final ClientChargeRepositoryWrapper clientChargeRepository; + private final ClientTransactionRepository clientTransactionRepository; + private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; @Autowired public ClientChargeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ChargeRepositoryWrapper chargeRepository, final ClientChargeDataValidator clientChargeDataValidator, final ClientRepositoryWrapper clientRepository, final HolidayRepositoryWrapper holidayRepositoryWrapper, - final ConfigurationDomainService configurationDomainService, final ClientChargeRepository clientChargeRepository, - final WorkingDaysRepositoryWrapper workingDaysRepository) { + final ConfigurationDomainService configurationDomainService, final ClientChargeRepositoryWrapper clientChargeRepository, + final WorkingDaysRepositoryWrapper workingDaysRepository, final ClientTransactionRepository clientTransactionRepository, + final PaymentDetailWritePlatformService paymentDetailWritePlatformService) { this.context = context; this.chargeRepository = chargeRepository; this.clientChargeDataValidator = clientChargeDataValidator; @@ -59,6 +68,8 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client this.configurationDomainService = configurationDomainService; this.clientChargeRepository = clientChargeRepository; this.workingDaysRepository = workingDaysRepository; + this.clientTransactionRepository = clientTransactionRepository; + this.paymentDetailWritePlatformService = paymentDetailWritePlatformService; } @Override @@ -66,17 +77,14 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client this.clientChargeDataValidator.validateAdd(command.json()); - final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); - checkClientActive(client); + final Client client = clientRepository.getActiveClient(clientId); final Long chargeDefinitionId = command.longValueOfParameterNamed(ClientApiConstants.chargeIdParamName); final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(chargeDefinitionId); final ClientCharge clientCharge = ClientCharge.createNew(client, charge, command); - final Locale locale = command.extractLocale(); final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()); - validateDueDateOnWorkingDay(clientCharge, fmt); this.clientChargeRepository.save(clientCharge); @@ -88,37 +96,109 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client .build(); } + @Override + public CommandProcessingResult payCharge(Long clientId, Long clientChargeId, JsonCommand command) { + this.clientChargeDataValidator.validateAdd(command.json()); + + final Client client = this.clientRepository.getActiveClient(clientId); + + final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId); + + final Locale locale = command.extractLocale(); + 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 = validatePaymentDateAndAmount(client, clientCharge, fmt, transactionDate, amountPaid); + + // pay the charge + clientCharge.pay(clientCharge.getCurrency(), chargePaid); + + // create Payment Transaction + final Map changes = new LinkedHashMap<>(); + final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + + ClientTransaction clientTransaction = ClientTransaction.payCharge(client, client.getOffice(), paymentDetail, transactionDate, + chargePaid, clientCharge.getCurrency().getCode(), getAppUserIfPresent()); + this.clientTransactionRepository.save(clientTransaction); + + // update charge paid by associations + final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, amountPaid); + clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); + + return new CommandProcessingResultBuilder() // + .withEntityId(clientCharge.getId()) // + .withOfficeId(clientCharge.getClient().getOffice().getId()) // + .withClientId(clientCharge.getClient().getId()) // + .build(); + + } + /** - * Ensures that the charge due date is not on a holiday or a non working day + * Validates transaction to ensure that
+ * charge is active
+ * transaction date is valid (between client activation and todays date) + *
+ * charge is not already paid or waived
+ * amount is not more than total due * - * @param savingsAccountCharge + * @param client + * @param clientCharge * @param fmt + * @param transactionDate + * @param amountPaid + * @return */ - private void validateDueDateOnWorkingDay(final SavingsAccountCharge savingsAccountCharge, final DateTimeFormatter fmt) { + private Money validatePaymentDateAndAmount(final Client client, final ClientCharge clientCharge, final DateTimeFormatter fmt, + final LocalDate transactionDate, final BigDecimal amountPaid) { final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); - if (savingsAccountCharge.getDueLocalDate() != null) { - // transaction date should not be on a holiday or non working day - if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() - && this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { - baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) - .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday"); - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } - } - if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() - && !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { - baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) - .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day"); - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } - } + 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 (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 + if (clientCharge.isWaived()) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived"); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } else if (clientCharge.isPaid()) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid"); + 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); } + } + return chargePaid; } + /** + * @param clientId + * @return + */ @Override public CommandProcessingResult updateCharge(Long clientId, JsonCommand command) { - // TODO Auto-generated method stub + this.clientChargeDataValidator.validateAdd(command.json()); + final Client client = clientRepository.getActiveClient(clientId); return null; } @@ -134,22 +214,73 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client return null; } - @Override - public CommandProcessingResult payCharge(Long clientId, Long clientChargeId, JsonCommand command) { - // TODO Auto-generated method stub - return null; - } - @Override public CommandProcessingResult inactivateCharge(Long clientId, Long clientChargeId) { // TODO Auto-generated method stub return null; } - private void checkClientActive(Client client) { - if (client != null) { - if (client.isNotActive()) { throw new ClientNotActiveException(client.getId()); } + /** + * Ensures that the charge due date is not on a holiday or a non working day + * + * @param clientCharge + * @param fmt + */ + private void validateDueDateOnWorkingDay(final ClientCharge clientCharge, final DateTimeFormatter fmt) { + validateActivityDateFallOnAWorkingDay(clientCharge.getDueLocalDate(), clientCharge.getOfficeId(), + ClientApiConstants.dueAsOfDateParamName, "charge.due.date.is.on.holiday", "charge.due.date.is.a.non.workingday", fmt); + } + + /** + * Ensures that the charge transaction date (for payments) is not on a + * holiday or a non working day + * + * @param savingsAccountCharge + * @param fmt + */ + private void validateTransactionDateOnWorkingDay(final LocalDate transactionDate, final ClientCharge clientCharge, + final DateTimeFormatter fmt) { + validateActivityDateFallOnAWorkingDay(transactionDate, clientCharge.getOfficeId(), ClientApiConstants.transactionDateParamName, + "transaction.not.allowed.transaction.date.is.on.holiday", "transaction.not.allowed.transaction.date.is.a.non.workingday", + fmt); + } + + /** + * @param date + * @param officeId + * @param jsonPropertyName + * @param errorMessageFragment + * @param fmt + */ + private void validateActivityDateFallOnAWorkingDay(final LocalDate date, final Long officeId, final String jsonPropertyName, + final String errorMessageFragmentForActivityOnHoliday, final String errorMessageFragmentForActivityOnNonWorkingDay, + final DateTimeFormatter fmt) { + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); + if (date != null) { + // transaction date should not be on a holiday or non working day + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() && this.holidayRepository.isHoliday(officeId, date)) { + baseDataValidator.reset().parameter(jsonPropertyName).value(date.toString(fmt)) + .failWithCodeNoParameterAddedToErrorCode(errorMessageFragmentForActivityOnHoliday); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } + + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(date)) { + baseDataValidator.reset().parameter(jsonPropertyName).value(date.toString(fmt)) + .failWithCodeNoParameterAddedToErrorCode(errorMessageFragmentForActivityOnNonWorkingDay); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } } } + private AppUser getAppUserIfPresent() { + AppUser user = null; + if (this.context != null) { + user = this.context.getAuthenticatedUserIfPresent(); + } + return user; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java new file mode 100644 index 000000000..7feb5a2b0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformService.java @@ -0,0 +1,16 @@ +package org.mifosplatform.portfolio.client.service; + +import java.util.Collection; + +import org.mifosplatform.portfolio.client.data.ClientTransactionData; +import org.springframework.transaction.annotation.Transactional; + +public interface ClientTransactionReadPlatformService { + + @Transactional(readOnly = true) + public Collection retrieveAllTransactions(final Long clientId); + + @Transactional(readOnly = true) + public ClientTransactionData retrieveTransaction(Long clientId, Long transactionId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java new file mode 100644 index 000000000..a905e77fc --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java @@ -0,0 +1,123 @@ +package org.mifosplatform.portfolio.client.service; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +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.paymentdetail.data.PaymentDetailData; +import org.mifosplatform.portfolio.paymenttype.data.PaymentTypeData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; + +public class ClientTransactionReadPlatformServiceImpl implements ClientTransactionReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final ClientTransactionMapper clientTransactionMapper; + + @Autowired + public ClientTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.clientTransactionMapper = new ClientTransactionMapper(); + + } + + private static final class ClientTransactionMapper implements RowMapper { + + private final String schemaSql; + + public ClientTransactionMapper() { + + final StringBuilder sqlBuilder = new StringBuilder(400); + sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, "); + 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("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( + "tr.currency_code as currencyCode, curr.decimal_places as currencyDigits, curr.currency_multiplesof as inMultiplesOf, "); + sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); + sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); + sqlBuilder.append("pt.value as paymentTypeName "); + sqlBuilder.append("from m_client c "); + sqlBuilder.append("join m_client_transaction tr on tr.client_id = c.id "); + sqlBuilder.append("join m_currency curr on curr.code = tr.currency_code "); + 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 "); + this.schemaSql = sqlBuilder.toString(); + } + + public String schema() { + return this.schemaSql; + } + + @Override + public ClientTransactionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + final Long id = rs.getLong("transactionId"); + final Long officeId = rs.getLong("officeId"); + final String officeName = rs.getString("officeName"); + final String externalId = rs.getString("externalId"); + final int transactionTypeInt = JdbcSupport.getInteger(rs, "transactionType"); + final EnumOptionData transactionType = ClientEnumerations.clientTransactionType(transactionTypeInt); + + final LocalDate date = JdbcSupport.getLocalDate(rs, "transactionDate"); + final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); + final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transactionAmount"); + final boolean reversed = rs.getBoolean("reversed"); + + PaymentDetailData paymentDetailData = null; + if (ClientTransactionType.fromInt(transactionType.getId().intValue()).equals(ClientTransactionType.PAY_CHARGE)) { + final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType"); + if (paymentTypeId != null) { + final String typeName = rs.getString("paymentTypeName"); + final PaymentTypeData paymentType = PaymentTypeData.instance(paymentTypeId, typeName); + final String accountNumber = rs.getString("accountNumber"); + final String checkNumber = rs.getString("checkNumber"); + final String routingCode = rs.getString("routingCode"); + final String receiptNumber = rs.getString("receiptNumber"); + final String bankNumber = rs.getString("bankNumber"); + paymentDetailData = new PaymentDetailData(id, paymentType, accountNumber, checkNumber, routingCode, receiptNumber, + bankNumber); + } + } + + 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"); + final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol, + currencyNameCode); + + return ClientTransactionData.create(id, officeId, officeName, transactionType, date, currency, paymentDetailData, amount, + externalId, submittedOnDate, reversed); + } + } + + @Override + public Collection 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 }); + } + + @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 }); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index d54033ac5..5ee801fb2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -2208,7 +2208,7 @@ public class SavingsAccount extends AbstractPersistable { } if (DateUtils.isDateInTheFuture(transactionDate)) { - baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getSubmittedOnLocalDate().toString(formatter)) + baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(formatter)) .failWithCodeNoParameterAddedToErrorCode("transaction.is.futureDate"); throw new PlatformApiDataValidationException(dataValidationErrors); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index b381e2ea7..52567e10e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -41,6 +41,7 @@ import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; import org.mifosplatform.infrastructure.jobs.exception.JobExecutionException; import org.mifosplatform.infrastructure.jobs.service.JobName; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; @@ -48,6 +49,7 @@ 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.staff.domain.Staff; +import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.mifosplatform.organisation.workingdays.service.WorkingDaysWritePlatformService; import org.mifosplatform.portfolio.account.PortfolioAccountType; import org.mifosplatform.portfolio.account.data.AccountTransferDTO; @@ -119,13 +121,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo private final AccountTransfersReadPlatformService accountTransfersReadPlatformService; private final ChargeRepositoryWrapper chargeRepository; private final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository; - private final HolidayWritePlatformService holidayWritePlatformService; - private final WorkingDaysWritePlatformService workingDaysWritePlatformService; private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; private final AccountTransfersWritePlatformService accountTransfersWritePlatformService; private final DepositAccountReadPlatformService depositAccountReadPlatformService; private final CalendarInstanceRepository calendarInstanceRepository; private final ConfigurationDomainService configurationDomainService; + private final HolidayRepositoryWrapper holidayRepository; + private final WorkingDaysRepositoryWrapper workingDaysRepository; @Autowired public DepositAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, @@ -139,9 +141,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final JournalEntryWritePlatformService journalEntryWritePlatformService, final DepositAccountDomainService depositAccountDomainService, final NoteRepository noteRepository, final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final ChargeRepositoryWrapper chargeRepository, - final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository, - final HolidayWritePlatformService holidayWritePlatformService, - final WorkingDaysWritePlatformService workingDaysWritePlatformService, + final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository, final HolidayRepositoryWrapper holidayRepository, + final WorkingDaysRepositoryWrapper workingDaysRepository, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, final AccountTransfersWritePlatformService accountTransfersWritePlatformService, final DepositAccountReadPlatformService depositAccountReadPlatformService, @@ -161,8 +162,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo this.accountTransfersReadPlatformService = accountTransfersReadPlatformService; this.chargeRepository = chargeRepository; this.savingsAccountChargeRepository = savingsAccountChargeRepository; - this.holidayWritePlatformService = holidayWritePlatformService; - this.workingDaysWritePlatformService = workingDaysWritePlatformService; + this.holidayRepository = holidayRepository; + this.workingDaysRepository = workingDaysRepository; this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; this.accountTransfersWritePlatformService = accountTransfersWritePlatformService; this.depositAccountReadPlatformService = depositAccountReadPlatformService; @@ -318,7 +319,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final boolean isInterestTransfer = false; if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate())) { final LocalDate today = DateUtils.getLocalDateOfTenant(); - account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); } else { final LocalDate today = DateUtils.getLocalDateOfTenant(); account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, @@ -364,8 +366,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final LocalDate depositAmountUpdateEffectiveFromDate = command .localDateValueOfParameterNamed(DepositsApiConstants.effectiveDateParamName); - final RecurringDepositAccount recurringDepositAccount = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom( - savingsId, DepositAccountType.RECURRING_DEPOSIT); + final RecurringDepositAccount recurringDepositAccount = (RecurringDepositAccount) this.depositAccountAssembler + .assembleFrom(savingsId, DepositAccountType.RECURRING_DEPOSIT); DepositAccountRecurringDetail recurringDetail = recurringDepositAccount.getRecurringDetail(); Map changes = recurringDetail.updateMandatoryRecommendedDepositAmount(mandatoryRecommendedDepositAmount, depositAmountUpdateEffectiveFromDate, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); @@ -419,7 +421,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo @Transactional @Override - public CommandProcessingResult withdrawal(final Long savingsId, final JsonCommand command, final DepositAccountType depositAccountType) { + public CommandProcessingResult withdrawal(final Long savingsId, final JsonCommand command, + final DepositAccountType depositAccountType) { boolean isRegularTransaction = true; @@ -560,10 +563,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo .findOneByIdAndSavingsAccountId(transactionId, savingsId); if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); } - if (!allowAccountTransferModification - && this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( - "error.msg.recurring.deposit.account.transfer.transaction.update.not.allowed", "Recurring deposit account transaction:" - + transactionId + " update not allowed as it involves in account transfer", transactionId); } + if (!allowAccountTransferModification && this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, + PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( + "error.msg.recurring.deposit.account.transfer.transaction.update.not.allowed", + "Recurring deposit account transaction:" + transactionId + " update not allowed as it involves in account transfer", + transactionId); } final LocalDate today = DateUtils.getLocalDateOfTenant(); final MathContext mc = MathContext.DECIMAL64; @@ -584,7 +588,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo account.validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.undoTransactionAction); // account.activateAccountBasedOnBalance(); final boolean isPreMatureClosure = false; - account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); final LocalDate overdueUptoDate = DateUtils.getLocalDateOfTenant(); @@ -627,12 +632,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo .findOneByIdAndSavingsAccountId(transactionId, savingsId); if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); } - if (!(savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal()) || savingsAccountTransaction.isReversed()) { throw new TransactionUpdateNotAllowedException( - savingsId, transactionId); } + if (!(savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal()) + || savingsAccountTransaction.isReversed()) { throw new TransactionUpdateNotAllowedException(savingsId, transactionId); } - if (this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( - "error.msg.saving.account.transfer.transaction.update.not.allowed", "Deposit account transaction:" + transactionId - + " update not allowed as it involves in account transfer", transactionId); } + if (this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, + PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( + "error.msg.saving.account.transfer.transaction.update.not.allowed", + "Deposit account transaction:" + transactionId + " update not allowed as it involves in account transfer", + transactionId); } final LocalDate today = DateUtils.getLocalDateOfTenant(); @@ -995,15 +1002,15 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo if (savingsAccountCharge.getDueLocalDate() != null) { // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -1050,15 +1057,15 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -1088,8 +1095,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); // Get Savings account from savings charge final SavingsAccount account = savingsAccountCharge.savingsAccount(); @@ -1134,8 +1141,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsAccountId, depositAccountType); checkClientOrGroupActive(savingsAccount); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); savingsAccount.removeCharge(savingsAccountCharge); this.savingAccountRepository.saveAndFlush(savingsAccount); @@ -1161,23 +1168,23 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(amountParamName); final LocalDate transactionDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(SAVINGS_ACCOUNT_RESOURCE_NAME); // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(transactionDate)) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(transactionDate)) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -1200,8 +1207,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo @SuppressWarnings("unused") final DepositAccountType depositAccountType) { // always use current date as transaction date for batch job final LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, accountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, accountId); final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy"); @@ -1289,8 +1296,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo @Override public SavingsAccountTransaction mandatorySavingsAccountDeposit(final SavingsAccountTransactionDTO accountTransactionDTO) { boolean isRegularTransaction = false; - final RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler.assembleFrom( - accountTransactionDTO.getSavingsAccountId(), DepositAccountType.RECURRING_DEPOSIT); + 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); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 86a8a990a..925a0a27f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -40,7 +40,7 @@ import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.jobs.annotation.CronTarget; import org.mifosplatform.infrastructure.jobs.service.JobName; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService; +import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; @@ -48,7 +48,7 @@ import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.office.domain.Office; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; -import org.mifosplatform.organisation.workingdays.service.WorkingDaysWritePlatformService; +import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.mifosplatform.portfolio.account.PortfolioAccountType; import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService; import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService; @@ -111,8 +111,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService; private final ChargeRepositoryWrapper chargeRepository; private final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository; - private final HolidayWritePlatformService holidayWritePlatformService; - private final WorkingDaysWritePlatformService workingDaysWritePlatformService; + private final HolidayRepositoryWrapper holidayRepository; + private final WorkingDaysRepositoryWrapper workingDaysRepository; private final ConfigurationDomainService configurationDomainService; @Autowired @@ -126,11 +126,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper, final JournalEntryWritePlatformService journalEntryWritePlatformService, final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository, - final AccountTransfersReadPlatformService accountTransfersReadPlatformService, + final AccountTransfersReadPlatformService accountTransfersReadPlatformService, final HolidayRepositoryWrapper holidayRepository, + final WorkingDaysRepositoryWrapper workingDaysRepository, final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService, final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository, - final HolidayWritePlatformService holidayWritePlatformService, - final WorkingDaysWritePlatformService workingDaysWritePlatformService, final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountRepositoryWrapper savingsRepository, final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService) { this.context = context; @@ -148,8 +147,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService; this.chargeRepository = chargeRepository; this.savingsAccountChargeRepository = savingsAccountChargeRepository; - this.holidayWritePlatformService = holidayWritePlatformService; - this.workingDaysWritePlatformService = workingDaysWritePlatformService; + this.holidayRepository = holidayRepository; + this.workingDaysRepository = workingDaysRepository; this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.savingsRepository = savingsRepository; this.staffRepository = staffRepository; @@ -296,8 +295,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi AppUser user = getAppUserIfPresent(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, accountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, accountId); final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy"); @@ -389,8 +388,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi @CronTarget(jobName = JobName.POST_INTEREST_FOR_SAVINGS) @Override public void postInterestForAccounts() { - final List savingsAccounts = this.savingAccountRepository.findSavingAccountByStatus(SavingsAccountStatusType.ACTIVE - .getValue()); + final List savingsAccounts = this.savingAccountRepository + .findSavingAccountByStatus(SavingsAccountStatusType.ACTIVE.getValue()); for (final SavingsAccount savingsAccount : savingsAccounts) { this.savingAccountAssembler.assignSavingAccountHelpers(savingsAccount); postInterest(savingsAccount); @@ -415,13 +414,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); } if (!allowAccountTransferModification - && this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( - "error.msg.saving.account.transfer.transaction.update.not.allowed", "Savings account transaction:" + transactionId - + " update not allowed as it involves in account transfer", transactionId); } + && this.accountTransfersReadPlatformService + .isAccountTransfer(transactionId, + PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( + "error.msg.saving.account.transfer.transaction.update.not.allowed", "Savings account transaction:" + + transactionId + " update not allowed as it involves in account transfer", + transactionId); } - if (!account.allowModify()) { throw new PlatformServiceUnavailableException( - "error.msg.saving.account.transaction.update.not.allowed", "Savings account transaction:" + transactionId - + " update not allowed for this savings type", transactionId); } + if (!account + .allowModify()) { throw new PlatformServiceUnavailableException("error.msg.saving.account.transaction.update.not.allowed", + "Savings account transaction:" + transactionId + " update not allowed for this savings type", transactionId); } final LocalDate today = DateUtils.getLocalDateOfTenant(); final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN); @@ -475,12 +477,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .findOneByIdAndSavingsAccountId(transactionId, savingsId); if (savingsAccountTransaction == null) { throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId); } - if (!(savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal()) || savingsAccountTransaction.isReversed()) { throw new TransactionUpdateNotAllowedException( - savingsId, transactionId); } + if (!(savingsAccountTransaction.isDeposit() || savingsAccountTransaction.isWithdrawal()) + || savingsAccountTransaction.isReversed()) { throw new TransactionUpdateNotAllowedException(savingsId, transactionId); } - if (this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( - "error.msg.saving.account.transfer.transaction.update.not.allowed", "Savings account transaction:" + transactionId - + " update not allowed as it involves in account transfer", transactionId); } + if (this.accountTransfersReadPlatformService.isAccountTransfer(transactionId, + PortfolioAccountType.SAVINGS)) { throw new PlatformServiceUnavailableException( + "error.msg.saving.account.transfer.transaction.update.not.allowed", + "Savings account transaction:" + transactionId + " update not allowed as it involves in account transfer", + transactionId); } this.savingsAccountTransactionDataValidator.validate(command); @@ -490,9 +494,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi if (account.isNotActive()) { throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction); } - if (!account.allowModify()) { throw new PlatformServiceUnavailableException( - "error.msg.saving.account.transaction.update.not.allowed", "Savings account transaction:" + transactionId - + " update not allowed for this savings type", transactionId); } + if (!account + .allowModify()) { throw new PlatformServiceUnavailableException("error.msg.saving.account.transaction.update.not.allowed", + "Savings account transaction:" + transactionId + " update not allowed for this savings type", transactionId); } final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); @@ -762,15 +766,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi if (savingsAccountCharge.getDueLocalDate() != null) { // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -817,15 +821,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -854,8 +858,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); // Get Savings account from savings charge final SavingsAccount account = savingsAccountCharge.savingsAccount(); @@ -900,8 +904,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId); checkClientOrGroupActive(savingsAccount); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); savingsAccount.removeCharge(savingsAccountCharge); this.savingAccountRepository.saveAndFlush(savingsAccount); @@ -926,23 +930,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final BigDecimal amountPaid = command.bigDecimalValueOfParameterNamed(amountParamName); final LocalDate transactionDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) .resource(SAVINGS_ACCOUNT_RESOURCE_NAME); // transaction date should not be on a holiday or non working day - if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday() - && this.holidayWritePlatformService.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) { + if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled() + && this.holidayRepository.isHoliday(savingsAccountCharge.savingsAccount().officeId(), transactionDate)) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.on.holiday"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay() - && !this.workingDaysWritePlatformService.isWorkingDay(transactionDate)) { + if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled() + && !this.workingDaysRepository.isWorkingDay(transactionDate)) { baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt)) .failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.a.nonworking.day"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } @@ -966,8 +970,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi AppUser user = null; final LocalDate transactionDate = DateUtils.getLocalDateOfTenant(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, accountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, accountId); final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy"); fmt.withZone(DateUtils.getDateTimeZoneOfTenant()); @@ -1032,8 +1036,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi this.context.authenticatedUser(); - final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection( - savingsAccountChargeId, savingsAccountId); + final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository + .findOneWithNotFoundDetection(savingsAccountChargeId, savingsAccountId); final SavingsAccount account = savingsAccountCharge.savingsAccount(); this.savingAccountAssembler.assignSavingAccountHelpers(account); @@ -1111,16 +1115,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final LocalDate dateOfSavingsOfficerAssignment = command.localDateValueOfParameterNamed("assignmentDate"); if (fromSavingsOfficerId != null) { - fromSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(fromSavingsOfficerId, savingsForUpdate - .office().getHierarchy()); + fromSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(fromSavingsOfficerId, + savingsForUpdate.office().getHierarchy()); } if (toSavingsOfficerId != null) { - toSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(toSavingsOfficerId, savingsForUpdate - .office().getHierarchy()); + toSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(toSavingsOfficerId, + savingsForUpdate.office().getHierarchy()); actualChanges.put("toSavingsOfficerId", toSavingsOfficer.getId()); } - if (!savingsForUpdate.hasSavingsOfficer(fromSavingsOfficer)) { throw new SavingsOfficerAssignmentException(savingsAccountId, - fromSavingsOfficerId); } + if (!savingsForUpdate.hasSavingsOfficer( + fromSavingsOfficer)) { throw new SavingsOfficerAssignmentException(savingsAccountId, fromSavingsOfficerId); } savingsForUpdate.reassignSavingsOfficer(toSavingsOfficer, dateOfSavingsOfficerAssignment); diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V266__client_fees.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V266__client_fees.sql new file mode 100644 index 000000000..1eef3622c --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V266__client_fees.sql @@ -0,0 +1,9 @@ +-- add permissions for Client Fees + +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'CREATE_CLIENTCHARGE', 'CLIENTCHARGE', 'CREATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'DELETE_CLIENTCHARGE', 'CLIENTCHARGE', 'DELETE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'WAIVE_CLIENTCHARGE', 'CLIENTCHARGE', 'WAIVE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'PAY_CLIENTCHARGE', 'CLIENTCHARGE', 'PAY', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'INACTIVATE_CLIENTCHARGE', 'CLIENTCHARGE', 'INACTIVATE', 0); +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'UPDATE_CLIENTCHARGE', 'CLIENTCHARGE', 'UPDATE', 0); +