Postgres has no gap locks, so the lock-then-read pattern (plain SELECT ... FOR UPDATE before a grouped read) only serializes on rows that already exist. Two sites had reachable races where the lock set is empty or disjoint: - Pick list: two pick lists against the same SO item submitted concurrently lock only docstatus=1 rows, so with no previously-submitted picks their lock sets are disjoint and both pass validate_picked_qty (over-pick; picked_qty last-writer-wins). Gate on the referenced Sales Order Item / Packed Item rows, which always exist. - Stock reservation: the first concurrent reservations for an (item, warehouse) find no SRE rows to lock, so both pass and reserved qty can exceed actual. Gate on the Bin row, which exists once there is stock. MariaDB is unchanged (its gap locks already serialize both; the gates are postgres-only). Also: ORDER BY on the small-set postgres lock selects for deterministic lock order, and the repost pre-lock in get_future_stock_vouchers selects a constant instead of shipping every matching SLE name to the client.
Accounts module contains masters and transactions to manage a traditional double entry accounting system.
Accounting heads are called "Accounts" and they can be groups in a tree like "Chart of Accounts"
Entries are:
- Journal Entries
- Sales Invoice (Itemised)
- Purchase Invoice (Itemised)
All accounting entries are stored in the General Ledger
Payment Ledger
Transactions on Receivable and Payable Account types will also be stored in Payment Ledger. This is so that payment reconciliation process only requires update on this ledger.
Key Fields
| Field | Description |
|---|---|
account_type |
Receivable/Payable |
account |
Accounting head |
party |
Party Name |
voucher_no |
Voucher No |
against_voucher_no |
Linked voucher(secondary effect) |
amount |
can be +ve/-ve |
Design
debit and credit have been replaced with account_type and amount. against_voucher_no is populated for all entries. So, outstanding amount can be calculated by summing up amount only using against_voucher_no.
Ex:
- Consider an invoice for ₹100 and a partial payment of ₹80 against that invoice. Payment Ledger will have following entries.
| voucher_no | against_voucher_no | amount |
|---|---|---|
| SINV-01 | SINV-01 | 100 |
| PAY-01 | SINV-01 | -80 |
- Reconcile a Credit Note against an invoice using a Journal Entry
An invoice for ₹100 partially reconciled against a credit of ₹70 using a Journal Entry. Payment Ledger will have the following entries.
| voucher_no | against_voucher_no | amount |
|---|---|---|
| SINV-01 | SINV-01 | 100 |
| CR-NOTE-01 | CR-NOTE-01 | -70 |
| JE-01 | CR-NOTE-01 | +70 |
| JE-01 | SINV-01 | -70 |