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;
|
package org.apache.fineract.accounting.journalentry;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||||
@@ -45,7 +46,7 @@ public interface JournalEntryMapper {
|
|||||||
@Mapping(target = "amount", source = "amount")
|
@Mapping(target = "amount", source = "amount")
|
||||||
@Mapping(target = "entityType", source = "entityType", qualifiedByName = "entityType")
|
@Mapping(target = "entityType", source = "entityType", qualifiedByName = "entityType")
|
||||||
@Mapping(target = "entityId", source = "entityId")
|
@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 = "transactionId", source = "transactionId")
|
||||||
@Mapping(target = "currency", source = "currencyCode")
|
@Mapping(target = "currency", source = "currencyCode")
|
||||||
@Mapping(target = "manualEntry", source = "manualEntry")
|
@Mapping(target = "manualEntry", source = "manualEntry")
|
||||||
|
|||||||
+5
-4
@@ -20,6 +20,7 @@ package org.apache.fineract.accounting.journalentry.data;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||||
@@ -60,7 +61,7 @@ public class JournalEntryData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private Long createdByUserId;
|
private Long createdByUserId;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private LocalDate createdDate;
|
private OffsetDateTime createdDate;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private String createdByUserName;
|
private String createdByUserName;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@@ -79,7 +80,7 @@ public class JournalEntryData {
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private TransactionDetailData transactionDetails;
|
private TransactionDetailData transactionDetails;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private LocalDate submittedOnDate;
|
private OffsetDateTime submittedOnDate;
|
||||||
|
|
||||||
// import fields
|
// import fields
|
||||||
private transient Integer rowIndex;
|
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,
|
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 String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate,
|
||||||
final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry,
|
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 String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
||||||
@@ -251,7 +252,7 @@ public class JournalEntryData {
|
|||||||
final EnumOptionData entityType = null;
|
final EnumOptionData entityType = null;
|
||||||
final Long entityId = null;
|
final Long entityId = null;
|
||||||
final Long createdByUserId = null;
|
final Long createdByUserId = null;
|
||||||
final LocalDate submittedOnDate = null;
|
final OffsetDateTime submittedOnDate = null;
|
||||||
final String createdByUserName = null;
|
final String createdByUserName = null;
|
||||||
final String comments = null;
|
final String comments = null;
|
||||||
final Boolean reversed = null;
|
final Boolean reversed = null;
|
||||||
|
|||||||
+20
@@ -291,6 +291,17 @@ public class CurrentAccount extends AbstractAuditableCustom {
|
|||||||
@Column(name = "avg_balance_calc_period", length = 10)
|
@Column(name = "avg_balance_calc_period", length = 10)
|
||||||
private String avgBalanceCalcPeriod;
|
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
|
// Relationships
|
||||||
@OneToMany(mappedBy = "currentAccount", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
@OneToMany(mappedBy = "currentAccount", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
private List<CurrentAccountTransaction> transactions = new ArrayList<>();
|
private List<CurrentAccountTransaction> transactions = new ArrayList<>();
|
||||||
@@ -383,4 +394,13 @@ public class CurrentAccount extends AbstractAuditableCustom {
|
|||||||
this.statusEnum = 600;
|
this.statusEnum = 600;
|
||||||
this.closedOnDate = closedOnDate;
|
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;
|
private LocalDate chargeResetDate;
|
||||||
|
|
||||||
protected CurrentAccountCharge() {}
|
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)
|
@Column(name = "mobile_banking", nullable = false)
|
||||||
private boolean mobileBanking = false;
|
private boolean mobileBanking = false;
|
||||||
|
|
||||||
protected CurrentAccountFacilityConfig() {}
|
public CurrentAccountFacilityConfig() {}
|
||||||
|
|
||||||
public static CurrentAccountFacilityConfig createFor(CurrentAccount account) {
|
public static CurrentAccountFacilityConfig createFor(CurrentAccount account) {
|
||||||
CurrentAccountFacilityConfig cfg = new CurrentAccountFacilityConfig();
|
CurrentAccountFacilityConfig cfg = new CurrentAccountFacilityConfig();
|
||||||
|
|||||||
+12
@@ -122,6 +122,18 @@ public class CurrentAccountTransaction extends AbstractPersistableCustom<Long> {
|
|||||||
return txn;
|
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,
|
public static CurrentAccountTransaction withdrawal(CurrentAccount account, Office office,
|
||||||
BigDecimal amount, LocalDate transactionDate, String refNo) {
|
BigDecimal amount, LocalDate transactionDate, String refNo) {
|
||||||
CurrentAccountTransaction txn = new CurrentAccountTransaction();
|
CurrentAccountTransaction txn = new CurrentAccountTransaction();
|
||||||
|
|||||||
+12
@@ -447,6 +447,10 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
|
|||||||
return this.withHoldTax;
|
return this.withHoldTax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLienAllowed() { return this.lienAllowed; }
|
||||||
|
public BigDecimal getMaxAllowedLienLimit() { return this.maxAllowedLienLimit; }
|
||||||
|
public BigDecimal getMinBalanceForInterestCalculation() { return this.minBalanceForInterestCalculation; }
|
||||||
|
|
||||||
public TaxGroup getTaxGroup() {
|
public TaxGroup getTaxGroup() {
|
||||||
return this.taxGroup;
|
return this.taxGroup;
|
||||||
}
|
}
|
||||||
@@ -867,6 +871,14 @@ public class CurrentProduct extends AbstractPersistableCustom<Long> {
|
|||||||
public void setLastInterestDate(LocalDate lastInterestDate) { this.lastInterestDate = lastInterestDate; }
|
public void setLastInterestDate(LocalDate lastInterestDate) { this.lastInterestDate = lastInterestDate; }
|
||||||
public boolean isEnableLockinPeriod() { return enableLockinPeriod; }
|
public boolean isEnableLockinPeriod() { return enableLockinPeriod; }
|
||||||
public void setEnableLockinPeriod(boolean enableLockinPeriod) { this.enableLockinPeriod = 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 String getBalanceFrequency() { return balanceFrequency; }
|
||||||
public void setBalanceFrequency(String balanceFrequency) { this.balanceFrequency = balanceFrequency; }
|
public void setBalanceFrequency(String balanceFrequency) { this.balanceFrequency = balanceFrequency; }
|
||||||
public Boolean getAccountClosedZeroBalanceInDayClosing() { return accountClosedZeroBalanceInDayClosing; }
|
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.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
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.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(" 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(" 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(" 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(" curr.display_symbol as currencyDisplaySymbol, curr.decimal_places as currencyDigits, curr.currency_multiplesof as inMultiplesOf, ")
|
||||||
.append(" eao.external_id as externalAssetOwner ");
|
.append(" eao.external_id as externalAssetOwner ");
|
||||||
@@ -157,7 +158,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
|||||||
|
|
||||||
final Long entityId = JdbcSupport.getLong(rs, "entityId");
|
final Long entityId = JdbcSupport.getLong(rs, "entityId");
|
||||||
final Long createdByUserId = rs.getLong("createdByUserId");
|
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 createdByUserName = rs.getString("createdByUserName");
|
||||||
final String comments = rs.getString("comments");
|
final String comments = rs.getString("comments");
|
||||||
final Boolean reversed = rs.getBoolean("reversed");
|
final Boolean reversed = rs.getBoolean("reversed");
|
||||||
|
|||||||
+152
-2
@@ -63,7 +63,154 @@ public class CurrentAccountReadPlatformServiceImpl implements CurrentAccountRead
|
|||||||
if (rows.isEmpty()) {
|
if (rows.isEmpty()) {
|
||||||
throw new CurrentAccountNotFoundException(accountId);
|
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
|
@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>> rows = jdbcTemplate.query(BASE_SQL, new FlatRowMapper());
|
||||||
List<Map<String, Object>> result = new ArrayList<>();
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
for (Map<String, Object> row : rows) {
|
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;
|
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.currentaccount.service.CurrentAccountNumberGenerator;
|
||||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProduct;
|
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProduct;
|
||||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProductRepository;
|
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.SavingsAccountNotFoundException;
|
||||||
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -61,6 +69,10 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
private final OfficeRepositoryWrapper officeRepository;
|
private final OfficeRepositoryWrapper officeRepository;
|
||||||
private final CurrentAccountNumberGenerator accountNumberGenerator;
|
private final CurrentAccountNumberGenerator accountNumberGenerator;
|
||||||
private final ClientNomineeWritePlatformService clientNomineeWritePlatformService;
|
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
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -114,6 +126,26 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
product.getInterestCalculateSelector(), product.getAveragePeriod(),
|
product.getInterestCalculateSelector(), product.getAveragePeriod(),
|
||||||
product.getAvgBalanceCalcPeriod());
|
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()) {
|
if (json.has("establishmentDate") && !json.get("establishmentDate").isJsonNull()) {
|
||||||
account.setEstablishmentDate(parseDate(json.get("establishmentDate").getAsString(), dateFormat, locale));
|
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 (introducerClientId != null) account.setIntroducerClientId(introducerClientId);
|
||||||
|
|
||||||
if (json.has("externalId") && !json.get("externalId").isJsonNull()) {
|
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()) {
|
if (json.has("accountStatus") && !json.get("accountStatus").isJsonNull()) {
|
||||||
account.setAccountStatus(json.get("accountStatus").getAsString());
|
account.setAccountStatus(json.get("accountStatus").getAsString());
|
||||||
@@ -221,8 +254,73 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
|
|||||||
final JsonObject json = command.parsedJson().getAsJsonObject();
|
final JsonObject json = command.parsedJson().getAsJsonObject();
|
||||||
LocalDate activatedOnDate = parseDate(getString(json, "activatedOnDate"), getString(json, "dateFormat"), getString(json, "locale"));
|
LocalDate activatedOnDate = parseDate(getString(json, "activatedOnDate"), getString(json, "dateFormat"), getString(json, "locale"));
|
||||||
if (activatedOnDate == null) activatedOnDate = LocalDate.now();
|
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);
|
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);
|
currentAccountRepository.saveAndFlush(account);
|
||||||
|
|
||||||
|
// Post GL journal entries — deposits in batch, each charge individually
|
||||||
|
postGlEntries(account, depositTxns, chargeEntries);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder().withEntityId(accountId).build();
|
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.note.domain.NoteRepository;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
|
||||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
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.SavingsAccountTransactionType;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
|
||||||
@@ -165,6 +166,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
private final GSIMRepositoy gsimRepository;
|
private final GSIMRepositoy gsimRepository;
|
||||||
private final SavingsAccountInterestPostingService savingsAccountInterestPostingService;
|
private final SavingsAccountInterestPostingService savingsAccountInterestPostingService;
|
||||||
private final ErrorHandler errorHandler;
|
private final ErrorHandler errorHandler;
|
||||||
|
private final FacilityChargeAutoApplyService facilityChargeAutoApplyService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
@@ -199,6 +201,24 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
|
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);
|
checkClientOrGroupActive(account);
|
||||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||||
@@ -214,6 +234,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
final Locale locale = command.extractLocale();
|
final Locale locale = command.extractLocale();
|
||||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||||
processPostActiveActions(account, fmt, existingTransactionIds, existingReversedTransactionIds);
|
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);
|
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.SavingsProductFacilityLimit;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository;
|
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.DepositAccountInterestRateChartReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformServiceImpl;
|
import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformServiceImpl;
|
||||||
import org.apache.fineract.portfolio.savings.service.DepositAccountOnHoldTransactionReadPlatformService;
|
import org.apache.fineract.portfolio.savings.service.DepositAccountOnHoldTransactionReadPlatformService;
|
||||||
@@ -423,7 +424,7 @@ public class SavingsConfiguration {
|
|||||||
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, AppUserRepositoryWrapper appuserRepository,
|
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, AppUserRepositoryWrapper appuserRepository,
|
||||||
StandingInstructionRepository standingInstructionRepository, BusinessEventNotifierService businessEventNotifierService,
|
StandingInstructionRepository standingInstructionRepository, BusinessEventNotifierService businessEventNotifierService,
|
||||||
GSIMRepositoy gsimRepository, SavingsAccountInterestPostingService savingsAccountInterestPostingService,
|
GSIMRepositoy gsimRepository, SavingsAccountInterestPostingService savingsAccountInterestPostingService,
|
||||||
ErrorHandler errorHandler) {
|
ErrorHandler errorHandler, FacilityChargeAutoApplyService facilityChargeAutoApplyService) {
|
||||||
return new SavingsAccountWritePlatformServiceJpaRepositoryImpl(context, fromApiJsonDeserializer, savingAccountRepositoryWrapper,
|
return new SavingsAccountWritePlatformServiceJpaRepositoryImpl(context, fromApiJsonDeserializer, savingAccountRepositoryWrapper,
|
||||||
staffRepository, savingsAccountTransactionRepository, savingAccountAssembler, savingsAccountTransactionDataValidator,
|
staffRepository, savingsAccountTransactionRepository, savingAccountAssembler, savingsAccountTransactionDataValidator,
|
||||||
savingsAccountChargeDataValidator, paymentDetailWritePlatformService, journalEntryWritePlatformService,
|
savingsAccountChargeDataValidator, paymentDetailWritePlatformService, journalEntryWritePlatformService,
|
||||||
@@ -431,7 +432,7 @@ public class SavingsConfiguration {
|
|||||||
chargeRepository, savingsAccountChargeRepository, holidayRepository, workingDaysRepository, configurationDomainService,
|
chargeRepository, savingsAccountChargeRepository, holidayRepository, workingDaysRepository, configurationDomainService,
|
||||||
depositAccountOnHoldTransactionRepository, entityDatatableChecksWritePlatformService, appuserRepository,
|
depositAccountOnHoldTransactionRepository, entityDatatableChecksWritePlatformService, appuserRepository,
|
||||||
standingInstructionRepository, businessEventNotifierService, gsimRepository, savingsAccountInterestPostingService,
|
standingInstructionRepository, businessEventNotifierService, gsimRepository, savingsAccountInterestPostingService,
|
||||||
errorHandler);
|
errorHandler, facilityChargeAutoApplyService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
+1
-1
@@ -65,7 +65,7 @@ public class SavingsAccountConstant extends SavingsApiConstants {
|
|||||||
Arrays.asList(idParamName, accountNoParamName));
|
Arrays.asList(idParamName, accountNoParamName));
|
||||||
|
|
||||||
protected static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
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<>(
|
protected static final Set<String> SAVINGS_ACCOUNT_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>(
|
||||||
Arrays.asList(localeParamName, dateFormatParamName, closedOnDateParamName, noteParamName, paymentTypeIdParamName,
|
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);
|
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() {
|
public void setSubStatusDormant() {
|
||||||
this.sub_status = SavingsAccountSubStatusEnum.DORMANT.getValue();
|
this.sub_status = SavingsAccountSubStatusEnum.DORMANT.getValue();
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -377,7 +377,6 @@ public class SavingsProductAssembler {
|
|||||||
facilityConfigJson.get("depositFacilityKyc").getAsBoolean() : false);
|
facilityConfigJson.get("depositFacilityKyc").getAsBoolean() : false);
|
||||||
config.setVirtualDebitCard(facilityConfigJson.has("virtualDebitCard") ?
|
config.setVirtualDebitCard(facilityConfigJson.has("virtualDebitCard") ?
|
||||||
facilityConfigJson.get("virtualDebitCard").getAsBoolean() : false);
|
facilityConfigJson.get("virtualDebitCard").getAsBoolean() : false);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-124
@@ -95,146 +95,58 @@ public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long
|
|||||||
this.savingsProduct = savingsProduct;
|
this.savingsProduct = savingsProduct;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters and setters
|
public SavingsProduct getSavingsProduct() { return savingsProduct; }
|
||||||
public SavingsProduct getSavingsProduct() {
|
public void setSavingsProduct(SavingsProduct savingsProduct) { this.savingsProduct = savingsProduct; }
|
||||||
return savingsProduct;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSavingsProduct(SavingsProduct savingsProduct) {
|
public Boolean getAtmFacility() { return atmFacility; }
|
||||||
this.savingsProduct = savingsProduct;
|
public void setAtmFacility(Boolean v) { this.atmFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getAtmFacility() {
|
public Boolean getAtmWithdrawalFacility() { return atmWithdrawalFacility; }
|
||||||
return atmFacility;
|
public void setAtmWithdrawalFacility(Boolean v) { this.atmWithdrawalFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setAtmFacility(Boolean atmFacility) {
|
public Boolean getUpiFacility() { return upiFacility; }
|
||||||
this.atmFacility = atmFacility != null ? atmFacility : false;
|
public void setUpiFacility(Boolean v) { this.upiFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getAtmWithdrawalFacility() {
|
public Boolean getPosTransactionsFacility() { return posTransactionsFacility; }
|
||||||
return atmWithdrawalFacility;
|
public void setPosTransactionsFacility(Boolean v) { this.posTransactionsFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setAtmWithdrawalFacility(Boolean atmWithdrawalFacility) {
|
public Boolean getChequeBook() { return chequeBook; }
|
||||||
this.atmWithdrawalFacility = atmWithdrawalFacility != null ? atmWithdrawalFacility : false;
|
public void setChequeBook(Boolean v) { this.chequeBook = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getUpiFacility() {
|
public Boolean getImpsFacility() { return impsFacility; }
|
||||||
return upiFacility;
|
public void setImpsFacility(Boolean v) { this.impsFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpiFacility(Boolean upiFacility) {
|
public Boolean getSmsAlerts() { return smsAlerts; }
|
||||||
this.upiFacility = upiFacility != null ? upiFacility : false;
|
public void setSmsAlerts(Boolean v) { this.smsAlerts = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getPosTransactionsFacility() {
|
public Boolean getBbpsFacility() { return bbpsFacility; }
|
||||||
return posTransactionsFacility;
|
public void setBbpsFacility(Boolean v) { this.bbpsFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setPosTransactionsFacility(Boolean posTransactionsFacility) {
|
public Boolean getInsuranceCover() { return insuranceCover; }
|
||||||
this.posTransactionsFacility = posTransactionsFacility != null ? posTransactionsFacility : false;
|
public void setInsuranceCover(Boolean v) { this.insuranceCover = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getChequeBook() {
|
public Boolean getBepgFacility() { return bepgFacility; }
|
||||||
return chequeBook;
|
public void setBepgFacility(Boolean v) { this.bepgFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setChequeBook(Boolean chequeBook) {
|
public Boolean getNeftFacility() { return neftFacility; }
|
||||||
this.chequeBook = chequeBook != null ? chequeBook : false;
|
public void setNeftFacility(Boolean v) { this.neftFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getImpsFacility() {
|
public Boolean getRtgsFacility() { return rtgsFacility; }
|
||||||
return impsFacility;
|
public void setRtgsFacility(Boolean v) { this.rtgsFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setImpsFacility(Boolean impsFacility) {
|
public Boolean getInterBankTotalCapFacility() { return interBankTotalCapFacility; }
|
||||||
this.impsFacility = impsFacility != null ? impsFacility : false;
|
public void setInterBankTotalCapFacility(Boolean v) { this.interBankTotalCapFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getSmsAlerts() {
|
public Boolean getWithdrawalFacility() { return withdrawalFacility; }
|
||||||
return smsAlerts;
|
public void setWithdrawalFacility(Boolean v) { this.withdrawalFacility = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setSmsAlerts(Boolean smsAlerts) {
|
public Boolean getDepositFacilityKyc() { return depositFacilityKyc; }
|
||||||
this.smsAlerts = smsAlerts != null ? smsAlerts : false;
|
public void setDepositFacilityKyc(Boolean v) { this.depositFacilityKyc = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getBbpsFacility() {
|
public Boolean getVirtualDebitCard() { return virtualDebitCard; }
|
||||||
return bbpsFacility;
|
public void setVirtualDebitCard(Boolean v) { this.virtualDebitCard = v != null ? v : false; }
|
||||||
}
|
|
||||||
|
|
||||||
public void setBbpsFacility(Boolean bbpsFacility) {
|
public LocalDateTime getCreatedDate() { return createdDate; }
|
||||||
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 void updateFrom(SavingsProductFacilityConfig other) {
|
public void updateFrom(SavingsProductFacilityConfig other) {
|
||||||
this.atmFacility = other.getAtmFacility();
|
this.atmFacility = other.getAtmFacility();
|
||||||
@@ -254,4 +166,4 @@ public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long
|
|||||||
this.depositFacilityKyc = other.getDepositFacilityKyc();
|
this.depositFacilityKyc = other.getDepositFacilityKyc();
|
||||||
this.virtualDebitCard = other.getVirtualDebitCard();
|
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/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/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/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>
|
</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