fix: resolve payment state calculation and enable expense sheet refusal by handling move reversals and cancellations

This commit is contained in:
Suherdy Yacob 2026-04-06 11:11:00 +07:00
parent fa8f270c5b
commit b916bedbbc

View File

@ -137,6 +137,82 @@ class HrExpenseSheet(models.Model):
else:
sheet.receipt_status = 'pending'
@api.depends('account_move_ids.payment_state', 'account_move_ids.amount_residual', 'account_move_ids.state')
def _compute_from_account_move_ids(self):
"""
Overriding to fix the 'IN PAYMENT' ribbon issue.
Standard Odoo assumes 'paid' if any move exists for company_account.
We check if the moves are actually in 'posted' state.
"""
for sheet in self:
if sheet.payment_mode == 'company_account':
if sheet.account_move_ids:
# Filter for moves that are NOT canceled
active_moves = sheet.account_move_ids.filtered(lambda m: m.state == 'posted')
if active_moves:
# If there are active moves that are not reversed
if active_moves - active_moves.filtered('reversal_move_id'):
sheet.payment_state = 'paid'
sheet.amount_residual = 0.
else:
sheet.payment_state = 'reversed'
sheet.amount_residual = sum(sheet.account_move_ids.mapped('amount_residual'))
else:
# Moves exist but none are 'posted' (e.g. they are all 'cancel' or 'draft')
sheet.payment_state = 'not_paid'
sheet.amount_residual = sum(sheet.account_move_ids.mapped('amount_residual'))
else:
sheet.payment_state = 'not_paid'
sheet.amount_residual = 0.0
else:
# Standard Odoo logic for own_account
if sheet.account_move_ids:
sheet.amount_residual = sum(sheet.account_move_ids.mapped('amount_residual'))
sheet.payment_state = sheet.account_move_ids[:1].payment_state
else:
sheet.amount_residual = 0.0
sheet.payment_state = 'not_paid'
def _do_refuse(self, reason):
"""
Bypass the standard Odoo lock: 'You cannot cancel an expense sheet linked to a journal entry'.
We allow it but we'll try to cancel the moves first.
"""
self._do_reverse_moves()
# Explicitly call the original _do_refuse but WITHOUT the check,
# but since we already reversed/deleted moves, the original check won't trigger.
return super()._do_refuse(reason)
def _do_reverse_moves(self):
"""
Overriding to handle account.payment explicitly.
Odoo's _do_reverse_moves calls _reverse_moves, which fails for payments.
"""
self = self.with_context(clean_context(self.env.context))
moves = self.account_move_ids
if moves:
for sheet in self:
# Handle payments linked to this sheet
payments = sheet.account_move_ids.mapped('payment_id')
if payments:
# Cancel the payments directly
for payment in payments:
if payment.state == 'posted':
payment.action_cancel()
elif payment.state == 'draft':
payment.action_cancel()
# Standard reversal for non-payment moves (if any)
non_payment_moves = sheet.account_move_ids.filtered(lambda m: not m.payment_id)
if non_payment_moves:
non_payment_moves._reverse_moves(
default_values_list=[{'invoice_date': fields.Date.context_today(move), 'ref': False} for move in non_payment_moves],
cancel=True
)
# Unlink draft moves (including payment moves that are now draft/cancel)
sheet.account_move_ids.filtered(lambda m: m.state == 'draft').unlink()
def action_reset_expense_sheets(self):
"""
Overriding reset to handle realizations.