-
Notifications
You must be signed in to change notification settings - Fork 105
Cash Payment Design
This document describes the design for Cash Payments and Server-Side logic for the Cash Payments page.
Design
Cash payments describe two types of payments:
- Payments against Future Transactions (Cautions)
- Payments against Previous Invoices (Cash)
Both payment types are stored in the cash
and cash_item
tables. Cash Payments can be against multiple invoices. If the payment is not enough to cover the total cost, value is allocated in ascending order of the invoice date - oldest invoices are covered before newer ones until the value is allocated to all invoices.
Considering Exchange Rates
Cash Payments can be made in any currency, so they must consider the exchange rate of the day the payment is made.
- The payment information in the
cash
table is in the payment currency. - The payment information coped to the
posting_journal
is in the enterprise currency.
To calculate the value of a cash payment in the enterprise currency, the exchange rate of payment date is used (see Exchange Rate Design). This step occurs in during the posting process.
Posting Cash Payments to the Posting Journal
Cash Payment records are written and posted using MySQL stored procedures StageCash()
, StageCashItem()
, CalculateCashInvoiceBalances()
, WriteCash()
, WriteCashItems()
, and PostCash()
. The Stage*
procedures simply copy data from JavaScript into temporary tables.
CalculateCashInvoiceBalances()
Note: this procedure is only called if the payment is not a Caution.
This procedure collects the data of all unbalanced invoices for that patient. In order to reduce rounding errors, it converts all debts (stored in the enterprise currency) into the payment currency. These these values are written into the stage_cash_invoice_balances
table to be used later.
WriteCash()
This procedure simply copies data into the cash
table.
WriteCashItems()
Note: this procedure is only called if the payment is not a Caution.
This procedure uses the stage_cash_invoice_balances
table to compute the amount allocated to each invoice. It loops through the debts and balances the invoice if the amount of cash paid is greater than the invoice amount. The cash amount is reduced by the amount allocated at each step. If the amount of money paid is not enough to cover all unbalanced invoices, the amount of money remaining credited to the final invoice and the algorithm terminates.
Note that the amount paid for each invoice might not be the same as the amount of owed, due to rounding. For example, an invoice that costs 930FC will be paid in full by paying 950FC. This is because FC only comes in units of 50FC, so the software rounds up. The unit is set in the min_monentary_unit
column of the currency table. In this case, the cash
record will list have amount
as 950, but the cash_item
will have amount
as 930 allocated to one invoice. This imbalance shows that we must round.
PostCash()
This procedure posts values to the posting journal. It copies the line crediting the debtor to for the full amount paid. If the payment is a caution payment, a second line is written debiting the cashbox account for the balanced amount.
If the payment is not a caution, each payment item in cash_item
is copied to the Posting Journal.
Handling Rounding
If there is a difference between the sum of all cash_item
amounts and the cash
amount, we must round. The algorithm first checks to make sure that they are within the min_monentary_unit
range (and errors if not). Otherwise:
- If
cash.amount - SUM(cash_item.amount) > 0
, the enterprise received a gain on rounding. This value is debited to thegain_account_id
found in theenterprise
table. - If
cash.amount - SUM(cash_item.amount) < 0
, the enterprise took a loss on rounding. This value is credited to theloss_account_id
found in theenterprise
table.