implemented a Maker-Checker workflow for Products, with approval-based updates and product locking to prevent concurrent edits
This commit is contained in:
+2
@@ -495,6 +495,7 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
private Boolean allowDebitTxnAfterDueDate;
|
||||
private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
private String balanceFrequency;
|
||||
private Boolean isPendingApproval;
|
||||
|
||||
// Template option setters
|
||||
public void setInterestCalculationTypeOption(Collection<org.apache.fineract.infrastructure.core.data.EnumOptionData> v) { this.interestCalculationTypeOption = v; }
|
||||
@@ -541,6 +542,7 @@ public final class FixedDepositProductData extends DepositProductData {
|
||||
public void setAllowDebitTxnAfterDueDate(Boolean v) { this.allowDebitTxnAfterDueDate = v; }
|
||||
public void setAccountClosedZeroBalanceInDayClosing(Boolean v) { this.accountClosedZeroBalanceInDayClosing = v; }
|
||||
public void setBalanceFrequency(String v) { this.balanceFrequency = v; }
|
||||
public void setIsPendingApproval(Boolean v) { this.isPendingApproval = v; }
|
||||
|
||||
// CBS field getters
|
||||
public String getProductCode() { return productCode; }
|
||||
|
||||
+2
@@ -98,6 +98,7 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
private Boolean deceasedSettlement;
|
||||
private Boolean allowDebitTxnAfterDueDate;
|
||||
private Boolean withdrawalFeeForTransfers;
|
||||
private Boolean isPendingApproval;
|
||||
|
||||
public void setInterestCalculationTypeOption(Collection<EnumOptionData> v) { this.interestCalculationTypeOption = v; }
|
||||
public void setPeriodFrequencyOptions(Collection<EnumOptionData> v) { this.periodFrequencyOptions = v; }
|
||||
@@ -140,6 +141,7 @@ public final class RecurringDepositProductData extends DepositProductData {
|
||||
public void setDeceasedSettlement(Boolean v) { this.deceasedSettlement = v; }
|
||||
public void setAllowDebitTxnAfterDueDate(Boolean v) { this.allowDebitTxnAfterDueDate = v; }
|
||||
public void setWithdrawalFeeForTransfers(Boolean v) { this.withdrawalFeeForTransfers = v; }
|
||||
public void setIsPendingApproval(Boolean v) { this.isPendingApproval = v; }
|
||||
|
||||
/** Copy all CBS custom fields from source into this instance. */
|
||||
public void copyCbsFieldsFrom(final RecurringDepositProductData src) {
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class CurrentOnlyEditFields {
|
||||
|
||||
@Column(name = "avg_balance_calc_period")
|
||||
private String avgBalanceCalcPeriod;
|
||||
|
||||
@Column(name = "valid_for_period")
|
||||
private String validForPeriod;
|
||||
|
||||
@Column(name = "od_account_closed_zero_balance_in_day_closing")
|
||||
private Boolean odAccountClosedZeroBalanceInDayClosing;
|
||||
}
|
||||
+54
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Mirrors the "depositLimitKyc" JSON object - a 1:1 relationship today, so kept flat here. Note:
|
||||
* the real JSON shape is nested ({@code {general: {kycType, limit}, minor: {...}, smallSaving:
|
||||
* {...}}}), not flat siblings - the replay step is responsible for re-nesting these columns back
|
||||
* into that shape before handing off to the unchanged assembler.
|
||||
*/
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class DepositLimitKycEditFields {
|
||||
|
||||
@Column(name = "kyc_general_type")
|
||||
private String generalType;
|
||||
|
||||
@Column(name = "kyc_general_limit")
|
||||
private String generalLimit;
|
||||
|
||||
@Column(name = "kyc_minor_type")
|
||||
private String minorType;
|
||||
|
||||
@Column(name = "kyc_minor_limit")
|
||||
private Long minorLimit;
|
||||
|
||||
@Column(name = "kyc_small_saving_type")
|
||||
private String smallSavingType;
|
||||
|
||||
@Column(name = "kyc_small_saving_limit")
|
||||
private Long smallSavingLimit;
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/** Mirrors the "accountFacilityConfig" JSON object - a 1:1 relationship today, so kept flat here. */
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class FacilityConfigEditFields {
|
||||
|
||||
@Column(name = "fc_atm_facility")
|
||||
private Boolean atmFacility;
|
||||
|
||||
@Column(name = "fc_atm_withdrawal_facility")
|
||||
private Boolean atmWithdrawalFacility;
|
||||
|
||||
@Column(name = "fc_upi_facility")
|
||||
private Boolean upiFacility;
|
||||
|
||||
@Column(name = "fc_pos_transactions_facility")
|
||||
private Boolean posTransactionsFacility;
|
||||
|
||||
@Column(name = "fc_cheque_book")
|
||||
private Boolean chequeBook;
|
||||
|
||||
@Column(name = "fc_imps_facility")
|
||||
private Boolean impsFacility;
|
||||
|
||||
@Column(name = "fc_sms_alerts")
|
||||
private Boolean smsAlerts;
|
||||
|
||||
@Column(name = "fc_bbps_facility")
|
||||
private Boolean bbpsFacility;
|
||||
|
||||
@Column(name = "fc_insurance_cover")
|
||||
private Boolean insuranceCover;
|
||||
|
||||
@Column(name = "fc_bepg_facility")
|
||||
private Boolean bepgFacility;
|
||||
|
||||
@Column(name = "fc_neft_facility")
|
||||
private Boolean neftFacility;
|
||||
|
||||
@Column(name = "fc_rtgs_facility")
|
||||
private Boolean rtgsFacility;
|
||||
|
||||
@Column(name = "fc_inter_bank_total_cap_facility")
|
||||
private Boolean interBankTotalCapFacility;
|
||||
|
||||
@Column(name = "fc_withdrawal_facility")
|
||||
private Boolean withdrawalFacility;
|
||||
|
||||
@Column(name = "fc_deposit_facility_kyc")
|
||||
private Boolean depositFacilityKyc;
|
||||
|
||||
@Column(name = "fc_virtual_debit_card")
|
||||
private Boolean virtualDebitCard;
|
||||
}
|
||||
+71
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/** Also used by Recurring Deposit, which extends Fixed Deposit. */
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class FixedDepositEditFields {
|
||||
|
||||
@Column(name = "fd_type")
|
||||
private String fdType;
|
||||
|
||||
@Column(name = "pre_closure_penal_applicable")
|
||||
private Boolean preClosurePenalApplicable;
|
||||
|
||||
@Column(name = "pre_closure_penal_interest")
|
||||
private BigDecimal preClosurePenalInterest;
|
||||
|
||||
@Column(name = "pre_closure_penal_interest_on_type_id")
|
||||
private Integer preClosurePenalInterestOnTypeId;
|
||||
|
||||
@Column(name = "min_deposit_term")
|
||||
private Integer minDepositTerm;
|
||||
|
||||
@Column(name = "max_deposit_term")
|
||||
private Integer maxDepositTerm;
|
||||
|
||||
@Column(name = "min_deposit_term_type_id")
|
||||
private Integer minDepositTermTypeId;
|
||||
|
||||
@Column(name = "max_deposit_term_type_id")
|
||||
private Integer maxDepositTermTypeId;
|
||||
|
||||
@Column(name = "in_multiples_of_deposit_term")
|
||||
private Integer inMultiplesOfDepositTerm;
|
||||
|
||||
@Column(name = "in_multiples_of_deposit_term_type_id")
|
||||
private Integer inMultiplesOfDepositTermTypeId;
|
||||
|
||||
@Column(name = "min_deposit_amount")
|
||||
private BigDecimal minDepositAmount;
|
||||
|
||||
@Column(name = "max_deposit_amount")
|
||||
private BigDecimal maxDepositAmount;
|
||||
|
||||
@Column(name = "deposit_amount")
|
||||
private BigDecimal depositAmount;
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Scalar (1:1) GL account mapping ids. No FK constraints to the accounting GL table - the
|
||||
* existing validator already checks GL account validity at submit time. The 3 array-shaped GL
|
||||
* mappings (payment-channel/fee/penalty to income account) live in m_product_temp_gl_mapping
|
||||
* instead, since those are genuinely one-to-many.
|
||||
*/
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class GlAccountMappingEditFields {
|
||||
|
||||
@Column(name = "gl_savings_reference_account_id")
|
||||
private Long savingsReferenceAccountId;
|
||||
|
||||
@Column(name = "gl_savings_control_account_id")
|
||||
private Long savingsControlAccountId;
|
||||
|
||||
@Column(name = "gl_income_from_fee_account_id")
|
||||
private Long incomeFromFeeAccountId;
|
||||
|
||||
@Column(name = "gl_income_from_penalty_account_id")
|
||||
private Long incomeFromPenaltyAccountId;
|
||||
|
||||
@Column(name = "gl_interest_on_savings_account_id")
|
||||
private Long interestOnSavingsAccountId;
|
||||
|
||||
@Column(name = "gl_transfers_in_suspense_account_id")
|
||||
private Long transfersInSuspenseAccountId;
|
||||
|
||||
@Column(name = "gl_overdraft_portfolio_control_id")
|
||||
private Long overdraftPortfolioControlId;
|
||||
|
||||
@Column(name = "gl_income_from_interest_id")
|
||||
private Long incomeFromInterestId;
|
||||
|
||||
@Column(name = "gl_write_off_account_id")
|
||||
private Long writeOffAccountId;
|
||||
|
||||
@Column(name = "gl_escheat_liability_id")
|
||||
private Long escheatLiabilityId;
|
||||
|
||||
@Column(name = "gl_penalties_receivable_account_id")
|
||||
private Long penaltiesReceivableAccountId;
|
||||
|
||||
@Column(name = "gl_interest_receivable_account_id")
|
||||
private Long interestReceivableAccountId;
|
||||
|
||||
@Column(name = "gl_fees_receivable_account_id")
|
||||
private Long feesReceivableAccountId;
|
||||
|
||||
@Column(name = "gl_interest_payable_account_id")
|
||||
private Long interestPayableAccountId;
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
|
||||
/**
|
||||
* Holds a single pending product edit, shared across product types (Savings, Current Account, Share) in one table
|
||||
* (m_savings_product_temp). Presence of a row here for a given (productType, productId) with
|
||||
* {@code status = PENDING} is itself the lock - no separate "is locked" column anywhere. The full edit request body
|
||||
* is kept in {@link #proposedPayloadJson} so approval can replay it through each product's normal update path
|
||||
* (covering charges, GL/accounting mappings and other related tables, not just scalar columns).
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_savings_product_temp")
|
||||
@Getter
|
||||
@Setter
|
||||
public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
|
||||
|
||||
public static final String STATUS_PENDING = "PENDING";
|
||||
public static final String STATUS_APPROVED = "APPROVED";
|
||||
public static final String STATUS_REJECTED = "REJECTED";
|
||||
|
||||
public static final String TYPE_SAVINGS = "SAVINGS";
|
||||
public static final String TYPE_CURRENT = "CURRENT";
|
||||
public static final String TYPE_SHARE = "SHARE";
|
||||
public static final String TYPE_FD = "FD";
|
||||
public static final String TYPE_RD = "RD";
|
||||
|
||||
@Column(name = "product_id", nullable = false)
|
||||
private Long productId;
|
||||
|
||||
@Column(name = "product_type", nullable = false, length = 20)
|
||||
private String productType;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "maker_id", nullable = false)
|
||||
private AppUser maker;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "checker_id")
|
||||
private AppUser checker;
|
||||
|
||||
@Column(name = "created_on", nullable = false)
|
||||
private LocalDateTime createdOn;
|
||||
|
||||
@Column(name = "checked_on")
|
||||
private LocalDateTime checkedOn;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private String status;
|
||||
|
||||
@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
|
||||
* NULL as distinct in both PostgreSQL and MySQL/MariaDB, so only one PENDING row per (productType, productId)
|
||||
* can ever exist, while resolved rows are kept indefinitely for audit history without blocking future edits.
|
||||
*/
|
||||
@Column(name = "pending_lock_key", length = 40)
|
||||
private String pendingLockKey;
|
||||
|
||||
/** Links to the audit-only m_portfolio_command_source row created for this edit's submit/approve/reject. */
|
||||
@Column(name = "command_source_id")
|
||||
private Long commandSourceId;
|
||||
|
||||
/**
|
||||
* Typed replacement for proposedPayloadJson - one embeddable group per concern, all mapped
|
||||
* onto this same physical table. proposedPayloadJson is still populated (kept for a safe
|
||||
* deprecation window) but a product type's write-service uses these typed columns, plus the
|
||||
* satellite tables (ProductPendingEditCharge/FacilityLimit/GlMapping/MarketPrice) and the
|
||||
* ProductPendingEditSubmittedField manifest, to build and replay an edit once its cutover
|
||||
* (see SavingsProductWritePlatformServiceJpaRepositoryImpl and siblings) is complete.
|
||||
*/
|
||||
@Embedded
|
||||
private SavingsCoreEditFields coreFields = new SavingsCoreEditFields();
|
||||
|
||||
@Embedded
|
||||
private CurrentOnlyEditFields currentOnlyFields = new CurrentOnlyEditFields();
|
||||
|
||||
@Embedded
|
||||
private ShareOnlyEditFields shareOnlyFields = new ShareOnlyEditFields();
|
||||
|
||||
@Embedded
|
||||
private FixedDepositEditFields fixedDepositFields = new FixedDepositEditFields();
|
||||
|
||||
@Embedded
|
||||
private RecurringDepositEditFields recurringDepositFields = new RecurringDepositEditFields();
|
||||
|
||||
@Embedded
|
||||
private FacilityConfigEditFields facilityConfigFields = new FacilityConfigEditFields();
|
||||
|
||||
@Embedded
|
||||
private DepositLimitKycEditFields depositLimitKycFields = new DepositLimitKycEditFields();
|
||||
|
||||
@Embedded
|
||||
private GlAccountMappingEditFields glAccountMappingFields = new GlAccountMappingEditFields();
|
||||
|
||||
protected ProductPendingEdit() {}
|
||||
|
||||
public ProductPendingEdit(final String productType, final Long productId, final AppUser maker, final String proposedPayloadJson) {
|
||||
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);
|
||||
}
|
||||
|
||||
public static String lockKeyFor(final String productType, final Long productId) {
|
||||
return productType + ":" + productId;
|
||||
}
|
||||
|
||||
public Long getProductId() {
|
||||
return this.productId;
|
||||
}
|
||||
|
||||
public String getProductType() {
|
||||
return this.productType;
|
||||
}
|
||||
|
||||
public AppUser getMaker() {
|
||||
return this.maker;
|
||||
}
|
||||
|
||||
public AppUser getChecker() {
|
||||
return this.checker;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedOn() {
|
||||
return this.createdOn;
|
||||
}
|
||||
|
||||
public LocalDateTime getCheckedOn() {
|
||||
return this.checkedOn;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getRejectReason() {
|
||||
return this.rejectReason;
|
||||
}
|
||||
|
||||
public String getProposedPayloadJson() {
|
||||
return this.proposedPayloadJson;
|
||||
}
|
||||
|
||||
public Long getCommandSourceId() {
|
||||
return this.commandSourceId;
|
||||
}
|
||||
|
||||
public void setCommandSourceId(final Long commandSourceId) {
|
||||
this.commandSourceId = commandSourceId;
|
||||
}
|
||||
|
||||
public boolean isPending() {
|
||||
return STATUS_PENDING.equals(this.status);
|
||||
}
|
||||
|
||||
public void markApproved(final AppUser checker) {
|
||||
this.status = STATUS_APPROVED;
|
||||
this.checker = checker;
|
||||
this.checkedOn = LocalDateTime.now();
|
||||
this.pendingLockKey = null;
|
||||
}
|
||||
|
||||
public void markRejected(final AppUser checker, final String reason) {
|
||||
this.status = STATUS_REJECTED;
|
||||
this.checker = checker;
|
||||
this.checkedOn = LocalDateTime.now();
|
||||
this.rejectReason = reason;
|
||||
this.pendingLockKey = null;
|
||||
}
|
||||
}
|
||||
+50
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
/** One row per charge id proposed to be attached to the product, mirroring the "charges" array. */
|
||||
@Entity
|
||||
@Table(name = "m_product_temp_charge")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ProductPendingEditCharge extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "pending_edit_id", nullable = false)
|
||||
private ProductPendingEdit pendingEdit;
|
||||
|
||||
@Column(name = "charge_id", nullable = false)
|
||||
private Long chargeId;
|
||||
|
||||
public ProductPendingEditCharge(final ProductPendingEdit pendingEdit, final Long chargeId) {
|
||||
this.pendingEdit = pendingEdit;
|
||||
this.chargeId = chargeId;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditChargeRepository extends JpaRepository<ProductPendingEditCharge, Long> {
|
||||
|
||||
List<ProductPendingEditCharge> findByPendingEditId(Long pendingEditId);
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
/** One row per entry of the "accountFacilityLimits" array. Values can be "UNLIMITED"/"N/A"/numeric-as-string. */
|
||||
@Entity
|
||||
@Table(name = "m_product_temp_facility_limit")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ProductPendingEditFacilityLimit extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "pending_edit_id", nullable = false)
|
||||
private ProductPendingEdit pendingEdit;
|
||||
|
||||
@Column(name = "limit_type", nullable = false)
|
||||
private String limitType;
|
||||
|
||||
@Column(name = "general_limit")
|
||||
private String generalLimit;
|
||||
|
||||
@Column(name = "minor_account_limit")
|
||||
private String minorAccountLimit;
|
||||
|
||||
@Column(name = "small_saving_limit")
|
||||
private String smallSavingLimit;
|
||||
|
||||
public ProductPendingEditFacilityLimit(final ProductPendingEdit pendingEdit, final String limitType, final String generalLimit,
|
||||
final String minorAccountLimit, final String smallSavingLimit) {
|
||||
this.pendingEdit = pendingEdit;
|
||||
this.limitType = limitType;
|
||||
this.generalLimit = generalLimit;
|
||||
this.minorAccountLimit = minorAccountLimit;
|
||||
this.smallSavingLimit = smallSavingLimit;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditFacilityLimitRepository extends JpaRepository<ProductPendingEditFacilityLimit, Long> {
|
||||
|
||||
List<ProductPendingEditFacilityLimit> findByPendingEditId(Long pendingEditId);
|
||||
}
|
||||
+696
@@ -0,0 +1,696 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
|
||||
/**
|
||||
* Shared submit-time extraction / approve-time reconstruction logic for the scalar and 1:1
|
||||
* "container" fields that Savings, Current, Fixed Deposit and Recurring Deposit products all have
|
||||
* in common (FD/RD extend the Savings field set). Each populateXxx method reads present JSON
|
||||
* parameters into the corresponding typed embeddable, returning the set of parameter names it
|
||||
* found (which the caller must persist as {@link ProductPendingEditSubmittedField} rows - this is
|
||||
* how the manifest preserves "field omitted" vs "field explicitly null" vs "field has a value").
|
||||
* Each writeXxxToJson method is the exact inverse, used at approval time to rebuild a JsonObject
|
||||
* equivalent to what the maker originally submitted, before handing it to the unchanged
|
||||
* update()/updateProduct() methods via JsonCommand.fromJsonElement(...).
|
||||
*
|
||||
* Share Product's field set is largely disjoint from this shared core and is mapped separately.
|
||||
*/
|
||||
public final class ProductPendingEditFieldMapper {
|
||||
|
||||
private ProductPendingEditFieldMapper() {}
|
||||
|
||||
// ---- Savings/Current/FD/RD shared core fields ----------------------------------------------
|
||||
|
||||
public static Set<String> populateCoreFields(final JsonCommand command, final SavingsCoreEditFields f) {
|
||||
final Set<String> present = new HashSet<>();
|
||||
|
||||
if (command.hasParameter("name")) {
|
||||
f.setName(command.stringValueOfParameterNamed("name"));
|
||||
present.add("name");
|
||||
}
|
||||
if (command.hasParameter("shortName")) {
|
||||
f.setShortName(command.stringValueOfParameterNamed("shortName"));
|
||||
present.add("shortName");
|
||||
}
|
||||
if (command.hasParameter("description")) {
|
||||
f.setDescription(command.stringValueOfParameterNamed("description"));
|
||||
present.add("description");
|
||||
}
|
||||
if (command.hasParameter("currencyCode")) {
|
||||
f.setCurrencyCode(command.stringValueOfParameterNamed("currencyCode"));
|
||||
present.add("currencyCode");
|
||||
}
|
||||
if (command.hasParameter("digitsAfterDecimal")) {
|
||||
f.setDigitsAfterDecimal(command.integerValueOfParameterNamed("digitsAfterDecimal"));
|
||||
present.add("digitsAfterDecimal");
|
||||
}
|
||||
if (command.hasParameter("inMultiplesOf")) {
|
||||
f.setInMultiplesOf(command.integerValueOfParameterNamed("inMultiplesOf"));
|
||||
present.add("inMultiplesOf");
|
||||
}
|
||||
if (command.hasParameter("accountingRule")) {
|
||||
f.setAccountingRule(command.integerValueOfParameterNamed("accountingRule"));
|
||||
present.add("accountingRule");
|
||||
}
|
||||
if (command.hasParameter("nominalAnnualInterestRate")) {
|
||||
f.setNominalAnnualInterestRate(command.bigDecimalValueOfParameterNamed("nominalAnnualInterestRate"));
|
||||
present.add("nominalAnnualInterestRate");
|
||||
}
|
||||
if (command.hasParameter("interestCompoundingPeriodType")) {
|
||||
f.setInterestCompoundingPeriodType(command.integerValueOfParameterNamed("interestCompoundingPeriodType"));
|
||||
present.add("interestCompoundingPeriodType");
|
||||
}
|
||||
if (command.hasParameter("interestPostingPeriodType")) {
|
||||
f.setInterestPostingPeriodType(command.integerValueOfParameterNamed("interestPostingPeriodType"));
|
||||
present.add("interestPostingPeriodType");
|
||||
}
|
||||
if (command.hasParameter("interestCalculationType")) {
|
||||
f.setInterestCalculationType(command.integerValueOfParameterNamed("interestCalculationType"));
|
||||
present.add("interestCalculationType");
|
||||
}
|
||||
if (command.hasParameter("interestCalculationDaysInYearType")) {
|
||||
f.setInterestCalculationDaysInYearType(command.integerValueOfParameterNamed("interestCalculationDaysInYearType"));
|
||||
present.add("interestCalculationDaysInYearType");
|
||||
}
|
||||
if (command.hasParameter("minRequiredOpeningBalance")) {
|
||||
f.setMinRequiredOpeningBalance(command.bigDecimalValueOfParameterNamed("minRequiredOpeningBalance"));
|
||||
present.add("minRequiredOpeningBalance");
|
||||
}
|
||||
if (command.hasParameter("lockinPeriodFrequency")) {
|
||||
f.setLockinPeriodFrequency(command.integerValueOfParameterNamed("lockinPeriodFrequency"));
|
||||
present.add("lockinPeriodFrequency");
|
||||
}
|
||||
if (command.hasParameter("lockinPeriodFrequencyType")) {
|
||||
f.setLockinPeriodFrequencyType(command.integerValueOfParameterNamed("lockinPeriodFrequencyType"));
|
||||
present.add("lockinPeriodFrequencyType");
|
||||
}
|
||||
if (command.hasParameter("withdrawalFeeForTransfers")) {
|
||||
f.setWithdrawalFeeForTransfers(command.booleanObjectValueOfParameterNamed("withdrawalFeeForTransfers"));
|
||||
present.add("withdrawalFeeForTransfers");
|
||||
}
|
||||
if (command.hasParameter("allowOverdraft")) {
|
||||
f.setAllowOverdraft(command.booleanObjectValueOfParameterNamed("allowOverdraft"));
|
||||
present.add("allowOverdraft");
|
||||
}
|
||||
if (command.hasParameter("overdraftLimit")) {
|
||||
f.setOverdraftLimit(command.bigDecimalValueOfParameterNamed("overdraftLimit"));
|
||||
present.add("overdraftLimit");
|
||||
}
|
||||
if (command.hasParameter("nominalAnnualInterestRateOverdraft")) {
|
||||
f.setNominalAnnualInterestRateOverdraft(command.bigDecimalValueOfParameterNamed("nominalAnnualInterestRateOverdraft"));
|
||||
present.add("nominalAnnualInterestRateOverdraft");
|
||||
}
|
||||
if (command.hasParameter("minOverdraftForInterestCalculation")) {
|
||||
f.setMinOverdraftForInterestCalculation(command.bigDecimalValueOfParameterNamed("minOverdraftForInterestCalculation"));
|
||||
present.add("minOverdraftForInterestCalculation");
|
||||
}
|
||||
if (command.hasParameter("enforceMinRequiredBalance")) {
|
||||
f.setEnforceMinRequiredBalance(command.booleanObjectValueOfParameterNamed("enforceMinRequiredBalance"));
|
||||
present.add("enforceMinRequiredBalance");
|
||||
}
|
||||
if (command.hasParameter("minRequiredBalance")) {
|
||||
f.setMinRequiredBalance(command.bigDecimalValueOfParameterNamed("minRequiredBalance"));
|
||||
present.add("minRequiredBalance");
|
||||
}
|
||||
if (command.hasParameter("lienAllowed")) {
|
||||
f.setLienAllowed(command.booleanObjectValueOfParameterNamed("lienAllowed"));
|
||||
present.add("lienAllowed");
|
||||
}
|
||||
if (command.hasParameter("maxAllowedLienLimit")) {
|
||||
f.setMaxAllowedLienLimit(command.bigDecimalValueOfParameterNamed("maxAllowedLienLimit"));
|
||||
present.add("maxAllowedLienLimit");
|
||||
}
|
||||
if (command.hasParameter("minBalanceForInterestCalculation")) {
|
||||
f.setMinBalanceForInterestCalculation(command.bigDecimalValueOfParameterNamed("minBalanceForInterestCalculation"));
|
||||
present.add("minBalanceForInterestCalculation");
|
||||
}
|
||||
if (command.hasParameter("withHoldTax")) {
|
||||
f.setWithHoldTax(command.booleanObjectValueOfParameterNamed("withHoldTax"));
|
||||
present.add("withHoldTax");
|
||||
}
|
||||
if (command.hasParameter("taxGroupId")) {
|
||||
f.setTaxGroupId(command.longValueOfParameterNamed("taxGroupId"));
|
||||
present.add("taxGroupId");
|
||||
}
|
||||
if (command.hasParameter("otherGlMappings")) {
|
||||
f.setOtherGlMappings(command.stringValueOfParameterNamed("otherGlMappings"));
|
||||
present.add("otherGlMappings");
|
||||
}
|
||||
if (command.hasParameter("isDormancyTrackingActive")) {
|
||||
f.setIsDormancyTrackingActive(command.booleanObjectValueOfParameterNamed("isDormancyTrackingActive"));
|
||||
present.add("isDormancyTrackingActive");
|
||||
}
|
||||
if (command.hasParameter("daysToInactive")) {
|
||||
f.setDaysToInactive(command.integerValueOfParameterNamed("daysToInactive"));
|
||||
present.add("daysToInactive");
|
||||
}
|
||||
if (command.hasParameter("daysToDormancy")) {
|
||||
f.setDaysToDormancy(command.integerValueOfParameterNamed("daysToDormancy"));
|
||||
present.add("daysToDormancy");
|
||||
}
|
||||
if (command.hasParameter("daysToEscheat")) {
|
||||
f.setDaysToEscheat(command.integerValueOfParameterNamed("daysToEscheat"));
|
||||
present.add("daysToEscheat");
|
||||
}
|
||||
if (command.hasParameter("accountType")) {
|
||||
f.setAccountType(command.stringValueOfParameterNamed("accountType"));
|
||||
present.add("accountType");
|
||||
}
|
||||
if (command.hasParameter("customerSegment")) {
|
||||
f.setCustomerSegment(command.stringValueOfParameterNamed("customerSegment"));
|
||||
present.add("customerSegment");
|
||||
}
|
||||
if (command.hasParameter("productCode")) {
|
||||
f.setProductCode(command.stringValueOfParameterNamed("productCode"));
|
||||
present.add("productCode");
|
||||
}
|
||||
if (command.hasParameter("glAccountId")) {
|
||||
f.setGlAccountId(command.longValueOfParameterNamed("glAccountId"));
|
||||
present.add("glAccountId");
|
||||
}
|
||||
if (command.hasParameter("effectiveDate")) {
|
||||
f.setEffectiveDate(command.localDateValueOfParameterNamed("effectiveDate"));
|
||||
present.add("effectiveDate");
|
||||
}
|
||||
if (command.hasParameter("effectiveTo")) {
|
||||
f.setEffectiveTo(command.localDateValueOfParameterNamed("effectiveTo"));
|
||||
present.add("effectiveTo");
|
||||
}
|
||||
if (command.hasParameter("endDate")) {
|
||||
f.setEndDate(command.localDateValueOfParameterNamed("endDate"));
|
||||
present.add("endDate");
|
||||
}
|
||||
if (command.hasParameter("introducerRequired")) {
|
||||
f.setIntroducerRequired(command.booleanObjectValueOfParameterNamed("introducerRequired"));
|
||||
present.add("introducerRequired");
|
||||
}
|
||||
if (command.hasParameter("shareLinkingEnabled")) {
|
||||
f.setShareLinkingEnabled(command.booleanObjectValueOfParameterNamed("shareLinkingEnabled"));
|
||||
present.add("shareLinkingEnabled");
|
||||
}
|
||||
if (command.hasParameter("nominationFacility")) {
|
||||
f.setNominationFacility(command.booleanObjectValueOfParameterNamed("nominationFacility"));
|
||||
present.add("nominationFacility");
|
||||
}
|
||||
if (command.hasParameter("dormancyAlert")) {
|
||||
f.setDormancyAlert(command.booleanObjectValueOfParameterNamed("dormancyAlert"));
|
||||
present.add("dormancyAlert");
|
||||
}
|
||||
if (command.hasParameter("interestCalculateSelector")) {
|
||||
f.setInterestCalculateSelector(command.integerValueOfParameterNamed("interestCalculateSelector"));
|
||||
present.add("interestCalculateSelector");
|
||||
}
|
||||
if (command.hasParameter("averagePeriod")) {
|
||||
f.setAveragePeriod(command.stringValueOfParameterNamed("averagePeriod"));
|
||||
present.add("averagePeriod");
|
||||
}
|
||||
if (command.hasParameter("autoPost")) {
|
||||
f.setAutoPost(command.booleanObjectValueOfParameterNamed("autoPost"));
|
||||
present.add("autoPost");
|
||||
}
|
||||
if (command.hasParameter("frequencyFixDay")) {
|
||||
f.setFrequencyFixDay(command.integerValueOfParameterNamed("frequencyFixDay"));
|
||||
present.add("frequencyFixDay");
|
||||
}
|
||||
if (command.hasParameter("lastInterestDate")) {
|
||||
f.setLastInterestDate(command.localDateValueOfParameterNamed("lastInterestDate"));
|
||||
present.add("lastInterestDate");
|
||||
}
|
||||
if (command.hasParameter("enableLockinPeriod")) {
|
||||
f.setEnableLockinPeriod(command.booleanObjectValueOfParameterNamed("enableLockinPeriod"));
|
||||
present.add("enableLockinPeriod");
|
||||
}
|
||||
if (command.hasParameter("balanceFrequency")) {
|
||||
f.setBalanceFrequency(command.stringValueOfParameterNamed("balanceFrequency"));
|
||||
present.add("balanceFrequency");
|
||||
}
|
||||
if (command.hasParameter("accountClosedZeroBalanceInDayClosing")) {
|
||||
f.setAccountClosedZeroBalanceInDayClosing(command.booleanObjectValueOfParameterNamed("accountClosedZeroBalanceInDayClosing"));
|
||||
present.add("accountClosedZeroBalanceInDayClosing");
|
||||
}
|
||||
if (command.hasParameter("balanceSwapOption")) {
|
||||
f.setBalanceSwapOption(command.booleanObjectValueOfParameterNamed("balanceSwapOption"));
|
||||
present.add("balanceSwapOption");
|
||||
}
|
||||
if (command.hasParameter("msme")) {
|
||||
f.setMsme(command.booleanObjectValueOfParameterNamed("msme"));
|
||||
present.add("msme");
|
||||
}
|
||||
if (command.hasParameter("autoDebitFacility")) {
|
||||
f.setAutoDebitFacility(command.booleanObjectValueOfParameterNamed("autoDebitFacility"));
|
||||
present.add("autoDebitFacility");
|
||||
}
|
||||
if (command.hasParameter("loanFacility")) {
|
||||
f.setLoanFacility(command.booleanObjectValueOfParameterNamed("loanFacility"));
|
||||
present.add("loanFacility");
|
||||
}
|
||||
if (command.hasParameter("prematureWithdrawalOption")) {
|
||||
f.setPrematureWithdrawalOption(command.booleanObjectValueOfParameterNamed("prematureWithdrawalOption"));
|
||||
present.add("prematureWithdrawalOption");
|
||||
}
|
||||
if (command.hasParameter("tenureFlexibility")) {
|
||||
f.setTenureFlexibility(command.booleanObjectValueOfParameterNamed("tenureFlexibility"));
|
||||
present.add("tenureFlexibility");
|
||||
}
|
||||
if (command.hasParameter("lienMarked")) {
|
||||
f.setLienMarked(command.booleanObjectValueOfParameterNamed("lienMarked"));
|
||||
present.add("lienMarked");
|
||||
}
|
||||
if (command.hasParameter("maturityInstructions")) {
|
||||
f.setMaturityInstructions(command.booleanObjectValueOfParameterNamed("maturityInstructions"));
|
||||
present.add("maturityInstructions");
|
||||
}
|
||||
if (command.hasParameter("creditMaturityProceeds")) {
|
||||
f.setCreditMaturityProceeds(command.booleanObjectValueOfParameterNamed("creditMaturityProceeds"));
|
||||
present.add("creditMaturityProceeds");
|
||||
}
|
||||
if (command.hasParameter("penaltyGracePeriodMissedInstallments")) {
|
||||
f.setPenaltyGracePeriodMissedInstallments(command.booleanObjectValueOfParameterNamed("penaltyGracePeriodMissedInstallments"));
|
||||
present.add("penaltyGracePeriodMissedInstallments");
|
||||
}
|
||||
if (command.hasParameter("panelRequestApplicable")) {
|
||||
f.setPanelRequestApplicable(command.booleanObjectValueOfParameterNamed("panelRequestApplicable"));
|
||||
present.add("panelRequestApplicable");
|
||||
}
|
||||
if (command.hasParameter("noPenaltyNomineeHeirClosure")) {
|
||||
f.setNoPenaltyNomineeHeirClosure(command.booleanObjectValueOfParameterNamed("noPenaltyNomineeHeirClosure"));
|
||||
present.add("noPenaltyNomineeHeirClosure");
|
||||
}
|
||||
if (command.hasParameter("deceasedSettlement")) {
|
||||
f.setDeceasedSettlement(command.booleanObjectValueOfParameterNamed("deceasedSettlement"));
|
||||
present.add("deceasedSettlement");
|
||||
}
|
||||
if (command.hasParameter("allowDebitTxnAfterDueDate")) {
|
||||
f.setAllowDebitTxnAfterDueDate(command.booleanObjectValueOfParameterNamed("allowDebitTxnAfterDueDate"));
|
||||
present.add("allowDebitTxnAfterDueDate");
|
||||
}
|
||||
return present;
|
||||
}
|
||||
|
||||
public static void writeCoreFieldsToJson(final JsonObject root, final SavingsCoreEditFields f, final Set<String> submitted) {
|
||||
putString(root, submitted, "name", f.getName());
|
||||
putString(root, submitted, "shortName", f.getShortName());
|
||||
putString(root, submitted, "description", f.getDescription());
|
||||
putString(root, submitted, "currencyCode", f.getCurrencyCode());
|
||||
putNumber(root, submitted, "digitsAfterDecimal", f.getDigitsAfterDecimal());
|
||||
putNumber(root, submitted, "inMultiplesOf", f.getInMultiplesOf());
|
||||
putNumber(root, submitted, "accountingRule", f.getAccountingRule());
|
||||
putNumber(root, submitted, "nominalAnnualInterestRate", f.getNominalAnnualInterestRate());
|
||||
putNumber(root, submitted, "interestCompoundingPeriodType", f.getInterestCompoundingPeriodType());
|
||||
putNumber(root, submitted, "interestPostingPeriodType", f.getInterestPostingPeriodType());
|
||||
putNumber(root, submitted, "interestCalculationType", f.getInterestCalculationType());
|
||||
putNumber(root, submitted, "interestCalculationDaysInYearType", f.getInterestCalculationDaysInYearType());
|
||||
putNumber(root, submitted, "minRequiredOpeningBalance", f.getMinRequiredOpeningBalance());
|
||||
putNumber(root, submitted, "lockinPeriodFrequency", f.getLockinPeriodFrequency());
|
||||
putNumber(root, submitted, "lockinPeriodFrequencyType", f.getLockinPeriodFrequencyType());
|
||||
putBoolean(root, submitted, "withdrawalFeeForTransfers", f.getWithdrawalFeeForTransfers());
|
||||
putBoolean(root, submitted, "allowOverdraft", f.getAllowOverdraft());
|
||||
putNumber(root, submitted, "overdraftLimit", f.getOverdraftLimit());
|
||||
putNumber(root, submitted, "nominalAnnualInterestRateOverdraft", f.getNominalAnnualInterestRateOverdraft());
|
||||
putNumber(root, submitted, "minOverdraftForInterestCalculation", f.getMinOverdraftForInterestCalculation());
|
||||
putBoolean(root, submitted, "enforceMinRequiredBalance", f.getEnforceMinRequiredBalance());
|
||||
putNumber(root, submitted, "minRequiredBalance", f.getMinRequiredBalance());
|
||||
putBoolean(root, submitted, "lienAllowed", f.getLienAllowed());
|
||||
putNumber(root, submitted, "maxAllowedLienLimit", f.getMaxAllowedLienLimit());
|
||||
putNumber(root, submitted, "minBalanceForInterestCalculation", f.getMinBalanceForInterestCalculation());
|
||||
putBoolean(root, submitted, "withHoldTax", f.getWithHoldTax());
|
||||
putNumber(root, submitted, "taxGroupId", f.getTaxGroupId());
|
||||
putString(root, submitted, "otherGlMappings", f.getOtherGlMappings());
|
||||
putBoolean(root, submitted, "isDormancyTrackingActive", f.getIsDormancyTrackingActive());
|
||||
putNumber(root, submitted, "daysToInactive", f.getDaysToInactive());
|
||||
putNumber(root, submitted, "daysToDormancy", f.getDaysToDormancy());
|
||||
putNumber(root, submitted, "daysToEscheat", f.getDaysToEscheat());
|
||||
putString(root, submitted, "accountType", f.getAccountType());
|
||||
putString(root, submitted, "customerSegment", f.getCustomerSegment());
|
||||
putString(root, submitted, "productCode", f.getProductCode());
|
||||
putNumber(root, submitted, "glAccountId", f.getGlAccountId());
|
||||
putDate(root, submitted, "effectiveDate", f.getEffectiveDate());
|
||||
putDate(root, submitted, "effectiveTo", f.getEffectiveTo());
|
||||
putDate(root, submitted, "endDate", f.getEndDate());
|
||||
putBoolean(root, submitted, "introducerRequired", f.getIntroducerRequired());
|
||||
putBoolean(root, submitted, "shareLinkingEnabled", f.getShareLinkingEnabled());
|
||||
putBoolean(root, submitted, "nominationFacility", f.getNominationFacility());
|
||||
putBoolean(root, submitted, "dormancyAlert", f.getDormancyAlert());
|
||||
putNumber(root, submitted, "interestCalculateSelector", f.getInterestCalculateSelector());
|
||||
putString(root, submitted, "averagePeriod", f.getAveragePeriod());
|
||||
putBoolean(root, submitted, "autoPost", f.getAutoPost());
|
||||
putNumber(root, submitted, "frequencyFixDay", f.getFrequencyFixDay());
|
||||
putDate(root, submitted, "lastInterestDate", f.getLastInterestDate());
|
||||
putBoolean(root, submitted, "enableLockinPeriod", f.getEnableLockinPeriod());
|
||||
putString(root, submitted, "balanceFrequency", f.getBalanceFrequency());
|
||||
putBoolean(root, submitted, "accountClosedZeroBalanceInDayClosing", f.getAccountClosedZeroBalanceInDayClosing());
|
||||
putBoolean(root, submitted, "balanceSwapOption", f.getBalanceSwapOption());
|
||||
putBoolean(root, submitted, "msme", f.getMsme());
|
||||
putBoolean(root, submitted, "autoDebitFacility", f.getAutoDebitFacility());
|
||||
putBoolean(root, submitted, "loanFacility", f.getLoanFacility());
|
||||
putBoolean(root, submitted, "prematureWithdrawalOption", f.getPrematureWithdrawalOption());
|
||||
putBoolean(root, submitted, "tenureFlexibility", f.getTenureFlexibility());
|
||||
putBoolean(root, submitted, "lienMarked", f.getLienMarked());
|
||||
putBoolean(root, submitted, "maturityInstructions", f.getMaturityInstructions());
|
||||
putBoolean(root, submitted, "creditMaturityProceeds", f.getCreditMaturityProceeds());
|
||||
putBoolean(root, submitted, "penaltyGracePeriodMissedInstallments", f.getPenaltyGracePeriodMissedInstallments());
|
||||
putBoolean(root, submitted, "panelRequestApplicable", f.getPanelRequestApplicable());
|
||||
putBoolean(root, submitted, "noPenaltyNomineeHeirClosure", f.getNoPenaltyNomineeHeirClosure());
|
||||
putBoolean(root, submitted, "deceasedSettlement", f.getDeceasedSettlement());
|
||||
putBoolean(root, submitted, "allowDebitTxnAfterDueDate", f.getAllowDebitTxnAfterDueDate());
|
||||
}
|
||||
|
||||
// ---- accountFacilityConfig (1:1 container) --------------------------------------------------
|
||||
|
||||
public static boolean populateFacilityConfig(final JsonCommand command, final FacilityConfigEditFields f) {
|
||||
if (!command.hasParameter("accountFacilityConfig")) {
|
||||
return false;
|
||||
}
|
||||
f.setAtmFacility(booleanOf(command, "accountFacilityConfig", "atmFacility"));
|
||||
f.setAtmWithdrawalFacility(booleanOf(command, "accountFacilityConfig", "atmWithdrawalFacility"));
|
||||
f.setUpiFacility(booleanOf(command, "accountFacilityConfig", "upiFacility"));
|
||||
f.setPosTransactionsFacility(booleanOf(command, "accountFacilityConfig", "posTransactionsFacility"));
|
||||
f.setChequeBook(booleanOf(command, "accountFacilityConfig", "chequeBook"));
|
||||
f.setImpsFacility(booleanOf(command, "accountFacilityConfig", "impsFacility"));
|
||||
f.setSmsAlerts(booleanOf(command, "accountFacilityConfig", "smsAlerts"));
|
||||
f.setBbpsFacility(booleanOf(command, "accountFacilityConfig", "bbpsFacility"));
|
||||
f.setInsuranceCover(booleanOf(command, "accountFacilityConfig", "insuranceCover"));
|
||||
f.setBepgFacility(booleanOf(command, "accountFacilityConfig", "bepgFacility"));
|
||||
f.setNeftFacility(booleanOf(command, "accountFacilityConfig", "neftFacility"));
|
||||
f.setRtgsFacility(booleanOf(command, "accountFacilityConfig", "rtgsFacility"));
|
||||
f.setInterBankTotalCapFacility(booleanOf(command, "accountFacilityConfig", "interBankTotalCapFacility"));
|
||||
f.setWithdrawalFacility(booleanOf(command, "accountFacilityConfig", "withdrawalFacility"));
|
||||
f.setDepositFacilityKyc(booleanOf(command, "accountFacilityConfig", "depositFacilityKyc"));
|
||||
f.setVirtualDebitCard(booleanOf(command, "accountFacilityConfig", "virtualDebitCard"));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void writeFacilityConfigToJson(final JsonObject root, final FacilityConfigEditFields f, final boolean submitted) {
|
||||
if (!submitted) {
|
||||
return;
|
||||
}
|
||||
final JsonObject config = new JsonObject();
|
||||
config.addProperty("atmFacility", f.getAtmFacility());
|
||||
config.addProperty("atmWithdrawalFacility", f.getAtmWithdrawalFacility());
|
||||
config.addProperty("upiFacility", f.getUpiFacility());
|
||||
config.addProperty("posTransactionsFacility", f.getPosTransactionsFacility());
|
||||
config.addProperty("chequeBook", f.getChequeBook());
|
||||
config.addProperty("impsFacility", f.getImpsFacility());
|
||||
config.addProperty("smsAlerts", f.getSmsAlerts());
|
||||
config.addProperty("bbpsFacility", f.getBbpsFacility());
|
||||
config.addProperty("insuranceCover", f.getInsuranceCover());
|
||||
config.addProperty("bepgFacility", f.getBepgFacility());
|
||||
config.addProperty("neftFacility", f.getNeftFacility());
|
||||
config.addProperty("rtgsFacility", f.getRtgsFacility());
|
||||
config.addProperty("interBankTotalCapFacility", f.getInterBankTotalCapFacility());
|
||||
config.addProperty("withdrawalFacility", f.getWithdrawalFacility());
|
||||
config.addProperty("depositFacilityKyc", f.getDepositFacilityKyc());
|
||||
config.addProperty("virtualDebitCard", f.getVirtualDebitCard());
|
||||
root.add("accountFacilityConfig", config);
|
||||
}
|
||||
|
||||
// ---- depositLimitKyc (1:1 container, nested general/minor/smallSaving shape) ----------------
|
||||
|
||||
public static boolean populateDepositLimitKyc(final JsonCommand command, final DepositLimitKycEditFields f) {
|
||||
if (!command.hasParameter("depositLimitKyc")) {
|
||||
return false;
|
||||
}
|
||||
final com.google.gson.JsonElement raw = command.parsedJson().getAsJsonObject().get("depositLimitKyc");
|
||||
if (raw == null || !raw.isJsonObject()) {
|
||||
return true;
|
||||
}
|
||||
final JsonObject kyc = raw.getAsJsonObject();
|
||||
if (kyc.has("general") && kyc.get("general").isJsonObject()) {
|
||||
final JsonObject general = kyc.getAsJsonObject("general");
|
||||
f.setGeneralType(stringOrNull(general, "kycType"));
|
||||
f.setGeneralLimit(stringOrNull(general, "limit"));
|
||||
}
|
||||
if (kyc.has("minor") && kyc.get("minor").isJsonObject()) {
|
||||
final JsonObject minor = kyc.getAsJsonObject("minor");
|
||||
f.setMinorType(stringOrNull(minor, "kycType"));
|
||||
final String minorLimit = stringOrNull(minor, "limit");
|
||||
f.setMinorLimit(minorLimit == null ? null : Long.valueOf(minorLimit));
|
||||
}
|
||||
if (kyc.has("smallSaving") && kyc.get("smallSaving").isJsonObject()) {
|
||||
final JsonObject smallSaving = kyc.getAsJsonObject("smallSaving");
|
||||
f.setSmallSavingType(stringOrNull(smallSaving, "kycType"));
|
||||
final String smallSavingLimit = stringOrNull(smallSaving, "limit");
|
||||
f.setSmallSavingLimit(smallSavingLimit == null ? null : Long.valueOf(smallSavingLimit));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void writeDepositLimitKycToJson(final JsonObject root, final DepositLimitKycEditFields f, final boolean submitted) {
|
||||
if (!submitted) {
|
||||
return;
|
||||
}
|
||||
final JsonObject kyc = new JsonObject();
|
||||
final JsonObject general = new JsonObject();
|
||||
general.addProperty("kycType", f.getGeneralType());
|
||||
general.addProperty("limit", f.getGeneralLimit());
|
||||
kyc.add("general", general);
|
||||
final JsonObject minor = new JsonObject();
|
||||
minor.addProperty("kycType", f.getMinorType());
|
||||
if (f.getMinorLimit() != null) {
|
||||
minor.addProperty("limit", f.getMinorLimit());
|
||||
}
|
||||
kyc.add("minor", minor);
|
||||
final JsonObject smallSaving = new JsonObject();
|
||||
smallSaving.addProperty("kycType", f.getSmallSavingType());
|
||||
if (f.getSmallSavingLimit() != null) {
|
||||
smallSaving.addProperty("limit", f.getSmallSavingLimit());
|
||||
}
|
||||
kyc.add("smallSaving", smallSaving);
|
||||
root.add("depositLimitKyc", kyc);
|
||||
}
|
||||
|
||||
// ---- GL scalar account mapping (1:1) ----------------------------------------------------------
|
||||
|
||||
public static boolean populateGlAccountMapping(final JsonCommand command, final GlAccountMappingEditFields f) {
|
||||
boolean any = false;
|
||||
any |= setIfPresent(command, "savingsReferenceAccountId", f::setSavingsReferenceAccountId);
|
||||
any |= setIfPresent(command, "savingsControlAccountId", f::setSavingsControlAccountId);
|
||||
any |= setIfPresent(command, "incomeFromFeeAccountId", f::setIncomeFromFeeAccountId);
|
||||
any |= setIfPresent(command, "incomeFromPenaltyAccountId", f::setIncomeFromPenaltyAccountId);
|
||||
any |= setIfPresent(command, "interestOnSavingsAccountId", f::setInterestOnSavingsAccountId);
|
||||
any |= setIfPresent(command, "transfersInSuspenseAccountId", f::setTransfersInSuspenseAccountId);
|
||||
any |= setIfPresent(command, "overdraftPortfolioControlId", f::setOverdraftPortfolioControlId);
|
||||
any |= setIfPresent(command, "incomeFromInterestId", f::setIncomeFromInterestId);
|
||||
any |= setIfPresent(command, "writeOffAccountId", f::setWriteOffAccountId);
|
||||
any |= setIfPresent(command, "escheatLiabilityId", f::setEscheatLiabilityId);
|
||||
any |= setIfPresent(command, "penaltiesReceivableAccountId", f::setPenaltiesReceivableAccountId);
|
||||
any |= setIfPresent(command, "interestReceivableAccountId", f::setInterestReceivableAccountId);
|
||||
any |= setIfPresent(command, "feesReceivableAccountId", f::setFeesReceivableAccountId);
|
||||
any |= setIfPresent(command, "interestPayableAccountId", f::setInterestPayableAccountId);
|
||||
return any;
|
||||
}
|
||||
|
||||
public static void writeGlAccountMappingToJson(final JsonObject root, final GlAccountMappingEditFields f) {
|
||||
putNumber(root, "savingsReferenceAccountId", f.getSavingsReferenceAccountId());
|
||||
putNumber(root, "savingsControlAccountId", f.getSavingsControlAccountId());
|
||||
putNumber(root, "incomeFromFeeAccountId", f.getIncomeFromFeeAccountId());
|
||||
putNumber(root, "incomeFromPenaltyAccountId", f.getIncomeFromPenaltyAccountId());
|
||||
putNumber(root, "interestOnSavingsAccountId", f.getInterestOnSavingsAccountId());
|
||||
putNumber(root, "transfersInSuspenseAccountId", f.getTransfersInSuspenseAccountId());
|
||||
putNumber(root, "overdraftPortfolioControlId", f.getOverdraftPortfolioControlId());
|
||||
putNumber(root, "incomeFromInterestId", f.getIncomeFromInterestId());
|
||||
putNumber(root, "writeOffAccountId", f.getWriteOffAccountId());
|
||||
putNumber(root, "escheatLiabilityId", f.getEscheatLiabilityId());
|
||||
putNumber(root, "penaltiesReceivableAccountId", f.getPenaltiesReceivableAccountId());
|
||||
putNumber(root, "interestReceivableAccountId", f.getInterestReceivableAccountId());
|
||||
putNumber(root, "feesReceivableAccountId", f.getFeesReceivableAccountId());
|
||||
putNumber(root, "interestPayableAccountId", f.getInterestPayableAccountId());
|
||||
}
|
||||
|
||||
// ---- charges (1:many, satellite table) --------------------------------------------------------
|
||||
|
||||
/** Returns null if "charges" wasn't present at all, else the (possibly empty) list of charge ids. */
|
||||
public static List<Long> extractChargeIds(final JsonCommand command) {
|
||||
if (!command.hasParameter("charges")) {
|
||||
return null;
|
||||
}
|
||||
final com.google.gson.JsonElement raw = command.parsedJson().getAsJsonObject().get("charges");
|
||||
final List<Long> ids = new java.util.ArrayList<>();
|
||||
if (raw != null && raw.isJsonArray()) {
|
||||
for (final com.google.gson.JsonElement el : raw.getAsJsonArray()) {
|
||||
if (el.isJsonObject() && el.getAsJsonObject().has("id")) {
|
||||
ids.add(el.getAsJsonObject().get("id").getAsLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
public static void writeChargesToJson(final JsonObject root, final List<ProductPendingEditCharge> charges) {
|
||||
final JsonArray array = new JsonArray();
|
||||
for (final ProductPendingEditCharge charge : charges) {
|
||||
final JsonObject entry = new JsonObject();
|
||||
entry.addProperty("id", charge.getChargeId());
|
||||
array.add(entry);
|
||||
}
|
||||
root.add("charges", array);
|
||||
}
|
||||
|
||||
// ---- accountFacilityLimits (1:many, satellite table) -------------------------------------------
|
||||
|
||||
public static List<ProductPendingEditFacilityLimit> extractFacilityLimits(final JsonCommand command, final ProductPendingEdit edit) {
|
||||
if (!command.hasParameter("accountFacilityLimits")) {
|
||||
return null;
|
||||
}
|
||||
final com.google.gson.JsonElement raw = command.parsedJson().getAsJsonObject().get("accountFacilityLimits");
|
||||
final List<ProductPendingEditFacilityLimit> limits = new java.util.ArrayList<>();
|
||||
if (raw != null && raw.isJsonArray()) {
|
||||
for (final com.google.gson.JsonElement el : raw.getAsJsonArray()) {
|
||||
final JsonObject o = el.getAsJsonObject();
|
||||
limits.add(new ProductPendingEditFacilityLimit(edit, stringOrNull(o, "limitType"), stringOrNull(o, "generalLimit"),
|
||||
stringOrNull(o, "minorAccountLimit"), stringOrNull(o, "smallSavingLimit")));
|
||||
}
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
||||
public static void writeFacilityLimitsToJson(final JsonObject root, final List<ProductPendingEditFacilityLimit> limits) {
|
||||
final JsonArray array = new JsonArray();
|
||||
for (final ProductPendingEditFacilityLimit limit : limits) {
|
||||
final JsonObject entry = new JsonObject();
|
||||
entry.addProperty("limitType", limit.getLimitType());
|
||||
entry.addProperty("generalLimit", limit.getGeneralLimit());
|
||||
entry.addProperty("minorAccountLimit", limit.getMinorAccountLimit());
|
||||
entry.addProperty("smallSavingLimit", limit.getSmallSavingLimit());
|
||||
array.add(entry);
|
||||
}
|
||||
root.add("accountFacilityLimits", array);
|
||||
}
|
||||
|
||||
// ---- GL array mappings (1:many, satellite table) -----------------------------------------------
|
||||
|
||||
public static List<ProductPendingEditGlMapping> extractGlArrayMappings(final JsonCommand command, final ProductPendingEdit edit) {
|
||||
final List<ProductPendingEditGlMapping> mappings = new java.util.ArrayList<>();
|
||||
boolean any = false;
|
||||
any |= extractGlArray(command, edit, "paymentChannelToFundSourceMappings", ProductPendingEditGlMapping.TYPE_PAYMENT_CHANNEL,
|
||||
"paymentTypeId", mappings);
|
||||
any |= extractGlArray(command, edit, "feeToIncomeAccountMappings", ProductPendingEditGlMapping.TYPE_FEE, "chargeId", mappings);
|
||||
any |= extractGlArray(command, edit, "penaltyToIncomeAccountMappings", ProductPendingEditGlMapping.TYPE_PENALTY, "chargeId",
|
||||
mappings);
|
||||
return any ? mappings : null;
|
||||
}
|
||||
|
||||
private static boolean extractGlArray(final JsonCommand command, final ProductPendingEdit edit, final String paramName,
|
||||
final String mappingType, final String idFieldName, final List<ProductPendingEditGlMapping> out) {
|
||||
if (!command.hasParameter(paramName)) {
|
||||
return false;
|
||||
}
|
||||
final com.google.gson.JsonElement raw = command.parsedJson().getAsJsonObject().get(paramName);
|
||||
if (raw != null && raw.isJsonArray()) {
|
||||
for (final com.google.gson.JsonElement el : raw.getAsJsonArray()) {
|
||||
final JsonObject o = el.getAsJsonObject();
|
||||
final Long idFieldValue = o.has(idFieldName) ? o.get(idFieldName).getAsLong() : null;
|
||||
final Long glAccountId = o.has("glAccountId") ? o.get("glAccountId").getAsLong() : null;
|
||||
final Long paymentTypeId = "paymentTypeId".equals(idFieldName) ? idFieldValue : null;
|
||||
final Long chargeId = "chargeId".equals(idFieldName) ? idFieldValue : null;
|
||||
out.add(new ProductPendingEditGlMapping(edit, mappingType, paymentTypeId, chargeId, glAccountId));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void writeGlArrayMappingsToJson(final JsonObject root, final List<ProductPendingEditGlMapping> mappings) {
|
||||
writeGlArrayGroup(root, mappings, ProductPendingEditGlMapping.TYPE_PAYMENT_CHANNEL, "paymentChannelToFundSourceMappings",
|
||||
"paymentTypeId");
|
||||
writeGlArrayGroup(root, mappings, ProductPendingEditGlMapping.TYPE_FEE, "feeToIncomeAccountMappings", "chargeId");
|
||||
writeGlArrayGroup(root, mappings, ProductPendingEditGlMapping.TYPE_PENALTY, "penaltyToIncomeAccountMappings", "chargeId");
|
||||
}
|
||||
|
||||
private static void writeGlArrayGroup(final JsonObject root, final List<ProductPendingEditGlMapping> mappings, final String type,
|
||||
final String paramName, final String idFieldName) {
|
||||
final JsonArray array = new JsonArray();
|
||||
for (final ProductPendingEditGlMapping mapping : mappings) {
|
||||
if (!type.equals(mapping.getMappingType())) {
|
||||
continue;
|
||||
}
|
||||
final JsonObject entry = new JsonObject();
|
||||
final Long idFieldValue = "paymentTypeId".equals(idFieldName) ? mapping.getPaymentTypeId() : mapping.getChargeId();
|
||||
entry.addProperty(idFieldName, idFieldValue);
|
||||
entry.addProperty("glAccountId", mapping.getGlAccountId());
|
||||
array.add(entry);
|
||||
}
|
||||
root.add(paramName, array);
|
||||
}
|
||||
|
||||
// ---- small helpers -----------------------------------------------------------------------------
|
||||
|
||||
private static boolean booleanOf(final JsonCommand command, final String containerName, final String fieldName) {
|
||||
final com.google.gson.JsonElement raw = command.parsedJson().getAsJsonObject().get(containerName);
|
||||
if (raw == null || !raw.isJsonObject()) {
|
||||
return false;
|
||||
}
|
||||
final JsonObject container = raw.getAsJsonObject();
|
||||
return container.has(fieldName) && !container.get(fieldName).isJsonNull() && container.get(fieldName).getAsBoolean();
|
||||
}
|
||||
|
||||
private static String stringOrNull(final JsonObject o, final String field) {
|
||||
return (o.has(field) && !o.get(field).isJsonNull()) ? o.get(field).getAsString() : null;
|
||||
}
|
||||
|
||||
private interface LongSetter {
|
||||
|
||||
void set(Long value);
|
||||
}
|
||||
|
||||
private static boolean setIfPresent(final JsonCommand command, final String paramName, final LongSetter setter) {
|
||||
if (!command.hasParameter(paramName)) {
|
||||
return false;
|
||||
}
|
||||
setter.set(command.longValueOfParameterNamed(paramName));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void putString(final JsonObject root, final Set<String> submitted, final String name, final String value) {
|
||||
if (submitted.contains(name)) {
|
||||
root.addProperty(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void putNumber(final JsonObject root, final Set<String> submitted, final String name, final Number value) {
|
||||
if (submitted.contains(name)) {
|
||||
root.addProperty(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void putBoolean(final JsonObject root, final Set<String> submitted, final String name, final Boolean value) {
|
||||
if (submitted.contains(name)) {
|
||||
root.addProperty(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void putDate(final JsonObject root, final Set<String> submitted, final String name, final LocalDate value) {
|
||||
if (submitted.contains(name)) {
|
||||
root.addProperty(name, value == null ? null : value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void putNumber(final JsonObject root, final String name, final Number value) {
|
||||
if (value != null) {
|
||||
root.addProperty(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
/**
|
||||
* One row per entry of the 3 array-shaped GL mappings (paymentChannelToFundSourceMappings,
|
||||
* feeToIncomeAccountMappings, penaltyToIncomeAccountMappings), distinguished by mappingType.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_product_temp_gl_mapping")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ProductPendingEditGlMapping extends AbstractPersistableCustom<Long> {
|
||||
|
||||
public static final String TYPE_PAYMENT_CHANNEL = "PAYMENT_CHANNEL";
|
||||
public static final String TYPE_FEE = "FEE";
|
||||
public static final String TYPE_PENALTY = "PENALTY";
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "pending_edit_id", nullable = false)
|
||||
private ProductPendingEdit pendingEdit;
|
||||
|
||||
@Column(name = "mapping_type", nullable = false)
|
||||
private String mappingType;
|
||||
|
||||
@Column(name = "payment_type_id")
|
||||
private Long paymentTypeId;
|
||||
|
||||
@Column(name = "charge_id")
|
||||
private Long chargeId;
|
||||
|
||||
@Column(name = "gl_account_id", nullable = false)
|
||||
private Long glAccountId;
|
||||
|
||||
public ProductPendingEditGlMapping(final ProductPendingEdit pendingEdit, final String mappingType, final Long paymentTypeId,
|
||||
final Long chargeId, final Long glAccountId) {
|
||||
this.pendingEdit = pendingEdit;
|
||||
this.mappingType = mappingType;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.chargeId = chargeId;
|
||||
this.glAccountId = glAccountId;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditGlMappingRepository extends JpaRepository<ProductPendingEditGlMapping, Long> {
|
||||
|
||||
List<ProductPendingEditGlMapping> findByPendingEditId(Long pendingEditId);
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
/** One row per entry of Share Product's "marketPrice" array (create/update/delete-by-id semantics). */
|
||||
@Entity
|
||||
@Table(name = "m_product_temp_share_market_price")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ProductPendingEditMarketPrice extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "pending_edit_id", nullable = false)
|
||||
private ProductPendingEdit pendingEdit;
|
||||
|
||||
/** id of the existing m_share_product_market_price row this entry updates/deletes, null if new. */
|
||||
@Column(name = "source_id")
|
||||
private Long sourceId;
|
||||
|
||||
@Column(name = "delete_flag", nullable = false)
|
||||
private boolean deleteFlag;
|
||||
|
||||
@Column(name = "from_date")
|
||||
private LocalDate fromDate;
|
||||
|
||||
@Column(name = "share_value")
|
||||
private BigDecimal shareValue;
|
||||
|
||||
public ProductPendingEditMarketPrice(final ProductPendingEdit pendingEdit, final Long sourceId, final boolean deleteFlag,
|
||||
final LocalDate fromDate, final BigDecimal shareValue) {
|
||||
this.pendingEdit = pendingEdit;
|
||||
this.sourceId = sourceId;
|
||||
this.deleteFlag = deleteFlag;
|
||||
this.fromDate = fromDate;
|
||||
this.shareValue = shareValue;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditMarketPriceRepository extends JpaRepository<ProductPendingEditMarketPrice, Long> {
|
||||
|
||||
List<ProductPendingEditMarketPrice> findByPendingEditId(Long pendingEditId);
|
||||
}
|
||||
+32
@@ -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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditRepository extends JpaRepository<ProductPendingEdit, Long> {
|
||||
|
||||
Optional<ProductPendingEdit> findByProductTypeAndProductIdAndStatus(String productType, Long productId, String status);
|
||||
|
||||
List<ProductPendingEdit> findByProductTypeAndStatus(String productType, String status);
|
||||
}
|
||||
+56
@@ -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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
|
||||
/**
|
||||
* Records which top-level JSON parameter names were actually present in the maker's original
|
||||
* request. Typed nullable columns can't by themselves distinguish "field omitted" from "field
|
||||
* explicitly sent as null" from "field has a value" - and every existing command.hasParameter(...)
|
||||
* branch in the write-services and assemblers depends on that distinction - so this table is the
|
||||
* relational replacement for the information a raw JSON blob used to carry implicitly.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "m_product_temp_submitted_field")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class ProductPendingEditSubmittedField extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "pending_edit_id", nullable = false)
|
||||
private ProductPendingEdit pendingEdit;
|
||||
|
||||
@Column(name = "field_name", nullable = false)
|
||||
private String fieldName;
|
||||
|
||||
public ProductPendingEditSubmittedField(final ProductPendingEdit pendingEdit, final String fieldName) {
|
||||
this.pendingEdit = pendingEdit;
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface ProductPendingEditSubmittedFieldRepository extends JpaRepository<ProductPendingEditSubmittedField, Long> {
|
||||
|
||||
List<ProductPendingEditSubmittedField> findByPendingEditId(Long pendingEditId);
|
||||
|
||||
@Query("SELECT f.fieldName FROM ProductPendingEditSubmittedField f WHERE f.pendingEdit.id = :pendingEditId")
|
||||
List<String> findFieldNamesByPendingEditId(@Param("pendingEditId") Long pendingEditId);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class RecurringDepositEditFields {
|
||||
|
||||
@Column(name = "is_mandatory_deposit")
|
||||
private Boolean isMandatoryDeposit;
|
||||
|
||||
@Column(name = "allow_withdrawal")
|
||||
private Boolean allowWithdrawal;
|
||||
|
||||
@Column(name = "adjust_advance_towards_future_payments")
|
||||
private Boolean adjustAdvanceTowardsFuturePayments;
|
||||
}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Lob;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Scalar edit fields shared by Savings, Current, Fixed Deposit and Recurring Deposit products
|
||||
* (FD/RD extend the Savings field set). Column names are the snake_case of the JSON API parameter
|
||||
* name each field stores, not the underlying product table's own column name.
|
||||
*/
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class SavingsCoreEditFields {
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "short_name")
|
||||
private String shortName;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "currency_code")
|
||||
private String currencyCode;
|
||||
|
||||
@Column(name = "digits_after_decimal")
|
||||
private Integer digitsAfterDecimal;
|
||||
|
||||
@Column(name = "in_multiples_of")
|
||||
private Integer inMultiplesOf;
|
||||
|
||||
@Column(name = "accounting_rule")
|
||||
private Integer accountingRule;
|
||||
|
||||
@Column(name = "nominal_annual_interest_rate")
|
||||
private BigDecimal nominalAnnualInterestRate;
|
||||
|
||||
@Column(name = "interest_compounding_period_type")
|
||||
private Integer interestCompoundingPeriodType;
|
||||
|
||||
@Column(name = "interest_posting_period_type")
|
||||
private Integer interestPostingPeriodType;
|
||||
|
||||
@Column(name = "interest_calculation_type")
|
||||
private Integer interestCalculationType;
|
||||
|
||||
@Column(name = "interest_calculation_days_in_year_type")
|
||||
private Integer interestCalculationDaysInYearType;
|
||||
|
||||
@Column(name = "min_required_opening_balance")
|
||||
private BigDecimal minRequiredOpeningBalance;
|
||||
|
||||
@Column(name = "lockin_period_frequency")
|
||||
private Integer lockinPeriodFrequency;
|
||||
|
||||
@Column(name = "lockin_period_frequency_type")
|
||||
private Integer lockinPeriodFrequencyType;
|
||||
|
||||
@Column(name = "withdrawal_fee_for_transfers")
|
||||
private Boolean withdrawalFeeForTransfers;
|
||||
|
||||
@Column(name = "allow_overdraft")
|
||||
private Boolean allowOverdraft;
|
||||
|
||||
@Column(name = "overdraft_limit")
|
||||
private BigDecimal overdraftLimit;
|
||||
|
||||
@Column(name = "nominal_annual_interest_rate_overdraft")
|
||||
private BigDecimal nominalAnnualInterestRateOverdraft;
|
||||
|
||||
@Column(name = "min_overdraft_for_interest_calculation")
|
||||
private BigDecimal minOverdraftForInterestCalculation;
|
||||
|
||||
@Column(name = "enforce_min_required_balance")
|
||||
private Boolean enforceMinRequiredBalance;
|
||||
|
||||
@Column(name = "min_required_balance")
|
||||
private BigDecimal minRequiredBalance;
|
||||
|
||||
@Column(name = "lien_allowed")
|
||||
private Boolean lienAllowed;
|
||||
|
||||
@Column(name = "max_allowed_lien_limit")
|
||||
private BigDecimal maxAllowedLienLimit;
|
||||
|
||||
@Column(name = "min_balance_for_interest_calculation")
|
||||
private BigDecimal minBalanceForInterestCalculation;
|
||||
|
||||
@Column(name = "with_hold_tax")
|
||||
private Boolean withHoldTax;
|
||||
|
||||
@Column(name = "tax_group_id")
|
||||
private Long taxGroupId;
|
||||
|
||||
@Lob
|
||||
@Column(name = "other_gl_mappings")
|
||||
private String otherGlMappings;
|
||||
|
||||
@Column(name = "is_dormancy_tracking_active")
|
||||
private Boolean isDormancyTrackingActive;
|
||||
|
||||
@Column(name = "days_to_inactive")
|
||||
private Integer daysToInactive;
|
||||
|
||||
@Column(name = "days_to_dormancy")
|
||||
private Integer daysToDormancy;
|
||||
|
||||
@Column(name = "days_to_escheat")
|
||||
private Integer daysToEscheat;
|
||||
|
||||
@Column(name = "account_type")
|
||||
private String accountType;
|
||||
|
||||
@Column(name = "customer_segment")
|
||||
private String customerSegment;
|
||||
|
||||
@Column(name = "product_code")
|
||||
private String productCode;
|
||||
|
||||
@Column(name = "gl_account_id")
|
||||
private Long glAccountId;
|
||||
|
||||
@Column(name = "effective_date")
|
||||
private LocalDate effectiveDate;
|
||||
|
||||
@Column(name = "effective_to")
|
||||
private LocalDate effectiveTo;
|
||||
|
||||
@Column(name = "end_date")
|
||||
private LocalDate endDate;
|
||||
|
||||
@Column(name = "introducer_required")
|
||||
private Boolean introducerRequired;
|
||||
|
||||
@Column(name = "share_linking_enabled")
|
||||
private Boolean shareLinkingEnabled;
|
||||
|
||||
@Column(name = "nomination_facility")
|
||||
private Boolean nominationFacility;
|
||||
|
||||
@Column(name = "dormancy_alert")
|
||||
private Boolean dormancyAlert;
|
||||
|
||||
@Column(name = "interest_calculate_selector")
|
||||
private Integer interestCalculateSelector;
|
||||
|
||||
@Column(name = "average_period")
|
||||
private String averagePeriod;
|
||||
|
||||
@Column(name = "auto_post")
|
||||
private Boolean autoPost;
|
||||
|
||||
@Column(name = "frequency_fix_day")
|
||||
private Integer frequencyFixDay;
|
||||
|
||||
@Column(name = "last_interest_date")
|
||||
private LocalDate lastInterestDate;
|
||||
|
||||
@Column(name = "enable_lockin_period")
|
||||
private Boolean enableLockinPeriod;
|
||||
|
||||
@Column(name = "balance_frequency")
|
||||
private String balanceFrequency;
|
||||
|
||||
@Column(name = "account_closed_zero_balance_in_day_closing")
|
||||
private Boolean accountClosedZeroBalanceInDayClosing;
|
||||
|
||||
@Column(name = "balance_swap_option")
|
||||
private Boolean balanceSwapOption;
|
||||
|
||||
@Column(name = "msme")
|
||||
private Boolean msme;
|
||||
|
||||
@Column(name = "auto_debit_facility")
|
||||
private Boolean autoDebitFacility;
|
||||
|
||||
@Column(name = "loan_facility")
|
||||
private Boolean loanFacility;
|
||||
|
||||
@Column(name = "premature_withdrawal_option")
|
||||
private Boolean prematureWithdrawalOption;
|
||||
|
||||
@Column(name = "tenure_flexibility")
|
||||
private Boolean tenureFlexibility;
|
||||
|
||||
@Column(name = "lien_marked")
|
||||
private Boolean lienMarked;
|
||||
|
||||
@Column(name = "maturity_instructions")
|
||||
private Boolean maturityInstructions;
|
||||
|
||||
@Column(name = "credit_maturity_proceeds")
|
||||
private Boolean creditMaturityProceeds;
|
||||
|
||||
@Column(name = "penalty_grace_period_missed_installments")
|
||||
private Boolean penaltyGracePeriodMissedInstallments;
|
||||
|
||||
@Column(name = "panel_request_applicable")
|
||||
private Boolean panelRequestApplicable;
|
||||
|
||||
@Column(name = "no_penalty_nominee_heir_closure")
|
||||
private Boolean noPenaltyNomineeHeirClosure;
|
||||
|
||||
@Column(name = "deceased_settlement")
|
||||
private Boolean deceasedSettlement;
|
||||
|
||||
@Column(name = "allow_debit_txn_after_due_date")
|
||||
private Boolean allowDebitTxnAfterDueDate;
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.savings.domain;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class ShareOnlyEditFields {
|
||||
|
||||
@Column(name = "total_shares")
|
||||
private Long totalShares;
|
||||
|
||||
@Column(name = "total_shares_issued")
|
||||
private Long totalSharesIssued;
|
||||
|
||||
@Column(name = "unit_price")
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@Column(name = "minimum_shares")
|
||||
private Long minimumShares;
|
||||
|
||||
@Column(name = "nominal_shares")
|
||||
private Long nominalShares;
|
||||
|
||||
@Column(name = "maximum_shares")
|
||||
private Long maximumShares;
|
||||
|
||||
@Column(name = "allow_dividend_calc_for_inactive_clients")
|
||||
private Boolean allowDividendCalcForInactiveClients;
|
||||
|
||||
@Column(name = "minimum_active_period_for_dividends")
|
||||
private Integer minimumActivePeriodForDividends;
|
||||
|
||||
@Column(name = "minimum_active_period_frequency_type")
|
||||
private Integer minimumActivePeriodFrequencyType;
|
||||
|
||||
@Column(name = "share_lockin_period")
|
||||
private Integer shareLockinPeriod;
|
||||
|
||||
@Column(name = "share_lockin_period_frequency_type")
|
||||
private Integer shareLockinPeriodFrequencyType;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class SavingsProductEditPendingApprovalException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public SavingsProductEditPendingApprovalException(final Long productId) {
|
||||
super("error.msg.savingsproduct.edit.pending.approval",
|
||||
"Savings product with identifier " + productId + " already has an edit pending approval", productId);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class SavingsProductNoPendingEditException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public SavingsProductNoPendingEditException(final Long productId) {
|
||||
super("error.msg.savingsproduct.no.pending.edit",
|
||||
"Savings product with identifier " + productId + " has no edit pending approval", productId);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.savings.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class SavingsProductSelfApprovalNotAllowedException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public SavingsProductSelfApprovalNotAllowedException(final Long productId) {
|
||||
super("error.msg.savingsproduct.self.approval.not.allowed",
|
||||
"The maker of the pending edit for savings product " + productId + " cannot also approve or reject it", productId);
|
||||
}
|
||||
}
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.service;
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.data.DepositProductData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductTempData;
|
||||
|
||||
public interface DepositProductReadPlatformService {
|
||||
|
||||
@@ -32,4 +33,8 @@ public interface DepositProductReadPlatformService {
|
||||
|
||||
DepositProductData retrieveOneWithChartSlabs(DepositAccountType depositAccountType, Long productId);
|
||||
|
||||
Collection<SavingsProductTempData> retrieveAllPendingEdits(DepositAccountType depositAccountType);
|
||||
|
||||
SavingsProductTempData retrievePendingEdit(DepositAccountType depositAccountType, Long productId);
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -28,4 +28,10 @@ public interface FixedDepositProductWritePlatformService {
|
||||
CommandProcessingResult update(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult delete(Long productId);
|
||||
|
||||
CommandProcessingResult submitEditForApproval(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult approveEdit(Long productId);
|
||||
|
||||
CommandProcessingResult rejectEdit(Long productId, String rejectReason);
|
||||
}
|
||||
|
||||
+6
@@ -28,4 +28,10 @@ public interface RecurringDepositProductWritePlatformService {
|
||||
CommandProcessingResult update(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult delete(Long productId);
|
||||
|
||||
CommandProcessingResult submitEditForApproval(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult approveEdit(Long productId);
|
||||
|
||||
CommandProcessingResult rejectEdit(Long productId, String rejectReason);
|
||||
}
|
||||
|
||||
+5
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsProductTempData;
|
||||
|
||||
public interface SavingsProductReadPlatformService {
|
||||
|
||||
@@ -33,4 +34,8 @@ public interface SavingsProductReadPlatformService {
|
||||
|
||||
SavingsProductData retrieveOne(Long productId);
|
||||
|
||||
Collection<SavingsProductTempData> retrieveAllPendingEdits();
|
||||
|
||||
SavingsProductTempData retrievePendingEdit(Long productId);
|
||||
|
||||
}
|
||||
|
||||
+17
@@ -28,4 +28,21 @@ public interface SavingsProductWritePlatformService {
|
||||
CommandProcessingResult update(Long productId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult delete(Long productId);
|
||||
|
||||
/**
|
||||
* Submits an edit for approval instead of applying it directly. Fails if a pending edit already exists for this
|
||||
* product (that pending row is itself the lock).
|
||||
*/
|
||||
CommandProcessingResult submitEditForApproval(Long productId, JsonCommand command);
|
||||
|
||||
/**
|
||||
* Replays the stored pending edit through the normal update path and marks it approved. Fails if the approving
|
||||
* user is the same user who submitted the edit.
|
||||
*/
|
||||
CommandProcessingResult approveEdit(Long productId);
|
||||
|
||||
/**
|
||||
* Discards the pending edit. Fails if the rejecting user is the same user who submitted the edit.
|
||||
*/
|
||||
CommandProcessingResult rejectEdit(Long productId, String rejectReason);
|
||||
}
|
||||
|
||||
+10
@@ -39,4 +39,14 @@
|
||||
<include file="parts/2014_add_is_mandatory_to_joint_holders.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2015_add_senior_citizen_to_savings_account.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2016_add_share_linking_enabled_to_savings_account.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2017_add_saving_product_temp_table.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2018_fix_saving_product_temp_lock_constraint.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2019_add_command_source_link_to_saving_product_temp.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2020_generalize_product_temp_table.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2021_add_fd_rd_approval_permissions.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2022_add_product_checker_permissions.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2023_fix_product_approval_permissions.xml" relativeToChangelogFile="true" />
|
||||
<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" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
<?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="2017-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_savings_product_temp" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_savings_product_temp">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="savings_product_id" type="BIGINT">
|
||||
<constraints nullable="false" unique="true" uniqueConstraintName="sp_temp_unq_savings_product_id"
|
||||
foreignKeyName="fk_sp_temp_savings_product_id" references="m_savings_product(id)" />
|
||||
</column>
|
||||
<column name="maker_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_sp_temp_maker_id" references="m_appuser(id)" />
|
||||
</column>
|
||||
<column name="checker_id" type="BIGINT">
|
||||
<constraints nullable="true" foreignKeyName="fk_sp_temp_checker_id" references="m_appuser(id)" />
|
||||
</column>
|
||||
<column name="created_on" type="DATETIME">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="checked_on" type="DATETIME">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
<column name="status" type="VARCHAR(20)" defaultValue="PENDING">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="reject_reason" type="VARCHAR(500)">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
<column name="proposed_payload_json" type="CLOB">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2017-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_SAVINGSPRODUCT'</sqlCheck>
|
||||
</not>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_SAVINGSPRODUCT" />
|
||||
<column name="entity_name" value="SAVINGSPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_SAVINGSPRODUCT" />
|
||||
<column name="entity_name" value="SAVINGSPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
The original unique constraint on savings_product_id blocked ANY future edit on a product forever, once a
|
||||
single pending edit had been resolved - because resolved rows are kept (not deleted) for audit history.
|
||||
The lock must only apply while status = PENDING. Unique constraints treat NULL as distinct in both
|
||||
PostgreSQL and MySQL/MariaDB, so a nullable "lock key" column - set to the product id while pending, and
|
||||
cleared back to NULL on approve/reject - gives a correct, cross-database concurrency-safe lock.
|
||||
-->
|
||||
<changeSet author="fineract" id="2018-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<columnExists tableName="m_savings_product_temp" columnName="savings_product_id" />
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="pending_lock_key" />
|
||||
</not>
|
||||
</preConditions>
|
||||
|
||||
<dropUniqueConstraint tableName="m_savings_product_temp" constraintName="sp_temp_unq_savings_product_id" />
|
||||
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="pending_lock_key" type="BIGINT">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
</addColumn>
|
||||
|
||||
<sql>UPDATE m_savings_product_temp SET pending_lock_key = savings_product_id WHERE status = 'PENDING'</sql>
|
||||
|
||||
<addUniqueConstraint tableName="m_savings_product_temp" columnNames="pending_lock_key"
|
||||
constraintName="sp_temp_unq_pending_lock_key" />
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
Links each pending edit to the audit-only m_portfolio_command_source row created for it, so that
|
||||
submit/approve/reject also appear in System -> Audit Trails even though this feature bypasses the native
|
||||
maker-checker execution pipeline.
|
||||
-->
|
||||
<changeSet author="fineract" id="2019-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="command_source_id" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="command_source_id" type="BIGINT">
|
||||
<constraints nullable="true" foreignKeyName="fk_sp_temp_command_source_id"
|
||||
references="m_portfolio_command_source(id)" />
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
Generalizes m_savings_product_temp (kept as one shared table, per requirement) so it can hold pending edits
|
||||
for Current Account Products (m_current_product) and Share Products (m_share_product) as well as Savings
|
||||
Products (m_savings_product) - not just savings. A single BIGINT "product_id" can't carry a normal FK
|
||||
anymore since it now points at three different tables depending on product_type, so the old FK is dropped
|
||||
(application code, not the DB, is now responsible for referential validity here).
|
||||
|
||||
pending_lock_key changes from BIGINT to VARCHAR because a raw numeric id is no longer unique across product
|
||||
types (e.g. a current account product id=3 and a savings product id=3 must not collide). The new format is
|
||||
"<PRODUCT_TYPE>:<product_id>", e.g. "SAVINGS:3" / "CURRENT:3" / "SHARE:3".
|
||||
-->
|
||||
<changeSet author="fineract" id="2020-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="product_type" />
|
||||
</not>
|
||||
</preConditions>
|
||||
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="product_type" type="VARCHAR(20)" defaultValue="SAVINGS">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</addColumn>
|
||||
|
||||
<dropForeignKeyConstraint baseTableName="m_savings_product_temp" constraintName="fk_sp_temp_savings_product_id" />
|
||||
|
||||
<renameColumn tableName="m_savings_product_temp" oldColumnName="savings_product_id" newColumnName="product_id"
|
||||
columnDataType="BIGINT" />
|
||||
|
||||
<dropUniqueConstraint tableName="m_savings_product_temp" constraintName="sp_temp_unq_pending_lock_key" />
|
||||
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="pending_lock_key_new" type="VARCHAR(40)">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
</addColumn>
|
||||
<sql dbms="postgresql">UPDATE m_savings_product_temp SET pending_lock_key_new = 'SAVINGS:' || product_id WHERE status = 'PENDING'</sql>
|
||||
<sql dbms="mysql,mariadb">UPDATE m_savings_product_temp SET pending_lock_key_new = CONCAT('SAVINGS:', product_id) WHERE status = 'PENDING'</sql>
|
||||
<dropColumn tableName="m_savings_product_temp" columnName="pending_lock_key" />
|
||||
<renameColumn tableName="m_savings_product_temp" oldColumnName="pending_lock_key_new" newColumnName="pending_lock_key"
|
||||
columnDataType="VARCHAR(40)" />
|
||||
|
||||
<addUniqueConstraint tableName="m_savings_product_temp" columnNames="pending_lock_key"
|
||||
constraintName="sp_temp_unq_pending_lock_key" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2020-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_CURRENTPRODUCT'</sqlCheck>
|
||||
</not>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_CURRENTPRODUCT" />
|
||||
<column name="entity_name" value="CURRENTPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_CURRENTPRODUCT" />
|
||||
<column name="entity_name" value="CURRENTPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_SHAREPRODUCT" />
|
||||
<column name="entity_name" value="SHAREPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_SHAREPRODUCT" />
|
||||
<column name="entity_name" value="SHAREPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
<?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="2021-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_FIXEDDEPOSITPRODUCT'</sqlCheck>
|
||||
</not>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_FIXEDDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="FIXEDDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_FIXEDDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="FIXEDDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
AuditReadPlatformServiceImpl.retrieveAllEntriesToBeChecked() (backing GET /v1/makercheckers, the "Checker
|
||||
Inbox" tab) shows a pending m_portfolio_command_source row to a "limited" checker only if their role holds
|
||||
a permission whose action_name is "<ACTION>_CHECKER" and entity_name matches the row's entity_name (code
|
||||
convention: "<ACTION>_<ENTITY>_CHECKER", matching how core Fineract permissions like UPDATE_ROLE_CHECKER
|
||||
are seeded). Our custom pending-approval CommandSource rows for product edits (SAVINGSPRODUCT,
|
||||
CURRENTPRODUCT, SHAREPRODUCT, FIXEDDEPOSITPRODUCT, RECURRINGDEPOSITPRODUCT) already satisfy the base
|
||||
status=AWAITING_APPROVAL filter, but without these permission rows a limited checker's role has nothing to
|
||||
match against, so the rows never show up in Checker Inbox - only in our own Pending Product Edits screen.
|
||||
|
||||
UPDATE_SAVINGSPRODUCT_CHECKER already exists as a native Fineract permission, so each row below is its own
|
||||
changeset with its own precondition - one already-existing code must not block inserting the others.
|
||||
-->
|
||||
<changeSet author="fineract" id="2022-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'UPDATE_SAVINGSPRODUCT_CHECKER'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="UPDATE_SAVINGSPRODUCT_CHECKER" />
|
||||
<column name="entity_name" value="SAVINGSPRODUCT" />
|
||||
<column name="action_name" value="UPDATE_CHECKER" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2022-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'UPDATE_CURRENTPRODUCT_CHECKER'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="UPDATE_CURRENTPRODUCT_CHECKER" />
|
||||
<column name="entity_name" value="CURRENTPRODUCT" />
|
||||
<column name="action_name" value="UPDATE_CHECKER" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2022-3">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'UPDATE_SHAREPRODUCT_CHECKER'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="UPDATE_SHAREPRODUCT_CHECKER" />
|
||||
<column name="entity_name" value="SHAREPRODUCT" />
|
||||
<column name="action_name" value="UPDATE_CHECKER" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2022-4">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'UPDATE_FIXEDDEPOSITPRODUCT_CHECKER'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="UPDATE_FIXEDDEPOSITPRODUCT_CHECKER" />
|
||||
<column name="entity_name" value="FIXEDDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="UPDATE_CHECKER" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2022-5">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'UPDATE_RECURRINGDEPOSITPRODUCT_CHECKER'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="UPDATE_RECURRINGDEPOSITPRODUCT_CHECKER" />
|
||||
<column name="entity_name" value="RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="UPDATE_CHECKER" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
Changesets 2017-2, 2020-2 and 2021-1 used an inverted precondition - `<not><sqlCheck expectedResult="0">...`
|
||||
actually means "run only if the row ALREADY exists", the opposite of the intended idempotent-insert guard.
|
||||
On a fresh database (count=0) that precondition evaluates to false, so onFail="MARK_RAN" silently skipped
|
||||
the insert entirely - the APPROVE_*/REJECT_* permissions for all five product types were marked as applied
|
||||
in databasechangelog but never actually inserted. Those changesets are already recorded and must not be
|
||||
edited (Liquibase would fail on checksum mismatch), so this migration re-inserts the missing rows under
|
||||
fresh changeset ids, each with a correct (non-inverted) precondition and split per row so one already-
|
||||
existing code can never block the others.
|
||||
-->
|
||||
<changeSet author="fineract" id="2023-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_SAVINGSPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_SAVINGSPRODUCT" />
|
||||
<column name="entity_name" value="SAVINGSPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'REJECT_SAVINGSPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_SAVINGSPRODUCT" />
|
||||
<column name="entity_name" value="SAVINGSPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-3">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_CURRENTPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_CURRENTPRODUCT" />
|
||||
<column name="entity_name" value="CURRENTPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-4">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'REJECT_CURRENTPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_CURRENTPRODUCT" />
|
||||
<column name="entity_name" value="CURRENTPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-5">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_SHAREPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_SHAREPRODUCT" />
|
||||
<column name="entity_name" value="SHAREPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-6">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'REJECT_SHAREPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_SHAREPRODUCT" />
|
||||
<column name="entity_name" value="SHAREPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-7">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_FIXEDDEPOSITPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_FIXEDDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="FIXEDDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-8">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'REJECT_FIXEDDEPOSITPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_FIXEDDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="FIXEDDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-9">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'APPROVE_RECURRINGDEPOSITPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="APPROVE_RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="APPROVE" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2023-10">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_permission WHERE code = 'REJECT_RECURRINGDEPOSITPRODUCT'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="organisation" />
|
||||
<column name="code" value="REJECT_RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="entity_name" value="RECURRINGDEPOSITPRODUCT" />
|
||||
<column name="action_name" value="REJECT" />
|
||||
<column name="can_maker_checker" valueBoolean="false" />
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
m_savings_product_temp was dropped by an experimental changeset that was later removed from source without
|
||||
restoring the table. Recreates it with the final shape from the 2017/2018/2019/2020 migrations (guarded so
|
||||
it's a no-op wherever the table already exists) so ProductPendingEditRepository and the isPendingApproval
|
||||
subqueries in the product read services stop failing with "relation does not exist".
|
||||
-->
|
||||
<changeSet author="fineract" id="2025-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_savings_product_temp" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_savings_product_temp">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="product_id" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="product_type" type="VARCHAR(20)" defaultValue="SAVINGS">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="maker_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_sp_temp_maker_id" references="m_appuser(id)" />
|
||||
</column>
|
||||
<column name="checker_id" type="BIGINT">
|
||||
<constraints nullable="true" foreignKeyName="fk_sp_temp_checker_id" references="m_appuser(id)" />
|
||||
</column>
|
||||
<column name="created_on" type="DATETIME">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="checked_on" type="DATETIME">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
<column name="status" type="VARCHAR(20)" defaultValue="PENDING">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="reject_reason" type="VARCHAR(500)">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
<column name="proposed_payload_json" type="CLOB">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="pending_lock_key" type="VARCHAR(40)">
|
||||
<constraints nullable="true" unique="true" uniqueConstraintName="sp_temp_unq_pending_lock_key" />
|
||||
</column>
|
||||
<column name="command_source_id" type="BIGINT">
|
||||
<constraints nullable="true" foreignKeyName="fk_sp_temp_command_source_id"
|
||||
references="m_portfolio_command_source(id)" />
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
Adds typed columns to m_savings_product_temp so a pending product edit is stored as real,
|
||||
individually-inspectable columns instead of only the opaque proposed_payload_json blob.
|
||||
proposed_payload_json is kept (still written) for a safe deprecation window; nothing here
|
||||
removes or alters any existing column. Every changeset is purely additive (addColumn only)
|
||||
and guarded with a correctly-shaped precondition (<not><columnExists .../></not> - a
|
||||
boolean precondition, unlike the historical bug in 2017-2/2020-2 which wrapped a numeric
|
||||
<sqlCheck expectedResult="0"> in <not>, inverting its meaning).
|
||||
|
||||
Columns are grouped by which product type(s) apply them; unrelated columns are simply NULL
|
||||
for a given row's product_type. Names are the snake_case of the JSON API parameter name the
|
||||
column stores, not the source product table's own column name, since this table stores
|
||||
proposed *edits* (parameter values), not a mirror of product-table storage.
|
||||
-->
|
||||
|
||||
<!-- Group 1: fields shared across Savings, Current, FD and RD (FD/RD extend Savings) -->
|
||||
<changeSet author="fineract" id="2026-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="name" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="name" type="VARCHAR(100)" />
|
||||
<column name="short_name" type="VARCHAR(20)" />
|
||||
<column name="description" type="VARCHAR(500)" />
|
||||
<column name="currency_code" type="VARCHAR(3)" />
|
||||
<column name="digits_after_decimal" type="INTEGER" />
|
||||
<column name="in_multiples_of" type="INTEGER" />
|
||||
<column name="accounting_rule" type="INTEGER" />
|
||||
|
||||
<column name="nominal_annual_interest_rate" type="DECIMAL(19,6)" />
|
||||
<column name="interest_compounding_period_type" type="INTEGER" />
|
||||
<column name="interest_posting_period_type" type="INTEGER" />
|
||||
<column name="interest_calculation_type" type="INTEGER" />
|
||||
<column name="interest_calculation_days_in_year_type" type="INTEGER" />
|
||||
<column name="min_required_opening_balance" type="DECIMAL(19,6)" />
|
||||
<column name="lockin_period_frequency" type="INTEGER" />
|
||||
<column name="lockin_period_frequency_type" type="INTEGER" />
|
||||
<column name="withdrawal_fee_for_transfers" type="BOOLEAN" />
|
||||
<column name="allow_overdraft" type="BOOLEAN" />
|
||||
<column name="overdraft_limit" type="DECIMAL(19,6)" />
|
||||
<column name="nominal_annual_interest_rate_overdraft" type="DECIMAL(19,6)" />
|
||||
<column name="min_overdraft_for_interest_calculation" type="DECIMAL(19,6)" />
|
||||
<column name="enforce_min_required_balance" type="BOOLEAN" />
|
||||
<column name="min_required_balance" type="DECIMAL(19,6)" />
|
||||
<column name="lien_allowed" type="BOOLEAN" />
|
||||
<column name="max_allowed_lien_limit" type="DECIMAL(19,6)" />
|
||||
<column name="min_balance_for_interest_calculation" type="DECIMAL(19,6)" />
|
||||
<column name="with_hold_tax" type="BOOLEAN" />
|
||||
<column name="tax_group_id" type="BIGINT" />
|
||||
<column name="other_gl_mappings" type="CLOB" />
|
||||
<column name="is_dormancy_tracking_active" type="BOOLEAN" />
|
||||
<column name="days_to_inactive" type="INTEGER" />
|
||||
<column name="days_to_dormancy" type="INTEGER" />
|
||||
<column name="days_to_escheat" type="INTEGER" />
|
||||
<column name="account_type" type="VARCHAR(50)" />
|
||||
<column name="customer_segment" type="VARCHAR(50)" />
|
||||
<column name="product_code" type="VARCHAR(20)" />
|
||||
<column name="gl_account_id" type="BIGINT" />
|
||||
<column name="effective_date" type="DATE" />
|
||||
<column name="effective_to" type="DATE" />
|
||||
<column name="end_date" type="DATE" />
|
||||
<column name="introducer_required" type="BOOLEAN" />
|
||||
<column name="share_linking_enabled" type="BOOLEAN" />
|
||||
<column name="nomination_facility" type="BOOLEAN" />
|
||||
<column name="dormancy_alert" type="BOOLEAN" />
|
||||
<column name="interest_calculate_selector" type="INTEGER" />
|
||||
<column name="average_period" type="VARCHAR(20)" />
|
||||
<column name="auto_post" type="BOOLEAN" />
|
||||
<column name="frequency_fix_day" type="INTEGER" />
|
||||
<column name="last_interest_date" type="DATE" />
|
||||
<column name="enable_lockin_period" type="BOOLEAN" />
|
||||
<column name="balance_frequency" type="VARCHAR(50)" />
|
||||
<column name="account_closed_zero_balance_in_day_closing" type="BOOLEAN" />
|
||||
<column name="balance_swap_option" type="BOOLEAN" />
|
||||
<column name="msme" type="BOOLEAN" />
|
||||
<column name="auto_debit_facility" type="BOOLEAN" />
|
||||
<column name="loan_facility" type="BOOLEAN" />
|
||||
<column name="premature_withdrawal_option" type="BOOLEAN" />
|
||||
<column name="tenure_flexibility" type="BOOLEAN" />
|
||||
<column name="lien_marked" type="BOOLEAN" />
|
||||
<column name="maturity_instructions" type="BOOLEAN" />
|
||||
<column name="credit_maturity_proceeds" type="BOOLEAN" />
|
||||
<column name="penalty_grace_period_missed_installments" type="BOOLEAN" />
|
||||
<column name="panel_request_applicable" type="BOOLEAN" />
|
||||
<column name="no_penalty_nominee_heir_closure" type="BOOLEAN" />
|
||||
<column name="deceased_settlement" type="BOOLEAN" />
|
||||
<column name="allow_debit_txn_after_due_date" type="BOOLEAN" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 2: Current-product-only fields -->
|
||||
<changeSet author="fineract" id="2026-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="avg_balance_calc_period" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="avg_balance_calc_period" type="VARCHAR(10)" />
|
||||
<column name="valid_for_period" type="VARCHAR(10)" />
|
||||
<column name="od_account_closed_zero_balance_in_day_closing" type="BOOLEAN" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 3: Share-product-only fields -->
|
||||
<changeSet author="fineract" id="2026-3">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="total_shares" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="total_shares" type="BIGINT" />
|
||||
<column name="total_shares_issued" type="BIGINT" />
|
||||
<column name="unit_price" type="DECIMAL(19,6)" />
|
||||
<column name="minimum_shares" type="BIGINT" />
|
||||
<column name="nominal_shares" type="BIGINT" />
|
||||
<column name="maximum_shares" type="BIGINT" />
|
||||
<column name="allow_dividend_calc_for_inactive_clients" type="BOOLEAN" />
|
||||
<column name="minimum_active_period_for_dividends" type="INTEGER" />
|
||||
<column name="minimum_active_period_frequency_type" type="INTEGER" />
|
||||
<column name="share_lockin_period" type="INTEGER" />
|
||||
<column name="share_lockin_period_frequency_type" type="INTEGER" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 4: Fixed-Deposit-only fields (also used by Recurring Deposit, which extends FD) -->
|
||||
<changeSet author="fineract" id="2026-4">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="fd_type" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="fd_type" type="VARCHAR(20)" />
|
||||
<column name="pre_closure_penal_applicable" type="BOOLEAN" />
|
||||
<column name="pre_closure_penal_interest" type="DECIMAL(19,6)" />
|
||||
<column name="pre_closure_penal_interest_on_type_id" type="INTEGER" />
|
||||
<column name="min_deposit_term" type="INTEGER" />
|
||||
<column name="max_deposit_term" type="INTEGER" />
|
||||
<column name="min_deposit_term_type_id" type="INTEGER" />
|
||||
<column name="max_deposit_term_type_id" type="INTEGER" />
|
||||
<column name="in_multiples_of_deposit_term" type="INTEGER" />
|
||||
<column name="in_multiples_of_deposit_term_type_id" type="INTEGER" />
|
||||
<column name="min_deposit_amount" type="DECIMAL(19,6)" />
|
||||
<column name="max_deposit_amount" type="DECIMAL(19,6)" />
|
||||
<column name="deposit_amount" type="DECIMAL(19,6)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 5: Recurring-Deposit-only fields -->
|
||||
<changeSet author="fineract" id="2026-5">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="is_mandatory_deposit" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="is_mandatory_deposit" type="BOOLEAN" />
|
||||
<column name="allow_withdrawal" type="BOOLEAN" />
|
||||
<column name="adjust_advance_towards_future_payments" type="BOOLEAN" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 6: accountFacilityConfig (1:1 today - kept as flat columns, fc_ prefix) -->
|
||||
<changeSet author="fineract" id="2026-6">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="fc_atm_facility" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="fc_atm_facility" type="BOOLEAN" />
|
||||
<column name="fc_atm_withdrawal_facility" type="BOOLEAN" />
|
||||
<column name="fc_upi_facility" type="BOOLEAN" />
|
||||
<column name="fc_pos_transactions_facility" type="BOOLEAN" />
|
||||
<column name="fc_cheque_book" type="BOOLEAN" />
|
||||
<column name="fc_imps_facility" type="BOOLEAN" />
|
||||
<column name="fc_sms_alerts" type="BOOLEAN" />
|
||||
<column name="fc_bbps_facility" type="BOOLEAN" />
|
||||
<column name="fc_insurance_cover" type="BOOLEAN" />
|
||||
<column name="fc_bepg_facility" type="BOOLEAN" />
|
||||
<column name="fc_neft_facility" type="BOOLEAN" />
|
||||
<column name="fc_rtgs_facility" type="BOOLEAN" />
|
||||
<column name="fc_inter_bank_total_cap_facility" type="BOOLEAN" />
|
||||
<column name="fc_withdrawal_facility" type="BOOLEAN" />
|
||||
<column name="fc_deposit_facility_kyc" type="BOOLEAN" />
|
||||
<column name="fc_virtual_debit_card" type="BOOLEAN" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 7: depositLimitKyc (1:1 today - kept as flat columns, kyc_ prefix) -->
|
||||
<changeSet author="fineract" id="2026-7">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="kyc_general_type" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="kyc_general_type" type="VARCHAR(50)" />
|
||||
<column name="kyc_general_limit" type="VARCHAR(50)" />
|
||||
<column name="kyc_minor_type" type="VARCHAR(50)" />
|
||||
<column name="kyc_minor_limit" type="BIGINT" />
|
||||
<column name="kyc_small_saving_type" type="VARCHAR(50)" />
|
||||
<column name="kyc_small_saving_limit" type="BIGINT" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- Group 8: GL account mapping scalar ids (1:1 today - kept as flat columns, gl_ prefix). No FK
|
||||
constraints - the existing validator already checks GL account validity at submit time. -->
|
||||
<changeSet author="fineract" id="2026-8">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_savings_product_temp" columnName="gl_savings_reference_account_id" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_savings_product_temp">
|
||||
<column name="gl_savings_reference_account_id" type="BIGINT" />
|
||||
<column name="gl_savings_control_account_id" type="BIGINT" />
|
||||
<column name="gl_income_from_fee_account_id" type="BIGINT" />
|
||||
<column name="gl_income_from_penalty_account_id" type="BIGINT" />
|
||||
<column name="gl_interest_on_savings_account_id" type="BIGINT" />
|
||||
<column name="gl_transfers_in_suspense_account_id" type="BIGINT" />
|
||||
<column name="gl_overdraft_portfolio_control_id" type="BIGINT" />
|
||||
<column name="gl_income_from_interest_id" type="BIGINT" />
|
||||
<column name="gl_write_off_account_id" type="BIGINT" />
|
||||
<column name="gl_escheat_liability_id" type="BIGINT" />
|
||||
<column name="gl_penalties_receivable_account_id" type="BIGINT" />
|
||||
<column name="gl_interest_receivable_account_id" type="BIGINT" />
|
||||
<column name="gl_fees_receivable_account_id" type="BIGINT" />
|
||||
<column name="gl_interest_payable_account_id" type="BIGINT" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
Satellite tables for the genuine one-to-many pieces of a pending product edit (charges,
|
||||
facility limits, GL array mappings, share market prices) plus a "submitted field" manifest
|
||||
that records which top-level JSON parameters were actually present in the maker's request.
|
||||
|
||||
The manifest table is not optional bookkeeping: raw JSON storage implicitly distinguishes
|
||||
"field omitted" / "field explicitly null" / "field has a value", and every existing
|
||||
command.hasParameter(...) branch in the write-services and assemblers depends on that
|
||||
distinction. Typed nullable columns alone can't represent it, so this table is the
|
||||
relational replacement for that information - one row per parameter name that was present
|
||||
at submit time, per pending edit.
|
||||
|
||||
All tables reference m_savings_product_temp(id) - no cascade delete, since pending-edit
|
||||
rows are never hard-deleted (only status-flipped) once resolved.
|
||||
-->
|
||||
|
||||
<changeSet author="fineract" id="2027-1">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_product_temp_charge" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_product_temp_charge">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="pending_edit_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_ptc_pending_edit_id" references="m_savings_product_temp(id)" />
|
||||
</column>
|
||||
<column name="charge_id" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2027-2">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_product_temp_facility_limit" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_product_temp_facility_limit">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="pending_edit_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_ptfl_pending_edit_id" references="m_savings_product_temp(id)" />
|
||||
</column>
|
||||
<column name="limit_type" type="VARCHAR(100)">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="general_limit" type="VARCHAR(50)" />
|
||||
<column name="minor_account_limit" type="VARCHAR(50)" />
|
||||
<column name="small_saving_limit" type="VARCHAR(50)" />
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2027-3">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_product_temp_gl_mapping" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_product_temp_gl_mapping">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="pending_edit_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_ptgm_pending_edit_id" references="m_savings_product_temp(id)" />
|
||||
</column>
|
||||
<!-- PAYMENT_CHANNEL / FEE / PENALTY -->
|
||||
<column name="mapping_type" type="VARCHAR(30)">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="payment_type_id" type="BIGINT" />
|
||||
<column name="charge_id" type="BIGINT" />
|
||||
<column name="gl_account_id" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2027-4">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_product_temp_share_market_price" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_product_temp_share_market_price">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="pending_edit_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_ptsmp_pending_edit_id" references="m_savings_product_temp(id)" />
|
||||
</column>
|
||||
<column name="source_id" type="BIGINT" />
|
||||
<column name="delete_flag" type="BOOLEAN" defaultValueBoolean="false">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="from_date" type="DATE" />
|
||||
<column name="share_value" type="DECIMAL(19,6)" />
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="fineract" id="2027-5">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<tableExists tableName="m_product_temp_submitted_field" />
|
||||
</not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_product_temp_submitted_field">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false" />
|
||||
</column>
|
||||
<column name="pending_edit_id" type="BIGINT">
|
||||
<constraints nullable="false" foreignKeyName="fk_ptsf_pending_edit_id" references="m_savings_product_temp(id)" />
|
||||
</column>
|
||||
<column name="field_name" type="VARCHAR(100)">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</createTable>
|
||||
<addUniqueConstraint tableName="m_product_temp_submitted_field" columnNames="pending_edit_id, field_name"
|
||||
constraintName="ptsf_unq_pending_edit_field" />
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user