charges add module add in the saving account and current account
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
-- ============================================================
|
||||
-- Facility Charge Auto-Seed Migration
|
||||
-- Step 1: Create mapping table
|
||||
-- Step 2: Insert charges into m_charge
|
||||
-- Step 3: Insert mapping with charge IDs
|
||||
-- charge_applies_to_enum: 2=SAVINGS, 5=CURRENT_ACCOUNT
|
||||
-- charge_time_enum: 3=SAVINGS_ACTIVATION, 6=ANNUAL_FEE, 7=MONTHLY_FEE
|
||||
-- charge_calculation_enum: 1=FLAT
|
||||
-- ============================================================
|
||||
|
||||
-- Step 1: Mapping table
|
||||
CREATE TABLE IF NOT EXISTS m_facility_charge_mapping (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
facility_type VARCHAR(60) NOT NULL UNIQUE,
|
||||
charge_id BIGINT,
|
||||
charge_name VARCHAR(200) NOT NULL,
|
||||
default_amount DECIMAL(19,6) NOT NULL DEFAULT 0.000000,
|
||||
charge_time_type INT NOT NULL DEFAULT 3,
|
||||
charge_applies_to INT NOT NULL DEFAULT 2,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
FOREIGN KEY (charge_id) REFERENCES m_charge(id)
|
||||
);
|
||||
|
||||
-- Step 2: Insert charges into m_charge (only if not already exists)
|
||||
-- income_or_liability_account_id = first available INCOME DETAIL GL account
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'ATM Facility Charge', 'INR', 100.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'ATM Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'ATM Withdrawal Charge', 'INR', 20.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'ATM Withdrawal Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'UPI Facility Charge', 'INR', 100.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'UPI Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'POS Transaction Charge', 'INR', 100.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'POS Transaction Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Cheque Book Charge', 'INR', 300.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Cheque Book Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'IMPS Facility Charge', 'INR', 5.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'IMPS Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'SMS Alert Charge', 'INR', 15.00, 2, 7, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'SMS Alert Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'BBPS Facility Charge', 'INR', 2.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'BBPS Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Insurance Cover Charge', 'INR', 500.00, 2, 6, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Insurance Cover Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'BEPG Facility Charge', 'INR', 5.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'BEPG Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'NEFT Facility Charge', 'INR', 5.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'NEFT Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'RTGS Facility Charge', 'INR', 25.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'RTGS Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Inter-Bank Cap Charge', 'INR', 0.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Inter-Bank Cap Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Withdrawal Facility Charge', 'INR', 5.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Withdrawal Facility Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Deposit KYC Charge', 'INR', 5.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Deposit KYC Charge' AND is_deleted = 0);
|
||||
|
||||
INSERT IGNORE INTO m_charge
|
||||
(name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted,
|
||||
is_free_withdrawal, is_payment_type, income_or_liability_account_id)
|
||||
SELECT 'Virtual Debit Card Charge', 'INR', 199.00, 2, 3, 1, 0, 1, 0, 0, 0,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND usage_enum = 1 AND disabled = 0 ORDER BY id LIMIT 1)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_charge WHERE name = 'Virtual Debit Card Charge' AND is_deleted = 0);
|
||||
|
||||
-- Step 3: Insert mapping linking facility_type → charge_id
|
||||
INSERT IGNORE INTO m_facility_charge_mapping
|
||||
(facility_type, charge_name, default_amount, charge_time_type, charge_applies_to, charge_id)
|
||||
VALUES
|
||||
('ATM_FACILITY', 'ATM Facility Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'ATM Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('ATM_WITHDRAWAL', 'ATM Withdrawal Charge', 20.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'ATM Withdrawal Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('UPI_FACILITY', 'UPI Facility Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'UPI Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('POS_TRANSACTIONS', 'POS Transaction Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'POS Transaction Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('CHEQUE_BOOK', 'Cheque Book Charge', 300.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Cheque Book Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('IMPS_FACILITY', 'IMPS Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'IMPS Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('SMS_ALERTS', 'SMS Alert Charge', 15.00, 7, 2, (SELECT id FROM m_charge WHERE name = 'SMS Alert Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('BBPS_FACILITY', 'BBPS Facility Charge', 2.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'BBPS Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('INSURANCE_COVER', 'Insurance Cover Charge', 500.00, 6, 2, (SELECT id FROM m_charge WHERE name = 'Insurance Cover Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('BEPG_FACILITY', 'BEPG Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'BEPG Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('NEFT_FACILITY', 'NEFT Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'NEFT Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('RTGS_FACILITY', 'RTGS Facility Charge', 25.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'RTGS Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('INTER_BANK_TOTAL_CAP','Inter-Bank Cap Charge', 0.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Inter-Bank Cap Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('WITHDRAWAL_FACILITY', 'Withdrawal Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Withdrawal Facility Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('DEPOSIT_FACILITY_KYC','Deposit KYC Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Deposit KYC Charge' AND is_deleted = 0 LIMIT 1)),
|
||||
('VIRTUAL_DEBIT_CARD', 'Virtual Debit Card Charge', 199.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Virtual Debit Card Charge' AND is_deleted = 0 LIMIT 1));
|
||||
@@ -0,0 +1,79 @@
|
||||
-- Migration: Add facility charge columns to product facility config tables
|
||||
-- Each facility (ATM, UPI, IMPS, etc.) links to an existing m_charge entry
|
||||
-- When account is activated, enabled facilities auto-apply their linked charge
|
||||
|
||||
-- Current Product Facility Config
|
||||
ALTER TABLE m_current_product_facility_config
|
||||
ADD COLUMN IF NOT EXISTS atm_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS atm_withdrawal_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS upi_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS pos_transactions_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS cheque_book_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS imps_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS sms_alerts_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS bbps_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS insurance_cover_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS bepg_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS neft_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS rtgs_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS inter_bank_total_cap_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS withdrawal_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS deposit_facility_kyc_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS virtual_debit_card_charge_id BIGINT NULL;
|
||||
|
||||
-- Foreign key constraints for current product
|
||||
ALTER TABLE m_current_product_facility_config
|
||||
ADD CONSTRAINT fk_cpfc_atm_charge FOREIGN KEY (atm_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_atm_wd_charge FOREIGN KEY (atm_withdrawal_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_upi_charge FOREIGN KEY (upi_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_pos_charge FOREIGN KEY (pos_transactions_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_chq_charge FOREIGN KEY (cheque_book_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_imps_charge FOREIGN KEY (imps_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_sms_charge FOREIGN KEY (sms_alerts_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_bbps_charge FOREIGN KEY (bbps_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_ins_charge FOREIGN KEY (insurance_cover_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_bepg_charge FOREIGN KEY (bepg_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_neft_charge FOREIGN KEY (neft_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_rtgs_charge FOREIGN KEY (rtgs_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_ibtc_charge FOREIGN KEY (inter_bank_total_cap_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_wd_charge FOREIGN KEY (withdrawal_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_dep_charge FOREIGN KEY (deposit_facility_kyc_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_cpfc_vdc_charge FOREIGN KEY (virtual_debit_card_charge_id) REFERENCES m_charge(id);
|
||||
|
||||
-- Savings Product Facility Config
|
||||
ALTER TABLE m_savings_product_facility_config
|
||||
ADD COLUMN IF NOT EXISTS atm_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS atm_withdrawal_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS upi_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS pos_transactions_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS cheque_book_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS imps_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS sms_alerts_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS bbps_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS insurance_cover_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS bepg_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS neft_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS rtgs_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS inter_bank_total_cap_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS withdrawal_facility_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS deposit_facility_kyc_charge_id BIGINT NULL,
|
||||
ADD COLUMN IF NOT EXISTS virtual_debit_card_charge_id BIGINT NULL;
|
||||
|
||||
-- Foreign key constraints for savings product
|
||||
ALTER TABLE m_savings_product_facility_config
|
||||
ADD CONSTRAINT fk_spfc_atm_charge FOREIGN KEY (atm_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_atm_wd_charge FOREIGN KEY (atm_withdrawal_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_upi_charge FOREIGN KEY (upi_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_pos_charge FOREIGN KEY (pos_transactions_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_chq_charge FOREIGN KEY (cheque_book_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_imps_charge FOREIGN KEY (imps_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_sms_charge FOREIGN KEY (sms_alerts_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_bbps_charge FOREIGN KEY (bbps_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_ins_charge FOREIGN KEY (insurance_cover_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_bepg_charge FOREIGN KEY (bepg_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_neft_charge FOREIGN KEY (neft_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_rtgs_charge FOREIGN KEY (rtgs_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_ibtc_charge FOREIGN KEY (inter_bank_total_cap_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_wd_charge FOREIGN KEY (withdrawal_facility_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_dep_charge FOREIGN KEY (deposit_facility_kyc_charge_id) REFERENCES m_charge(id),
|
||||
ADD CONSTRAINT fk_spfc_vdc_charge FOREIGN KEY (virtual_debit_card_charge_id) REFERENCES m_charge(id);
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||
@@ -45,7 +46,7 @@ public interface JournalEntryMapper {
|
||||
@Mapping(target = "amount", source = "amount")
|
||||
@Mapping(target = "entityType", source = "entityType", qualifiedByName = "entityType")
|
||||
@Mapping(target = "entityId", source = "entityId")
|
||||
@Mapping(target = "submittedOnDate", source = "submittedOnDate")
|
||||
@Mapping(target = "submittedOnDate", expression = "java(journalEntry.getCreatedDate().orElse(null))")
|
||||
@Mapping(target = "transactionId", source = "transactionId")
|
||||
@Mapping(target = "currency", source = "currencyCode")
|
||||
@Mapping(target = "manualEntry", source = "manualEntry")
|
||||
|
||||
+5
-4
@@ -20,6 +20,7 @@ package org.apache.fineract.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
@@ -60,7 +61,7 @@ public class JournalEntryData {
|
||||
@SuppressWarnings("unused")
|
||||
private Long createdByUserId;
|
||||
@SuppressWarnings("unused")
|
||||
private LocalDate createdDate;
|
||||
private OffsetDateTime createdDate;
|
||||
@SuppressWarnings("unused")
|
||||
private String createdByUserName;
|
||||
@SuppressWarnings("unused")
|
||||
@@ -79,7 +80,7 @@ public class JournalEntryData {
|
||||
@SuppressWarnings("unused")
|
||||
private TransactionDetailData transactionDetails;
|
||||
@SuppressWarnings("unused")
|
||||
private LocalDate submittedOnDate;
|
||||
private OffsetDateTime submittedOnDate;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
@@ -189,7 +190,7 @@ public class JournalEntryData {
|
||||
public JournalEntryData(final Long id, final Long officeId, final String officeName, final String glAccountName, final Long glAccountId,
|
||||
final String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate,
|
||||
final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry,
|
||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final LocalDate submittedOnDate,
|
||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final OffsetDateTime submittedOnDate,
|
||||
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
||||
@@ -251,7 +252,7 @@ public class JournalEntryData {
|
||||
final EnumOptionData entityType = null;
|
||||
final Long entityId = null;
|
||||
final Long createdByUserId = null;
|
||||
final LocalDate submittedOnDate = null;
|
||||
final OffsetDateTime submittedOnDate = null;
|
||||
final String createdByUserName = null;
|
||||
final String comments = null;
|
||||
final Boolean reversed = null;
|
||||
|
||||
+20
@@ -291,6 +291,17 @@ public class CurrentAccount extends AbstractAuditableCustom {
|
||||
@Column(name = "avg_balance_calc_period", length = 10)
|
||||
private String avgBalanceCalcPeriod;
|
||||
|
||||
// Extra fields copied from product (not in m_savings_account dormancy set)
|
||||
@Column(name = "account_closed_zero_balance_in_day_closing")
|
||||
private Boolean accountClosedZeroBalanceInDayClosing = false;
|
||||
|
||||
@Column(name = "valid_for_period", length = 10)
|
||||
private String validForPeriod;
|
||||
|
||||
@Column(name = "od_account_closed_zero_balance_in_day_closing")
|
||||
private boolean odAccountClosedZeroBalanceInDayClosing = false;
|
||||
|
||||
|
||||
// Relationships
|
||||
@OneToMany(mappedBy = "currentAccount", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<CurrentAccountTransaction> transactions = new ArrayList<>();
|
||||
@@ -383,4 +394,13 @@ public class CurrentAccount extends AbstractAuditableCustom {
|
||||
this.statusEnum = 600;
|
||||
this.closedOnDate = closedOnDate;
|
||||
}
|
||||
|
||||
public void setMinRequiredOpeningBalance(java.math.BigDecimal val) { this.minRequiredOpeningBalance = val; }
|
||||
public void setMinRequiredBalance(java.math.BigDecimal val) { this.minRequiredBalance = val; }
|
||||
public void setEnforceMinRequiredBalance(boolean val) { this.enforceMinRequiredBalance = val; }
|
||||
public void setLockinPeriodFrequency(Integer val) { this.lockinPeriodFrequency = val; }
|
||||
public void setLockinPeriodFrequencyEnum(Integer val) { this.lockinPeriodFrequencyEnum = val; }
|
||||
public void setNominalAnnualInterestRateOverdraft(java.math.BigDecimal val) { this.nominalAnnualInterestRateOverdraft = val; }
|
||||
public void setWithdrawalFeeForTransfer(boolean val) { this.withdrawalFeeForTransfer = val; }
|
||||
public void setMinOverdraftForInterestCalculation(java.math.BigDecimal val) { this.minOverdraftForInterestCalculation = val; }
|
||||
}
|
||||
|
||||
+18
@@ -106,4 +106,22 @@ public class CurrentAccountCharge extends AbstractPersistableCustom<Long> {
|
||||
private LocalDate chargeResetDate;
|
||||
|
||||
protected CurrentAccountCharge() {}
|
||||
|
||||
public static CurrentAccountCharge createFromFacility(final CurrentAccount account, final Charge charge) {
|
||||
final CurrentAccountCharge c = new CurrentAccountCharge();
|
||||
c.currentAccount = account;
|
||||
c.charge = charge;
|
||||
c.chargeTimeEnum = charge.getChargeTimeType();
|
||||
c.chargeCalculationEnum = charge.getChargeCalculation();
|
||||
c.amount = charge.getAmount();
|
||||
c.amountOutstandingDerived = charge.getAmount();
|
||||
c.penalty = charge.isPenalty();
|
||||
c.active = true;
|
||||
if (charge.getFeeOnMonthDay() != null) {
|
||||
c.feeOnMonth = charge.getFeeOnMonthDay().getMonthValue();
|
||||
c.feeOnDay = charge.getFeeOnMonthDay().getDayOfMonth();
|
||||
}
|
||||
c.feeInterval = charge.getFeeInterval();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ public class CurrentAccountFacilityConfig extends AbstractPersistableCustom<Long
|
||||
@Column(name = "mobile_banking", nullable = false)
|
||||
private boolean mobileBanking = false;
|
||||
|
||||
protected CurrentAccountFacilityConfig() {}
|
||||
public CurrentAccountFacilityConfig() {}
|
||||
|
||||
public static CurrentAccountFacilityConfig createFor(CurrentAccount account) {
|
||||
CurrentAccountFacilityConfig cfg = new CurrentAccountFacilityConfig();
|
||||
|
||||
+12
@@ -122,6 +122,18 @@ public class CurrentAccountTransaction extends AbstractPersistableCustom<Long> {
|
||||
return txn;
|
||||
}
|
||||
|
||||
public static CurrentAccountTransaction chargeDeduction(CurrentAccount account, Office office,
|
||||
BigDecimal amount, LocalDate transactionDate) {
|
||||
CurrentAccountTransaction txn = new CurrentAccountTransaction();
|
||||
txn.currentAccount = account;
|
||||
txn.office = office;
|
||||
txn.transactionTypeEnum = 7; // PAY_CHARGE
|
||||
txn.amount = amount;
|
||||
txn.transactionDate = transactionDate;
|
||||
txn.submittedOnDate = transactionDate;
|
||||
return txn;
|
||||
}
|
||||
|
||||
public static CurrentAccountTransaction withdrawal(CurrentAccount account, Office office,
|
||||
BigDecimal amount, LocalDate transactionDate, String refNo) {
|
||||
CurrentAccountTransaction txn = new CurrentAccountTransaction();
|
||||
|
||||
+12
@@ -447,6 +447,10 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
|
||||
return this.withHoldTax;
|
||||
}
|
||||
|
||||
public boolean isLienAllowed() { return this.lienAllowed; }
|
||||
public BigDecimal getMaxAllowedLienLimit() { return this.maxAllowedLienLimit; }
|
||||
public BigDecimal getMinBalanceForInterestCalculation() { return this.minBalanceForInterestCalculation; }
|
||||
|
||||
public TaxGroup getTaxGroup() {
|
||||
return this.taxGroup;
|
||||
}
|
||||
@@ -867,6 +871,14 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
|
||||
public void setLastInterestDate(LocalDate lastInterestDate) { this.lastInterestDate = lastInterestDate; }
|
||||
public boolean isEnableLockinPeriod() { return enableLockinPeriod; }
|
||||
public void setEnableLockinPeriod(boolean enableLockinPeriod) { this.enableLockinPeriod = enableLockinPeriod; }
|
||||
public BigDecimal getMinRequiredOpeningBalance() { return minRequiredOpeningBalance; }
|
||||
public BigDecimal getMinRequiredBalance() { return minRequiredBalance; }
|
||||
public boolean isEnforceMinRequiredBalance() { return enforceMinRequiredBalance; }
|
||||
public Integer getLockinPeriodFrequency() { return lockinPeriodFrequency; }
|
||||
public Integer getLockinPeriodFrequencyType() { return lockinPeriodFrequencyType; }
|
||||
public BigDecimal getNominalAnnualInterestRateOverdraft() { return nominalAnnualInterestRateOverdraft; }
|
||||
public boolean isWithdrawalFeeApplicableForTransfer() { return withdrawalFeeApplicableForTransfer; }
|
||||
public BigDecimal getMinOverdraftForInterestCalculation() { return minOverdraftForInterestCalculation; }
|
||||
public String getBalanceFrequency() { return balanceFrequency; }
|
||||
public void setBalanceFrequency(String balanceFrequency) { this.balanceFrequency = balanceFrequency; }
|
||||
public Boolean getAccountClosedZeroBalanceInDayClosing() { return accountClosedZeroBalanceInDayClosing; }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+75286
-2468
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -24,6 +24,7 @@ import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -97,7 +98,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
.append(" journalEntry.type_enum as entryType,journalEntry.amount as amount, journalEntry.transaction_id as transactionId,")
|
||||
.append(" journalEntry.entity_type_enum as entityType, journalEntry.entity_id as entityId, creatingUser.id as createdByUserId, ")
|
||||
.append(" creatingUser.username as createdByUserName, journalEntry.description as comments, ")
|
||||
.append(" journalEntry.submitted_on_date as submittedOnDate, journalEntry.reversed as reversed, ")
|
||||
.append(" journalEntry.created_on_utc as submittedOnDate, journalEntry.reversed as reversed, ")
|
||||
.append(" journalEntry.currency_code as currencyCode, curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
|
||||
.append(" curr.display_symbol as currencyDisplaySymbol, curr.decimal_places as currencyDigits, curr.currency_multiplesof as inMultiplesOf, ")
|
||||
.append(" eao.external_id as externalAssetOwner ");
|
||||
@@ -157,7 +158,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
|
||||
final Long entityId = JdbcSupport.getLong(rs, "entityId");
|
||||
final Long createdByUserId = rs.getLong("createdByUserId");
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final OffsetDateTime submittedOnDate = rs.getObject("submittedOnDate", OffsetDateTime.class);
|
||||
final String createdByUserName = rs.getString("createdByUserName");
|
||||
final String comments = rs.getString("comments");
|
||||
final Boolean reversed = rs.getBoolean("reversed");
|
||||
|
||||
+152
-2
@@ -63,7 +63,154 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
|
||||
if (rows.isEmpty()) {
|
||||
throw new CurrentAccountNotFoundException(accountId);
|
||||
}
|
||||
return buildStructuredResponse(rows.get(0));
|
||||
final Map<String, Object> response = buildStructuredResponse(rows.get(0));
|
||||
response.put("charges", retrieveCharges(accountId));
|
||||
response.put("transactions", retrieveTransactions(accountId));
|
||||
return response;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> retrieveTransactions(Long accountId) {
|
||||
final String sql =
|
||||
"SELECT t.id, t.transaction_type_enum, t.transaction_date, t.amount, "
|
||||
+ "t.running_balance_derived, t.is_reversed, t.is_reversal, t.ref_no, t.remarks, "
|
||||
+ "t.submitted_on_date "
|
||||
+ "FROM m_current_account_transaction t "
|
||||
+ "WHERE t.current_account_id = ? "
|
||||
+ "ORDER BY t.transaction_date ASC, t.id ASC";
|
||||
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||
final Map<String, Object> t = new LinkedHashMap<>();
|
||||
t.put("id", rs.getLong("id"));
|
||||
|
||||
final int txnTypeEnum = rs.getInt("transaction_type_enum");
|
||||
t.put("transactionType", buildTransactionType(txnTypeEnum));
|
||||
|
||||
final java.time.LocalDate txnDate = rs.getObject("transaction_date", java.time.LocalDate.class);
|
||||
if (txnDate != null) {
|
||||
t.put("date", new int[]{txnDate.getYear(), txnDate.getMonthValue(), txnDate.getDayOfMonth()});
|
||||
} else {
|
||||
t.put("date", null);
|
||||
}
|
||||
|
||||
t.put("amount", rs.getBigDecimal("amount"));
|
||||
t.put("runningBalance", rs.getBigDecimal("running_balance_derived"));
|
||||
t.put("reversed", rs.getBoolean("is_reversed"));
|
||||
t.put("isReversal", rs.getBoolean("is_reversal"));
|
||||
t.put("refNo", rs.getString("ref_no"));
|
||||
t.put("remarks", rs.getString("remarks"));
|
||||
|
||||
final java.time.LocalDate submittedOn = rs.getObject("submitted_on_date", java.time.LocalDate.class);
|
||||
if (submittedOn != null) {
|
||||
t.put("submittedOnDate", new int[]{submittedOn.getYear(), submittedOn.getMonthValue(), submittedOn.getDayOfMonth()});
|
||||
} else {
|
||||
t.put("submittedOnDate", null);
|
||||
}
|
||||
return t;
|
||||
}, accountId);
|
||||
}
|
||||
|
||||
private Map<String, Object> buildTransactionType(int typeEnum) {
|
||||
final Map<String, Object> tt = new LinkedHashMap<>();
|
||||
tt.put("id", typeEnum);
|
||||
tt.put("deposit", typeEnum == 1);
|
||||
tt.put("withdrawal", typeEnum == 2);
|
||||
tt.put("interestPosting", typeEnum == 3);
|
||||
tt.put("feeDeduction", typeEnum == 4 || typeEnum == 7);
|
||||
tt.put("overdraftInterest", false);
|
||||
tt.put("withholdTax", false);
|
||||
tt.put("initiateTransfer", false);
|
||||
tt.put("approveTransfer", false);
|
||||
tt.put("withdrawTransfer", false);
|
||||
tt.put("rejectTransfer", false);
|
||||
tt.put("writtenoff", false);
|
||||
tt.put("overdraftFee", false);
|
||||
tt.put("escheat", false);
|
||||
tt.put("amountHold", false);
|
||||
tt.put("amountRelease", false);
|
||||
tt.put("accrual", false);
|
||||
switch (typeEnum) {
|
||||
case 1 -> { tt.put("code", "savingsTransactionType.deposit"); tt.put("value", "Deposit"); }
|
||||
case 2 -> { tt.put("code", "savingsTransactionType.withdrawal"); tt.put("value", "Withdrawal"); }
|
||||
case 3 -> { tt.put("code", "savingsTransactionType.interestPosting"); tt.put("value", "Interest Posting"); }
|
||||
case 4 -> { tt.put("code", "savingsTransactionType.feeDeduction"); tt.put("value", "Fee Deduction"); }
|
||||
case 7 -> { tt.put("code", "savingsTransactionType.payCharge"); tt.put("value", "Charge Deduction"); }
|
||||
default -> { tt.put("code", "savingsTransactionType.deposit"); tt.put("value", "Deposit"); }
|
||||
}
|
||||
return tt;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> retrieveCharges(Long accountId) {
|
||||
final String sql =
|
||||
"SELECT cac.id, cac.charge_id, ch.name AS charge_name, "
|
||||
+ "cac.charge_time_enum, cac.charge_due_date, cac.fee_on_month, cac.fee_on_day, "
|
||||
+ "cac.fee_interval, cac.charge_calculation_enum, "
|
||||
+ "cac.amount, cac.amount_paid_derived, cac.amount_waived_derived, "
|
||||
+ "cac.amount_writtenoff_derived, cac.amount_outstanding_derived, "
|
||||
+ "cac.is_paid_derived, cac.waived, cac.is_penalty, cac.is_active "
|
||||
+ "FROM m_current_account_charge cac "
|
||||
+ "JOIN m_charge ch ON ch.id = cac.charge_id "
|
||||
+ "WHERE cac.current_account_id = ? AND cac.is_active = true "
|
||||
+ "ORDER BY cac.id";
|
||||
|
||||
return jdbcTemplate.query(sql, (rs, rowNum) -> {
|
||||
final Map<String, Object> c = new LinkedHashMap<>();
|
||||
c.put("id", rs.getLong("id"));
|
||||
c.put("chargeId", rs.getLong("charge_id"));
|
||||
c.put("name", rs.getString("charge_name"));
|
||||
|
||||
final int chargeTimeEnum = rs.getInt("charge_time_enum");
|
||||
c.put("chargeTimeType", buildEnumOption(chargeTimeEnum, chargeTimeValue(chargeTimeEnum)));
|
||||
|
||||
c.put("chargeDueDate", rs.getDate("charge_due_date") != null ? rs.getDate("charge_due_date").toLocalDate().toString() : null);
|
||||
c.put("feeOnMonthDay", buildFeeOnMonthDay(rs.getObject("fee_on_month"), rs.getObject("fee_on_day")));
|
||||
c.put("feeInterval", rs.getObject("fee_interval"));
|
||||
|
||||
final int chargeCalcEnum = rs.getInt("charge_calculation_enum");
|
||||
c.put("chargeCalculationType", buildEnumOption(chargeCalcEnum, chargeCalcValue(chargeCalcEnum)));
|
||||
|
||||
c.put("amount", rs.getBigDecimal("amount"));
|
||||
c.put("amountPaid", rs.getBigDecimal("amount_paid_derived"));
|
||||
c.put("amountWaived", rs.getBigDecimal("amount_waived_derived"));
|
||||
c.put("amountWrittenOff", rs.getBigDecimal("amount_writtenoff_derived"));
|
||||
c.put("amountOutstanding", rs.getBigDecimal("amount_outstanding_derived"));
|
||||
c.put("paid", rs.getBoolean("is_paid_derived"));
|
||||
c.put("waived", rs.getBoolean("waived"));
|
||||
c.put("penalty", rs.getBoolean("is_penalty"));
|
||||
c.put("isActive", rs.getBoolean("is_active"));
|
||||
return c;
|
||||
}, accountId);
|
||||
}
|
||||
|
||||
private Map<String, Object> buildFeeOnMonthDay(Object month, Object day) {
|
||||
if (month == null || day == null) return null;
|
||||
final Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("month", month);
|
||||
m.put("day", day);
|
||||
return m;
|
||||
}
|
||||
|
||||
private String chargeTimeValue(int id) {
|
||||
return switch (id) {
|
||||
case 1 -> "Disbursement";
|
||||
case 2 -> "Specified due date";
|
||||
case 3 -> "Savings Activation";
|
||||
case 4 -> "Withdrawal Fee";
|
||||
case 5 -> "Annual Fee";
|
||||
case 6 -> "Annual Fee";
|
||||
case 7 -> "Monthly Fee";
|
||||
case 8 -> "Overdue Fee";
|
||||
default -> "Specified due date";
|
||||
};
|
||||
}
|
||||
|
||||
private String chargeCalcValue(int id) {
|
||||
return switch (id) {
|
||||
case 1 -> "Flat";
|
||||
case 2 -> "% Amount";
|
||||
case 3 -> "% Loan Amount + Interest";
|
||||
case 4 -> "% Interest";
|
||||
default -> "Flat";
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,7 +218,10 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
|
||||
List<Map<String, Object>> rows = jdbcTemplate.query(BASE_SQL, new FlatRowMapper());
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
result.add(buildStructuredResponse(row));
|
||||
final Map<String, Object> response = buildStructuredResponse(row);
|
||||
final Long id = ((Number) row.get("id")).longValue();
|
||||
response.put("charges", retrieveCharges(id));
|
||||
result.add(response);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+267
-1
@@ -44,6 +44,14 @@ import org.apache.fineract.portfolio.currentaccount.service.CurrentAccountWriteP
|
||||
import org.apache.fineract.portfolio.currentaccount.service.CurrentAccountNumberGenerator;
|
||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProduct;
|
||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProductRepository;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.apache.fineract.portfolio.PortfolioProductType;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -61,6 +69,10 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
private final OfficeRepositoryWrapper officeRepository;
|
||||
private final CurrentAccountNumberGenerator accountNumberGenerator;
|
||||
private final ClientNomineeWritePlatformService clientNomineeWritePlatformService;
|
||||
private final org.apache.fineract.portfolio.savings.domain.FacilityChargeMappingRepository facilityChargeMappingRepository;
|
||||
private final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransactionRepository currentAccountTransactionRepository;
|
||||
private final JournalEntryRepository journalEntryRepository;
|
||||
private final ProductToGLAccountMappingRepository productToGLAccountMappingRepository;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@@ -114,6 +126,26 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
product.getInterestCalculateSelector(), product.getAveragePeriod(),
|
||||
product.getAvgBalanceCalcPeriod());
|
||||
|
||||
// Copy product-level fields that are not in createNew()
|
||||
account.setMinRequiredOpeningBalance(product.getMinRequiredOpeningBalance());
|
||||
account.setMinRequiredBalance(product.getMinRequiredBalance());
|
||||
account.setEnforceMinRequiredBalance(product.isEnforceMinRequiredBalance());
|
||||
account.setLockinPeriodFrequency(product.getLockinPeriodFrequency());
|
||||
account.setLockinPeriodFrequencyEnum(product.getLockinPeriodFrequencyType());
|
||||
account.setNominalAnnualInterestRateOverdraft(product.getNominalAnnualInterestRateOverdraft());
|
||||
account.setWithdrawalFeeForTransfer(product.isWithdrawalFeeApplicableForTransfer());
|
||||
account.setMinOverdraftForInterestCalculation(product.getMinOverdraftForInterestCalculation());
|
||||
account.setFrequencyFixDay(product.getFrequencyFixDay());
|
||||
account.setEnableLockinPeriod(product.isEnableLockinPeriod());
|
||||
account.setBalanceFrequency(product.getBalanceFrequency());
|
||||
account.setAccountClosedZeroBalanceInDayClosing(product.getAccountClosedZeroBalanceInDayClosing());
|
||||
account.setValidForPeriod(product.getValidForPeriod());
|
||||
account.setOdAccountClosedZeroBalanceInDayClosing(product.isOdAccountClosedZeroBalanceInDayClosing());
|
||||
account.setLienAllowed(product.isLienAllowed());
|
||||
account.setMaxAllowedLienLimit(product.getMaxAllowedLienLimit());
|
||||
account.setMinBalanceForInterestCalculation(product.getMinBalanceForInterestCalculation());
|
||||
account.setWithholdTax(product.withHoldTax());
|
||||
|
||||
if (json.has("establishmentDate") && !json.get("establishmentDate").isJsonNull()) {
|
||||
account.setEstablishmentDate(parseDate(json.get("establishmentDate").getAsString(), dateFormat, locale));
|
||||
}
|
||||
@@ -141,7 +173,8 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
if (introducerClientId != null) account.setIntroducerClientId(introducerClientId);
|
||||
|
||||
if (json.has("externalId") && !json.get("externalId").isJsonNull()) {
|
||||
account.setExternalId(json.get("externalId").getAsString());
|
||||
final String extId = json.get("externalId").getAsString().trim();
|
||||
account.setExternalId(extId.isEmpty() ? null : extId);
|
||||
}
|
||||
if (json.has("accountStatus") && !json.get("accountStatus").isJsonNull()) {
|
||||
account.setAccountStatus(json.get("accountStatus").getAsString());
|
||||
@@ -221,8 +254,73 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
final JsonObject json = command.parsedJson().getAsJsonObject();
|
||||
LocalDate activatedOnDate = parseDate(getString(json, "activatedOnDate"), getString(json, "dateFormat"), getString(json, "locale"));
|
||||
if (activatedOnDate == null) activatedOnDate = LocalDate.now();
|
||||
// Validate minimum opening balance before activation
|
||||
java.math.BigDecimal openingBalanceValue = java.math.BigDecimal.ZERO;
|
||||
if (json.has("openingBalance") && !json.get("openingBalance").isJsonNull()) {
|
||||
try { openingBalanceValue = json.get("openingBalance").getAsBigDecimal(); } catch (Exception ignored) {}
|
||||
}
|
||||
final java.math.BigDecimal minRequired = account.getMinRequiredOpeningBalance();
|
||||
if (minRequired != null && minRequired.compareTo(java.math.BigDecimal.ZERO) > 0
|
||||
&& openingBalanceValue.compareTo(minRequired) < 0) {
|
||||
throw new org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException(
|
||||
java.util.List.of(org.apache.fineract.infrastructure.core.data.ApiParameterError.parameterError(
|
||||
"openingBalance",
|
||||
"Opening balance (" + openingBalanceValue + ") is less than minimum required opening balance (" + minRequired + ")",
|
||||
"validation.msg.currentaccount.openingBalance.less.than.min.required",
|
||||
openingBalanceValue, minRequired)));
|
||||
}
|
||||
|
||||
account.activate(activatedOnDate);
|
||||
applyFacilityChargesOnActivation(account);
|
||||
|
||||
java.math.BigDecimal currentBalance = java.math.BigDecimal.ZERO;
|
||||
final java.util.List<org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction> depositTxns = new java.util.ArrayList<>();
|
||||
final java.util.List<ChargeGlEntry> chargeEntries = new java.util.ArrayList<>();
|
||||
|
||||
// Opening balance deposit transaction
|
||||
if (openingBalanceValue.compareTo(java.math.BigDecimal.ZERO) > 0) {
|
||||
try {
|
||||
final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction deposit =
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction
|
||||
.deposit(account, account.getOffice(), openingBalanceValue, activatedOnDate, "OPENING-BALANCE");
|
||||
deposit.setRunningBalanceDerived(openingBalanceValue);
|
||||
account.setTotalDepositsDerived(openingBalanceValue);
|
||||
currentAccountTransactionRepository.saveAndFlush(deposit);
|
||||
currentBalance = openingBalanceValue;
|
||||
depositTxns.add(deposit);
|
||||
log.info("Opening balance deposit {} created for account id={}", openingBalanceValue, accountId);
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not process openingBalance for account id={}: {}", accountId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-deduct activation charges (chargeTimeEnum=3) from opening balance
|
||||
for (final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountCharge charge : account.getCharges()) {
|
||||
if (charge.getChargeTimeEnum() != null && charge.getChargeTimeEnum() == 3
|
||||
&& charge.getAmount() != null
|
||||
&& charge.getAmount().compareTo(java.math.BigDecimal.ZERO) > 0
|
||||
&& charge.getCharge() != null) {
|
||||
charge.setAmountPaidDerived(charge.getAmount());
|
||||
charge.setAmountOutstandingDerived(java.math.BigDecimal.ZERO);
|
||||
charge.setPaid(true);
|
||||
currentBalance = currentBalance.subtract(charge.getAmount());
|
||||
final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction chargeTxn =
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction
|
||||
.chargeDeduction(account, account.getOffice(), charge.getAmount(), activatedOnDate);
|
||||
chargeTxn.setRunningBalanceDerived(currentBalance);
|
||||
currentAccountTransactionRepository.saveAndFlush(chargeTxn);
|
||||
chargeEntries.add(new ChargeGlEntry(chargeTxn, charge));
|
||||
log.info("Auto-deducted activation charge '{}' {} from account id={}, running balance={}",
|
||||
charge.getCharge().getName(), charge.getAmount(), accountId, currentBalance);
|
||||
}
|
||||
}
|
||||
|
||||
account.setAccountBalanceDerived(currentBalance);
|
||||
currentAccountRepository.saveAndFlush(account);
|
||||
|
||||
// Post GL journal entries — deposits in batch, each charge individually
|
||||
postGlEntries(account, depositTxns, chargeEntries);
|
||||
|
||||
return new CommandProcessingResultBuilder().withEntityId(accountId).build();
|
||||
}
|
||||
|
||||
@@ -396,4 +494,172 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyFacilityChargesOnActivation(final CurrentAccount account) {
|
||||
// Use account-level facility config — reflects what was selected at account opening time
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountFacilityConfig config =
|
||||
account.getFacilityConfig();
|
||||
|
||||
log.info("[FacilityCharge] Activating account id={}, facilityConfig={}",
|
||||
account.getId(), config != null ? "FOUND" : "NULL");
|
||||
|
||||
if (config == null) {
|
||||
// Fallback: use product-level facility config
|
||||
log.info("[FacilityCharge] No account-level config, falling back to product id={}", account.getProductId());
|
||||
config = currentProductRepository.findById(account.getProductId())
|
||||
.map(p -> {
|
||||
final var pc = p.getFacilityConfig();
|
||||
if (pc == null) {
|
||||
log.info("[FacilityCharge] Product has no facility config either");
|
||||
return null;
|
||||
}
|
||||
// Map product config to account config fields inline
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountFacilityConfig ac =
|
||||
new org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountFacilityConfig();
|
||||
ac.setAtmFacility(Boolean.TRUE.equals(pc.getAtmFacility()));
|
||||
ac.setAtmWithdrawalFacility(Boolean.TRUE.equals(pc.getAtmWithdrawalFacility()));
|
||||
ac.setUpiFacility(Boolean.TRUE.equals(pc.getUpiFacility()));
|
||||
ac.setPosTransactionsFacility(Boolean.TRUE.equals(pc.getPosTransactionsFacility()));
|
||||
ac.setChequeBook(Boolean.TRUE.equals(pc.getChequeBook()));
|
||||
ac.setImpsFacility(Boolean.TRUE.equals(pc.getImpsFacility()));
|
||||
ac.setSmsAlerts(Boolean.TRUE.equals(pc.getSmsAlerts()));
|
||||
ac.setBbpsFacility(Boolean.TRUE.equals(pc.getBbpsFacility()));
|
||||
ac.setInsuranceCover(Boolean.TRUE.equals(pc.getInsuranceCover()));
|
||||
ac.setBepgFacility(Boolean.TRUE.equals(pc.getBepgFacility()));
|
||||
ac.setNeftFacility(Boolean.TRUE.equals(pc.getNeftFacility()));
|
||||
ac.setRtgsFacility(Boolean.TRUE.equals(pc.getRtgsFacility()));
|
||||
ac.setInterBankTotalCapFacility(Boolean.TRUE.equals(pc.getInterBankTotalCapFacility()));
|
||||
ac.setWithdrawalFacility(Boolean.TRUE.equals(pc.getWithdrawalFacility()));
|
||||
ac.setDepositFacilityKyc(Boolean.TRUE.equals(pc.getDepositFacilityKyc()));
|
||||
ac.setVirtualDebitCard(Boolean.TRUE.equals(pc.getVirtualDebitCard()));
|
||||
return ac;
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
log.warn("[FacilityCharge] No facility config found for account id={} — no charges applied", account.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountFacilityConfig fc = config;
|
||||
log.info("[FacilityCharge] Config found — ATM={} UPI={} NEFT={} RTGS={} CHEQUE={} SMS={} IMPs={} POS={} BBPS={} INS={} BEPG={} IBCAP={} WD={} KYC={} VCARD={} ATM_WD={}",
|
||||
fc.isAtmFacility(), fc.isUpiFacility(), fc.isNeftFacility(), fc.isRtgsFacility(),
|
||||
fc.isChequeBook(), fc.isSmsAlerts(), fc.isImpsFacility(), fc.isPosTransactionsFacility(),
|
||||
fc.isBbpsFacility(), fc.isInsuranceCover(), fc.isBepgFacility(), fc.isInterBankTotalCapFacility(),
|
||||
fc.isWithdrawalFacility(), fc.isDepositFacilityKyc(), fc.isVirtualDebitCard(), fc.isAtmWithdrawalFacility());
|
||||
applyMapped(account, fc.isAtmFacility(), "ATM_FACILITY");
|
||||
applyMapped(account, fc.isAtmWithdrawalFacility(), "ATM_WITHDRAWAL");
|
||||
applyMapped(account, fc.isUpiFacility(), "UPI_FACILITY");
|
||||
applyMapped(account, fc.isPosTransactionsFacility(), "POS_TRANSACTIONS");
|
||||
applyMapped(account, fc.isChequeBook(), "CHEQUE_BOOK");
|
||||
applyMapped(account, fc.isImpsFacility(), "IMPS_FACILITY");
|
||||
applyMapped(account, fc.isSmsAlerts(), "SMS_ALERTS");
|
||||
applyMapped(account, fc.isBbpsFacility(), "BBPS_FACILITY");
|
||||
applyMapped(account, fc.isInsuranceCover(), "INSURANCE_COVER");
|
||||
applyMapped(account, fc.isBepgFacility(), "BEPG_FACILITY");
|
||||
applyMapped(account, fc.isNeftFacility(), "NEFT_FACILITY");
|
||||
applyMapped(account, fc.isRtgsFacility(), "RTGS_FACILITY");
|
||||
applyMapped(account, fc.isInterBankTotalCapFacility(),"INTER_BANK_TOTAL_CAP");
|
||||
applyMapped(account, fc.isWithdrawalFacility(), "WITHDRAWAL_FACILITY");
|
||||
applyMapped(account, fc.isDepositFacilityKyc(), "DEPOSIT_FACILITY_KYC");
|
||||
applyMapped(account, fc.isVirtualDebitCard(), "VIRTUAL_DEBIT_CARD");
|
||||
}
|
||||
|
||||
// Wrapper to carry a charge transaction together with its charge entity for GL posting
|
||||
private record ChargeGlEntry(
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction txn,
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountCharge charge) {}
|
||||
|
||||
// entity type for savings/current accounts in acc_gl_journal_entry
|
||||
private static final int ENTITY_TYPE_SAVINGS = 2;
|
||||
|
||||
private void postGlEntries(final CurrentAccount account,
|
||||
final java.util.List<org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction> depositTxns,
|
||||
final java.util.List<ChargeGlEntry> chargeEntries) {
|
||||
try {
|
||||
final CurrentProduct product = currentProductRepository.findById(account.getProductId()).orElse(null);
|
||||
if (product == null) return;
|
||||
|
||||
final Integer accountingRule = product.getAccountingType();
|
||||
if (accountingRule == null || accountingRule.equals(AccountingRuleType.NONE.getValue())) {
|
||||
log.debug("[GL] Product {} accounting=NONE — skipping", account.getProductId());
|
||||
return;
|
||||
}
|
||||
|
||||
final GLAccount cashAccount = findGlAccount(account.getProductId(), CashAccountsForSavings.SAVINGS_REFERENCE.getValue());
|
||||
final GLAccount controlAccount = findGlAccount(account.getProductId(), CashAccountsForSavings.SAVINGS_CONTROL.getValue());
|
||||
final GLAccount feeIncomeAccount = findGlAccount(account.getProductId(), CashAccountsForSavings.INCOME_FROM_FEES.getValue());
|
||||
|
||||
if (cashAccount == null || controlAccount == null) {
|
||||
log.warn("[GL] Missing GL account mappings for product id={} — skipping GL posting", account.getProductId());
|
||||
return;
|
||||
}
|
||||
|
||||
final String transactionRef = "CA" + account.getId();
|
||||
|
||||
// Deposits: DR SAVINGS_REFERENCE (cash in), CR SAVINGS_CONTROL (liability)
|
||||
if (depositTxns != null) {
|
||||
for (final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction txn : depositTxns) {
|
||||
if (txn.getId() == null || txn.getAmount() == null) continue;
|
||||
postEntry(account, cashAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
postEntry(account, controlAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
log.info("[GL] Deposit GL posted for account id={}, amount={}", account.getId(), txn.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
// Charges: DR SAVINGS_CONTROL (liability reduced), CR INCOME_FROM_FEES
|
||||
if (chargeEntries != null && feeIncomeAccount != null) {
|
||||
for (final ChargeGlEntry entry : chargeEntries) {
|
||||
final org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountTransaction txn = entry.txn();
|
||||
if (txn.getId() == null || txn.getAmount() == null) continue;
|
||||
postEntry(account, controlAccount, JournalEntryType.DEBIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
postEntry(account, feeIncomeAccount, JournalEntryType.CREDIT, txn.getAmount(), txn.getTransactionDate(), transactionRef);
|
||||
log.info("[GL] Charge GL posted for account id={}, charge={}, amount={}", account.getId(), entry.charge().getCharge().getName(), txn.getAmount());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[GL] Failed GL posting for current account id={}: {}", account.getId(), e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private GLAccount findGlAccount(final Long productId, final int financialAccountType) {
|
||||
final org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping mapping =
|
||||
productToGLAccountMappingRepository.findByProductIdAndProductTypeAndFinancialAccountTypeAndPaymentTypeId(
|
||||
productId, PortfolioProductType.SAVING.getValue(), financialAccountType, null);
|
||||
return mapping != null ? mapping.getGlAccount() : null;
|
||||
}
|
||||
|
||||
private void postEntry(final CurrentAccount account, final GLAccount glAccount,
|
||||
final JournalEntryType entryType, final java.math.BigDecimal amount,
|
||||
final LocalDate date, final String transactionRef) {
|
||||
final JournalEntry entry = JournalEntry.createNew(
|
||||
account.getOffice(), null, glAccount,
|
||||
account.getCurrencyCode(), transactionRef,
|
||||
false, date, entryType, amount,
|
||||
"Current Account activation",
|
||||
ENTITY_TYPE_SAVINGS, account.getId(),
|
||||
null, null, null, null, null);
|
||||
journalEntryRepository.save(entry);
|
||||
}
|
||||
|
||||
private void applyMapped(final CurrentAccount account, final boolean enabled, final String facilityType) {
|
||||
if (!enabled) {
|
||||
log.debug("[FacilityCharge] {} disabled — skip", facilityType);
|
||||
return;
|
||||
}
|
||||
final var mappingOpt = facilityChargeMappingRepository.findByFacilityType(facilityType);
|
||||
if (mappingOpt.isEmpty()) {
|
||||
log.warn("[FacilityCharge] {} enabled but NO mapping found in m_facility_charge_mapping", facilityType);
|
||||
return;
|
||||
}
|
||||
final org.apache.fineract.portfolio.charge.domain.Charge charge = mappingOpt.get().getCharge();
|
||||
if (charge == null) {
|
||||
log.warn("[FacilityCharge] {} mapping exists but charge_id is NULL", facilityType);
|
||||
return;
|
||||
}
|
||||
log.info("[FacilityCharge] Applying charge '{}' (id={}) for facility {}", charge.getName(), charge.getId(), facilityType);
|
||||
account.getCharges().add(
|
||||
org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountCharge
|
||||
.createFromFacility(account, charge));
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -96,6 +96,7 @@ import org.apache.fineract.portfolio.note.domain.Note;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.FacilityChargeAutoApplyService;
|
||||
import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||
@@ -165,6 +166,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final GSIMRepositoy gsimRepository;
|
||||
private final SavingsAccountInterestPostingService savingsAccountInterestPostingService;
|
||||
private final ErrorHandler errorHandler;
|
||||
private final FacilityChargeAutoApplyService facilityChargeAutoApplyService;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -199,6 +201,24 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
||||
|
||||
// Validate minimum opening balance
|
||||
BigDecimal openingBalanceForValidation = BigDecimal.ZERO;
|
||||
if (command.parameterExists("openingBalance")) {
|
||||
final BigDecimal ob = command.bigDecimalValueOfParameterNamed("openingBalance");
|
||||
if (ob != null) openingBalanceForValidation = ob;
|
||||
}
|
||||
final BigDecimal minRequiredOpening = account.getMinRequiredOpeningBalance();
|
||||
if (minRequiredOpening != null && minRequiredOpening.compareTo(BigDecimal.ZERO) > 0
|
||||
&& openingBalanceForValidation.compareTo(minRequiredOpening) < 0) {
|
||||
final List<ApiParameterError> errors = new ArrayList<>();
|
||||
errors.add(ApiParameterError.parameterError(
|
||||
"openingBalance",
|
||||
"Opening balance (" + openingBalanceForValidation + ") is less than minimum required opening balance (" + minRequiredOpening + ")",
|
||||
"validation.msg.savingsaccount.openingBalance.less.than.min.required",
|
||||
openingBalanceForValidation, minRequiredOpening));
|
||||
throw new PlatformApiDataValidationException(errors);
|
||||
}
|
||||
|
||||
checkClientOrGroupActive(account);
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
@@ -214,6 +234,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||
processPostActiveActions(account, fmt, existingTransactionIds, existingReversedTransactionIds);
|
||||
// Auto-apply facility charges based on product facility config
|
||||
facilityChargeAutoApplyService.applyFacilityChargesOnActivation(account);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
// Collect any newly added facility activation charges (after flush so amountOutstanding is set)
|
||||
// payCharge() internally adds transactions to account.transactions via handleChargeTransactions
|
||||
// Do NOT add to existingTransactionIds — postJournalEntries must include them for GL posting
|
||||
facilityChargeAutoApplyService.collectActivationCharges(account);
|
||||
this.savingAccountRepositoryWrapper.saveAndFlush(account);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -98,6 +98,7 @@ import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
|
||||
import org.apache.fineract.portfolio.savings.service.FacilityChargeAutoApplyService;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformService;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformServiceImpl;
|
||||
import org.apache.fineract.portfolio.savings.service.DepositAccountOnHoldTransactionReadPlatformService;
|
||||
@@ -423,7 +424,7 @@ public class SavingsConfiguration {
|
||||
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, AppUserRepositoryWrapper appuserRepository,
|
||||
StandingInstructionRepository standingInstructionRepository, BusinessEventNotifierService businessEventNotifierService,
|
||||
GSIMRepositoy gsimRepository, SavingsAccountInterestPostingService savingsAccountInterestPostingService,
|
||||
ErrorHandler errorHandler) {
|
||||
ErrorHandler errorHandler, FacilityChargeAutoApplyService facilityChargeAutoApplyService) {
|
||||
return new SavingsAccountWritePlatformServiceJpaRepositoryImpl(context, fromApiJsonDeserializer, savingAccountRepositoryWrapper,
|
||||
staffRepository, savingsAccountTransactionRepository, savingAccountAssembler, savingsAccountTransactionDataValidator,
|
||||
savingsAccountChargeDataValidator, paymentDetailWritePlatformService, journalEntryWritePlatformService,
|
||||
@@ -431,7 +432,7 @@ public class SavingsConfiguration {
|
||||
chargeRepository, savingsAccountChargeRepository, holidayRepository, workingDaysRepository, configurationDomainService,
|
||||
depositAccountOnHoldTransactionRepository, entityDatatableChecksWritePlatformService, appuserRepository,
|
||||
standingInstructionRepository, businessEventNotifierService, gsimRepository, savingsAccountInterestPostingService,
|
||||
errorHandler);
|
||||
errorHandler, facilityChargeAutoApplyService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public class SavingsAccountConstant extends SavingsApiConstants {
|
||||
Arrays.asList(idParamName, accountNoParamName));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(localeParamName, dateFormatParamName, activatedOnDateParamName));
|
||||
Arrays.asList(localeParamName, dateFormatParamName, activatedOnDateParamName, "openingBalance"));
|
||||
|
||||
protected static final Set<String> SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(localeParamName, dateFormatParamName, closedOnDateParamName, noteParamName, paymentTypeIdParamName,
|
||||
|
||||
+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.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_facility_charge_mapping")
|
||||
@Getter
|
||||
@Setter
|
||||
public class FacilityChargeMapping {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "facility_type", nullable = false, unique = true, length = 60)
|
||||
private String facilityType;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "charge_id")
|
||||
private Charge charge;
|
||||
|
||||
@Column(name = "charge_name", nullable = false, length = 200)
|
||||
private String chargeName;
|
||||
|
||||
@Column(name = "default_amount", nullable = false, precision = 19, scale = 6)
|
||||
private BigDecimal defaultAmount;
|
||||
|
||||
@Column(name = "charge_time_type", nullable = false)
|
||||
private Integer chargeTimeType;
|
||||
|
||||
@Column(name = "charge_applies_to", nullable = false)
|
||||
private Integer chargeAppliesTo;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private Boolean isActive = true;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface FacilityChargeMappingRepository extends JpaRepository<FacilityChargeMapping, Long> {
|
||||
|
||||
Optional<FacilityChargeMapping> findByFacilityType(String facilityType);
|
||||
|
||||
List<FacilityChargeMapping> findAllByIsActiveTrue();
|
||||
}
|
||||
+5
@@ -3487,6 +3487,11 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
|
||||
public void recalculateBalancesAfterFacilityCharges(final LocalDate transactionDate) {
|
||||
recalculateDailyBalances(Money.zero(this.currency), transactionDate, false, false);
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
}
|
||||
|
||||
public void setSubStatusDormant() {
|
||||
this.sub_status = SavingsAccountSubStatusEnum.DORMANT.getValue();
|
||||
}
|
||||
|
||||
-1
@@ -377,7 +377,6 @@ public class SavingsProductAssembler {
|
||||
facilityConfigJson.get("depositFacilityKyc").getAsBoolean() : false);
|
||||
config.setVirtualDebitCard(facilityConfigJson.has("virtualDebitCard") ?
|
||||
facilityConfigJson.get("virtualDebitCard").getAsBoolean() : false);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
+36
-124
@@ -95,146 +95,58 @@ public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
public SavingsProduct getSavingsProduct() {
|
||||
return savingsProduct;
|
||||
}
|
||||
public SavingsProduct getSavingsProduct() { return savingsProduct; }
|
||||
public void setSavingsProduct(SavingsProduct savingsProduct) { this.savingsProduct = savingsProduct; }
|
||||
|
||||
public void setSavingsProduct(SavingsProduct savingsProduct) {
|
||||
this.savingsProduct = savingsProduct;
|
||||
}
|
||||
public Boolean getAtmFacility() { return atmFacility; }
|
||||
public void setAtmFacility(Boolean v) { this.atmFacility = v != null ? v : false; }
|
||||
|
||||
public Boolean getAtmFacility() {
|
||||
return atmFacility;
|
||||
}
|
||||
public Boolean getAtmWithdrawalFacility() { return atmWithdrawalFacility; }
|
||||
public void setAtmWithdrawalFacility(Boolean v) { this.atmWithdrawalFacility = v != null ? v : false; }
|
||||
|
||||
public void setAtmFacility(Boolean atmFacility) {
|
||||
this.atmFacility = atmFacility != null ? atmFacility : false;
|
||||
}
|
||||
public Boolean getUpiFacility() { return upiFacility; }
|
||||
public void setUpiFacility(Boolean v) { this.upiFacility = v != null ? v : false; }
|
||||
|
||||
public Boolean getAtmWithdrawalFacility() {
|
||||
return atmWithdrawalFacility;
|
||||
}
|
||||
public Boolean getPosTransactionsFacility() { return posTransactionsFacility; }
|
||||
public void setPosTransactionsFacility(Boolean v) { this.posTransactionsFacility = v != null ? v : false; }
|
||||
|
||||
public void setAtmWithdrawalFacility(Boolean atmWithdrawalFacility) {
|
||||
this.atmWithdrawalFacility = atmWithdrawalFacility != null ? atmWithdrawalFacility : false;
|
||||
}
|
||||
public Boolean getChequeBook() { return chequeBook; }
|
||||
public void setChequeBook(Boolean v) { this.chequeBook = v != null ? v : false; }
|
||||
|
||||
public Boolean getUpiFacility() {
|
||||
return upiFacility;
|
||||
}
|
||||
public Boolean getImpsFacility() { return impsFacility; }
|
||||
public void setImpsFacility(Boolean v) { this.impsFacility = v != null ? v : false; }
|
||||
|
||||
public void setUpiFacility(Boolean upiFacility) {
|
||||
this.upiFacility = upiFacility != null ? upiFacility : false;
|
||||
}
|
||||
public Boolean getSmsAlerts() { return smsAlerts; }
|
||||
public void setSmsAlerts(Boolean v) { this.smsAlerts = v != null ? v : false; }
|
||||
|
||||
public Boolean getPosTransactionsFacility() {
|
||||
return posTransactionsFacility;
|
||||
}
|
||||
public Boolean getBbpsFacility() { return bbpsFacility; }
|
||||
public void setBbpsFacility(Boolean v) { this.bbpsFacility = v != null ? v : false; }
|
||||
|
||||
public void setPosTransactionsFacility(Boolean posTransactionsFacility) {
|
||||
this.posTransactionsFacility = posTransactionsFacility != null ? posTransactionsFacility : false;
|
||||
}
|
||||
public Boolean getInsuranceCover() { return insuranceCover; }
|
||||
public void setInsuranceCover(Boolean v) { this.insuranceCover = v != null ? v : false; }
|
||||
|
||||
public Boolean getChequeBook() {
|
||||
return chequeBook;
|
||||
}
|
||||
public Boolean getBepgFacility() { return bepgFacility; }
|
||||
public void setBepgFacility(Boolean v) { this.bepgFacility = v != null ? v : false; }
|
||||
|
||||
public void setChequeBook(Boolean chequeBook) {
|
||||
this.chequeBook = chequeBook != null ? chequeBook : false;
|
||||
}
|
||||
public Boolean getNeftFacility() { return neftFacility; }
|
||||
public void setNeftFacility(Boolean v) { this.neftFacility = v != null ? v : false; }
|
||||
|
||||
public Boolean getImpsFacility() {
|
||||
return impsFacility;
|
||||
}
|
||||
public Boolean getRtgsFacility() { return rtgsFacility; }
|
||||
public void setRtgsFacility(Boolean v) { this.rtgsFacility = v != null ? v : false; }
|
||||
|
||||
public void setImpsFacility(Boolean impsFacility) {
|
||||
this.impsFacility = impsFacility != null ? impsFacility : false;
|
||||
}
|
||||
public Boolean getInterBankTotalCapFacility() { return interBankTotalCapFacility; }
|
||||
public void setInterBankTotalCapFacility(Boolean v) { this.interBankTotalCapFacility = v != null ? v : false; }
|
||||
|
||||
public Boolean getSmsAlerts() {
|
||||
return smsAlerts;
|
||||
}
|
||||
public Boolean getWithdrawalFacility() { return withdrawalFacility; }
|
||||
public void setWithdrawalFacility(Boolean v) { this.withdrawalFacility = v != null ? v : false; }
|
||||
|
||||
public void setSmsAlerts(Boolean smsAlerts) {
|
||||
this.smsAlerts = smsAlerts != null ? smsAlerts : false;
|
||||
}
|
||||
public Boolean getDepositFacilityKyc() { return depositFacilityKyc; }
|
||||
public void setDepositFacilityKyc(Boolean v) { this.depositFacilityKyc = v != null ? v : false; }
|
||||
|
||||
public Boolean getBbpsFacility() {
|
||||
return bbpsFacility;
|
||||
}
|
||||
public Boolean getVirtualDebitCard() { return virtualDebitCard; }
|
||||
public void setVirtualDebitCard(Boolean v) { this.virtualDebitCard = v != null ? v : false; }
|
||||
|
||||
public void setBbpsFacility(Boolean bbpsFacility) {
|
||||
this.bbpsFacility = bbpsFacility != null ? bbpsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getInsuranceCover() {
|
||||
return insuranceCover;
|
||||
}
|
||||
|
||||
public void setInsuranceCover(Boolean insuranceCover) {
|
||||
this.insuranceCover = insuranceCover != null ? insuranceCover : false;
|
||||
}
|
||||
|
||||
public Boolean getBepgFacility() {
|
||||
return bepgFacility;
|
||||
}
|
||||
|
||||
public void setBepgFacility(Boolean bepgFacility) {
|
||||
this.bepgFacility = bepgFacility != null ? bepgFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getNeftFacility() {
|
||||
return neftFacility;
|
||||
}
|
||||
|
||||
public void setNeftFacility(Boolean neftFacility) {
|
||||
this.neftFacility = neftFacility != null ? neftFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getRtgsFacility() {
|
||||
return rtgsFacility;
|
||||
}
|
||||
|
||||
public void setRtgsFacility(Boolean rtgsFacility) {
|
||||
this.rtgsFacility = rtgsFacility != null ? rtgsFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getInterBankTotalCapFacility() {
|
||||
return interBankTotalCapFacility;
|
||||
}
|
||||
|
||||
public void setInterBankTotalCapFacility(Boolean interBankTotalCapFacility) {
|
||||
this.interBankTotalCapFacility = interBankTotalCapFacility != null ? interBankTotalCapFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getWithdrawalFacility() {
|
||||
return withdrawalFacility;
|
||||
}
|
||||
|
||||
public void setWithdrawalFacility(Boolean withdrawalFacility) {
|
||||
this.withdrawalFacility = withdrawalFacility != null ? withdrawalFacility : false;
|
||||
}
|
||||
|
||||
public Boolean getDepositFacilityKyc() {
|
||||
return depositFacilityKyc;
|
||||
}
|
||||
|
||||
public void setDepositFacilityKyc(Boolean depositFacilityKyc) {
|
||||
this.depositFacilityKyc = depositFacilityKyc != null ? depositFacilityKyc : false;
|
||||
}
|
||||
|
||||
public Boolean getVirtualDebitCard() {
|
||||
return virtualDebitCard;
|
||||
}
|
||||
|
||||
public void setVirtualDebitCard(Boolean virtualDebitCard) {
|
||||
this.virtualDebitCard = virtualDebitCard != null ? virtualDebitCard : false;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
public LocalDateTime getCreatedDate() { return createdDate; }
|
||||
|
||||
public void updateFrom(SavingsProductFacilityConfig other) {
|
||||
this.atmFacility = other.getAtmFacility();
|
||||
@@ -254,4 +166,4 @@ public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long
|
||||
this.depositFacilityKyc = other.getDepositFacilityKyc();
|
||||
this.virtualDebitCard = other.getVirtualDebitCard();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.MonthDay;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.savings.domain.FacilityChargeMapping;
|
||||
import org.apache.fineract.portfolio.savings.domain.FacilityChargeMappingRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountFacilityConfig;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Reads account's facility config (Yes/No per facility) and auto-applies
|
||||
* the corresponding charge from m_facility_charge_mapping.
|
||||
* No manual charge selection needed — fully automatic.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FacilityChargeAutoApplyService {
|
||||
|
||||
private final FacilityChargeMappingRepository mappingRepository;
|
||||
private final SavingsAccountChargeRepository savingsAccountChargeRepository;
|
||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
||||
|
||||
public void applyFacilityChargesOnActivation(final SavingsAccount account) {
|
||||
// Use account-level facility config — this reflects what was selected at account opening time
|
||||
final SavingsAccountFacilityConfig config = account.getFacilityConfig();
|
||||
|
||||
if (config == null) {
|
||||
// Fallback: use product-level config if account config not set
|
||||
applyFromProductConfig(account);
|
||||
return;
|
||||
}
|
||||
|
||||
final List<SavingsAccountCharge> chargesToApply = new ArrayList<>();
|
||||
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getAtmFacility()), "ATM_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getAtmWithdrawalFacility()), "ATM_WITHDRAWAL", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getUpiFacility()), "UPI_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getPosTransactionsFacility()), "POS_TRANSACTIONS", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getChequeBook()), "CHEQUE_BOOK", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getImpsFacility()), "IMPS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getSmsAlerts()), "SMS_ALERTS", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getBbpsFacility()), "BBPS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getInsuranceCover()), "INSURANCE_COVER", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getBepgFacility()), "BEPG_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getNeftFacility()), "NEFT_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getRtgsFacility()), "RTGS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getInterBankTotalCapFacility()),"INTER_BANK_TOTAL_CAP",chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getWithdrawalFacility()), "WITHDRAWAL_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getDepositFacilityKyc()), "DEPOSIT_FACILITY_KYC",chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getVirtualDebitCard()), "VIRTUAL_DEBIT_CARD", chargesToApply);
|
||||
|
||||
if (!chargesToApply.isEmpty()) {
|
||||
savingsAccountChargeRepository.saveAll(chargesToApply);
|
||||
log.info("Auto-applied {} facility charge(s) to savings account id={}",
|
||||
chargesToApply.size(), account.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all unpaid SavingsActivation charges on the account.
|
||||
* Called after facility charges are saved and flushed, so amounts are properly initialized.
|
||||
*/
|
||||
public List<SavingsAccountTransaction> collectActivationCharges(final SavingsAccount account) {
|
||||
final List<SavingsAccountTransaction> transactions = new ArrayList<>();
|
||||
final LocalDate activationDate = account.getActivationDate();
|
||||
|
||||
for (final SavingsAccountCharge charge : account.charges()) {
|
||||
if (!charge.isSavingsActivation()) continue;
|
||||
if (charge.isPaid() || charge.isWaived()) continue;
|
||||
|
||||
final BigDecimal amount = charge.getAmount(account.getCurrency()).getAmount();
|
||||
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) continue;
|
||||
|
||||
try {
|
||||
final org.apache.fineract.organisation.monetary.domain.Money amountMoney =
|
||||
org.apache.fineract.organisation.monetary.domain.Money.of(account.getCurrency(), amount);
|
||||
final SavingsAccountTransaction txn = account.payCharge(charge, amountMoney, activationDate, false, null);
|
||||
if (txn != null) {
|
||||
transactions.add(txn);
|
||||
log.info("Collected activation charge '{}' ₹{} from savings account id={}",
|
||||
charge.getCharge().getName(), amount, account.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not collect activation charge '{}' from savings account id={}: {}",
|
||||
charge.getCharge() != null ? charge.getCharge().getName() : "?", account.getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (!transactions.isEmpty()) {
|
||||
savingsAccountTransactionRepository.saveAll(transactions);
|
||||
account.recalculateBalancesAfterFacilityCharges(activationDate);
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
||||
private void autoCollectSavingsActivationCharges(final SavingsAccount account,
|
||||
final List<SavingsAccountCharge> charges) {
|
||||
final LocalDate activationDate = account.getActivationDate();
|
||||
final List<SavingsAccountTransaction> transactions = new ArrayList<>();
|
||||
|
||||
for (final SavingsAccountCharge charge : charges) {
|
||||
if (!charge.isSavingsActivation()) continue;
|
||||
final BigDecimal amount = charge.getAmountOutstanding(account.getCurrency()).getAmount();
|
||||
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) continue;
|
||||
|
||||
try {
|
||||
final Money amountMoney = Money.of(account.getCurrency(), amount);
|
||||
final SavingsAccountTransaction txn = account.payCharge(charge, amountMoney, activationDate, false, null);
|
||||
if (txn != null) transactions.add(txn);
|
||||
log.info("Auto-collected facility charge '{}' ₹{} from account id={}",
|
||||
charge.getCharge().getName(), amount, account.getId());
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not auto-collect facility charge '{}' from account id={}: {}",
|
||||
charge.getCharge().getName(), account.getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (!transactions.isEmpty()) {
|
||||
savingsAccountTransactionRepository.saveAll(transactions);
|
||||
account.recalculateBalancesAfterFacilityCharges(activationDate);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyIfEnabled(final SavingsAccount account, final boolean facilityEnabled,
|
||||
final String facilityType, final List<SavingsAccountCharge> collector) {
|
||||
|
||||
if (!facilityEnabled) return;
|
||||
|
||||
// Skip if this charge is already applied to the account
|
||||
boolean alreadyApplied = account.charges().stream()
|
||||
.anyMatch(c -> c.getCharge() != null
|
||||
&& c.getCharge().getName() != null
|
||||
&& c.getCharge().getName().equals(getChargeName(facilityType)));
|
||||
if (alreadyApplied) return;
|
||||
|
||||
mappingRepository.findByFacilityType(facilityType).ifPresent(mapping -> {
|
||||
final Charge charge = mapping.getCharge();
|
||||
if (charge == null) return;
|
||||
|
||||
final MonthDay feeOnMonthDay = resolveFeeOnMonthDay(charge);
|
||||
final SavingsAccountCharge accountCharge = SavingsAccountCharge.createNewWithoutSavingsAccount(
|
||||
charge,
|
||||
charge.getAmount(),
|
||||
null, // chargeTime derived from Charge definition
|
||||
null, // chargeCalculation derived from Charge definition
|
||||
resolveDueDate(charge),
|
||||
true,
|
||||
feeOnMonthDay,
|
||||
charge.getFeeInterval());
|
||||
|
||||
accountCharge.update(account);
|
||||
account.charges().add(accountCharge);
|
||||
collector.add(accountCharge);
|
||||
});
|
||||
}
|
||||
|
||||
private MonthDay resolveFeeOnMonthDay(final Charge charge) {
|
||||
if (charge.getFeeOnMonthDay() != null) return charge.getFeeOnMonthDay();
|
||||
if (charge.isMonthlyFee() || charge.isAnnualFee()) {
|
||||
// Default: 1st of the month
|
||||
return MonthDay.of(LocalDate.now().plusMonths(1).getMonth(), 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LocalDate resolveDueDate(final Charge charge) {
|
||||
if (charge.isMonthlyFee()) {
|
||||
return LocalDate.now().plusMonths(1).withDayOfMonth(1);
|
||||
} else if (charge.isAnnualFee()) {
|
||||
return LocalDate.now().plusYears(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getChargeName(final String facilityType) {
|
||||
return mappingRepository.findByFacilityType(facilityType)
|
||||
.map(FacilityChargeMapping::getChargeName)
|
||||
.orElse("");
|
||||
}
|
||||
|
||||
private void applyFromProductConfig(final SavingsAccount account) {
|
||||
final SavingsProductFacilityConfig config = account.savingsProduct() != null
|
||||
? account.savingsProduct().getFacilityConfig() : null;
|
||||
if (config == null) return;
|
||||
|
||||
final List<SavingsAccountCharge> chargesToApply = new ArrayList<>();
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getAtmFacility()), "ATM_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getAtmWithdrawalFacility()), "ATM_WITHDRAWAL", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getUpiFacility()), "UPI_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getPosTransactionsFacility()), "POS_TRANSACTIONS", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getChequeBook()), "CHEQUE_BOOK", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getImpsFacility()), "IMPS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getSmsAlerts()), "SMS_ALERTS", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getBbpsFacility()), "BBPS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getInsuranceCover()), "INSURANCE_COVER", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getBepgFacility()), "BEPG_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getNeftFacility()), "NEFT_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getRtgsFacility()), "RTGS_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getInterBankTotalCapFacility()),"INTER_BANK_TOTAL_CAP",chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getWithdrawalFacility()), "WITHDRAWAL_FACILITY", chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getDepositFacilityKyc()), "DEPOSIT_FACILITY_KYC",chargesToApply);
|
||||
applyIfEnabled(account, Boolean.TRUE.equals(config.getVirtualDebitCard()), "VIRTUAL_DEBIT_CARD", chargesToApply);
|
||||
if (!chargesToApply.isEmpty()) {
|
||||
savingsAccountChargeRepository.saveAll(chargesToApply);
|
||||
}
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Seeds default facility charges on service startup via JDBC.
|
||||
* For each facility type (ATM, UPI, NEFT etc.), ensures a charge exists in m_charge
|
||||
* and a mapping exists in m_facility_charge_mapping.
|
||||
* Bank staff can change amounts from the Charges admin screen later.
|
||||
* Seeder only creates records that are missing — safe to run repeatedly.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FacilityChargeSeederService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
// facilityType → [chargeName, defaultAmount, chargeTimeType, chargeAppliesTo]
|
||||
// chargeTimeType: 3=SAVINGS_ACTIVATION, 6=ANNUAL_FEE, 7=MONTHLY_FEE
|
||||
// chargeAppliesTo: 2=SAVINGS, 5=CURRENT_ACCOUNT
|
||||
// chargeCalculation: 1=FLAT
|
||||
private static final Map<String, Object[]> FACILITY_DEFAULTS = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
FACILITY_DEFAULTS.put("ATM_FACILITY", new Object[]{"ATM Facility Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("ATM_WITHDRAWAL", new Object[]{"ATM Withdrawal Charge", 20.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("UPI_FACILITY", new Object[]{"UPI Facility Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("POS_TRANSACTIONS", new Object[]{"POS Transaction Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("CHEQUE_BOOK", new Object[]{"Cheque Book Charge", 300.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("IMPS_FACILITY", new Object[]{"IMPS Facility Charge", 5.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("SMS_ALERTS", new Object[]{"SMS Alert Monthly Charge", 15.00, 7, 2});
|
||||
FACILITY_DEFAULTS.put("BBPS_FACILITY", new Object[]{"BBPS Facility Charge", 2.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("INSURANCE_COVER", new Object[]{"Insurance Cover Charge", 500.00, 6, 2});
|
||||
FACILITY_DEFAULTS.put("BEPG_FACILITY", new Object[]{"BEPG Facility Charge", 5.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("NEFT_FACILITY", new Object[]{"NEFT Facility Charge", 5.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("RTGS_FACILITY", new Object[]{"RTGS Facility Charge", 25.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("INTER_BANK_TOTAL_CAP", new Object[]{"Inter-Bank Cap Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("WITHDRAWAL_FACILITY", new Object[]{"Withdrawal Facility Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("DEPOSIT_FACILITY_KYC", new Object[]{"Deposit KYC Charge", 0.00, 3, 2});
|
||||
FACILITY_DEFAULTS.put("VIRTUAL_DEBIT_CARD", new Object[]{"Virtual Debit Card Charge", 199.00, 3, 2});
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@Transactional
|
||||
public void seedFacilityCharges() {
|
||||
try {
|
||||
// Find an income GL account to link charges (prefer DETAIL type income account)
|
||||
Long incomeGlAccountId = findIncomeGlAccountId();
|
||||
|
||||
for (Map.Entry<String, Object[]> entry : FACILITY_DEFAULTS.entrySet()) {
|
||||
final String facilityType = entry.getKey();
|
||||
final Object[] def = entry.getValue();
|
||||
final String chargeName = (String) def[0];
|
||||
final double amount = (double) def[1];
|
||||
final int chargeTimeType = (int) def[2];
|
||||
final int chargeAppliesTo = (int) def[3];
|
||||
|
||||
// 1. Check if mapping row exists and already has a charge linked
|
||||
List<Long> existingChargeId = jdbcTemplate.queryForList(
|
||||
"SELECT charge_id FROM m_facility_charge_mapping WHERE facility_type = ? AND charge_id IS NOT NULL",
|
||||
Long.class, facilityType);
|
||||
|
||||
if (!existingChargeId.isEmpty()) {
|
||||
continue; // Already seeded
|
||||
}
|
||||
|
||||
// 2. Check if charge with this name already exists in m_charge
|
||||
List<Long> chargeIds = jdbcTemplate.queryForList(
|
||||
"SELECT id FROM m_charge WHERE name = ? AND is_deleted = false LIMIT 1",
|
||||
Long.class, chargeName);
|
||||
|
||||
Long chargeId;
|
||||
if (chargeIds.isEmpty()) {
|
||||
// 3. Insert charge into m_charge
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, "
|
||||
+ "charge_time_enum, charge_calculation_enum, is_penalty, is_active, is_deleted, "
|
||||
+ "is_free_withdrawal, is_payment_type, income_or_liability_account_id) "
|
||||
+ "VALUES (?, 'INR', ?, ?, ?, true, false, true, false, false, false, ?)",
|
||||
chargeName, amount, chargeAppliesTo, chargeTimeType, incomeGlAccountId);
|
||||
|
||||
chargeId = jdbcTemplate.queryForObject(
|
||||
"SELECT id FROM m_charge WHERE name = ? AND is_deleted = false ORDER BY id DESC LIMIT 1",
|
||||
Long.class, chargeName);
|
||||
|
||||
log.info("FacilityChargeSeeder: inserted charge '{}' id={}", chargeName, chargeId);
|
||||
} else {
|
||||
chargeId = chargeIds.get(0);
|
||||
}
|
||||
|
||||
// 4. Update or insert mapping row
|
||||
int updated = jdbcTemplate.update(
|
||||
"UPDATE m_facility_charge_mapping SET charge_id = ? WHERE facility_type = ?",
|
||||
chargeId, facilityType);
|
||||
|
||||
if (updated == 0) {
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO m_facility_charge_mapping "
|
||||
+ "(facility_type, charge_id, charge_name, default_amount, charge_time_type, charge_applies_to, is_active) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, 1)",
|
||||
facilityType, chargeId, chargeName, amount, chargeTimeType, chargeAppliesTo);
|
||||
}
|
||||
|
||||
log.info("FacilityChargeSeeder: mapped facility '{}' → charge id={}", facilityType, chargeId);
|
||||
}
|
||||
|
||||
log.info("FacilityChargeSeeder: seeding complete.");
|
||||
} catch (Exception e) {
|
||||
log.warn("FacilityChargeSeeder: skipped — {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Long findIncomeGlAccountId() {
|
||||
try {
|
||||
// Prefer "INCOME FROM ALL" GL account for facility charges
|
||||
List<Long> ids = jdbcTemplate.queryForList(
|
||||
"SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 "
|
||||
+ "AND disabled = false AND name = 'INCOME FROM ALL' LIMIT 1",
|
||||
Long.class);
|
||||
if (!ids.isEmpty()) return ids.get(0);
|
||||
|
||||
// Fallback: first available income detail account
|
||||
ids = jdbcTemplate.queryForList(
|
||||
"SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 "
|
||||
+ "AND disabled = false ORDER BY id ASC LIMIT 1",
|
||||
Long.class);
|
||||
return ids.isEmpty() ? null : ids.get(0);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
<?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 id="2012-current-account-permissions" author="lincpay">
|
||||
<comment>Seed all current account permissions and assign to super-admin role</comment>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) VALUES
|
||||
('currentaccount', 'READ_CURRENTACCOUNT', 'CURRENTACCOUNT', 'READ', false),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CREATE', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UPDATE', false),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'DELETE', false),
|
||||
('currentaccount', 'APPROVE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPROVE', true),
|
||||
('currentaccount', 'APPROVALUNDO_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPROVALUNDO', true),
|
||||
('currentaccount', 'REJECT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'REJECT', true),
|
||||
('currentaccount', 'WITHDRAW_CURRENTACCOUNT', 'CURRENTACCOUNT', 'WITHDRAW', true),
|
||||
('currentaccount', 'ACTIVATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'ACTIVATE', true),
|
||||
('currentaccount', 'CLOSE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CLOSE', true),
|
||||
('currentaccount', 'DEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'DEPOSIT', true),
|
||||
('currentaccount', 'WITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'WITHDRAWAL', true),
|
||||
('currentaccount', 'POSTINTEREST_CURRENTACCOUNT', 'CURRENTACCOUNT', 'POSTINTEREST', true),
|
||||
('currentaccount', 'CALCULATEINTEREST_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CALCULATEINTEREST', false),
|
||||
('currentaccount', 'BLOCK_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCK', true),
|
||||
('currentaccount', 'UNBLOCK_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCK', true),
|
||||
('currentaccount', 'BLOCKDEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCKDEPOSIT', true),
|
||||
('currentaccount', 'UNBLOCKDEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCKDEPOSIT', true),
|
||||
('currentaccount', 'BLOCKWITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCKWITHDRAWAL', true),
|
||||
('currentaccount', 'UNBLOCKWITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCKWITHDRAWAL', true),
|
||||
('currentaccount', 'HOLDAMOUNT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'HOLDAMOUNT', true),
|
||||
('currentaccount', 'UPDATESAVINGSOFFICER_CURRENTACCOUNT','CURRENTACCOUNT', 'UPDATESAVINGSOFFICER',false),
|
||||
('currentaccount', 'REMOVESAVINGSOFFICER_CURRENTACCOUNT','CURRENTACCOUNT', 'REMOVESAVINGSOFFICER',false),
|
||||
('currentaccount', 'APPLYANNUALFEE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPLYANNUALFEE', true),
|
||||
('currentaccount', 'UPDATEWITHHOLDTAX_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UPDATEWITHHOLDTAX', true),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'CREATE', true),
|
||||
('currentaccount', 'READ_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'READ', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'UPDATE', true),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'DELETE', true),
|
||||
('currentaccount', 'PAY_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'PAY', true),
|
||||
('currentaccount', 'WAIVE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'WAIVE', true),
|
||||
('currentaccount', 'INACTIVATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'INACTIVATE', true),
|
||||
('currentaccount', 'READ_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'READ', false),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'CREATE', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'UPDATE', false),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'DELETE', false)
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
</sql>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_role_permission (role_id, permission_id)
|
||||
SELECT 1, id FROM m_permission
|
||||
WHERE grouping = 'currentaccount'
|
||||
ON CONFLICT DO NOTHING;
|
||||
</sql>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_role_permission (role_id, permission_id)
|
||||
SELECT DISTINCT rp.role_id, p2.id
|
||||
FROM m_role_permission rp
|
||||
JOIN m_permission p1 ON rp.permission_id = p1.id AND p1.code = 'READ_SAVINGSACCOUNT'
|
||||
JOIN m_permission p2 ON p2.grouping = 'currentaccount'
|
||||
WHERE rp.role_id != 1
|
||||
ON CONFLICT DO NOTHING;
|
||||
</sql>
|
||||
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+3
@@ -33,4 +33,7 @@
|
||||
<include file="parts/2008_add_other_gl_mappings_to_savings_product.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2009_add_gl_account_id_to_savings_product.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2010_add_savings_account_cbs_fields.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2011_add_facility_charge_mapping.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2012_add_current_account_permissions.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2013_add_missing_current_account_columns.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
<?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">
|
||||
|
||||
<!-- Step 1: Create facility charge mapping table -->
|
||||
<changeSet id="2011-1" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><tableExists tableName="m_facility_charge_mapping"/></not>
|
||||
</preConditions>
|
||||
<createTable tableName="m_facility_charge_mapping">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="facility_type" type="VARCHAR(60)">
|
||||
<constraints nullable="false" unique="true"/>
|
||||
</column>
|
||||
<column name="charge_id" type="BIGINT">
|
||||
<constraints nullable="true" foreignKeyName="fk_facility_charge" references="m_charge(id)"/>
|
||||
</column>
|
||||
<column name="charge_name" type="VARCHAR(200)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="default_amount" type="DECIMAL(19,6)" defaultValueNumeric="0.000000">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="charge_time_type" type="INT" defaultValueNumeric="3">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="charge_applies_to" type="INT" defaultValueNumeric="2">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="is_active" type="BOOLEAN" defaultValueBoolean="true">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<!-- Step 2: Insert facility charges into m_charge (only if not already present) -->
|
||||
<!-- Note: PostgreSQL uses false/true for boolean columns, not 0/1 -->
|
||||
<changeSet id="2011-2" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'ATM Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'ATM Facility Charge', 'INR', 100.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-3" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'ATM Withdrawal Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'ATM Withdrawal Charge', 'INR', 20.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-4" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'UPI Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'UPI Facility Charge', 'INR', 100.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-5" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'POS Transaction Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'POS Transaction Charge', 'INR', 100.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-6" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Cheque Book Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Cheque Book Charge', 'INR', 300.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-7" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'IMPS Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'IMPS Facility Charge', 'INR', 5.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-8" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'SMS Alert Monthly Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'SMS Alert Monthly Charge', 'INR', 15.00, 2, 7, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-9" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'BBPS Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'BBPS Facility Charge', 'INR', 2.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-10" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Insurance Cover Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Insurance Cover Charge', 'INR', 500.00, 2, 6, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-11" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'BEPG Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'BEPG Facility Charge', 'INR', 5.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-12" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'NEFT Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'NEFT Facility Charge', 'INR', 5.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-13" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'RTGS Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'RTGS Facility Charge', 'INR', 25.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-14" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Inter-Bank Cap Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Inter-Bank Cap Charge', 'INR', 0.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-15" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Withdrawal Facility Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Withdrawal Facility Charge', 'INR', 5.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-16" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Deposit KYC Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Deposit KYC Charge', 'INR', 0.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="2011-17" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_charge WHERE name = 'Virtual Debit Card Charge' AND is_deleted = false</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_charge (name, currency_code, amount, charge_applies_to_enum, charge_time_enum,
|
||||
charge_calculation_enum, is_penalty, is_active, is_deleted, is_free_withdrawal, is_payment_type,
|
||||
income_or_liability_account_id)
|
||||
SELECT 'Virtual Debit Card Charge', 'INR', 199.00, 2, 3, 1, false, true, false, false, false,
|
||||
(SELECT id FROM acc_gl_account WHERE classification_enum = 4 AND account_usage = 1 AND disabled = false ORDER BY id LIMIT 1);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<!-- Step 3: Insert mapping rows linking facility_type → charge_id -->
|
||||
<changeSet id="2011-18" author="cbs-nitesh">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_facility_charge_mapping WHERE facility_type = 'ATM_FACILITY'</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_facility_charge_mapping (facility_type, charge_name, default_amount, charge_time_type, charge_applies_to, charge_id, is_active)
|
||||
VALUES
|
||||
('ATM_FACILITY', 'ATM Facility Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'ATM Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('ATM_WITHDRAWAL', 'ATM Withdrawal Charge', 20.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'ATM Withdrawal Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('UPI_FACILITY', 'UPI Facility Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'UPI Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('POS_TRANSACTIONS', 'POS Transaction Charge', 100.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'POS Transaction Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('CHEQUE_BOOK', 'Cheque Book Charge', 300.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Cheque Book Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('IMPS_FACILITY', 'IMPS Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'IMPS Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('SMS_ALERTS', 'SMS Alert Monthly Charge', 15.00, 7, 2, (SELECT id FROM m_charge WHERE name = 'SMS Alert Monthly Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('BBPS_FACILITY', 'BBPS Facility Charge', 2.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'BBPS Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('INSURANCE_COVER', 'Insurance Cover Charge', 500.00, 6, 2, (SELECT id FROM m_charge WHERE name = 'Insurance Cover Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('BEPG_FACILITY', 'BEPG Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'BEPG Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('NEFT_FACILITY', 'NEFT Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'NEFT Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('RTGS_FACILITY', 'RTGS Facility Charge', 25.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'RTGS Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('INTER_BANK_TOTAL_CAP','Inter-Bank Cap Charge', 0.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Inter-Bank Cap Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('WITHDRAWAL_FACILITY', 'Withdrawal Facility Charge', 5.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Withdrawal Facility Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('DEPOSIT_FACILITY_KYC','Deposit KYC Charge', 0.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Deposit KYC Charge' AND is_deleted = false LIMIT 1), true),
|
||||
('VIRTUAL_DEBIT_CARD', 'Virtual Debit Card Charge', 199.00, 3, 2, (SELECT id FROM m_charge WHERE name = 'Virtual Debit Card Charge' AND is_deleted = false LIMIT 1), true);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
<?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 id="2012-current-account-permissions" author="lincpay">
|
||||
<comment>Seed all current account permissions and assign to super-admin role</comment>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker) VALUES
|
||||
('currentaccount', 'READ_CURRENTACCOUNT', 'CURRENTACCOUNT', 'READ', false),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CREATE', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UPDATE', false),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'DELETE', false),
|
||||
('currentaccount', 'APPROVE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPROVE', true),
|
||||
('currentaccount', 'APPROVALUNDO_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPROVALUNDO', true),
|
||||
('currentaccount', 'REJECT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'REJECT', true),
|
||||
('currentaccount', 'WITHDRAW_CURRENTACCOUNT', 'CURRENTACCOUNT', 'WITHDRAW', true),
|
||||
('currentaccount', 'ACTIVATE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'ACTIVATE', true),
|
||||
('currentaccount', 'CLOSE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CLOSE', true),
|
||||
('currentaccount', 'DEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'DEPOSIT', true),
|
||||
('currentaccount', 'WITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'WITHDRAWAL', true),
|
||||
('currentaccount', 'POSTINTEREST_CURRENTACCOUNT', 'CURRENTACCOUNT', 'POSTINTEREST', true),
|
||||
('currentaccount', 'CALCULATEINTEREST_CURRENTACCOUNT', 'CURRENTACCOUNT', 'CALCULATEINTEREST', false),
|
||||
('currentaccount', 'BLOCK_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCK', true),
|
||||
('currentaccount', 'UNBLOCK_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCK', true),
|
||||
('currentaccount', 'BLOCKDEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCKDEPOSIT', true),
|
||||
('currentaccount', 'UNBLOCKDEPOSIT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCKDEPOSIT', true),
|
||||
('currentaccount', 'BLOCKWITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'BLOCKWITHDRAWAL', true),
|
||||
('currentaccount', 'UNBLOCKWITHDRAWAL_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UNBLOCKWITHDRAWAL', true),
|
||||
('currentaccount', 'HOLDAMOUNT_CURRENTACCOUNT', 'CURRENTACCOUNT', 'HOLDAMOUNT', true),
|
||||
('currentaccount', 'UPDATESAVINGSOFFICER_CURRENTACCOUNT','CURRENTACCOUNT', 'UPDATESAVINGSOFFICER',false),
|
||||
('currentaccount', 'REMOVESAVINGSOFFICER_CURRENTACCOUNT','CURRENTACCOUNT', 'REMOVESAVINGSOFFICER',false),
|
||||
('currentaccount', 'APPLYANNUALFEE_CURRENTACCOUNT', 'CURRENTACCOUNT', 'APPLYANNUALFEE', true),
|
||||
('currentaccount', 'UPDATEWITHHOLDTAX_CURRENTACCOUNT', 'CURRENTACCOUNT', 'UPDATEWITHHOLDTAX', true),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'CREATE', true),
|
||||
('currentaccount', 'READ_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'READ', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'UPDATE', true),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'DELETE', true),
|
||||
('currentaccount', 'PAY_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'PAY', true),
|
||||
('currentaccount', 'WAIVE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'WAIVE', true),
|
||||
('currentaccount', 'INACTIVATE_CURRENTACCOUNTCHARGE', 'CURRENTACCOUNTCHARGE', 'INACTIVATE', true),
|
||||
('currentaccount', 'READ_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'READ', false),
|
||||
('currentaccount', 'CREATE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'CREATE', false),
|
||||
('currentaccount', 'UPDATE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'UPDATE', false),
|
||||
('currentaccount', 'DELETE_CURRENTACCOUNTNOTE', 'CURRENTACCOUNTNOTE', 'DELETE', false)
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
</sql>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_role_permission (role_id, permission_id)
|
||||
SELECT 1, id FROM m_permission
|
||||
WHERE grouping = 'currentaccount'
|
||||
ON CONFLICT DO NOTHING;
|
||||
</sql>
|
||||
|
||||
<sql>
|
||||
INSERT INTO m_role_permission (role_id, permission_id)
|
||||
SELECT DISTINCT rp.role_id, p2.id
|
||||
FROM m_role_permission rp
|
||||
JOIN m_permission p1 ON rp.permission_id = p1.id AND p1.code = 'READ_SAVINGSACCOUNT'
|
||||
JOIN m_permission p2 ON p2.grouping = 'currentaccount'
|
||||
WHERE rp.role_id != 1
|
||||
ON CONFLICT DO NOTHING;
|
||||
</sql>
|
||||
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?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 id="2013-add-missing-current-account-columns" author="fineract">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not>
|
||||
<columnExists tableName="m_current_account" columnName="account_closed_zero_balance_in_day_closing"/>
|
||||
</not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_current_account">
|
||||
<column name="account_closed_zero_balance_in_day_closing" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="valid_for_period" type="varchar(10)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="od_account_closed_zero_balance_in_day_closing" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user