feat: add reset to draft functionality and automate receipt status synchronization for expense realizations

This commit is contained in:
Suherdy Yacob 2026-05-08 17:00:28 +07:00
parent 8dccf0cd9a
commit 9c8a1dc96c
4 changed files with 34 additions and 1 deletions

View File

@ -111,6 +111,12 @@ class HrExpense(models.Model):
else:
expense.receipt_overdue = False
def _update_receipt_received_status(self):
for expense in self:
if expense.payment_mode == 'company_account':
has_valid_realization = any(r.state in ['confirmed', 'posted'] for r in expense.realization_ids)
expense.receipt_received = has_valid_realization
def _prepare_move_lines_vals(self):
res = super()._prepare_move_lines_vals()
if res.get('price_unit'):

View File

@ -81,13 +81,37 @@ class HrExpenseRealization(models.Model):
vals['name'] = self.env['ir.sequence'].next_by_code('hr.expense.realization') or _('New')
return super().create(vals_list)
def unlink(self):
expenses = self.mapped('expense_id')
for rec in self:
if rec.state == 'posted':
raise UserError(_("You cannot delete a posted realization."))
res = super().unlink()
if expenses:
expenses._update_receipt_received_status()
# Recompute sheet status for affected expenses
sheets = expenses.mapped('sheet_id')
if sheets:
sheets._compute_receipt_status()
return res
def action_draft(self):
for rec in self:
if rec.state == 'posted':
raise UserError(_("You cannot reset a posted realization to draft. Please cancel the journal entry first."))
rec.state = 'draft'
if rec.expense_id:
rec.expense_id._update_receipt_received_status()
if rec.expense_id.sheet_id:
rec.expense_id.sheet_id._compute_receipt_status()
def action_confirm(self):
self.ensure_one()
if not self.line_ids:
raise UserError(_("Please add at least one receipt line."))
self.state = 'confirmed'
if self.expense_id:
self.expense_id.write({'receipt_received': True})
self.expense_id._update_receipt_received_status()
# Explicitly trigger recompute of the sheet status
if self.expense_id.sheet_id:
self.expense_id.sheet_id._compute_receipt_status()

View File

@ -258,6 +258,7 @@ class HrExpenseSheet(models.Model):
# Reset draft/confirmed ones back to draft if resetting the sheet
realizations.filtered(lambda r: r.state != 'posted').write({'state': 'draft'})
sheet.expense_line_ids._update_receipt_received_status()
return super().action_reset_expense_sheets()
@ -268,6 +269,7 @@ class HrExpenseSheet(models.Model):
if realizations.filtered(lambda r: r.state == 'posted'):
raise UserError(_("You cannot refuse this report because it has Posted Realizations. Revert them first."))
realizations.write({'state': 'draft'})
sheet.expense_line_ids._update_receipt_received_status()
return super().action_refuse_expense_sheets()
def action_recompute_state(self):

View File

@ -24,6 +24,7 @@
<form string="Expense Realization">
<header>
<button name="action_confirm" string="Confirm" type="object" class="oe_highlight" invisible="state != 'draft'"/>
<button name="action_draft" string="Reset to Draft" type="object" invisible="state != 'confirmed'"/>
<button name="action_post" string="Post Journal" type="object" class="oe_highlight" groups="account.group_account_invoice" invisible="state != 'confirmed'"/>
<!-- Discrepancy Buttons -->