FINERACT-1932: Fineract modularization - fineract-charge

This commit is contained in:
Jose Alberto Hernandez
2024-05-21 22:53:36 +02:00
committed by Adam Saghy
parent e13a9cba01
commit a3fb836b73
53 changed files with 306 additions and 8 deletions
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.api;
public final class ChargesApiConstants {
private ChargesApiConstants() {
}
public static final String glAccountIdParamName = "incomeAccountId";
public static final String taxGroupIdParamName = "taxGroupId";
}
@@ -0,0 +1,187 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
import org.springframework.stereotype.Component;
@Path("/v1/charges")
@Component
@Tag(name = "Charges", description = "Its typical for MFIs to add extra costs for their financial products. These are typically Fees or Penalties.\n"
+ "\n" + "A Charge on fineract platform is what we use to model both Fees and Penalties.\n" + "\n"
+ "At present we support defining charges for use with Client accounts and both loan and saving products.")
@RequiredArgsConstructor
public class ChargesApiResource {
private static final Set<String> CHARGES_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "name", "amount", "currency", "penalty",
"active", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions",
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions", "loanChargeCalculationTypeOptions",
"loanChargeTimeTypeOptions", "savingsChargeCalculationTypeOptions", "savingsChargeTimeTypeOptions", "incomeAccount",
"clientChargeCalculationTypeOptions", "clientChargeTimeTypeOptions"));
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "CHARGE";
private final PlatformSecurityContext context;
private final ChargeReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<ChargeData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Charges", description = "Returns the list of defined charges.\n" + "\n" + "Example Requests:\n" + "\n"
+ "charges")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesResponse.class)))) })
public String retrieveAllCharges(@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
final Collection<ChargeData> charges = this.readPlatformService.retrieveAllCharges();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, charges, CHARGES_DATA_PARAMETERS);
}
@GET
@Path("{chargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Charge", description = "Returns the details of a defined Charge.\n" + "\n" + "Example Requests:\n"
+ "\n" + "charges/1")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesResponse.class))) })
public String retrieveCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId,
@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
ChargeData charge = this.readPlatformService.retrieveCharge(chargeId);
if (settings.isTemplate()) {
final ChargeData templateData = this.readPlatformService.retrieveNewChargeDetails();
charge = ChargeData.withTemplate(charge, templateData);
}
return this.toApiJsonSerializer.serialize(settings, charge, CHARGES_DATA_PARAMETERS);
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Charge Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n"
+ "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "\n" + "charges/template\n")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesTemplateResponse.class))) })
public String retrieveNewChargeDetails(@Context final UriInfo uriInfo) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
final ChargeData charge = this.readPlatformService.retrieveNewChargeDetails();
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, charge, CHARGES_DATA_PARAMETERS);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create/Define a Charge", description = "Define a new charge that can later be associated with loans and savings through their respective product definitions or directly on each account instance.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PostChargesRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PostChargesResponse.class))) })
public String createCharge(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createCharge().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{chargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update a Charge", description = "Updates the details of a Charge.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PutChargesChargeIdRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PutChargesChargeIdResponse.class))) })
public String updateCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId,
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCharge(chargeId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@DELETE
@Path("{chargeId}")
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete a Charge", description = "Deletes a Charge.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.DeleteChargesChargeIdResponse.class))) })
public String deleteCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCharge(chargeId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -0,0 +1,237 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.api;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Set;
/**
* Created by Chirag Gupta on 12/01/17.
*/
final class ChargesApiResourceSwagger {
@Schema(description = "GetChargesResponse")
public static final class GetChargesResponse {
private GetChargesResponse() {}
static final class GetChargesCurrencyResponse {
@Schema(example = "USD")
public String code;
@Schema(example = "US Dollar")
public String name;
@Schema(example = "2")
public Integer decimalPlaces;
@Schema(example = "$")
public String displaySymbol;
@Schema(example = "currency.USD")
public String nameCode;
@Schema(example = "US Dollar ($)")
public String displayLabel;
}
static final class GetChargesTimeTypeResponse {
private GetChargesTimeTypeResponse() {}
@Schema(example = "1")
public Long id;
@Schema(example = "chargeTimeType.disbursement")
public String code;
@Schema(example = "Disbursement")
public String description;
}
static final class GetChargesAppliesToResponse {
private GetChargesAppliesToResponse() {}
@Schema(example = "1")
public Long id;
@Schema(example = "chargeAppliesTo.loan")
public String code;
@Schema(example = "Loan")
public String description;
}
static final class GetChargesCalculationTypeResponse {
private GetChargesCalculationTypeResponse() {}
@Schema(example = "1")
public Long id;
@Schema(example = "chargeCalculationType.flat")
public String code;
@Schema(example = "Flat")
public String description;
}
static final class GetChargesPaymentModeResponse {
private GetChargesPaymentModeResponse() {}
@Schema(example = "1")
public Long id;
@Schema(example = "chargepaymentmode.accounttransfer")
public String code;
@Schema(example = "Account Transfer")
public String description;
}
@Schema(example = "1")
public Long id;
@Schema(example = "Loan Service fee")
public String name;
@Schema(example = "true")
public boolean active;
@Schema(example = "false")
public boolean penalty;
public GetChargesCurrencyResponse currency;
@Schema(example = "230.56")
public Double amount;
public GetChargesTimeTypeResponse chargeTimeType;
public GetChargesAppliesToResponse chargeAppliesTo;
public GetChargesCalculationTypeResponse chargeCalculationType;
public GetChargesPaymentModeResponse chargePaymentMode;
}
@Schema(description = "PostChargesRequest")
public static final class PostChargesRequest {
private PostChargesRequest() {}
@Schema(example = "Loan Service fee")
public String name;
@Schema(example = "1")
public Integer chargeAppliesTo;
@Schema(example = "USD")
public String currencyCode;
@Schema(example = "en")
public String locale;
@Schema(example = "230.56")
public Double amount;
@Schema(example = "1")
public Integer chargeTimeType;
@Schema(example = "1")
public Integer chargeCalculationType;
@Schema(example = "1")
public Integer chargePaymentMode;
@Schema(example = "true")
public boolean active;
@Schema(example = "dd MMMM")
public String monthDayFormat;
@Schema(example = "false")
public boolean penalty;
}
@Schema(description = "PostChargesResponse")
public static final class PostChargesResponse {
private PostChargesResponse() {}
@Schema(example = "1")
public Long resourceId;
}
@Schema(description = "PutChargesChargeIdRequest")
public static final class PutChargesChargeIdRequest {
private PutChargesChargeIdRequest() {}
@Schema(example = "Loan service fee(changed)")
public String name;
}
@Schema(description = "PutChargesChargeIdResponse")
public static final class PutChargesChargeIdResponse {
private PutChargesChargeIdResponse() {}
@Schema(example = "1")
public Long resourceId;
public PutChargesChargeIdRequest changes;
}
@Schema(description = "DeleteChargesChargeIdResponse")
public static final class DeleteChargesChargeIdResponse {
private DeleteChargesChargeIdResponse() {}
@Schema(example = "1")
public Long resourceId;
}
@Schema(description = "GetChargesTemplateResponse")
public static final class GetChargesTemplateResponse {
private GetChargesTemplateResponse() {}
static final class GetChargesTemplateLoanChargeCalculationTypeOptions {
private GetChargesTemplateLoanChargeCalculationTypeOptions() {}
@Schema(example = "1")
public Long id;
@Schema(example = "chargeCalculationType.flat")
public String code;
@Schema(example = "Flat")
public String description;
}
static final class GetChargesTemplateLoanChargeTimeTypeOptions {
private GetChargesTemplateLoanChargeTimeTypeOptions() {}
@Schema(example = "2")
public Long id;
@Schema(example = "chargeTimeType.specifiedDueDate")
public String code;
@Schema(example = "Specified due date")
public String description;
}
static final class GetChargesTemplateFeeFrequencyOptions {
private GetChargesTemplateFeeFrequencyOptions() {}
@Schema(example = "0")
public Long id;
@Schema(example = "loanTermFrequency.periodFrequencyType.days")
public String code;
@Schema(example = "Days")
public String description;
}
@Schema(example = "false")
public boolean active;
@Schema(example = "false")
public boolean penalty;
public Set<GetChargesResponse.GetChargesCurrencyResponse> currencyOptions;
public Set<GetChargesResponse.GetChargesCalculationTypeResponse> chargeCalculationTypeOptions;
public Set<GetChargesResponse.GetChargesAppliesToResponse> chargeAppliesToOptions;
public Set<GetChargesResponse.GetChargesTimeTypeResponse> chargeTimeTypeOptions;
public Set<GetChargesResponse.GetChargesPaymentModeResponse> chargePaymentModeOptions;
public Set<GetChargesTemplateLoanChargeCalculationTypeOptions> loanChargeCalculationTypeOptions;
public Set<GetChargesTemplateLoanChargeTimeTypeOptions> loanChargeTimeTypeOptions;
public Set<GetChargesTemplateLoanChargeCalculationTypeOptions> savingsChargeCalculationTypeOptions;
public Set<GetChargesTemplateLoanChargeTimeTypeOptions> savingsChargeTimeTypeOptions;
public Set<GetChargesTemplateFeeFrequencyOptions> feeFrequencyOptions;
}
}
@@ -0,0 +1,783 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.math.BigDecimal;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.portfolio.charge.api.ChargesApiConstants;
import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.exception.ChargeDueAtDisbursementCannotBePenaltyException;
import org.apache.fineract.portfolio.charge.exception.ChargeMustBePenaltyException;
import org.apache.fineract.portfolio.charge.exception.ChargeParameterUpdateNotSupportedException;
import org.apache.fineract.portfolio.charge.service.ChargeEnumerations;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentType;
import org.apache.fineract.portfolio.tax.data.TaxGroupData;
import org.apache.fineract.portfolio.tax.domain.TaxGroup;
@Entity
@Table(name = "m_charge", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name") })
public class Charge extends AbstractPersistableCustom {
@Column(name = "name", length = 100)
private String name;
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
private BigDecimal amount;
@Column(name = "currency_code", length = 3)
private String currencyCode;
@Column(name = "charge_applies_to_enum", nullable = false)
private Integer chargeAppliesTo;
@Column(name = "charge_time_enum", nullable = false)
private Integer chargeTimeType;
@Column(name = "charge_calculation_enum")
private Integer chargeCalculation;
@Column(name = "charge_payment_mode_enum", nullable = true)
private Integer chargePaymentMode;
@Column(name = "fee_on_day", nullable = true)
private Integer feeOnDay;
@Column(name = "fee_interval", nullable = true)
private Integer feeInterval;
@Column(name = "fee_on_month", nullable = true)
private Integer feeOnMonth;
@Column(name = "is_penalty", nullable = false)
private boolean penalty;
@Column(name = "is_active", nullable = false)
private boolean active;
@Column(name = "is_deleted", nullable = false)
private boolean deleted = false;
@Column(name = "min_cap", scale = 6, precision = 19, nullable = true)
private BigDecimal minCap;
@Column(name = "max_cap", scale = 6, precision = 19, nullable = true)
private BigDecimal maxCap;
@Column(name = "fee_frequency", nullable = true)
private Integer feeFrequency;
@Column(name = "is_free_withdrawal", nullable = false)
private boolean enableFreeWithdrawal;
@Column(name = "free_withdrawal_charge_frequency", nullable = true)
private Integer freeWithdrawalFrequency;
@Column(name = "restart_frequency", nullable = true)
private Integer restartFrequency;
@Column(name = "restart_frequency_enum", nullable = true)
private Integer restartFrequencyEnum;
@Column(name = "is_payment_type", nullable = false)
private boolean enablePaymentType;
@ManyToOne
@JoinColumn(name = "payment_type_id", nullable = false)
private PaymentType paymentType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "income_or_liability_account_id")
private GLAccount account;
@ManyToOne
@JoinColumn(name = "tax_group_id")
private TaxGroup taxGroup;
public static Charge fromJson(final JsonCommand command, final GLAccount account, final TaxGroup taxGroup,
final PaymentType paymentType) {
final String name = command.stringValueOfParameterNamed("name");
final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
final ChargeAppliesTo chargeAppliesTo = ChargeAppliesTo.fromInt(command.integerValueOfParameterNamed("chargeAppliesTo"));
final ChargeTimeType chargeTimeType = ChargeTimeType.fromInt(command.integerValueOfParameterNamed("chargeTimeType"));
final ChargeCalculationType chargeCalculationType = ChargeCalculationType
.fromInt(command.integerValueOfParameterNamed("chargeCalculationType"));
final Integer chargePaymentMode = command.integerValueOfParameterNamed("chargePaymentMode");
final ChargePaymentMode paymentMode = chargePaymentMode == null ? null : ChargePaymentMode.fromInt(chargePaymentMode);
final boolean penalty = command.booleanPrimitiveValueOfParameterNamed("penalty");
final boolean active = command.booleanPrimitiveValueOfParameterNamed("active");
final MonthDay feeOnMonthDay = command.extractMonthDayNamed("feeOnMonthDay");
final Integer feeInterval = command.integerValueOfParameterNamed("feeInterval");
final BigDecimal minCap = command.bigDecimalValueOfParameterNamed("minCap");
final BigDecimal maxCap = command.bigDecimalValueOfParameterNamed("maxCap");
final Integer feeFrequency = command.integerValueOfParameterNamed("feeFrequency");
boolean enableFreeWithdrawalCharge = false;
enableFreeWithdrawalCharge = command.booleanPrimitiveValueOfParameterNamed("enableFreeWithdrawalCharge");
boolean enablePaymentType = false;
enablePaymentType = command.booleanPrimitiveValueOfParameterNamed("enablePaymentType");
Integer freeWithdrawalFrequency = null;
Integer restartCountFrequency = null;
PeriodFrequencyType countFrequencyType = null;
if (enableFreeWithdrawalCharge) {
freeWithdrawalFrequency = command.integerValueOfParameterNamed("freeWithdrawalFrequency");
restartCountFrequency = command.integerValueOfParameterNamed("restartCountFrequency");
countFrequencyType = PeriodFrequencyType.fromInt(command.integerValueOfParameterNamed("countFrequencyType"));
}
return new Charge(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculationType, penalty, active, paymentMode,
feeOnMonthDay, feeInterval, minCap, maxCap, feeFrequency, enableFreeWithdrawalCharge, freeWithdrawalFrequency,
restartCountFrequency, countFrequencyType, account, taxGroup, enablePaymentType, paymentType);
}
protected Charge() {}
private Charge(final String name, final BigDecimal amount, final String currencyCode, final ChargeAppliesTo chargeAppliesTo,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculationType, final boolean penalty, final boolean active,
final ChargePaymentMode paymentMode, final MonthDay feeOnMonthDay, final Integer feeInterval, final BigDecimal minCap,
final BigDecimal maxCap, final Integer feeFrequency, final boolean enableFreeWithdrawalCharge,
final Integer freeWithdrawalFrequency, final Integer restartFrequency, final PeriodFrequencyType restartFrequencyEnum,
final GLAccount account, final TaxGroup taxGroup, final boolean enablePaymentType, final PaymentType paymentType) {
this.name = name;
this.amount = amount;
this.currencyCode = currencyCode;
this.chargeAppliesTo = chargeAppliesTo.getValue();
this.chargeTimeType = chargeTime.getValue();
this.chargeCalculation = chargeCalculationType.getValue();
this.penalty = penalty;
this.active = active;
this.account = account;
this.taxGroup = taxGroup;
this.chargePaymentMode = paymentMode == null ? null : paymentMode.getValue();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges");
if (isMonthlyFee() || isAnnualFee()) {
this.feeOnMonth = feeOnMonthDay.getMonthValue();
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
}
this.feeInterval = feeInterval;
this.feeFrequency = feeFrequency;
if (isSavingsCharge()) {
// TODO vishwas, this validation seems unnecessary as identical
// validation is performed in the write service
if (!isAllowedSavingsChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
}
// TODO vishwas, this validation seems unnecessary as identical
// validation is performed in the writeservice
if (!isAllowedSavingsChargeCalculationType()) {
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
}
if (!(ChargeTimeType.fromInt(getChargeTimeType()).isWithdrawalFee()
|| ChargeTimeType.fromInt(getChargeTimeType()).isSavingsNoActivityFee())
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
.failWithCodeNoParameterAddedToErrorCode(
"savings.charge.calculation.type.percentage.allowed.only.for.withdrawal.or.NoActivity");
}
if (enableFreeWithdrawalCharge) {
this.enableFreeWithdrawal = true;
this.freeWithdrawalFrequency = freeWithdrawalFrequency;
this.restartFrequency = restartFrequency;
this.restartFrequencyEnum = restartFrequencyEnum.getValue();
}
if (enablePaymentType) {
if (paymentType != null) {
this.enablePaymentType = true;
this.paymentType = paymentType;
}
}
} else if (isLoanCharge()) {
if (penalty && (chargeTime.isTimeOfDisbursement() || chargeTime.isTrancheDisbursement())) {
throw new ChargeDueAtDisbursementCannotBePenaltyException(name);
}
if (!penalty && chargeTime.isOverdueInstallment()) {
throw new ChargeMustBePenaltyException(name);
}
// TODO vishwas, this validation seems unnecessary as identical
// validation is performed in the write service
if (!isAllowedLoanChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
}
}
if (isPercentageOfApprovedAmount()) {
this.minCap = minCap;
this.maxCap = maxCap;
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
public String getName() {
return this.name;
}
public BigDecimal getAmount() {
return this.amount;
}
public String getCurrencyCode() {
return this.currencyCode;
}
public Integer getChargeTimeType() {
return this.chargeTimeType;
}
public Integer getChargeCalculation() {
return this.chargeCalculation;
}
public boolean isActive() {
return this.active;
}
public boolean isPenalty() {
return this.penalty;
}
public boolean isDeleted() {
return this.deleted;
}
public boolean isLoanCharge() {
return ChargeAppliesTo.fromInt(this.chargeAppliesTo).isLoanCharge();
}
public boolean isAllowedLoanChargeTime() {
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedLoanChargeTime();
}
public boolean isAllowedClientChargeTime() {
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedClientChargeTime();
}
public boolean isSavingsCharge() {
return ChargeAppliesTo.fromInt(this.chargeAppliesTo).isSavingsCharge();
}
public boolean isClientCharge() {
return ChargeAppliesTo.fromInt(this.chargeAppliesTo).isClientCharge();
}
public boolean isAllowedSavingsChargeTime() {
return ChargeTimeType.fromInt(this.chargeTimeType).isAllowedSavingsChargeTime();
}
public boolean isAllowedSavingsChargeCalculationType() {
return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedSavingsChargeCalculationType();
}
public boolean isAllowedClientChargeCalculationType() {
return ChargeCalculationType.fromInt(this.chargeCalculation).isAllowedClientChargeCalculationType();
}
public boolean isPercentageOfApprovedAmount() {
return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfAmount();
}
public boolean isPercentageOfDisbursementAmount() {
return ChargeCalculationType.fromInt(this.chargeCalculation).isPercentageOfDisbursementAmount();
}
public BigDecimal getMinCap() {
return this.minCap;
}
public BigDecimal getMaxCap() {
return this.maxCap;
}
public boolean isEnableFreeWithdrawal() {
return this.enableFreeWithdrawal;
}
public boolean isEnablePaymentType() {
return this.enablePaymentType;
}
public Integer getFrequencyFreeWithdrawalCharge() {
return this.freeWithdrawalFrequency;
}
public Integer getRestartFrequency() {
return this.restartFrequency;
}
public Integer getRestartFrequencyEnum() {
return this.restartFrequencyEnum;
}
public PaymentType getPaymentType() {
return this.paymentType;
}
public void setPaymentType(PaymentType paymentType) {
this.paymentType = paymentType;
}
private Long getPaymentTypeId() {
Long paymentTypeId = null;
if (this.paymentType != null) {
paymentTypeId = this.paymentType.getId();
}
return paymentTypeId;
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
final Locale locale = command.extractLocale();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charges");
final String nameParamName = "name";
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(nameParamName);
actualChanges.put(nameParamName, newValue);
this.name = newValue;
}
final String currencyCodeParamName = "currencyCode";
if (command.isChangeInStringParameterNamed(currencyCodeParamName, this.currencyCode)) {
final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName);
actualChanges.put(currencyCodeParamName, newValue);
this.currencyCode = newValue;
}
final String amountParamName = "amount";
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName, locale);
actualChanges.put(amountParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.amount = newValue;
}
final String chargeTimeParamName = "chargeTimeType";
if (command.isChangeInIntegerParameterNamed(chargeTimeParamName, this.chargeTimeType)) {
final Integer newValue = command.integerValueOfParameterNamed(chargeTimeParamName);
actualChanges.put(chargeTimeParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.chargeTimeType = ChargeTimeType.fromInt(newValue).getValue();
if (isSavingsCharge()) {
if (!isAllowedSavingsChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.savings");
}
// if charge time is changed to monthly then validate for
// feeOnMonthDay and feeInterval
if (isMonthlyFee()) {
final MonthDay monthDay = command.extractMonthDayNamed("feeOnMonthDay");
baseDataValidator.reset().parameter("feeOnMonthDay").value(monthDay).notNull();
final Integer feeInterval = command.integerValueOfParameterNamed("feeInterval");
baseDataValidator.reset().parameter("feeInterval").value(feeInterval).notNull().inMinMaxRange(1, 12);
}
} else if (isLoanCharge()) {
if (!isAllowedLoanChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.loan");
}
} else if (isClientCharge()) {
if (!isAllowedLoanChargeTime()) {
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.time.for.client");
}
}
}
final String freeWithdrawalFrequencyParamName = "freeWithdrawalFrequency";
if (command.isChangeInIntegerParameterNamed(freeWithdrawalFrequencyParamName, this.freeWithdrawalFrequency)) {
final Integer enableFreeWithdrawalChargeNewValue = command.integerValueOfParameterNamed(freeWithdrawalFrequencyParamName);
actualChanges.put(freeWithdrawalFrequencyParamName, enableFreeWithdrawalChargeNewValue);
this.freeWithdrawalFrequency = enableFreeWithdrawalChargeNewValue;
}
final String restartCountFrequencyParamName = "restartCountFrequency";
if (command.isChangeInIntegerParameterNamed(restartCountFrequencyParamName, this.restartFrequency)) {
final Integer restartCountFrequencyNewValue = command.integerValueOfParameterNamed(restartCountFrequencyParamName);
actualChanges.put(restartCountFrequencyParamName, restartCountFrequencyNewValue);
this.restartFrequency = restartCountFrequencyNewValue;
}
final String countFrequencyTypeParamName = "countFrequencyType";
if (command.isChangeInIntegerParameterNamed(countFrequencyTypeParamName, this.restartFrequencyEnum)) {
final Integer countFrequencyTypeNewValue = command.integerValueOfParameterNamed(countFrequencyTypeParamName);
actualChanges.put(countFrequencyTypeParamName, countFrequencyTypeNewValue);
this.restartFrequencyEnum = ChargeTimeType.fromInt(countFrequencyTypeNewValue).getValue();
}
final String enableFreeWithdrawalChargeParamName = "enableFreeWithdrawalCharge";
if (command.isChangeInBooleanParameterNamed(enableFreeWithdrawalChargeParamName, this.enableFreeWithdrawal)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enableFreeWithdrawalChargeParamName);
actualChanges.put(enableFreeWithdrawalChargeParamName, newValue);
this.enableFreeWithdrawal = newValue;
}
final String enablePaymentTypeParamName = "enablePaymentType";
if (command.isChangeInBooleanParameterNamed(enablePaymentTypeParamName, this.enablePaymentType)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enablePaymentTypeParamName);
actualChanges.put(enablePaymentTypeParamName, newValue);
this.enablePaymentType = newValue;
}
final String paymentTypeParamName = "paymentTypeId";
if (command.isChangeInLongParameterNamed(paymentTypeParamName, getPaymentTypeId())) {
final Long newValue = command.longValueOfParameterNamed(paymentTypeParamName);
actualChanges.put(paymentTypeParamName, newValue);
}
final String chargeAppliesToParamName = "chargeAppliesTo";
if (command.isChangeInIntegerParameterNamed(chargeAppliesToParamName, this.chargeAppliesTo)) {
/*
* final Integer newValue = command.integerValueOfParameterNamed(chargeAppliesToParamName);
* actualChanges.put(chargeAppliesToParamName, newValue); actualChanges.put("locale", localeAsInput);
* this.chargeAppliesTo = ChargeAppliesTo.fromInt(newValue).getValue();
*/
// AA: Do not allow to change chargeAppliesTo.
final String errorMessage = "Update of Charge applies to is not supported";
throw new ChargeParameterUpdateNotSupportedException("charge.applies.to", errorMessage);
}
final String chargeCalculationParamName = "chargeCalculationType";
if (command.isChangeInIntegerParameterNamed(chargeCalculationParamName, this.chargeCalculation)) {
final Integer newValue = command.integerValueOfParameterNamed(chargeCalculationParamName);
actualChanges.put(chargeCalculationParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue();
if (isSavingsCharge()) {
if (!isAllowedSavingsChargeCalculationType()) {
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.savings");
}
if (!(ChargeTimeType.fromInt(getChargeTimeType()).isWithdrawalFee()
|| ChargeTimeType.fromInt(getChargeTimeType()).isSavingsNoActivityFee())
&& ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
.failWithCodeNoParameterAddedToErrorCode(
"charge.calculation.type.percentage.allowed.only.for.withdrawal.or.noactivity");
}
} else if (isClientCharge()) {
if (!isAllowedClientChargeCalculationType()) {
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
.failWithCodeNoParameterAddedToErrorCode("not.allowed.charge.calculation.type.for.client");
}
}
}
// validate only for loan charge
if (isLoanCharge()) {
final String paymentModeParamName = "chargePaymentMode";
if (command.isChangeInIntegerParameterNamed(paymentModeParamName, this.chargePaymentMode)) {
final Integer newValue = command.integerValueOfParameterNamed(paymentModeParamName);
actualChanges.put(paymentModeParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.chargePaymentMode = ChargePaymentMode.fromInt(newValue).getValue();
}
}
if (command.hasParameter("feeOnMonthDay")) {
final MonthDay monthDay = command.extractMonthDayNamed("feeOnMonthDay");
final String actualValueEntered = command.stringValueOfParameterNamed("feeOnMonthDay");
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
if (!this.feeOnDay.equals(dayOfMonthValue)) {
actualChanges.put("feeOnMonthDay", actualValueEntered);
actualChanges.put("locale", locale.getLanguage());
this.feeOnDay = dayOfMonthValue;
}
final Integer monthOfYear = monthDay.getMonthValue();
if (!this.feeOnMonth.equals(monthOfYear)) {
actualChanges.put("feeOnMonthDay", actualValueEntered);
actualChanges.put("locale", locale.getLanguage());
this.feeOnMonth = monthOfYear;
}
}
final String feeInterval = "feeInterval";
if (command.isChangeInIntegerParameterNamed(feeInterval, this.feeInterval)) {
final Integer newValue = command.integerValueOfParameterNamed(feeInterval);
actualChanges.put(feeInterval, newValue);
actualChanges.put("locale", locale.getLanguage());
this.feeInterval = newValue;
}
final String feeFrequency = "feeFrequency";
if (command.isChangeInIntegerParameterNamed(feeFrequency, this.feeFrequency)) {
final Integer newValue = command.integerValueOfParameterNamed(feeFrequency);
actualChanges.put(feeFrequency, newValue);
actualChanges.put("locale", locale.getLanguage());
this.feeFrequency = newValue;
}
if (this.feeFrequency != null) {
baseDataValidator.reset().parameter("feeInterval").value(this.feeInterval).notNull();
}
final String penaltyParamName = "penalty";
if (command.isChangeInBooleanParameterNamed(penaltyParamName, this.penalty)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(penaltyParamName);
actualChanges.put(penaltyParamName, newValue);
this.penalty = newValue;
}
final String activeParamName = "active";
if (command.isChangeInBooleanParameterNamed(activeParamName, this.active)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(activeParamName);
actualChanges.put(activeParamName, newValue);
this.active = newValue;
}
// allow min and max cap to be only added to PERCENT_OF_AMOUNT for now
if (isPercentageOfApprovedAmount()) {
final String minCapParamName = "minCap";
if (command.isChangeInBigDecimalParameterNamed(minCapParamName, this.minCap)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minCapParamName);
actualChanges.put(minCapParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.minCap = newValue;
}
final String maxCapParamName = "maxCap";
if (command.isChangeInBigDecimalParameterNamed(maxCapParamName, this.maxCap)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxCapParamName);
actualChanges.put(maxCapParamName, newValue);
actualChanges.put("locale", locale.getLanguage());
this.maxCap = newValue;
}
}
if (this.penalty && ChargeTimeType.fromInt(this.chargeTimeType).isTimeOfDisbursement()) {
throw new ChargeDueAtDisbursementCannotBePenaltyException(this.name);
}
if (!penalty && ChargeTimeType.fromInt(this.chargeTimeType).isOverdueInstallment()) {
throw new ChargeMustBePenaltyException(name);
}
if (command.isChangeInLongParameterNamed(ChargesApiConstants.glAccountIdParamName, getIncomeAccountId())) {
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.glAccountIdParamName);
actualChanges.put(ChargesApiConstants.glAccountIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ChargesApiConstants.taxGroupIdParamName, getTaxGroupId())) {
final Long newValue = command.longValueOfParameterNamed(ChargesApiConstants.taxGroupIdParamName);
actualChanges.put(ChargesApiConstants.taxGroupIdParamName, newValue);
if (taxGroup != null) {
baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).failWithCode("modification.not.supported");
}
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
return actualChanges;
}
/**
* Delete is a <i>soft delete</i>. Updates flag on charge so it wont appear in query/report results.
*
* Any fields with unique constraints and prepended with id of record.
*/
public void delete() {
this.deleted = true;
this.name = getId() + "_" + this.name;
}
public ChargeData toData() {
final EnumOptionData chargeTimeType = ChargeEnumerations.chargeTimeType(this.chargeTimeType);
final EnumOptionData chargeAppliesTo = ChargeEnumerations.chargeAppliesTo(this.chargeAppliesTo);
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(this.chargeCalculation);
final EnumOptionData chargePaymentMode = ChargeEnumerations.chargePaymentMode(this.chargePaymentMode);
EnumOptionData feeFrequencyType = null;
if (this.feeFrequency != null) {
feeFrequencyType = ChargeEnumerations.feeFrequencyType(this.feeFrequency);
}
GLAccountData accountData = null;
if (account != null) {
accountData = new GLAccountData().setId(account.getId()).setName(account.getName()).setGlCode(account.getGlCode());
}
TaxGroupData taxGroupData = null;
if (this.taxGroup != null) {
taxGroupData = TaxGroupData.lookup(taxGroup.getId(), taxGroup.getName());
}
PaymentTypeData paymentTypeData = null;
if (this.paymentType != null) {
paymentTypeData = PaymentTypeData.instance(paymentType.getId(), paymentType.getName());
}
final CurrencyData currency = new CurrencyData(this.currencyCode, null, 0, 0, null, null);
return ChargeData.instance(getId(), this.name, this.amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType,
chargePaymentMode, getFeeOnMonthDay(), this.feeInterval, this.penalty, this.active, this.enableFreeWithdrawal,
this.freeWithdrawalFrequency, this.restartFrequency, this.restartFrequencyEnum, this.enablePaymentType, paymentTypeData,
this.minCap, this.maxCap, feeFrequencyType, accountData, taxGroupData);
}
public Integer getChargePaymentMode() {
return this.chargePaymentMode;
}
public Integer getFeeInterval() {
return this.feeInterval;
}
public boolean isMonthlyFee() {
return ChargeTimeType.fromInt(this.chargeTimeType).isMonthlyFee();
}
public boolean isAnnualFee() {
return ChargeTimeType.fromInt(this.chargeTimeType).isAnnualFee();
}
public boolean isOverdueInstallment() {
return ChargeTimeType.fromInt(this.chargeTimeType).isOverdueInstallment();
}
public MonthDay getFeeOnMonthDay() {
MonthDay feeOnMonthDay = null;
if (this.feeOnDay != null && this.feeOnMonth != null) {
feeOnMonthDay = MonthDay.now(DateUtils.getDateTimeZoneOfTenant()).withMonth(this.feeOnMonth).withDayOfMonth(this.feeOnDay);
}
return feeOnMonthDay;
}
public Integer feeInterval() {
return this.feeInterval;
}
public Integer feeFrequency() {
return this.feeFrequency;
}
public GLAccount getAccount() {
return this.account;
}
public void setAccount(GLAccount account) {
this.account = account;
}
public Long getIncomeAccountId() {
Long incomeAccountId = null;
if (this.account != null) {
incomeAccountId = this.account.getId();
}
return incomeAccountId;
}
private Long getTaxGroupId() {
Long taxGroupId = null;
if (this.taxGroup != null) {
taxGroupId = this.taxGroup.getId();
}
return taxGroupId;
}
public boolean isDisbursementCharge() {
return ChargeTimeType.fromInt(this.chargeTimeType).equals(ChargeTimeType.DISBURSEMENT)
|| ChargeTimeType.fromInt(this.chargeTimeType).equals(ChargeTimeType.TRANCHE_DISBURSEMENT);
}
public TaxGroup getTaxGroup() {
return this.taxGroup;
}
public void setTaxGroup(TaxGroup taxGroup) {
this.taxGroup = taxGroup;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Charge)) {
return false;
}
Charge other = (Charge) o;
return Objects.equals(name, other.name) && Objects.equals(amount, other.amount) && Objects.equals(currencyCode, other.currencyCode)
&& Objects.equals(chargeAppliesTo, other.chargeAppliesTo) && Objects.equals(chargeTimeType, other.chargeTimeType)
&& Objects.equals(chargeCalculation, other.chargeCalculation) && Objects.equals(chargePaymentMode, other.chargePaymentMode)
&& Objects.equals(feeOnDay, other.feeOnDay) && Objects.equals(feeInterval, other.feeInterval)
&& Objects.equals(feeOnMonth, other.feeOnMonth) && penalty == other.penalty && active == other.active
&& deleted == other.deleted && Objects.equals(minCap, other.minCap) && Objects.equals(maxCap, other.maxCap)
&& Objects.equals(feeFrequency, other.feeFrequency) && Objects.equals(account, other.account)
&& Objects.equals(taxGroup, other.taxGroup);
}
@Override
public int hashCode() {
return Objects.hash(name, amount, currencyCode, chargeAppliesTo, chargeTimeType, chargeCalculation, chargePaymentMode, feeOnDay,
feeInterval, feeOnMonth, penalty, active, deleted, minCap, maxCap, feeFrequency, account, taxGroup);
}
}
@@ -0,0 +1,90 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
public enum ChargeAppliesTo {
INVALID(0, "chargeAppliesTo.invalid"), //
LOAN(1, "chargeAppliesTo.loan"), //
SAVINGS(2, "chargeAppliesTo.savings"), //
CLIENT(3, "chargeAppliesTo.client"), SHARES(4, "chargeAppliesTo.shares");
private final Integer value;
private final String code;
ChargeAppliesTo(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
public static ChargeAppliesTo fromInt(final Integer chargeAppliesTo) {
ChargeAppliesTo chargeAppliesToType = ChargeAppliesTo.INVALID;
if (chargeAppliesTo != null) {
switch (chargeAppliesTo) {
case 1:
chargeAppliesToType = LOAN;
break;
case 2:
chargeAppliesToType = SAVINGS;
break;
case 3:
chargeAppliesToType = CLIENT;
break;
case 4:
chargeAppliesToType = SHARES;
break;
default:
chargeAppliesToType = INVALID;
break;
}
}
return chargeAppliesToType;
}
public boolean isLoanCharge() {
return this.value.equals(ChargeAppliesTo.LOAN.getValue());
}
public boolean isSavingsCharge() {
return this.value.equals(ChargeAppliesTo.SAVINGS.getValue());
}
public boolean isClientCharge() {
return this.value.equals(ChargeAppliesTo.CLIENT.getValue());
}
public boolean isSharesCharge() {
return this.value.equals(SHARES.getValue());
}
public static Object[] validValues() {
return new Object[] { ChargeAppliesTo.LOAN.getValue(), ChargeAppliesTo.SAVINGS.getValue(), ChargeAppliesTo.CLIENT.getValue(),
ChargeAppliesTo.SHARES.getValue() };
}
}
@@ -0,0 +1,126 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
public enum ChargeCalculationType {
INVALID(0, "chargeCalculationType.invalid"), //
FLAT(1, "chargeCalculationType.flat"), //
PERCENT_OF_AMOUNT(2, "chargeCalculationType.percent.of.amount"), //
PERCENT_OF_AMOUNT_AND_INTEREST(3, "chargeCalculationType.percent.of.amount.and.interest"), //
PERCENT_OF_INTEREST(4, "chargeCalculationType.percent.of.interest"), PERCENT_OF_DISBURSEMENT_AMOUNT(5,
"chargeCalculationType.percent.of.disbursement.amount");
private final Integer value;
private final String code;
ChargeCalculationType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
public static Object[] validValuesForLoan() {
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue(),
ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue(), ChargeCalculationType.PERCENT_OF_INTEREST.getValue(),
ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue() };
}
public static Object[] validValuesForSavings() {
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue() };
}
public static Object[] validValuesForShares() {
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue() };
}
public static Object[] validValuesForClients() {
return new Integer[] { ChargeCalculationType.FLAT.getValue() };
}
public static Object[] validValuesForShareAccountActivation() {
return new Integer[] { ChargeCalculationType.FLAT.getValue() };
}
public static Object[] validValuesForTrancheDisbursement() {
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue() };
}
public static ChargeCalculationType fromInt(final Integer chargeCalculation) {
ChargeCalculationType chargeCalculationType = ChargeCalculationType.INVALID;
switch (chargeCalculation) {
case 1:
chargeCalculationType = FLAT;
break;
case 2:
chargeCalculationType = PERCENT_OF_AMOUNT;
break;
case 3:
chargeCalculationType = PERCENT_OF_AMOUNT_AND_INTEREST;
break;
case 4:
chargeCalculationType = PERCENT_OF_INTEREST;
break;
case 5:
chargeCalculationType = PERCENT_OF_DISBURSEMENT_AMOUNT;
break;
}
return chargeCalculationType;
}
public boolean isPercentageOfAmount() {
return this.value.equals(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue());
}
public boolean isPercentageOfAmountAndInterest() {
return this.value.equals(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue());
}
public boolean isPercentageOfInterest() {
return this.value.equals(ChargeCalculationType.PERCENT_OF_INTEREST.getValue());
}
public boolean isFlat() {
return this.value.equals(ChargeCalculationType.FLAT.getValue());
}
public boolean isAllowedSavingsChargeCalculationType() {
return isFlat() || isPercentageOfAmount();
}
public boolean isAllowedClientChargeCalculationType() {
return isFlat();
}
public boolean isPercentageBased() {
return isPercentageOfAmount() || isPercentageOfAmountAndInterest() || isPercentageOfInterest()
|| isPercentageOfDisbursementAmount();
}
public boolean isPercentageOfDisbursementAmount() {
return this.value.equals(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue());
}
}
@@ -0,0 +1,62 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
public enum ChargePaymentMode {
REGULAR(0, "chargepaymentmode.regular"), //
ACCOUNT_TRANSFER(1, "chargepaymentmode.accounttransfer");
private final Integer value;
private final String code;
ChargePaymentMode(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return this.code;
}
public static Object[] validValues() {
return new Integer[] { ChargePaymentMode.REGULAR.getValue(), ChargePaymentMode.ACCOUNT_TRANSFER.getValue() };
}
public static ChargePaymentMode fromInt(final Integer paymentMode) {
ChargePaymentMode chargeAppliesToType = ChargePaymentMode.REGULAR;
switch (paymentMode) {
case 1:
chargeAppliesToType = ACCOUNT_TRANSFER;
break;
default:
chargeAppliesToType = REGULAR;
break;
}
return chargeAppliesToType;
}
public boolean isPaymentModeAccountTransfer() {
return this.value.equals(ChargePaymentMode.ACCOUNT_TRANSFER.getValue());
}
}
@@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface ChargeRepository extends JpaRepository<Charge, Long>, JpaSpecificationExecutor<Charge> {
// no added behaviour
}
@@ -0,0 +1,59 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.domain;
import org.apache.fineract.portfolio.charge.exception.ChargeIsNotActiveException;
import org.apache.fineract.portfolio.charge.exception.ChargeNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <p>
* Wrapper for {@link ChargeRepository} that is responsible for checking if {@link Charge} is returned when using
* <code>findOne</code> repository method and throwing an appropriate not found exception.
* </p>
*
* <p>
* This is to avoid need for checking and throwing in multiple areas of code base where {@link ChargeRepository} is
* required.
* </p>
*/
@Service
public class ChargeRepositoryWrapper {
private final ChargeRepository repository;
@Autowired
public ChargeRepositoryWrapper(final ChargeRepository repository) {
this.repository = repository;
}
public Charge findOneWithNotFoundDetection(final Long id) {
final Charge chargeDefinition = this.repository.findById(id).orElseThrow(() -> new ChargeNotFoundException(id));
if (chargeDefinition.isDeleted()) {
throw new ChargeNotFoundException(id);
}
if (!chargeDefinition.isActive()) {
throw new ChargeIsNotActiveException(id, chargeDefinition.getName());
}
return chargeDefinition;
}
}
@@ -0,0 +1,30 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class ChargeCannotBeAppliedToException extends AbstractPlatformDomainRuleException {
public ChargeCannotBeAppliedToException(final String postFix, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
super("error.msg.charge.cannot.be.applied.to" + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class ChargeCannotBeDeletedException extends AbstractPlatformDomainRuleException {
public ChargeCannotBeDeletedException(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class ChargeCannotBeUpdatedException extends AbstractPlatformDomainRuleException {
public ChargeCannotBeUpdatedException(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when attempting to crate charge of type penalty due at
* disbursement .
*/
public class ChargeDueAtDisbursementCannotBePenaltyException extends AbstractPlatformDomainRuleException {
public ChargeDueAtDisbursementCannotBePenaltyException(final String name) {
super("error.msg.charge.due.at.disbursement.cannot.be.penalty", "Charge '" + name + "' is invalid.", name, name);
}
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when charge is not active.
*/
public class ChargeIsNotActiveException extends AbstractPlatformDomainRuleException {
public ChargeIsNotActiveException(final Long id, final String name) {
super("error.msg.charge.is.not.active", "Charge '" + name + "' with identifier " + id + " is not active", name, id);
}
}
@@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when attempting to crate charge of type penalty due at
* disbursement .
*/
public class ChargeMustBePenaltyException extends AbstractPlatformDomainRuleException {
public ChargeMustBePenaltyException(final String name) {
super("error.msg.charge.must.be.penalty", "Charge '" + name + "' is invalid.", name, name);
}
}
@@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
import org.springframework.dao.EmptyResultDataAccessException;
public class ChargeNotFoundException extends AbstractPlatformResourceNotFoundException {
public ChargeNotFoundException(final Long id) {
super("error.msg.charge.id.invalid", "Charge with identifier " + id + " does not exist", id);
}
public ChargeNotFoundException(Long id, EmptyResultDataAccessException e) {
super("error.msg.charge.id.invalid", "Charge with identifier " + id + " does not exist", id, e);
}
}
@@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when loan charge is not allowed to be added to the loan.
*/
public class LoanChargeCannotBeAddedException extends AbstractPlatformDomainRuleException {
public LoanChargeCannotBeAddedException(final String entity, final String postFix, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super("error.msg." + entity + ".cannot.be.added.as." + postFix, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,56 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanChargeCannotBeDeletedException extends AbstractPlatformDomainRuleException {
/*** enum of reasons of why Loan Charge cannot be waived **/
public enum LoanChargeCannotBeDeletedReason {
ALREADY_PAID, ALREADY_WAIVED, LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "This loan charge has been partially/completely paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "This loan charge has already been waived";
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "This charge cannot be deleted as the loan it is associated with is not in submitted and pending approval stage";
}
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "error.msg.loan.charge.already.paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "error.msg.loan.charge.already.waived";
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage";
}
return name().toString();
}
}
public LoanChargeCannotBeDeletedException(final LoanChargeCannotBeDeletedReason reason, final Long loanChargeId) {
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
}
}
@@ -0,0 +1,65 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanChargeCannotBePayedException extends AbstractPlatformDomainRuleException {
/*** enum of reasons of why Loan Charge cannot be waived **/
public enum LoanChargeCannotBePayedReason {
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, CHARGE_NOT_ACCOUNT_TRANSFER, CHARGE_NOT_PAYABLE;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "This loan charge has been completely paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "This loan charge has already been waived";
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
return "This loan charge can be payed as the loan associated with it is currently inactive";
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
return "This loan charge can be payed as the charge payment mode is not account transfer";
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_PAYABLE")) {
return "This loan charge is not Payable through account transfer";
}
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "error.msg.loan.charge.already.paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "error.msg.loan.charge.already.waived";
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
return "error.msg.loan.charge.associated.loan.inactive";
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
return "error.msg.loan.charge.payment.mode.not.account.transfer";
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_PAYABLE")) {
return "error.msg.loan.charge.payment.not.allowed.account.transfer";
}
return name().toString();
}
}
public LoanChargeCannotBePayedException(final LoanChargeCannotBePayedReason reason, final Long loanChargeId) {
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
}
}
@@ -0,0 +1,56 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanChargeCannotBeUpdatedException extends AbstractPlatformDomainRuleException {
/*** enum of reasons of why Loan Charge cannot be waived **/
public enum LoanChargeCannotBeUpdatedReason {
ALREADY_PAID, ALREADY_WAIVED, LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "This loan charge has been partially/completely paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "This loan charge has already been waived";
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "This charge cannot be updated as the loan it is associated with is not in submitted and pending approval stage";
}
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "error.msg.loan.charge.already.paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "error.msg.loan.charge.already.waived";
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage";
}
return name().toString();
}
}
public LoanChargeCannotBeUpdatedException(final LoanChargeCannotBeUpdatedReason reason, final Long loanChargeId) {
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
}
}
@@ -0,0 +1,61 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanChargeCannotBeWaivedException extends AbstractPlatformDomainRuleException {
/*** enum of reasons of why Loan Charge cannot be waived **/
public enum LoanChargeCannotBeWaivedReason {
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, WAIVE_NOT_ALLOWED_FOR_CHARGE;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "This loan charge has been completely paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "This loan charge has already been waived";
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
return "This loan charge can be waived as the loan associated with it is currently inactive";
} else if (name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
return "This loan charge can be waived";
}
return name().toString();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
return "error.msg.loan.charge.already.paid";
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
return "error.msg.loan.charge.already.waived";
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
return "error.msg.loan.charge.associated.loan.inactive";
} else if (name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
return "error.msg.loan.charge.waive.not.allowed";
}
return name().toString();
}
}
public LoanChargeCannotBeWaivedException(final LoanChargeCannotBeWaivedReason reason, final Long loanChargeId) {
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
}
}
@@ -0,0 +1,54 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
import org.springframework.dao.EmptyResultDataAccessException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when loan charge does not exist.
*/
public class LoanChargeNotFoundException extends AbstractPlatformResourceNotFoundException {
public LoanChargeNotFoundException() {
super("error.msg.loanCharge.invalid", "Loan charge cannot be found");
}
public LoanChargeNotFoundException(final Long id) {
super("error.msg.loanCharge.id.invalid", "Loan charge with identifier " + id + " does not exist", id);
}
public LoanChargeNotFoundException(final Long id, final Long loanId) {
super("error.msg.loanCharge.id.invalid.for.given.loan", "Loan charge with identifier " + id + " does not exist for loan " + loanId,
id, loanId);
}
public LoanChargeNotFoundException(final Long id, final Long loanId, final EmptyResultDataAccessException e) {
super("error.msg.loanCharge.id.invalid.for.given.loan", "Loan charge with identifier " + id + " does not exist for loan " + loanId,
id, loanId, e);
}
public LoanChargeNotFoundException(ExternalId externalId) {
super("error.msg.loanCharge.external.id.invalid", "Loan Charge with external identifier "
+ ObjectUtils.defaultIfNull(externalId, ExternalId.empty()).getValue() + " does not exist", externalId);
}
}
@@ -0,0 +1,71 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class LoanChargeWaiveCannotBeReversedException extends AbstractPlatformDomainRuleException {
/*** enum of reasons of why Loan Charge waive cannot undo **/
public enum LoanChargeWaiveCannotUndoReason {
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, WAIVE_NOT_ALLOWED_FOR_CHARGE, NOT_WAIVED, ALREADY_REVERSED;
public String errorMessage() {
if (name().equalsIgnoreCase("ALREADY_PAID")) {
return "This loan charge has been completely paid";
} else if (name().equalsIgnoreCase("ALREADY_WAIVED")) {
return "This loan charge has already been waived";
} else if (name().equalsIgnoreCase("LOAN_INACTIVE")) {
return "This loan charge can be waived as the loan associated with it is currently inactive";
} else if (name().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
return "This loan charge can be waived";
} else if (name().equalsIgnoreCase("NOT_WAIVED")) {
return "This loan charge waive cannot be reversed as this charge is not waived";
} else if (name().equalsIgnoreCase("ALREADY_REVERSED")) {
return "This loan charge waive cannot be reversed as this transaction is already reversed";
}
return name();
}
public String errorCode() {
if (name().equalsIgnoreCase("ALREADY_PAID")) {
return "error.msg.loan.charge.already.paid";
} else if (name().equalsIgnoreCase("ALREADY_WAIVED")) {
return "error.msg.loan.charge.already.waived";
} else if (name().equalsIgnoreCase("LOAN_INACTIVE")) {
return "error.msg.loan.charge.associated.loan.inactive";
} else if (name().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
return "error.msg.loan.charge.waive.not.allowed";
} else if (name().equalsIgnoreCase("NOT_WAIVED")) {
return "error.msg.loan.charge.waive.cannot.undo";
} else if (name().equalsIgnoreCase("ALREADY_REVERSED")) {
return "error.msg.transaction.cannot.reverse";
}
return name();
}
}
public LoanChargeWaiveCannotBeReversedException(final LoanChargeWaiveCannotUndoReason reason, final Long id) {
super(reason.errorCode(), reason.errorMessage(), id);
}
}
@@ -0,0 +1,33 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* {@link AbstractPlatformDomainRuleException} thrown when currency mismatch occurs
*/
public class ShareAccountChargeWithoutMandatoryFieldException extends AbstractPlatformDomainRuleException {
public ShareAccountChargeWithoutMandatoryFieldException(final String entity, final String postFix, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super("error.msg." + entity + "." + postFix + ".cannot.be.blank", defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.charge.service.ChargeWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "CHARGE", action = "CREATE")
public class CreateChargeDefinitionCommandHandler implements NewCommandSourceHandler {
private final ChargeWritePlatformService clientWritePlatformService;
@Autowired
public CreateChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) {
this.clientWritePlatformService = clientWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.clientWritePlatformService.createCharge(command);
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.charge.service.ChargeWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "CHARGE", action = "DELETE")
public class DeleteChargeDefinitionCommandHandler implements NewCommandSourceHandler {
private final ChargeWritePlatformService clientWritePlatformService;
@Autowired
public DeleteChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) {
this.clientWritePlatformService = clientWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.clientWritePlatformService.deleteCharge(command.entityId());
}
}
@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.handler;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.charge.service.ChargeWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "CHARGE", action = "UPDATE")
public class UpdateChargeDefinitionCommandHandler implements NewCommandSourceHandler {
private final ChargeWritePlatformService clientWritePlatformService;
@Autowired
public UpdateChargeDefinitionCommandHandler(final ChargeWritePlatformService clientWritePlatformService) {
this.clientWritePlatformService = clientWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.clientWritePlatformService.updateCharge(command.entityId(), command);
}
}
@@ -0,0 +1,487 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.serialization;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.portfolio.charge.api.ChargesApiConstants;
import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public final class ChargeDefinitionCommandFromApiJsonDeserializer {
public static final String NAME = "name";
public static final String AMOUNT = "amount";
public static final String LOCALE = "locale";
public static final String CURRENCY_CODE = "currencyCode";
public static final String PENALTY = "penalty";
public static final String CHARGE_CALCULATION_TYPE_OPTIONS = "chargeCalculationTypeOptions";
public static final String CHARGE_CALCULATION_TYPE = "chargeCalculationType";
public static final String CHARGE_TIME_TYPE = "chargeTimeType";
public static final String CHARGE_APPLIES_TO = "chargeAppliesTo";
public static final String CURRENCY_OPTIONS = "currencyOptions";
public static final String ACTIVE = "active";
public static final String CHARGE_PAYMENT_MODE = "chargePaymentMode";
public static final String FEE_ON_MONTH_DAY = "feeOnMonthDay";
public static final String FEE_INTERVAL = "feeInterval";
public static final String MONTH_DAY_FORMAT = "monthDayFormat";
public static final String MIN_CAP = "minCap";
public static final String MAX_CAP = "maxCap";
public static final String FEE_FREQUENCY = "feeFrequency";
public static final String ENABLE_FREE_WITHDRAWAL_CHARGE = "enableFreeWithdrawalCharge";
public static final String FREE_WITHDRAWAL_FREQUENCY = "freeWithdrawalFrequency";
public static final String RESTART_COUNT_FREQUENCY = "restartCountFrequency";
public static final String COUNT_FREQUENCY_TYPE = "countFrequencyType";
public static final String ENABLE_PAYMENT_TYPE = "enablePaymentType";
public static final String PAYMENT_TYPE_ID = "paymentTypeId";
public static final String CHARGE = "charge";
/**
* The parameters supported for this command.
*/
private static final Set<String> SUPPORTED_PARAMETERS = new HashSet<>(Arrays.asList(NAME, AMOUNT, LOCALE, CURRENCY_CODE,
CURRENCY_OPTIONS, CHARGE_APPLIES_TO, CHARGE_TIME_TYPE, CHARGE_CALCULATION_TYPE, CHARGE_CALCULATION_TYPE_OPTIONS, PENALTY,
ACTIVE, CHARGE_PAYMENT_MODE, FEE_ON_MONTH_DAY, FEE_INTERVAL, MONTH_DAY_FORMAT, MIN_CAP, MAX_CAP, FEE_FREQUENCY,
ENABLE_FREE_WITHDRAWAL_CHARGE, FREE_WITHDRAWAL_FREQUENCY, RESTART_COUNT_FREQUENCY, COUNT_FREQUENCY_TYPE, PAYMENT_TYPE_ID,
ENABLE_PAYMENT_TYPE, ChargesApiConstants.glAccountIdParamName, ChargesApiConstants.taxGroupIdParamName));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public ChargeDefinitionCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element);
baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull();
if (chargeAppliesTo != null) {
baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).isOneOfTheseValues(ChargeAppliesTo.validValues());
}
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_CALCULATION_TYPE, element);
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType).notNull();
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(FEE_INTERVAL, element, Locale.getDefault());
baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).integerGreaterThanZero();
final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed(FEE_FREQUENCY, element, Locale.getDefault());
baseDataValidator.reset().parameter(FEE_FREQUENCY).value(feeFrequency).inMinMaxRange(0, 3);
if (this.fromApiJsonHelper.parameterExists(ENABLE_FREE_WITHDRAWAL_CHARGE, element)) {
final Boolean enableFreeWithdrawalCharge = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_FREE_WITHDRAWAL_CHARGE, element);
baseDataValidator.reset().parameter(ENABLE_FREE_WITHDRAWAL_CHARGE).value(enableFreeWithdrawalCharge).notNull();
if (enableFreeWithdrawalCharge) {
final Integer freeWithdrawalFrequency = this.fromApiJsonHelper.extractIntegerNamed(FREE_WITHDRAWAL_FREQUENCY, element,
Locale.getDefault());
baseDataValidator.reset().parameter(FREE_WITHDRAWAL_FREQUENCY).value(freeWithdrawalFrequency).integerGreaterThanZero();
final Integer restartCountFrequency = this.fromApiJsonHelper.extractIntegerNamed(RESTART_COUNT_FREQUENCY, element,
Locale.getDefault());
baseDataValidator.reset().parameter(RESTART_COUNT_FREQUENCY).value(restartCountFrequency).integerGreaterThanZero();
final Integer countFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(COUNT_FREQUENCY_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(COUNT_FREQUENCY_TYPE).value(countFrequencyType);
}
}
if (this.fromApiJsonHelper.parameterExists(ENABLE_PAYMENT_TYPE, element)) {
final boolean enablePaymentType = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_PAYMENT_TYPE, element);
baseDataValidator.reset().parameter(ENABLE_PAYMENT_TYPE).value(enablePaymentType).notNull();
if (enablePaymentType) {
final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerNamed(PAYMENT_TYPE_ID, element, Locale.getDefault());
baseDataValidator.reset().parameter(PAYMENT_TYPE_ID).value(paymentTypeId).integerGreaterThanZero();
}
}
if (feeFrequency != null) {
baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).notNull();
}
final ChargeAppliesTo appliesTo = ChargeAppliesTo.fromInt(chargeAppliesTo);
if (appliesTo.isLoanCharge()) {
// loan applicable validation
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element);
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull();
if (chargeTimeType != null) {
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType)
.isOneOfTheseValues(ChargeTimeType.validLoanValues());
}
final Integer chargePaymentMode = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_PAYMENT_MODE, element);
baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode).notNull()
.isOneOfTheseValues(ChargePaymentMode.validValues());
if (chargePaymentMode != null) {
baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode)
.isOneOfTheseValues(ChargePaymentMode.validValues());
}
if (chargeCalculationType != null) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForLoan());
}
if (chargeTimeType != null && chargeCalculationType != null) {
performChargeTimeNCalculationTypeValidation(baseDataValidator, chargeTimeType, chargeCalculationType);
}
} else if (appliesTo.isSavingsCharge()) {
// savings applicable validation
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element);
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull();
if (chargeTimeType != null) {
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType)
.isOneOfTheseValues(ChargeTimeType.validSavingsValues());
}
final ChargeTimeType ctt = ChargeTimeType.fromInt(chargeTimeType);
if (ctt.isWeeklyFee()) {
final String monthDay = this.fromApiJsonHelper.extractStringNamed(FEE_ON_MONTH_DAY, element);
baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).mustBeBlankWhenParameterProvidedIs(CHARGE_TIME_TYPE,
chargeTimeType);
}
if (ctt.isMonthlyFee()) {
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element);
baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull();
baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).notNull().inMinMaxRange(1, 12);
}
if (ctt.isAnnualFee()) {
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element);
baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull();
}
if (chargeCalculationType != null) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForSavings());
}
} else if (appliesTo.isClientCharge()) {
// client applicable validation
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element);
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull();
if (chargeTimeType != null) {
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType)
.isOneOfTheseValues(ChargeTimeType.validClientValues());
}
if (chargeCalculationType != null) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForClients());
}
// GL Account can be linked to clients
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) {
final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element);
baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull()
.longGreaterThanZero();
}
} else if (appliesTo.isSharesCharge()) {
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element);
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull();
if (chargeTimeType != null) {
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType)
.isOneOfTheseValues(ChargeTimeType.validShareValues());
}
if (chargeCalculationType != null) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForShares());
}
if (chargeTimeType != null && chargeTimeType.equals(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue())
&& chargeCalculationType != null) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForShareAccountActivation());
}
}
final String name = this.fromApiJsonHelper.extractStringNamed(NAME, element);
baseDataValidator.reset().parameter(NAME).value(name).notBlank().notExceedingLengthOf(100);
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(CURRENCY_CODE, element);
baseDataValidator.reset().parameter(CURRENCY_CODE).value(currencyCode).notBlank().notExceedingLengthOf(3);
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(AMOUNT, element.getAsJsonObject());
baseDataValidator.reset().parameter(AMOUNT).value(amount).notNull().positiveAmount();
if (this.fromApiJsonHelper.parameterExists(PENALTY, element)) {
final Boolean penalty = this.fromApiJsonHelper.extractBooleanNamed(PENALTY, element);
baseDataValidator.reset().parameter(PENALTY).value(penalty).notNull();
}
if (this.fromApiJsonHelper.parameterExists(ACTIVE, element)) {
final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ACTIVE, element);
baseDataValidator.reset().parameter(ACTIVE).value(active).notNull();
}
if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) {
final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) {
final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.taxGroupIdParamName, element)) {
final Long taxGroupId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.taxGroupIdParamName, element);
baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).value(taxGroupId).notNull().longGreaterThanZero();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE);
final JsonElement element = this.fromApiJsonHelper.parse(json);
if (this.fromApiJsonHelper.parameterExists(NAME, element)) {
final String name = this.fromApiJsonHelper.extractStringNamed(NAME, element);
baseDataValidator.reset().parameter(NAME).value(name).notBlank().notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(CURRENCY_CODE, element)) {
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(CURRENCY_CODE, element);
baseDataValidator.reset().parameter(CURRENCY_CODE).value(currencyCode).notBlank().notExceedingLengthOf(3);
}
if (this.fromApiJsonHelper.parameterExists(AMOUNT, element)) {
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(AMOUNT, element.getAsJsonObject());
baseDataValidator.reset().parameter(AMOUNT).value(amount).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) {
final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) {
final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) {
final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element);
baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull()
.isOneOfTheseValues(ChargeAppliesTo.validValues());
}
Boolean enableFreeWithdrawalCharge = false;
if (this.fromApiJsonHelper.parameterExists(ENABLE_FREE_WITHDRAWAL_CHARGE, element)) {
enableFreeWithdrawalCharge = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_FREE_WITHDRAWAL_CHARGE, element);
baseDataValidator.reset().parameter(ENABLE_FREE_WITHDRAWAL_CHARGE).value(enableFreeWithdrawalCharge).notNull();
if (enableFreeWithdrawalCharge) {
final Integer freeWithdrawalFrequency = this.fromApiJsonHelper.extractIntegerNamed(FREE_WITHDRAWAL_FREQUENCY, element,
Locale.getDefault());
baseDataValidator.reset().parameter(FREE_WITHDRAWAL_FREQUENCY).value(freeWithdrawalFrequency).integerGreaterThanZero();
final Integer restartCountFrequency = this.fromApiJsonHelper.extractIntegerNamed(RESTART_COUNT_FREQUENCY, element,
Locale.getDefault());
baseDataValidator.reset().parameter(RESTART_COUNT_FREQUENCY).value(restartCountFrequency).integerGreaterThanZero();
final Integer countFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(COUNT_FREQUENCY_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(COUNT_FREQUENCY_TYPE).value(countFrequencyType);
}
Boolean enablePaymentType = false;
if (this.fromApiJsonHelper.parameterExists(ENABLE_PAYMENT_TYPE, element)) {
enablePaymentType = this.fromApiJsonHelper.extractBooleanNamed(ENABLE_PAYMENT_TYPE, element);
baseDataValidator.reset().parameter(ENABLE_PAYMENT_TYPE).value(enablePaymentType).notNull();
if (enablePaymentType) {
final Integer paymentTypeId = this.fromApiJsonHelper.extractIntegerNamed(PAYMENT_TYPE_ID, element, Locale.getDefault());
baseDataValidator.reset().parameter(PAYMENT_TYPE_ID).value(paymentTypeId).integerGreaterThanZero();
}
}
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) {
final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element);
baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull()
.isOneOfTheseValues(ChargeAppliesTo.validValues());
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_APPLIES_TO, element)) {
final Integer chargeAppliesTo = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_APPLIES_TO, element);
baseDataValidator.reset().parameter(CHARGE_APPLIES_TO).value(chargeAppliesTo).notNull()
.isOneOfTheseValues(ChargeAppliesTo.validValues());
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_TIME_TYPE, element)) {
final Integer chargeTimeType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CHARGE_TIME_TYPE, element);
final Collection<Object> validLoanValues = Arrays.asList(ChargeTimeType.validLoanValues());
final Collection<Object> validSavingsValues = Arrays.asList(ChargeTimeType.validSavingsValues());
final Collection<Object> validClientValues = Arrays.asList(ChargeTimeType.validClientValues());
final Collection<Object> validShareValues = Arrays.asList(ChargeTimeType.validShareValues());
final Collection<Object> allValidValues = new ArrayList<>(validLoanValues);
allValidValues.addAll(validSavingsValues);
allValidValues.addAll(validClientValues);
allValidValues.addAll(validShareValues);
baseDataValidator.reset().parameter(CHARGE_TIME_TYPE).value(chargeTimeType).notNull()
.isOneOfTheseValues(allValidValues.toArray(new Object[allValidValues.size()]));
}
if (this.fromApiJsonHelper.parameterExists(FEE_ON_MONTH_DAY, element)) {
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed(FEE_ON_MONTH_DAY, element);
baseDataValidator.reset().parameter(FEE_ON_MONTH_DAY).value(monthDay).notNull();
}
if (this.fromApiJsonHelper.parameterExists(FEE_INTERVAL, element)) {
final Integer feeInterval = this.fromApiJsonHelper.extractIntegerNamed(FEE_INTERVAL, element, Locale.getDefault());
baseDataValidator.reset().parameter(FEE_INTERVAL).value(feeInterval).integerGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_CALCULATION_TYPE, element)) {
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerNamed(CHARGE_CALCULATION_TYPE, element,
Locale.getDefault());
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType).notNull().inMinMaxRange(1, 5);
}
if (this.fromApiJsonHelper.parameterExists(CHARGE_PAYMENT_MODE, element)) {
final Integer chargePaymentMode = this.fromApiJsonHelper.extractIntegerNamed(CHARGE_PAYMENT_MODE, element, Locale.getDefault());
baseDataValidator.reset().parameter(CHARGE_PAYMENT_MODE).value(chargePaymentMode).notNull().inMinMaxRange(0, 1);
}
if (this.fromApiJsonHelper.parameterExists(PENALTY, element)) {
final Boolean penalty = this.fromApiJsonHelper.extractBooleanNamed(PENALTY, element);
baseDataValidator.reset().parameter(PENALTY).value(penalty).notNull();
}
if (this.fromApiJsonHelper.parameterExists(ACTIVE, element)) {
final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ACTIVE, element);
baseDataValidator.reset().parameter(ACTIVE).value(active).notNull();
}
if (this.fromApiJsonHelper.parameterExists(MIN_CAP, element)) {
final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MIN_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MIN_CAP).value(minCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(MAX_CAP, element)) {
final BigDecimal maxCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(MAX_CAP, element.getAsJsonObject());
baseDataValidator.reset().parameter(MAX_CAP).value(maxCap).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(FEE_FREQUENCY, element)) {
final Integer feeFrequency = this.fromApiJsonHelper.extractIntegerNamed(FEE_FREQUENCY, element, Locale.getDefault());
baseDataValidator.reset().parameter(FEE_FREQUENCY).value(feeFrequency).inMinMaxRange(0, 3);
}
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.glAccountIdParamName, element)) {
final Long glAccountId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.glAccountIdParamName, element);
baseDataValidator.reset().parameter(ChargesApiConstants.glAccountIdParamName).value(glAccountId).notNull()
.longGreaterThanZero();
}
if (this.fromApiJsonHelper.parameterExists(ChargesApiConstants.taxGroupIdParamName, element)) {
final Long taxGroupId = this.fromApiJsonHelper.extractLongNamed(ChargesApiConstants.taxGroupIdParamName, element);
baseDataValidator.reset().parameter(ChargesApiConstants.taxGroupIdParamName).value(taxGroupId).notNull().longGreaterThanZero();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateChargeTimeNCalculationType(Integer chargeTimeType, Integer chargeCalculationType) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CHARGE);
performChargeTimeNCalculationTypeValidation(baseDataValidator, chargeTimeType, chargeCalculationType);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void performChargeTimeNCalculationTypeValidation(DataValidatorBuilder baseDataValidator, final Integer chargeTimeType,
final Integer chargeCalculationType) {
if (chargeTimeType.equals(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue())) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForShareAccountActivation());
}
if (chargeTimeType.equals(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue())) {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isOneOfTheseValues(ChargeCalculationType.validValuesForTrancheDisbursement());
} else {
baseDataValidator.reset().parameter(CHARGE_CALCULATION_TYPE).value(chargeCalculationType)
.isNotOneOfTheseValues(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue());
}
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
}
@@ -0,0 +1,50 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.service;
import java.util.List;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
public interface ChargeDropdownReadPlatformService {
List<EnumOptionData> retrieveCalculationTypes();
List<EnumOptionData> retrieveApplicableToTypes();
List<EnumOptionData> retrieveCollectionTimeTypes();
List<EnumOptionData> retrivePaymentModes();
List<EnumOptionData> retrieveLoanCalculationTypes();
List<EnumOptionData> retrieveLoanCollectionTimeTypes();
List<EnumOptionData> retrieveSavingsCalculationTypes();
List<EnumOptionData> retrieveSavingsCollectionTimeTypes();
List<EnumOptionData> retrieveClientCalculationTypes();
List<EnumOptionData> retrieveClientCollectionTimeTypes();
List<EnumOptionData> retrieveSharesCalculationTypes();
List<EnumOptionData> retrieveSharesCollectionTimeTypes();
}
@@ -0,0 +1,127 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.service;
import static org.apache.fineract.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
import static org.apache.fineract.portfolio.charge.service.ChargeEnumerations.chargePaymentMode;
import static org.apache.fineract.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownReadPlatformService {
@Override
public List<EnumOptionData> retrieveCalculationTypes() {
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT));
}
@Override
public List<EnumOptionData> retrieveApplicableToTypes() {
final List<EnumOptionData> chargeAppliesToTypes = new ArrayList<>();
for (final ChargeAppliesTo chargeAppliesTo : ChargeAppliesTo.values()) {
if (ChargeAppliesTo.INVALID.equals(chargeAppliesTo)) {
continue;
}
chargeAppliesToTypes.add(ChargeEnumerations.chargeAppliesTo(chargeAppliesTo));
}
return chargeAppliesToTypes;
}
@Override
public List<EnumOptionData> retrieveCollectionTimeTypes() {
final List<EnumOptionData> chargeTimeTypes = new ArrayList<>();
for (final ChargeTimeType chargeTimeType : ChargeTimeType.values()) {
if (ChargeTimeType.INVALID.equals(chargeTimeType) || ChargeTimeType.SAVINGS_CLOSURE.equals(chargeTimeType)) {
continue;
}
chargeTimeTypes.add(ChargeEnumerations.chargeTimeType(chargeTimeType));
}
return chargeTimeTypes;
}
@Override
public List<EnumOptionData> retrivePaymentModes() {
return Arrays.asList(chargePaymentMode(ChargePaymentMode.REGULAR), chargePaymentMode(ChargePaymentMode.ACCOUNT_TRANSFER));
}
@Override
public List<EnumOptionData> retrieveLoanCalculationTypes() {
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT));
}
@Override
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE),
chargeTimeType(ChargeTimeType.INSTALMENT_FEE), chargeTimeType(ChargeTimeType.OVERDUE_INSTALLMENT),
chargeTimeType(ChargeTimeType.TRANCHE_DISBURSEMENT));
}
@Override
public List<EnumOptionData> retrieveSavingsCalculationTypes() {
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
}
@Override
public List<EnumOptionData> retrieveSavingsCollectionTimeTypes() {
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE), chargeTimeType(ChargeTimeType.SAVINGS_ACTIVATION),
// chargeTimeType(ChargeTimeType.SAVINGS_CLOSURE),
chargeTimeType(ChargeTimeType.WITHDRAWAL_FEE), chargeTimeType(ChargeTimeType.ANNUAL_FEE),
chargeTimeType(ChargeTimeType.MONTHLY_FEE), chargeTimeType(ChargeTimeType.WEEKLY_FEE),
chargeTimeType(ChargeTimeType.OVERDRAFT_FEE), chargeTimeType(ChargeTimeType.SAVINGS_NOACTIVITY_FEE));
}
@Override
public List<EnumOptionData> retrieveClientCalculationTypes() {
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT));
}
@Override
public List<EnumOptionData> retrieveClientCollectionTimeTypes() {
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
}
@Override
public List<EnumOptionData> retrieveSharesCalculationTypes() {
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
}
@Override
public List<EnumOptionData> retrieveSharesCollectionTimeTypes() {
return Arrays.asList(chargeTimeType(ChargeTimeType.SHAREACCOUNT_ACTIVATION), chargeTimeType(ChargeTimeType.SHARE_PURCHASE),
chargeTimeType(ChargeTimeType.SHARE_REDEEM));
}
}
@@ -0,0 +1,217 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.service;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.charge.domain.ChargeAppliesTo;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
public final class ChargeEnumerations {
private ChargeEnumerations() {
}
public static EnumOptionData chargeTimeType(final int id) {
return chargeTimeType(ChargeTimeType.fromInt(id));
}
public static EnumOptionData chargeTimeType(final ChargeTimeType type) {
EnumOptionData optionData = null;
switch (type) {
case DISBURSEMENT:
optionData = new EnumOptionData(ChargeTimeType.DISBURSEMENT.getValue().longValue(), ChargeTimeType.DISBURSEMENT.getCode(),
"Disbursement");
break;
case SPECIFIED_DUE_DATE:
optionData = new EnumOptionData(ChargeTimeType.SPECIFIED_DUE_DATE.getValue().longValue(),
ChargeTimeType.SPECIFIED_DUE_DATE.getCode(), "Specified due date");
break;
case SAVINGS_ACTIVATION:
optionData = new EnumOptionData(ChargeTimeType.SAVINGS_ACTIVATION.getValue().longValue(),
ChargeTimeType.SAVINGS_ACTIVATION.getCode(), "Savings Activation");
break;
case SAVINGS_CLOSURE:
optionData = new EnumOptionData(ChargeTimeType.SAVINGS_CLOSURE.getValue().longValue(),
ChargeTimeType.SAVINGS_CLOSURE.getCode(), "Savings Closure");
break;
case WITHDRAWAL_FEE:
optionData = new EnumOptionData(ChargeTimeType.WITHDRAWAL_FEE.getValue().longValue(),
ChargeTimeType.WITHDRAWAL_FEE.getCode(), "Withdrawal Fee");
break;
case ANNUAL_FEE:
optionData = new EnumOptionData(ChargeTimeType.ANNUAL_FEE.getValue().longValue(), ChargeTimeType.ANNUAL_FEE.getCode(),
"Annual Fee");
break;
case MONTHLY_FEE:
optionData = new EnumOptionData(ChargeTimeType.MONTHLY_FEE.getValue().longValue(), ChargeTimeType.MONTHLY_FEE.getCode(),
"Monthly Fee");
break;
case WEEKLY_FEE:
optionData = new EnumOptionData(ChargeTimeType.WEEKLY_FEE.getValue().longValue(), ChargeTimeType.WEEKLY_FEE.getCode(),
"Weekly Fee");
break;
case INSTALMENT_FEE:
optionData = new EnumOptionData(ChargeTimeType.INSTALMENT_FEE.getValue().longValue(),
ChargeTimeType.INSTALMENT_FEE.getCode(), "Installment Fee");
break;
case OVERDUE_INSTALLMENT:
optionData = new EnumOptionData(ChargeTimeType.OVERDUE_INSTALLMENT.getValue().longValue(),
ChargeTimeType.OVERDUE_INSTALLMENT.getCode(), "Overdue Fees");
break;
case OVERDRAFT_FEE:
optionData = new EnumOptionData(ChargeTimeType.OVERDRAFT_FEE.getValue().longValue(), ChargeTimeType.OVERDRAFT_FEE.getCode(),
"Overdraft Fee");
break;
case TRANCHE_DISBURSEMENT:
optionData = new EnumOptionData(ChargeTimeType.TRANCHE_DISBURSEMENT.getValue().longValue(),
ChargeTimeType.TRANCHE_DISBURSEMENT.getCode(), "Tranche Disbursement");
break;
case SHAREACCOUNT_ACTIVATION:
optionData = new EnumOptionData(ChargeTimeType.SHAREACCOUNT_ACTIVATION.getValue().longValue(),
ChargeTimeType.SHAREACCOUNT_ACTIVATION.getCode(), "Share Account Activate");
break;
case SHARE_PURCHASE:
optionData = new EnumOptionData(ChargeTimeType.SHARE_PURCHASE.getValue().longValue(),
ChargeTimeType.SHARE_PURCHASE.getCode(), "Share Purchase");
break;
case SHARE_REDEEM:
optionData = new EnumOptionData(ChargeTimeType.SHARE_REDEEM.getValue().longValue(), ChargeTimeType.SHARE_REDEEM.getCode(),
"Share Redeem");
break;
case SAVINGS_NOACTIVITY_FEE:
optionData = new EnumOptionData(ChargeTimeType.SAVINGS_NOACTIVITY_FEE.getValue().longValue(),
ChargeTimeType.SAVINGS_NOACTIVITY_FEE.getCode(), "Saving No Activity Fee");
break;
default:
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
break;
}
return optionData;
}
public static EnumOptionData chargeAppliesTo(final int id) {
return chargeAppliesTo(ChargeAppliesTo.fromInt(id));
}
public static EnumOptionData chargeAppliesTo(final ChargeAppliesTo type) {
EnumOptionData optionData = null;
switch (type) {
case LOAN:
optionData = new EnumOptionData(ChargeAppliesTo.LOAN.getValue().longValue(), ChargeAppliesTo.LOAN.getCode(), "Loan");
break;
case SAVINGS:
optionData = new EnumOptionData(ChargeAppliesTo.SAVINGS.getValue().longValue(), ChargeAppliesTo.SAVINGS.getCode(),
"Savings");
break;
case CLIENT:
optionData = new EnumOptionData(ChargeAppliesTo.CLIENT.getValue().longValue(), ChargeAppliesTo.CLIENT.getCode(), "Client");
break;
case SHARES:
optionData = new EnumOptionData(ChargeAppliesTo.SHARES.getValue().longValue(), ChargeAppliesTo.SHARES.getCode(), "Shares");
break;
default:
optionData = new EnumOptionData(ChargeAppliesTo.INVALID.getValue().longValue(), ChargeAppliesTo.INVALID.getCode(),
"Invalid");
break;
}
return optionData;
}
public static EnumOptionData chargeCalculationType(final int id) {
return chargeCalculationType(ChargeCalculationType.fromInt(id));
}
public static EnumOptionData chargeCalculationType(final ChargeCalculationType type) {
EnumOptionData optionData = null;
switch (type) {
case FLAT:
optionData = new EnumOptionData(ChargeCalculationType.FLAT.getValue().longValue(), ChargeCalculationType.FLAT.getCode(),
"Flat");
break;
case PERCENT_OF_AMOUNT:
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue().longValue(),
ChargeCalculationType.PERCENT_OF_AMOUNT.getCode(), "% Amount");
break;
case PERCENT_OF_AMOUNT_AND_INTEREST:
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue().longValue(),
ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getCode(), "% Loan Amount + Interest");
break;
case PERCENT_OF_INTEREST:
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_INTEREST.getValue().longValue(),
ChargeCalculationType.PERCENT_OF_INTEREST.getCode(), "% Interest");
break;
case PERCENT_OF_DISBURSEMENT_AMOUNT:
optionData = new EnumOptionData(ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getValue().longValue(),
ChargeCalculationType.PERCENT_OF_DISBURSEMENT_AMOUNT.getCode(), "% Disbursement Amount");
break;
default:
optionData = new EnumOptionData(ChargeCalculationType.INVALID.getValue().longValue(),
ChargeCalculationType.INVALID.getCode(), "Invalid");
break;
}
return optionData;
}
public static EnumOptionData chargePaymentMode(final int id) {
return chargePaymentMode(ChargePaymentMode.fromInt(id));
}
public static EnumOptionData chargePaymentMode(final ChargePaymentMode type) {
EnumOptionData optionData = null;
switch (type) {
case ACCOUNT_TRANSFER:
optionData = new EnumOptionData(ChargePaymentMode.ACCOUNT_TRANSFER.getValue().longValue(),
ChargePaymentMode.ACCOUNT_TRANSFER.getCode(), "Account transfer");
break;
default:
optionData = new EnumOptionData(ChargePaymentMode.REGULAR.getValue().longValue(), ChargePaymentMode.REGULAR.getCode(),
"Regular");
break;
}
return optionData;
}
public static EnumOptionData feeFrequencyType(final int id) {
return feeFrequencyType(PeriodFrequencyType.fromInt(id));
}
public static EnumOptionData feeFrequencyType(final PeriodFrequencyType frequencyType) {
EnumOptionData optionData;
switch (frequencyType) {
case DAYS -> optionData = new EnumOptionData(PeriodFrequencyType.DAYS.getValue().longValue(),
PeriodFrequencyType.DAYS.getCode(), "Daily");
case WEEKS -> optionData = new EnumOptionData(PeriodFrequencyType.WEEKS.getValue().longValue(),
PeriodFrequencyType.WEEKS.getCode(), "Weekly");
case MONTHS -> optionData = new EnumOptionData(PeriodFrequencyType.MONTHS.getValue().longValue(),
PeriodFrequencyType.MONTHS.getCode(), "Monthly");
case YEARS -> optionData = new EnumOptionData(PeriodFrequencyType.YEARS.getValue().longValue(),
PeriodFrequencyType.YEARS.getCode(), "Yearly");
case WHOLE_TERM -> optionData = new EnumOptionData(PeriodFrequencyType.WHOLE_TERM.getValue().longValue(),
PeriodFrequencyType.WHOLE_TERM.getCode(), "Whole term");
default -> throw new UnsupportedOperationException(frequencyType + " is not supported");
}
return optionData;
}
}
@@ -0,0 +1,124 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.service;
import java.util.Collection;
import org.apache.fineract.portfolio.charge.data.ChargeData;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
public interface ChargeReadPlatformService {
Collection<ChargeData> retrieveAllCharges();
Collection<ChargeData> retrieveAllChargesForCurrency(String currencyCode);
ChargeData retrieveCharge(Long chargeId);
ChargeData retrieveNewChargeDetails();
/**
* Returns all charges that can be applied to Cients
*
* @return
*/
Collection<ChargeData> retrieveAllChargesApplicableToClients();
/**
* Returns all Fees (excluding penalties) applicable for loans
*
* @return
*/
Collection<ChargeData> retrieveLoanApplicableFees();
/**
* Returns all charges applicable for a given loan account
*
* @param excludeChargeTimes
* Excludes Given List of Charge Types from the response
* @return
*/
Collection<ChargeData> retrieveLoanAccountApplicableCharges(Long loanId, ChargeTimeType[] excludeChargeTimes);
/**
* Returns all charges applicable for a given loan product (filter based on Currency of Selected Loan Product)
*
* @param excludeChargeTimes
* Excludes Given List of Charge Types from the response
* @return
*/
Collection<ChargeData> retrieveLoanProductApplicableCharges(Long loanProductId, ChargeTimeType[] excludeChargeTimes);
/**
* Returns all Penalties applicable for loans
*
* @return
*/
Collection<ChargeData> retrieveLoanApplicablePenalties();
/**
* Returns all Charges associated with a given Loan Product
*
* @param loanProductId
* @return
*/
Collection<ChargeData> retrieveLoanProductCharges(Long loanProductId);
/**
* Returns all charges applicable for a given loan product
*
* @param loanProductId
* @param chargeTime
* Filters based on the type of the charge to be returned
* @return
*/
Collection<ChargeData> retrieveLoanProductCharges(Long loanProductId, ChargeTimeType chargeTime);
/**
* Returns all charges applicable for savings
*
* @param feeChargesOnly
* @return
*/
Collection<ChargeData> retrieveSavingsProductApplicableCharges(boolean feeChargesOnly);
/**
* Returns all penalties applicable for savings
*
* @return
*/
Collection<ChargeData> retrieveSavingsApplicablePenalties();
/**
* Returns all charges applicable for a given savings product
*
* @param savingsProductId
* @return
*/
Collection<ChargeData> retrieveSavingsProductCharges(Long savingsProductId);
/** Retrieve savings account charges **/
Collection<ChargeData> retrieveSavingsAccountApplicableCharges(Long savingsId);
/**
* Returns charge definitions which are applicable for shares
*/
Collection<ChargeData> retrieveSharesApplicableCharges();
Collection<ChargeData> retrieveShareProductCharges(Long shareProductId);
}
@@ -0,0 +1,31 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.charge.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
public interface ChargeWritePlatformService {
CommandProcessingResult createCharge(JsonCommand command);
CommandProcessingResult updateCharge(Long chargeId, JsonCommand command);
CommandProcessingResult deleteCharge(Long chargeId);
}
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- Sequence is starting from 6000 to make it easier to move existing liquibase changesets here -->
</databaseChangeLog>
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<!-- This file is only used for static weaving, nothing more. -->
<!-- You can find the runtime configuration in the JPAConfig class -->
<persistence-unit name="jpa-pu" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<!-- Fineract core module -->
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
<class>org.apache.fineract.accounting.journalentry.domain.JournalEntry</class>
<class>org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom</class>
<class>org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom</class>
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
<class>org.apache.fineract.organisation.staff.domain.Staff</class>
<class>org.apache.fineract.organisation.office.domain.Office</class>
<class>org.apache.fineract.organisation.office.domain.OrganisationCurrency</class>
<class>org.apache.fineract.organisation.monetary.domain.ApplicationCurrency</class>
<class>org.apache.fineract.organisation.holiday.domain.Holiday</class>
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
<class>org.apache.fineract.portfolio.group.domain.Group</class>
<class>org.apache.fineract.portfolio.group.domain.GroupLevel</class>
<class>org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory</class>
<class>org.apache.fineract.portfolio.group.domain.GroupRole</class>
<class>org.apache.fineract.portfolio.client.domain.Client</class>
<class>org.apache.fineract.portfolio.client.domain.ClientIdentifier</class>
<class>org.apache.fineract.portfolio.rate.domain.Rate</class>
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket</class>
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange</class>
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
<class>org.apache.fineract.portfolio.tax.domain.TaxGroup</class>
<class>org.apache.fineract.portfolio.tax.domain.TaxGroupMappings</class>
<class>org.apache.fineract.portfolio.tax.domain.TaxComponent</class>
<class>org.apache.fineract.portfolio.tax.domain.TaxComponentHistory</class>
<class>org.apache.fineract.portfolio.floatingrates.domain.FloatingRate</class>
<class>org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod</class>
<class>org.apache.fineract.portfolio.calendar.domain.Calendar</class>
<class>org.apache.fineract.portfolio.calendar.domain.CalendarHistory</class>
<class>org.apache.fineract.portfolio.calendar.domain.CalendarInstance</class>
<class>org.apache.fineract.useradministration.domain.AppUser</class>
<class>org.apache.fineract.useradministration.domain.Role</class>
<class>org.apache.fineract.useradministration.domain.Permission</class>
<class>org.apache.fineract.useradministration.domain.AppUserClientMapping</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
</persistence>