table changes on Maker-Checker workflow for Products, with approval-based updates and product locking to prevent concurrent edits

This commit is contained in:
keshav898966
2026-07-06 17:49:39 +05:30
parent b0bfa386ce
commit 9980310c9e
21 changed files with 1175 additions and 232 deletions
@@ -39,7 +39,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
* (covering charges, GL/accounting mappings and other related tables, not just scalar columns).
*/
@Entity
@Table(name = "m_savings_product_temp")
@Table(name = "m_saving_product_temp")
@Getter
@Setter
public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
@@ -61,17 +61,17 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
private String productType;
@ManyToOne
@JoinColumn(name = "maker_id", nullable = false)
@JoinColumn(name = "createdby_id", nullable = false)
private AppUser maker;
@ManyToOne
@JoinColumn(name = "checker_id")
@JoinColumn(name = "lastmodifiedby_id")
private AppUser checker;
@Column(name = "created_on", nullable = false)
@Column(name = "created_date", nullable = false)
private LocalDateTime createdOn;
@Column(name = "checked_on")
@Column(name = "lastmodified_date")
private LocalDateTime checkedOn;
@Column(name = "status", nullable = false, length = 20)
@@ -80,9 +80,7 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
@Column(name = "reject_reason", length = 500)
private String rejectReason;
@Lob
@Column(name = "proposed_payload_json", nullable = false)
private String proposedPayloadJson;
/**
* "<productType>:<productId>" while PENDING, NULL otherwise - the real DB-level lock. Unique constraints treat
@@ -130,11 +128,10 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
protected ProductPendingEdit() {}
public ProductPendingEdit(final String productType, final Long productId, final AppUser maker, final String proposedPayloadJson) {
public ProductPendingEdit(final String productType, final Long productId, final AppUser maker) {
this.productType = productType;
this.productId = productId;
this.maker = maker;
this.proposedPayloadJson = proposedPayloadJson;
this.createdOn = LocalDateTime.now();
this.status = STATUS_PENDING;
this.pendingLockKey = lockKeyFor(productType, productId);
@@ -176,9 +173,7 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
return this.rejectReason;
}
public String getProposedPayloadJson() {
return this.proposedPayloadJson;
}
public Long getCommandSourceId() {
return this.commandSourceId;
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.domain;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
@@ -308,10 +309,25 @@ public final class ProductPendingEditFieldMapper {
f.setAllowDebitTxnAfterDueDate(command.booleanObjectValueOfParameterNamed("allowDebitTxnAfterDueDate"));
present.add("allowDebitTxnAfterDueDate");
}
if (command.hasParameter("depositTypeEnum")) {
f.setDepositTypeEnum(command.integerValueOfParameterNamed("depositTypeEnum"));
present.add("depositTypeEnum");
}
if (command.hasParameter("withdrawalFeeAmount")) {
f.setWithdrawalFeeAmount(command.bigDecimalValueOfParameterNamed("withdrawalFeeAmount"));
present.add("withdrawalFeeAmount");
}
if (command.hasParameter("withdrawalFeeTypeEnum")) {
f.setWithdrawalFeeTypeEnum(command.integerValueOfParameterNamed("withdrawalFeeTypeEnum"));
present.add("withdrawalFeeTypeEnum");
}
return present;
}
public static void writeCoreFieldsToJson(final JsonObject root, final SavingsCoreEditFields f, final Set<String> submitted) {
if (f == null) {
return;
}
putString(root, submitted, "name", f.getName());
putString(root, submitted, "shortName", f.getShortName());
putString(root, submitted, "description", f.getDescription());
@@ -377,6 +393,9 @@ public final class ProductPendingEditFieldMapper {
putBoolean(root, submitted, "noPenaltyNomineeHeirClosure", f.getNoPenaltyNomineeHeirClosure());
putBoolean(root, submitted, "deceasedSettlement", f.getDeceasedSettlement());
putBoolean(root, submitted, "allowDebitTxnAfterDueDate", f.getAllowDebitTxnAfterDueDate());
putNumber(root, submitted, "depositTypeEnum", f.getDepositTypeEnum());
putNumber(root, submitted, "withdrawalFeeAmount", f.getWithdrawalFeeAmount());
putNumber(root, submitted, "withdrawalFeeTypeEnum", f.getWithdrawalFeeTypeEnum());
}
// ---- accountFacilityConfig (1:1 container) --------------------------------------------------
@@ -405,7 +424,7 @@ public final class ProductPendingEditFieldMapper {
}
public static void writeFacilityConfigToJson(final JsonObject root, final FacilityConfigEditFields f, final boolean submitted) {
if (!submitted) {
if (f == null || !submitted) {
return;
}
final JsonObject config = new JsonObject();
@@ -460,7 +479,7 @@ public final class ProductPendingEditFieldMapper {
}
public static void writeDepositLimitKycToJson(final JsonObject root, final DepositLimitKycEditFields f, final boolean submitted) {
if (!submitted) {
if (f == null || !submitted) {
return;
}
final JsonObject kyc = new JsonObject();
@@ -505,6 +524,9 @@ public final class ProductPendingEditFieldMapper {
}
public static void writeGlAccountMappingToJson(final JsonObject root, final GlAccountMappingEditFields f) {
if (f == null) {
return;
}
putNumber(root, "savingsReferenceAccountId", f.getSavingsReferenceAccountId());
putNumber(root, "savingsControlAccountId", f.getSavingsControlAccountId());
putNumber(root, "incomeFromFeeAccountId", f.getIncomeFromFeeAccountId());
@@ -693,4 +715,282 @@ public final class ProductPendingEditFieldMapper {
root.addProperty(name, value);
}
}
public static Set<String> populateCurrentOnlyFields(final JsonCommand command, final CurrentOnlyEditFields f) {
final Set<String> present = new java.util.HashSet<>();
if (command.hasParameter("avgBalanceCalcPeriod")) {
f.setAvgBalanceCalcPeriod(command.stringValueOfParameterNamed("avgBalanceCalcPeriod"));
present.add("avgBalanceCalcPeriod");
}
if (command.hasParameter("validForPeriod")) {
f.setValidForPeriod(command.stringValueOfParameterNamed("validForPeriod"));
present.add("validForPeriod");
}
if (command.hasParameter("odAccountClosedZeroBalanceInDayClosing")) {
f.setOdAccountClosedZeroBalanceInDayClosing(command.booleanObjectValueOfParameterNamed("odAccountClosedZeroBalanceInDayClosing"));
present.add("odAccountClosedZeroBalanceInDayClosing");
}
return present;
}
public static void writeCurrentOnlyFieldsToJson(final JsonObject root, final CurrentOnlyEditFields f, final Set<String> submitted) {
if (f == null) {
return;
}
putString(root, submitted, "avgBalanceCalcPeriod", f.getAvgBalanceCalcPeriod());
putString(root, submitted, "validForPeriod", f.getValidForPeriod());
putBoolean(root, submitted, "odAccountClosedZeroBalanceInDayClosing", f.getOdAccountClosedZeroBalanceInDayClosing());
}
public static Set<String> populateShareOnlyFields(final JsonCommand command, final ShareOnlyEditFields f) {
final Set<String> present = new java.util.HashSet<>();
if (command.hasParameter("totalShares")) {
f.setTotalShares(command.longValueOfParameterNamed("totalShares"));
present.add("totalShares");
}
if (command.hasParameter("totalSharesIssued") || command.hasParameter("issuedShares")) {
final Long val = command.hasParameter("totalSharesIssued") ? command.longValueOfParameterNamed("totalSharesIssued") : command.longValueOfParameterNamed("issuedShares");
f.setTotalSharesIssued(val);
present.add("totalSharesIssued");
}
if (command.hasParameter("unitPrice")) {
f.setUnitPrice(command.bigDecimalValueOfParameterNamed("unitPrice"));
present.add("unitPrice");
}
if (command.hasParameter("minimumShares") || command.hasParameter("minimumClientShares")) {
final Long val = command.hasParameter("minimumShares") ? command.longValueOfParameterNamed("minimumShares") : command.longValueOfParameterNamed("minimumClientShares");
f.setMinimumShares(val);
present.add("minimumShares");
}
if (command.hasParameter("nominalShares") || command.hasParameter("nominalClientShares")) {
final Long val = command.hasParameter("nominalShares") ? command.longValueOfParameterNamed("nominalShares") : command.longValueOfParameterNamed("nominalClientShares");
f.setNominalShares(val);
present.add("nominalShares");
}
if (command.hasParameter("maximumShares") || command.hasParameter("maximumClientShares")) {
final Long val = command.hasParameter("maximumShares") ? command.longValueOfParameterNamed("maximumShares") : command.longValueOfParameterNamed("maximumClientShares");
f.setMaximumShares(val);
present.add("maximumShares");
}
if (command.hasParameter("allowDividendCalcForInactiveClients") || command.hasParameter("allowDividendsInactiveClients")) {
final Boolean val = command.hasParameter("allowDividendCalcForInactiveClients") ? command.booleanObjectValueOfParameterNamed("allowDividendCalcForInactiveClients") : command.booleanObjectValueOfParameterNamed("allowDividendsInactiveClients");
f.setAllowDividendCalcForInactiveClients(val);
present.add("allowDividendCalcForInactiveClients");
}
if (command.hasParameter("minimumActivePeriodForDividends") || command.hasParameter("minimumActivePeriodFrequency")) {
final Integer val = command.hasParameter("minimumActivePeriodForDividends") ? command.integerValueOfParameterNamed("minimumActivePeriodForDividends") : command.integerValueOfParameterNamed("minimumActivePeriodFrequency");
f.setMinimumActivePeriodForDividends(val);
present.add("minimumActivePeriodForDividends");
}
if (command.hasParameter("minimumActivePeriodFrequencyType") || command.hasParameter("minimumActivePeriodFrequencyEnum")) {
final Integer val = command.hasParameter("minimumActivePeriodFrequencyType") ? command.integerValueOfParameterNamed("minimumActivePeriodFrequencyType") : command.integerValueOfParameterNamed("minimumActivePeriodFrequencyEnum");
f.setMinimumActivePeriodFrequencyType(val);
present.add("minimumActivePeriodFrequencyType");
}
if (command.hasParameter("shareLockinPeriod")) {
f.setShareLockinPeriod(command.integerValueOfParameterNamed("shareLockinPeriod"));
present.add("shareLockinPeriod");
}
if (command.hasParameter("shareLockinPeriodFrequencyType")) {
f.setShareLockinPeriodFrequencyType(command.integerValueOfParameterNamed("shareLockinPeriodFrequencyType"));
present.add("shareLockinPeriodFrequencyType");
}
if (command.hasParameter("externalId")) {
f.setExternalId(command.stringValueOfParameterNamed("externalId"));
present.add("externalId");
}
if (command.hasParameter("startDate")) {
f.setStartDate(command.localDateValueOfParameterNamed("startDate"));
present.add("startDate");
}
if (command.hasParameter("totalsubscribedShares")) {
f.setTotalsubscribedShares(command.longValueOfParameterNamed("totalsubscribedShares"));
present.add("totalsubscribedShares");
}
if (command.hasParameter("capitalAmount") || command.hasParameter("shareCapital")) {
final BigDecimal val = command.hasParameter("capitalAmount") ? command.bigDecimalValueOfParameterNamed("capitalAmount") : command.bigDecimalValueOfParameterNamed("shareCapital");
f.setCapitalAmount(val);
present.add("shareCapital");
}
return present;
}
public static void writeShareOnlyFieldsToJson(final JsonObject root, final ShareOnlyEditFields f, final Set<String> submitted) {
if (f == null) {
return;
}
putNumber(root, submitted, "totalShares", f.getTotalShares());
putNumber(root, submitted, "totalSharesIssued", f.getTotalSharesIssued());
putNumber(root, submitted, "unitPrice", f.getUnitPrice());
putNumber(root, submitted, "minimumShares", f.getMinimumShares());
putNumber(root, submitted, "nominalShares", f.getNominalShares());
putNumber(root, submitted, "maximumShares", f.getMaximumShares());
putBoolean(root, submitted, "allowDividendCalcForInactiveClients", f.getAllowDividendCalcForInactiveClients());
putNumber(root, submitted, "minimumActivePeriodForDividends", f.getMinimumActivePeriodForDividends());
putNumber(root, submitted, "minimumActivePeriodFrequencyType", f.getMinimumActivePeriodFrequencyType());
putNumber(root, submitted, "shareLockinPeriod", f.getShareLockinPeriod());
putNumber(root, submitted, "shareLockinPeriodFrequencyType", f.getShareLockinPeriodFrequencyType());
putString(root, submitted, "externalId", f.getExternalId());
putDate(root, submitted, "startDate", f.getStartDate());
putNumber(root, submitted, "totalsubscribedShares", f.getTotalsubscribedShares());
if (submitted.contains("capitalAmount") || submitted.contains("shareCapital")) {
if (f.getCapitalAmount() != null) {
root.addProperty("shareCapital", f.getCapitalAmount());
}
}
}
public static Set<String> populateFixedDepositFields(final JsonCommand command, final FixedDepositEditFields f) {
final Set<String> present = new java.util.HashSet<>();
if (command.hasParameter("fdType")) {
f.setFdType(command.stringValueOfParameterNamed("fdType"));
present.add("fdType");
}
if (command.hasParameter("preClosurePenalApplicable")) {
f.setPreClosurePenalApplicable(command.booleanObjectValueOfParameterNamed("preClosurePenalApplicable"));
present.add("preClosurePenalApplicable");
}
if (command.hasParameter("preClosurePenalInterest")) {
f.setPreClosurePenalInterest(command.bigDecimalValueOfParameterNamed("preClosurePenalInterest"));
present.add("preClosurePenalInterest");
}
if (command.hasParameter("preClosurePenalInterestOnTypeId")) {
f.setPreClosurePenalInterestOnTypeId(command.integerValueOfParameterNamed("preClosurePenalInterestOnTypeId"));
present.add("preClosurePenalInterestOnTypeId");
}
if (command.hasParameter("minDepositTerm")) {
f.setMinDepositTerm(command.integerValueOfParameterNamed("minDepositTerm"));
present.add("minDepositTerm");
}
if (command.hasParameter("maxDepositTerm")) {
f.setMaxDepositTerm(command.integerValueOfParameterNamed("maxDepositTerm"));
present.add("maxDepositTerm");
}
if (command.hasParameter("minDepositTermTypeId")) {
f.setMinDepositTermTypeId(command.integerValueOfParameterNamed("minDepositTermTypeId"));
present.add("minDepositTermTypeId");
}
if (command.hasParameter("maxDepositTermTypeId")) {
f.setMaxDepositTermTypeId(command.integerValueOfParameterNamed("maxDepositTermTypeId"));
present.add("maxDepositTermTypeId");
}
if (command.hasParameter("inMultiplesOfDepositTerm")) {
f.setInMultiplesOfDepositTerm(command.integerValueOfParameterNamed("inMultiplesOfDepositTerm"));
present.add("inMultiplesOfDepositTerm");
}
if (command.hasParameter("inMultiplesOfDepositTermTypeId")) {
f.setInMultiplesOfDepositTermTypeId(command.integerValueOfParameterNamed("inMultiplesOfDepositTermTypeId"));
present.add("inMultiplesOfDepositTermTypeId");
}
if (command.hasParameter("minDepositAmount")) {
f.setMinDepositAmount(command.bigDecimalValueOfParameterNamed("minDepositAmount"));
present.add("minDepositAmount");
}
if (command.hasParameter("maxDepositAmount")) {
f.setMaxDepositAmount(command.bigDecimalValueOfParameterNamed("maxDepositAmount"));
present.add("maxDepositAmount");
}
if (command.hasParameter("depositAmount")) {
f.setDepositAmount(command.bigDecimalValueOfParameterNamed("depositAmount"));
present.add("depositAmount");
}
return present;
}
public static void writeFixedDepositFieldsToJson(final JsonObject root, final FixedDepositEditFields f, final Set<String> submitted) {
if (f == null) {
return;
}
if (f.getFdType() != null) putString(root, submitted, "fdType", f.getFdType());
if (f.getPreClosurePenalApplicable() != null) putBoolean(root, submitted, "preClosurePenalApplicable", f.getPreClosurePenalApplicable());
if (f.getPreClosurePenalInterest() != null) putNumber(root, submitted, "preClosurePenalInterest", f.getPreClosurePenalInterest());
if (f.getPreClosurePenalInterestOnTypeId() != null) putNumber(root, submitted, "preClosurePenalInterestOnTypeId", f.getPreClosurePenalInterestOnTypeId());
if (f.getMinDepositTerm() != null) putNumber(root, submitted, "minDepositTerm", f.getMinDepositTerm());
if (f.getMaxDepositTerm() != null) putNumber(root, submitted, "maxDepositTerm", f.getMaxDepositTerm());
if (f.getMinDepositTermTypeId() != null) putNumber(root, submitted, "minDepositTermTypeId", f.getMinDepositTermTypeId());
if (f.getMaxDepositTermTypeId() != null) putNumber(root, submitted, "maxDepositTermTypeId", f.getMaxDepositTermTypeId());
if (f.getInMultiplesOfDepositTerm() != null) putNumber(root, submitted, "inMultiplesOfDepositTerm", f.getInMultiplesOfDepositTerm());
if (f.getInMultiplesOfDepositTermTypeId() != null) putNumber(root, submitted, "inMultiplesOfDepositTermTypeId", f.getInMultiplesOfDepositTermTypeId());
if (f.getMinDepositAmount() != null) putNumber(root, submitted, "minDepositAmount", f.getMinDepositAmount());
if (f.getMaxDepositAmount() != null) putNumber(root, submitted, "maxDepositAmount", f.getMaxDepositAmount());
if (f.getDepositAmount() != null) putNumber(root, submitted, "depositAmount", f.getDepositAmount());
}
public static Set<String> populateRecurringDepositFields(final JsonCommand command, final RecurringDepositEditFields f) {
final Set<String> present = new java.util.HashSet<>();
if (command.hasParameter("isMandatoryDeposit")) {
f.setIsMandatoryDeposit(command.booleanObjectValueOfParameterNamed("isMandatoryDeposit"));
present.add("isMandatoryDeposit");
}
if (command.hasParameter("allowWithdrawal")) {
f.setAllowWithdrawal(command.booleanObjectValueOfParameterNamed("allowWithdrawal"));
present.add("allowWithdrawal");
}
if (command.hasParameter("adjustAdvanceTowardsFuturePayments")) {
f.setAdjustAdvanceTowardsFuturePayments(command.booleanObjectValueOfParameterNamed("adjustAdvanceTowardsFuturePayments"));
present.add("adjustAdvanceTowardsFuturePayments");
}
return present;
}
public static void writeRecurringDepositFieldsToJson(final JsonObject root, final RecurringDepositEditFields f, final Set<String> submitted) {
if (f == null) {
return;
}
if (f.getIsMandatoryDeposit() != null) putBoolean(root, submitted, "isMandatoryDeposit", f.getIsMandatoryDeposit());
if (f.getAllowWithdrawal() != null) putBoolean(root, submitted, "allowWithdrawal", f.getAllowWithdrawal());
if (f.getAdjustAdvanceTowardsFuturePayments() != null) putBoolean(root, submitted, "adjustAdvanceTowardsFuturePayments", f.getAdjustAdvanceTowardsFuturePayments());
}
public static java.util.Map<String, Object> reconstructProposedChangesMap(
final ProductPendingEdit pendingEdit,
final Set<String> submittedFields,
final ProductPendingEditChargeRepository pendingEditChargeRepository,
final ProductPendingEditGlMappingRepository pendingEditGlMappingRepository,
final ProductPendingEditFacilityLimitRepository pendingEditFacilityLimitRepository,
final com.google.gson.Gson gson) {
final JsonObject root = new JsonObject();
root.addProperty("locale", "en");
root.addProperty("dateFormat", "yyyy-MM-dd");
final String productType = pendingEdit.getProductType();
if ((ProductPendingEdit.TYPE_SAVINGS.equals(productType) || ProductPendingEdit.TYPE_CURRENT.equals(productType) || ProductPendingEdit.TYPE_FD.equals(productType) || ProductPendingEdit.TYPE_RD.equals(productType)) && pendingEdit.getCoreFields() != null) {
writeCoreFieldsToJson(root, pendingEdit.getCoreFields(), submittedFields);
}
if (ProductPendingEdit.TYPE_CURRENT.equals(productType) && pendingEdit.getCurrentOnlyFields() != null) {
writeCurrentOnlyFieldsToJson(root, pendingEdit.getCurrentOnlyFields(), submittedFields);
}
if (ProductPendingEdit.TYPE_SAVINGS.equals(productType) || ProductPendingEdit.TYPE_CURRENT.equals(productType)) {
if (submittedFields.contains("accountFacilityConfig") && pendingEdit.getFacilityConfigFields() != null) {
writeFacilityConfigToJson(root, pendingEdit.getFacilityConfigFields(), true);
}
if (submittedFields.contains("depositLimitKyc") && pendingEdit.getDepositLimitKycFields() != null) {
writeDepositLimitKycToJson(root, pendingEdit.getDepositLimitKycFields(), true);
}
if (submittedFields.contains("accountFacilityLimits") && pendingEditFacilityLimitRepository != null) {
writeFacilityLimitsToJson(root, pendingEditFacilityLimitRepository.findByPendingEditId(pendingEdit.getId()));
}
}
if ((ProductPendingEdit.TYPE_FD.equals(productType) || ProductPendingEdit.TYPE_RD.equals(productType)) && pendingEdit.getFixedDepositFields() != null) {
writeFixedDepositFieldsToJson(root, pendingEdit.getFixedDepositFields(), submittedFields);
}
if (ProductPendingEdit.TYPE_RD.equals(productType) && pendingEdit.getRecurringDepositFields() != null) {
writeRecurringDepositFieldsToJson(root, pendingEdit.getRecurringDepositFields(), submittedFields);
}
if (ProductPendingEdit.TYPE_SHARE.equals(productType) && pendingEdit.getShareOnlyFields() != null) {
writeShareOnlyFieldsToJson(root, pendingEdit.getShareOnlyFields(), submittedFields);
}
if (submittedFields.contains("glAccountMapping") && pendingEdit.getGlAccountMappingFields() != null) {
writeGlAccountMappingToJson(root, pendingEdit.getGlAccountMappingFields());
}
if (submittedFields.contains("charges") && pendingEditChargeRepository != null) {
writeChargesToJson(root, pendingEditChargeRepository.findByPendingEditId(pendingEdit.getId()));
}
if (submittedFields.contains("glArrayMappings") && pendingEditGlMappingRepository != null) {
writeGlArrayMappingsToJson(root, pendingEditGlMappingRepository.findByPendingEditId(pendingEdit.getId()));
}
final String json = gson.toJson(root);
return gson.fromJson(json, new com.google.gson.reflect.TypeToken<java.util.Map<String, Object>>() {}.getType());
}
}
@@ -48,28 +48,28 @@ public class SavingsCoreEditFields {
@Column(name = "currency_code")
private String currencyCode;
@Column(name = "digits_after_decimal")
@Column(name = "currency_digits")
private Integer digitsAfterDecimal;
@Column(name = "in_multiples_of")
@Column(name = "currency_multiplesof")
private Integer inMultiplesOf;
@Column(name = "accounting_rule")
@Column(name = "accounting_type")
private Integer accountingRule;
@Column(name = "nominal_annual_interest_rate")
private BigDecimal nominalAnnualInterestRate;
@Column(name = "interest_compounding_period_type")
@Column(name = "interest_compounding_period_enum")
private Integer interestCompoundingPeriodType;
@Column(name = "interest_posting_period_type")
@Column(name = "interest_posting_period_enum")
private Integer interestPostingPeriodType;
@Column(name = "interest_calculation_type")
@Column(name = "interest_calculation_type_enum")
private Integer interestCalculationType;
@Column(name = "interest_calculation_days_in_year_type")
@Column(name = "interest_calculation_days_in_year_type_enum")
private Integer interestCalculationDaysInYearType;
@Column(name = "min_required_opening_balance")
@@ -78,10 +78,10 @@ public class SavingsCoreEditFields {
@Column(name = "lockin_period_frequency")
private Integer lockinPeriodFrequency;
@Column(name = "lockin_period_frequency_type")
@Column(name = "lockin_period_frequency_enum")
private Integer lockinPeriodFrequencyType;
@Column(name = "withdrawal_fee_for_transfers")
@Column(name = "withdrawal_fee_for_transfer")
private Boolean withdrawalFeeForTransfers;
@Column(name = "allow_overdraft")
@@ -102,7 +102,7 @@ public class SavingsCoreEditFields {
@Column(name = "min_required_balance")
private BigDecimal minRequiredBalance;
@Column(name = "lien_allowed")
@Column(name = "is_lien_allowed")
private Boolean lienAllowed;
@Column(name = "max_allowed_lien_limit")
@@ -111,7 +111,7 @@ public class SavingsCoreEditFields {
@Column(name = "min_balance_for_interest_calculation")
private BigDecimal minBalanceForInterestCalculation;
@Column(name = "with_hold_tax")
@Column(name = "withhold_tax")
private Boolean withHoldTax;
@Column(name = "tax_group_id")
@@ -231,4 +231,13 @@ public class SavingsCoreEditFields {
@Column(name = "allow_debit_txn_after_due_date")
private Boolean allowDebitTxnAfterDueDate;
@Column(name = "deposit_type_enum")
private Integer depositTypeEnum;
@Column(name = "withdrawal_fee_amount")
private BigDecimal withdrawalFeeAmount;
@Column(name = "withdrawal_fee_type_enum")
private Integer withdrawalFeeTypeEnum;
}
@@ -32,28 +32,28 @@ public class ShareOnlyEditFields {
@Column(name = "total_shares")
private Long totalShares;
@Column(name = "total_shares_issued")
@Column(name = "issued_shares")
private Long totalSharesIssued;
@Column(name = "unit_price")
private BigDecimal unitPrice;
@Column(name = "minimum_shares")
@Column(name = "minimum_client_shares")
private Long minimumShares;
@Column(name = "nominal_shares")
@Column(name = "nominal_client_shares")
private Long nominalShares;
@Column(name = "maximum_shares")
@Column(name = "maximum_client_shares")
private Long maximumShares;
@Column(name = "allow_dividend_calc_for_inactive_clients")
@Column(name = "allow_dividends_inactive_clients")
private Boolean allowDividendCalcForInactiveClients;
@Column(name = "minimum_active_period_for_dividends")
@Column(name = "minimum_active_period_frequency")
private Integer minimumActivePeriodForDividends;
@Column(name = "minimum_active_period_frequency_type")
@Column(name = "minimum_active_period_frequency_enum")
private Integer minimumActivePeriodFrequencyType;
@Column(name = "share_lockin_period")
@@ -61,4 +61,16 @@ public class ShareOnlyEditFields {
@Column(name = "share_lockin_period_frequency_type")
private Integer shareLockinPeriodFrequencyType;
@Column(name = "external_id")
private String externalId;
@Column(name = "start_date")
private java.time.LocalDate startDate;
@Column(name = "totalsubscribed_shares")
private Long totalsubscribedShares;
@Column(name = "capital_amount")
private BigDecimal capitalAmount;
}
@@ -49,4 +49,6 @@
<include file="parts/2025_recreate_savings_product_temp_table.xml" relativeToChangelogFile="true" />
<include file="parts/2026_add_pending_edit_typed_columns.xml" relativeToChangelogFile="true" />
<include file="parts/2027_add_pending_edit_satellite_tables.xml" relativeToChangelogFile="true" />
<include file="parts/2028_update_saving_product_temp_table.xml" relativeToChangelogFile="true" />
<include file="parts/2029_remove_proposed_payload_json.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
@@ -0,0 +1,93 @@
<?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">
<!-- 1. Rename table m_savings_product_temp to m_saving_product_temp -->
<changeSet author="fineract" id="2028-1">
<preConditions onFail="MARK_RAN">
<tableExists tableName="m_savings_product_temp" />
</preConditions>
<renameTable oldTableName="m_savings_product_temp" newTableName="m_saving_product_temp" />
</changeSet>
<!-- 2. Recreate unique constraint on pending_lock_key if needed -->
<changeSet author="fineract" id="2028-2">
<preConditions onFail="MARK_RAN">
<tableExists tableName="m_saving_product_temp" />
</preConditions>
<dropUniqueConstraint tableName="m_saving_product_temp" constraintName="sp_temp_unq_pending_lock_key" />
<addUniqueConstraint tableName="m_saving_product_temp" columnNames="pending_lock_key" constraintName="sp_temp_unq_pending_lock_key" />
</changeSet>
<!-- 3. Rename columns to match exact user comparative list names -->
<changeSet author="fineract" id="2028-rename-core-columns">
<preConditions onFail="MARK_RAN">
<tableExists tableName="m_saving_product_temp" />
</preConditions>
<!-- Auditing -->
<renameColumn tableName="m_saving_product_temp" oldColumnName="maker_id" newColumnName="createdby_id" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="checker_id" newColumnName="lastmodifiedby_id" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="created_on" newColumnName="created_date" columnDataType="DATETIME" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="checked_on" newColumnName="lastmodified_date" columnDataType="DATETIME" />
<!-- Core fields -->
<renameColumn tableName="m_saving_product_temp" oldColumnName="digits_after_decimal" newColumnName="currency_digits" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="in_multiples_of" newColumnName="currency_multiplesof" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="accounting_rule" newColumnName="accounting_type" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_compounding_period_type" newColumnName="interest_compounding_period_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_posting_period_type" newColumnName="interest_posting_period_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_calculation_type" newColumnName="interest_calculation_type_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="interest_calculation_days_in_year_type" newColumnName="interest_calculation_days_in_year_type_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="lockin_period_frequency_type" newColumnName="lockin_period_frequency_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="withdrawal_fee_for_transfers" newColumnName="withdrawal_fee_for_transfer" columnDataType="BOOLEAN" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="lien_allowed" newColumnName="is_lien_allowed" columnDataType="BOOLEAN" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="with_hold_tax" newColumnName="withhold_tax" columnDataType="BOOLEAN" />
<!-- Share fields -->
<renameColumn tableName="m_saving_product_temp" oldColumnName="total_shares_issued" newColumnName="issued_shares" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_shares" newColumnName="minimum_client_shares" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="nominal_shares" newColumnName="nominal_client_shares" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="maximum_shares" newColumnName="maximum_client_shares" columnDataType="BIGINT" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_active_period_for_dividends" newColumnName="minimum_active_period_frequency" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="minimum_active_period_frequency_type" newColumnName="minimum_active_period_frequency_enum" columnDataType="INTEGER" />
<renameColumn tableName="m_saving_product_temp" oldColumnName="allow_dividend_calc_for_inactive_clients" newColumnName="allow_dividends_inactive_clients" columnDataType="BOOLEAN" />
</changeSet>
<!-- 4. Add the completely new columns to m_saving_product_temp -->
<changeSet author="fineract" id="2028-add-missing-columns">
<preConditions onFail="MARK_RAN">
<tableExists tableName="m_saving_product_temp" />
</preConditions>
<addColumn tableName="m_saving_product_temp">
<!-- If column does not already exist, it will be added. Guard is implicit via preCondition or Liquibase will skip. -->
<column name="deposit_type_enum" type="SMALLINT" />
<column name="withdrawal_fee_amount" type="DECIMAL(19, 6)" />
<column name="withdrawal_fee_type_enum" type="SMALLINT" />
<column name="external_id" type="VARCHAR(100)" />
<column name="start_date" type="DATE" />
<column name="totalsubscribed_shares" type="BIGINT" />
<column name="capital_amount" type="DECIMAL(20, 2)" />
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,30 @@
<?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">
<changeSet author="fineract" id="2029-remove-proposed-payload-json">
<preConditions onFail="MARK_RAN">
<columnExists tableName="m_saving_product_temp" columnName="proposed_payload_json" />
</preConditions>
<dropColumn tableName="m_saving_product_temp" columnName="proposed_payload_json" />
</changeSet>
</databaseChangeLog>