Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Cashier reports now reconcile against the drawer: - Received/Payment exclude what cannot be cash rather than admitting only proven cash, so registers that pay out without recording a denomination breakdown are no longer silently dropped - Closing report scoped to the cashier, with opening/closing balance, reversed counter transactions excluded, and cash DD receipts counted - Day book split into Cashier and Clerk sections, filed by whose cash moved rather than who raised the request Fixed one deposit or withdrawal raising two vouchers: the cashier deposit and clerk withdrawal registers did not suppress the inner savings command's voucher, doubling the day's cash on both reports. Sponsor DD: - Amendment request flow (beneficiary, payable-at branch and city) under maker-checker; face value and funding stay unamendable - Cash DD denominations were collected but never saved, and the amount check demanded a figure notes could not add to; both fixed and the breakdown is now required Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
69 lines
3.1 KiB
PL/PgSQL
69 lines
3.1 KiB
PL/PgSQL
-- Removes the duplicate vouchers left behind by the double-count bug.
|
|
--
|
|
-- Until 2026-09-03 the cashier deposit and clerk withdrawal registers did not wrap their inner
|
|
-- savings command in VoucherService.withOwnVoucher(...), so one counter transaction raised two
|
|
-- vouchers over the same money: the register's own (CASHIER_DEPOSIT_REQUEST / CLERK_WITHDRAWAL_
|
|
-- REQUEST) and a second one from the savings command (SAVINGS_TRANSACTION). The cashier's Received
|
|
-- and Payment reports counted both, doubling the day's cash.
|
|
--
|
|
-- The code is fixed, so no new duplicates are created. This clears the ones already recorded.
|
|
--
|
|
-- WHICH ONE IS DELETED: the SAVINGS_TRANSACTION voucher. The register's voucher is the keeper --
|
|
-- it is the one the register owns, attaches its DR/CR lines to, and stamps onto
|
|
-- m_savings_account_transaction.voucher_no. Deleting the register's voucher instead would break
|
|
-- that link and orphan the request row.
|
|
--
|
|
-- Run: psql -h localhost -U postgres -d fineract_default -v ON_ERROR_STOP=1 -f cleanup_duplicate_vouchers.sql
|
|
|
|
BEGIN;
|
|
|
|
-- The duplicates: a SAVINGS_TRANSACTION voucher whose transaction is already claimed by a
|
|
-- register voucher. Matching through savings_txn_id rather than by date or amount so that two
|
|
-- genuinely separate transactions of the same value on the same day are never confused.
|
|
CREATE TEMP TABLE dup_vouchers ON COMMIT DROP AS
|
|
SELECT sav.voucher_no
|
|
FROM m_voucher sav
|
|
JOIN m_voucher reg
|
|
ON reg.savings_txn_id = sav.reference_id
|
|
AND reg.reference_type IN ('CLERK_WITHDRAWAL_REQUEST', 'CASHIER_DEPOSIT_REQUEST')
|
|
WHERE sav.reference_type = 'SAVINGS_TRANSACTION'
|
|
AND sav.voucher_type IN ('DEPOSIT', 'WITHDRAWAL');
|
|
|
|
-- Refuse to run if anything else has attached itself to a voucher about to be deleted: a
|
|
-- verification or an attachment means someone acted on that slip, and it must be looked at by hand
|
|
-- rather than removed silently.
|
|
DO $$
|
|
DECLARE
|
|
blocked INT;
|
|
BEGIN
|
|
SELECT COUNT(*) INTO blocked
|
|
FROM (SELECT voucher_no FROM m_voucher_verification
|
|
WHERE voucher_no IN (SELECT voucher_no FROM dup_vouchers)
|
|
UNION ALL
|
|
SELECT voucher_no FROM m_voucher_attachment
|
|
WHERE voucher_no IN (SELECT voucher_no FROM dup_vouchers)) x;
|
|
IF blocked > 0 THEN
|
|
RAISE EXCEPTION 'Aborting: % duplicate voucher(s) carry a verification or attachment. Review these by hand.', blocked;
|
|
END IF;
|
|
END $$;
|
|
|
|
-- Likewise refuse if a savings transaction is stamped with a voucher about to be deleted. It should
|
|
-- carry the register's number, not the duplicate's; if it does not, the pair needs looking at.
|
|
DO $$
|
|
DECLARE
|
|
stamped INT;
|
|
BEGIN
|
|
SELECT COUNT(*) INTO stamped FROM m_savings_account_transaction
|
|
WHERE voucher_no IN (SELECT voucher_no FROM dup_vouchers);
|
|
IF stamped > 0 THEN
|
|
RAISE EXCEPTION 'Aborting: % savings transaction(s) are stamped with a duplicate voucher number.', stamped;
|
|
END IF;
|
|
END $$;
|
|
|
|
SELECT voucher_no AS "about to delete" FROM dup_vouchers ORDER BY voucher_no;
|
|
|
|
DELETE FROM m_voucher_line WHERE voucher_no IN (SELECT voucher_no FROM dup_vouchers);
|
|
DELETE FROM m_voucher WHERE voucher_no IN (SELECT voucher_no FROM dup_vouchers);
|
|
|
|
COMMIT;
|