feat: cash management backend - transfer, settlement, inter-cashier, reconciliation + cashier /me position endpoint
OVERVIEW
--------
Added complete cash management backend covering the full cashier workflow:
vault transfers, inter-cashier transfers, end-of-day settlement, GL
reconciliation, and a new authenticated /me endpoint for cashier position
lookup without needing to pass a cashier ID.
NEW API ENDPOINT
----------------
GET /cashreports/cashier-position/me
- Auto-detects the authenticated user via PlatformSecurityContext
- Resolves appUser -> staff -> cashier via m_cashiers JOIN chain
- Accepts optional ?asOfDate=YYYY-MM-DD query param (defaults to today)
- Reuses existing buildPositionForCashier(cashierId, dateFilter) internally
- Returns: { cashierId, asOfDate, totalAmount, denominations[] }
- Non-cashier users get empty denominations array (no error thrown)
- Used by Angular UI to show opening/closing denomination panels
CASH TRANSFER (vault -> cashier)
---------------------------------
CashTransferApiResource.java — REST endpoints (POST /cashtransfer, GET list/detail)
CashTransfer.java — JPA entity (m_cash_transfer)
CashTransferDetail.java — JPA entity (denomination breakdown, m_cash_transfer_detail)
CashTransferRepository.java — Spring Data JPA repository
CashTransferDetailRepository.java
DB migrations:
0014_cash_transfer.xml — creates m_cash_transfer + m_cash_transfer_detail tables
0015_cash_transfer_add_ids.xml — adds missing ID columns to transfer detail
CASH SETTLEMENT (end-of-day cashier close)
------------------------------------------
CashSettlementApiResource.java — REST endpoints (POST /cashsettlement, GET list/detail)
CashSettlement.java — JPA entity (m_cash_settlement)
CashSettlementDetail.java — JPA entity (denomination breakdown)
CashSettlementRepository.java
CashSettlementDetailRepository.java
DB migration:
0016_cash_settlement.xml — creates m_cash_settlement + m_cash_settlement_detail
INTER-CASHIER TRANSFER
-----------------------
CashInterCashierApiResource.java — REST endpoints (POST /cashintercashier, GET list/detail)
CashInterCashier.java — JPA entity (m_cash_inter_cashier)
CashInterCashierDetail.java — JPA entity (denomination breakdown)
CashInterCashierRepository.java
CashInterCashierDetailRepository.java
DB migration:
0017_cash_inter_cashier.xml — creates m_cash_inter_cashier + detail table
CASH RECONCILIATION
--------------------
CashReconciliationApiResource.java — REST endpoints (POST /cashreconciliation, GET list)
CashReconciliation.java — JPA entity (m_cash_reconciliation)
CashReconciliationDetail.java — JPA entity (denomination breakdown)
CashReconciliationRepository.java
CashReconciliationDetailRepository.java
DB migrations:
0018_cash_reconciliation.xml — creates m_cash_reconciliation + detail table
0019_cash_reversal_columns.xml — adds reversal tracking columns
0020_cash_permissions.xml — adds permissions for all cash management APIs
GL DISPATCH SERVICE
-------------------
GlDispatchService.java (portfolio/teller/service/)
- Shared service for posting GL journal entries for cash movements
- Used by settlement and reconciliation flows
CHANGELOG
---------
changelog-tenant.xml updated to include migrations 0014 through 0020.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
9a30ede278
commit
b89e653bcb
@@ -320,4 +320,11 @@
|
||||
<include file="parts/0301_add_current_account_to_transfer_details.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0012_denomination_master.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0013_cash_exchange.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0014_cash_transfer.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0015_cash_transfer_add_ids.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0016_cash_settlement.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0017_cash_inter_cashier.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0018_cash_reconciliation.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0019_cash_reversal_columns.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0020_cash_permissions.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_transfer_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_transfer">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="transfer_date" type="DATE"/>
|
||||
<column name="from_party" type="VARCHAR(100)"/>
|
||||
<column name="to_party" type="VARCHAR(100)"/>
|
||||
<column name="transfer_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="note" type="VARCHAR(500)"/>
|
||||
<column name="performed_by" type="BIGINT"/>
|
||||
<column name="performed_by_username" type="VARCHAR(100)"/>
|
||||
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="cash_transfer_detail_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_transfer_detail">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="transfer_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="denomination_id" type="BIGINT"/>
|
||||
<column name="denomination_value" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="count" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="total_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createIndex tableName="m_cash_transfer_detail" indexName="idx_cash_transfer_detail_tid">
|
||||
<column name="transfer_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_transfer_add_party_ids_001" author="CBS">
|
||||
<addColumn tableName="m_cash_transfer">
|
||||
<column name="from_teller_id" type="BIGINT"/>
|
||||
<column name="to_cashier_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_settlement_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_settlement">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="settlement_date" type="DATE"/>
|
||||
<column name="from_cashier_id" type="BIGINT"/>
|
||||
<column name="to_teller_id" type="BIGINT"/>
|
||||
<column name="from_party" type="VARCHAR(100)"/>
|
||||
<column name="to_party" type="VARCHAR(100)"/>
|
||||
<column name="settlement_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="note" type="VARCHAR(500)"/>
|
||||
<column name="performed_by" type="BIGINT"/>
|
||||
<column name="performed_by_username" type="VARCHAR(100)"/>
|
||||
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
|
||||
<column name="is_reversed" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="reversed_by" type="BIGINT"/>
|
||||
<column name="reversed_at" type="TIMESTAMP"/>
|
||||
<column name="reverse_reason" type="VARCHAR(500)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="cash_settlement_detail_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_settlement_detail">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="settlement_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="denomination_id" type="BIGINT"/>
|
||||
<column name="denomination_value" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="count" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="total_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createIndex tableName="m_cash_settlement_detail" indexName="idx_cash_settlement_detail_sid">
|
||||
<column name="settlement_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_inter_cashier_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_inter_cashier">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="transfer_date" type="DATE"/>
|
||||
<column name="teller_id" type="BIGINT"/>
|
||||
<column name="from_cashier_id" type="BIGINT"/>
|
||||
<column name="to_cashier_id" type="BIGINT"/>
|
||||
<column name="from_party" type="VARCHAR(100)"/>
|
||||
<column name="to_party" type="VARCHAR(100)"/>
|
||||
<column name="transfer_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="note" type="VARCHAR(500)"/>
|
||||
<column name="performed_by" type="BIGINT"/>
|
||||
<column name="performed_by_username" type="VARCHAR(100)"/>
|
||||
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
|
||||
<column name="is_reversed" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="reversed_by" type="BIGINT"/>
|
||||
<column name="reversed_at" type="TIMESTAMP"/>
|
||||
<column name="reverse_reason" type="VARCHAR(500)"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="cash_inter_cashier_detail_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_inter_cashier_detail">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="inter_cashier_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="denomination_id" type="BIGINT"/>
|
||||
<column name="denomination_value" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="count" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="total_amount" type="DECIMAL(19,6)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<createIndex tableName="m_cash_inter_cashier_detail" indexName="idx_cash_inter_cashier_detail_pid">
|
||||
<column name="inter_cashier_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_reconciliation_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_reconciliation">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="recon_date" type="DATE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="cashier_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="cashier_name" type="VARCHAR(150)"/>
|
||||
<column name="teller_id" type="BIGINT"/>
|
||||
<column name="expected_amount" type="DECIMAL(19,6)" defaultValueNumeric="0"/>
|
||||
<column name="physical_amount" type="DECIMAL(19,6)" defaultValueNumeric="0"/>
|
||||
<column name="variance" type="DECIMAL(19,6)" defaultValueNumeric="0"/>
|
||||
<column name="status" type="VARCHAR(10)" defaultValue="OK"/>
|
||||
<column name="note" type="VARCHAR(500)"/>
|
||||
<column name="performed_by" type="BIGINT"/>
|
||||
<column name="performed_by_username" type="VARCHAR(100)"/>
|
||||
<column name="created_at" type="TIMESTAMP" defaultValueComputed="CURRENT_TIMESTAMP"/>
|
||||
</createTable>
|
||||
<createIndex tableName="m_cash_reconciliation" indexName="idx_cash_recon_cashier_date">
|
||||
<column name="cashier_id"/>
|
||||
<column name="recon_date"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="cash_reconciliation_detail_table_001" author="CBS">
|
||||
<createTable tableName="m_cash_reconciliation_detail">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="reconciliation_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="denomination_id" type="BIGINT"/>
|
||||
<column name="denomination_value" type="INT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="expected_count" type="INT" defaultValueNumeric="0"/>
|
||||
<column name="physical_count" type="INT" defaultValueNumeric="0"/>
|
||||
<column name="variance_count" type="INT" defaultValueNumeric="0"/>
|
||||
<column name="variance_amount" type="DECIMAL(19,6)" defaultValueNumeric="0"/>
|
||||
</createTable>
|
||||
<createIndex tableName="m_cash_reconciliation_detail" indexName="idx_cash_recon_detail_rid">
|
||||
<column name="reconciliation_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_transfer_reversal_cols_001" author="CBS">
|
||||
<addColumn tableName="m_cash_transfer">
|
||||
<column name="is_reversed" type="BOOLEAN" defaultValueBoolean="false"/>
|
||||
<column name="reversed_by" type="BIGINT"/>
|
||||
<column name="reversed_at" type="TIMESTAMP"/>
|
||||
<column name="reverse_reason" type="VARCHAR(500)"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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="cash_module_permissions_001" author="CBS" runOnChange="false">
|
||||
<sql>
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'CREATE_CASHTRANSFER', 'CASHTRANSFER', 'CREATE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CASHTRANSFER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'READ_CASHTRANSFER', 'CASHTRANSFER', 'READ', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CASHTRANSFER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'REVERSE_CASHTRANSFER', 'CASHTRANSFER', 'REVERSE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'REVERSE_CASHTRANSFER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'CREATE_CASHSETTLEMENT', 'CASHSETTLEMENT', 'CREATE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CASHSETTLEMENT');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'READ_CASHSETTLEMENT', 'CASHSETTLEMENT', 'READ', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CASHSETTLEMENT');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'REVERSE_CASHSETTLEMENT', 'CASHSETTLEMENT', 'REVERSE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'REVERSE_CASHSETTLEMENT');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'CREATE_CASHINTERCASHIER', 'CASHINTERCASHIER', 'CREATE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CASHINTERCASHIER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'READ_CASHINTERCASHIER', 'CASHINTERCASHIER', 'READ', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CASHINTERCASHIER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'REVERSE_CASHINTERCASHIER', 'CASHINTERCASHIER', 'REVERSE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'REVERSE_CASHINTERCASHIER');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'CREATE_CASHRECONCILIATION', 'CASHRECONCILIATION', 'CREATE', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CASHRECONCILIATION');
|
||||
|
||||
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
|
||||
SELECT 'cashier', 'READ_CASHRECONCILIATION', 'CASHRECONCILIATION', 'READ', false
|
||||
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CASHRECONCILIATION');
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user