feat: add closing cash tracking fields and update session validation logic to suppress shortages instead of surpluses

This commit is contained in:
Suherdy Yacob 2026-06-09 09:41:44 +07:00
parent 064cef7b6b
commit 03b4637332
2 changed files with 36 additions and 8 deletions

View File

@ -6,7 +6,9 @@ This module provides adjustments for the POS opening cash mechanism in Odoo 19.
- Overrides `_set_opening_control_data` to properly initialize and track `opening_cash_expected` and `opening_cash_counted` while utilizing Odoo's native functionality. - Overrides `_set_opening_control_data` to properly initialize and track `opening_cash_expected` and `opening_cash_counted` while utilizing Odoo's native functionality.
- Tracks opening cash correctly so that the system correctly calculates differences. - Tracks opening cash correctly so that the system correctly calculates differences.
- Leverages standard Odoo 19 journal handling for robust accounting integration. - Leverages standard Odoo 19 journal handling for robust accounting integration.
- Suppresses positive cash differences automatically via standard backend validations, adjusting the `cash_register_balance_end_real` to match the expected balance when there is a surplus. - **Phantom Difference Prevention:** Relies on standard Odoo mechanisms to ensure no journal items are created when the expected cash mathematically matches the inputted cash (e.g. opening with 150k and closing with 150k, or opening with 200k, selling 100k, and closing with 300k).
- **Shortage Suppression:** Automatically adjusts the real balance to match the expected balance when a shortage is detected, avoiding loss/expense journal entries.
- **Surplus Recording:** Allows standard Odoo behavior to record a surplus as a profit journal entry.
## Technical Details ## Technical Details
This module modifies the `pos.session` object, tracking: This module modifies the `pos.session` object, tracking:
@ -14,7 +16,7 @@ This module modifies the `pos.session` object, tracking:
- **`opening_cash_counted`**: The actual cash counted by the cashier. - **`opening_cash_counted`**: The actual cash counted by the cashier.
- **`opening_cash_difference`**: Computed difference between counted and expected opening cash. - **`opening_cash_difference`**: Computed difference between counted and expected opening cash.
It modifies the standard `_validate_session` process strictly for suppressing positive discrepancies (where the ending cash register is higher than expected), logging the event into the chatter. It modifies the standard `_validate_session` process strictly for suppressing negative discrepancies (shortages where the ending cash register is lower than expected), logging the event into the chatter.
## Author ## Author
Suherdy Yacob Suherdy Yacob

View File

@ -25,6 +25,25 @@ class PosSession(models.Model):
help="Difference between the expected and the counted cash at session opening.", help="Difference between the expected and the counted cash at session opening.",
) )
closing_cash_expected = fields.Monetary(
string="Expected Closing Cash",
currency_field="currency_id",
readonly=True,
help="Expected cash amount in the drawer when the session is closed.",
)
closing_cash_counted = fields.Monetary(
string="Counted Closing Cash",
currency_field="currency_id",
readonly=True,
help="Actual cash amount counted by the cashier when the session is closed.",
)
closing_cash_difference = fields.Monetary(
string="Closing Cash Difference",
currency_field="currency_id",
readonly=True,
help="Difference between expected and counted cash at session closing.",
)
@api.depends("opening_cash_expected", "opening_cash_counted") @api.depends("opening_cash_expected", "opening_cash_counted")
def _compute_opening_cash_difference(self): def _compute_opening_cash_difference(self):
for session in self: for session in self:
@ -83,14 +102,21 @@ class PosSession(models.Model):
def _validate_session(self, balancing_account=False, amount_to_balance=0, bank_payment_method_diffs=None): def _validate_session(self, balancing_account=False, amount_to_balance=0, bank_payment_method_diffs=None):
for session in self: for session in self:
if session.config_id.cash_control: if session.config_id.cash_control:
difference = session.cash_register_balance_end_real - session.cash_register_balance_end expected = session.cash_register_balance_end
if session.currency_id.compare_amounts(difference, 0.0) > 0: counted = session.cash_register_balance_end_real
session.message_post(body="Auto-adjustment: Cashier input %s overridden to expected %s to suppress positive difference of %s." % ( difference = counted - expected
session.currency_id.format(session.cash_register_balance_end_real), session.write({
session.currency_id.format(session.cash_register_balance_end), 'closing_cash_expected': expected,
'closing_cash_counted': counted,
'closing_cash_difference': difference,
})
if session.currency_id.compare_amounts(difference, 0.0) < 0:
session.message_post(body="Auto-adjustment: Cashier input %s overridden to expected %s to suppress shortage difference of %s." % (
session.currency_id.format(counted),
session.currency_id.format(expected),
session.currency_id.format(difference) session.currency_id.format(difference)
)) ))
session.write({'cash_register_balance_end_real': session.cash_register_balance_end}) session.write({'cash_register_balance_end_real': expected})
for order in session.order_ids: for order in session.order_ids:
for payment in order.payment_ids: for payment in order.payment_ids: