refactor: simplify expense lock bypass using skip_expense_lock context in action_post and synchronization methods

This commit is contained in:
Suherdy Yacob 2026-04-06 12:06:40 +07:00
parent 70ac4baf8b
commit ca4daf1276

View File

@ -8,66 +8,35 @@ class AccountPayment(models.Model):
def action_post(self): def action_post(self):
""" """
Force synchronization before posting to ensure deductions are included, Force synchronization before posting to ensure deductions are included.
even if the payment was previously 'Reset to Draft' without edits. We use the 'skip_expense_lock' context to bypass hr_expense's strict validation.
We must wrap this in the same bypass logic as _synchronize_to_moves
to avoid the 'Invalid Operation' error from hr_expense.
""" """
# If we have draft payments linked to a sheet, we must bypass the hr_expense lock during posting return super(AccountPayment, self.with_context(skip_expense_lock=True)).action_post()
draft_payouts = self.filtered(lambda p: p.state == 'draft' and p.expense_sheet_id)
if draft_payouts:
links = {p.id: p.expense_sheet_id.id for p in draft_payouts}
# Hide the links temporarily
for p in draft_payouts:
p.env.cache.set(p, p._fields['expense_sheet_id'], False)
try:
# Force sync deductions
for p in draft_payouts:
p._synchronize_to_moves({'amount', 'deduction_line_ids', 'amount_substract'})
# Call original post logic
return super().action_post()
finally:
# Restore links
for p in draft_payouts:
if p.id in links:
p.env.cache.set(p, p._fields['expense_sheet_id'], self.env['hr.expense.sheet'].browse(links[p.id]))
return super().action_post()
def _synchronize_to_moves(self, changed_fields): def _synchronize_to_moves(self, changed_fields):
""" # Trigger deduction sync if needed
Bypass standard Odoo restriction for payments linked to expense reports
if the payment is still in Draft state. This allows applying deductions
or refining clearing accounts.
"""
# Include deduction fields in the fields that trigger synchronization
if 'deduction_line_ids' in changed_fields or 'amount_substract' in changed_fields: if 'deduction_line_ids' in changed_fields or 'amount_substract' in changed_fields:
# If deductions change, we MUST sync to moves to ensure the deduction lines are created if 'amount' not in changed_fields:
pass changed_fields = set(changed_fields) | {'amount'}
# If we have draft payments linked to a sheet, we want to skip the hr_expense UserError if self._context.get('skip_expense_lock'):
draft_payouts = self.filtered(lambda p: p.state == 'draft' and p.expense_sheet_id) # Safely call super() - the hr_expense override also checks context (via our own override below)
if draft_payouts: return super()._synchronize_to_moves(changed_fields)
# Store the original links
links = {p.id: p.expense_sheet_id.id for p in draft_payouts}
# Temporarily clear the field in the instance cache to fool the hr_expense method
for p in draft_payouts:
p.env.cache.set(p, p._fields['expense_sheet_id'], False)
try:
# This will call the chain, including hr_expense (which will now see no sheet)
# and finally reach account module to perform the move sync.
res = super()._synchronize_to_moves(changed_fields)
finally:
# Restore the links in the cache
for p in draft_payouts:
if p.id in links:
p.env.cache.set(p, p._fields['expense_sheet_id'], self.env['hr.expense.sheet'].browse(links[p.id]))
return res
# For manual edits, standard hr_expense error will apply via the super() chain
return super()._synchronize_to_moves(changed_fields) return super()._synchronize_to_moves(changed_fields)
def _synchronize_from_moves(self, changed_fields):
if self._context.get('skip_expense_lock'):
return super()._synchronize_from_moves(changed_fields)
return super()._synchronize_from_moves(changed_fields)
def write(self, vals):
if 'deduction_line_ids' in vals or 'amount_substract' in vals:
# Force trigger sync with bypass flag
return super(AccountPayment, self.with_context(skip_expense_lock=True)).write(vals)
return super().write(vals)
def write(self, vals): def write(self, vals):
""" """
Override write to manually trigger synchronization when deductions change. Override write to manually trigger synchronization when deductions change.