first commit

This commit is contained in:
Suherdy Yacob 2026-03-31 11:55:30 +07:00
commit 56d4c42956
6 changed files with 68 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.py[cod]
__pycache__/
*.swp
*~
.DS_Store

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# HR Expense Payment Status Override
## Overview
This custom Odoo 17 module overrides the default behavior for Expense Sheets (`hr.expense.sheet`) that are paid by the "Company" (`company_account`).
Natively, Odoo automatically marks an expense sheet as `Paid` as soon as the journal entries are posted, regardless of whether the generated `account.payment` is actually reconciled with a bank statement.
This module changes that behavior:
- It tracks the generated `account.payment`.
- If the payment is NOT matched to a bank statement (`is_matched == False`), the Expense Sheet status stops at **In Payment**.
- Once the payment is fully reconciled with a bank statement, the Expense Sheet correctly transitions to **Paid**.
## Dependencies
- `hr_expense`
- `account`
## Usage
1. Install the module.
2. Submit and approve an expense.
3. Post the journal entries (paid by Company).
4. Verify the status updates to "In Payment".
5. Reconcile the payment with a bank statement and verify the status updates to "Paid".

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from . import models

12
__manifest__.py Normal file
View File

@ -0,0 +1,12 @@
{
'name': 'HR Expense Payment Status Override',
'version': '17.0.1.0.0',
'summary': 'Override the hardcoded "Paid" status for expenses paid by the company, keeping them "In Payment" until reconciled.',
'category': 'Human Resources/Expenses',
'author': 'Suherdy Yacob',
'depends': ['hr_expense', 'account'],
'data': [],
'installable': True,
'application': False,
'license': 'LGPL-3',
}

1
models/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import hr_expense_sheet

View File

@ -0,0 +1,27 @@
from odoo import api, models
class HrExpenseSheet(models.Model):
_inherit = 'hr.expense.sheet'
@api.depends('account_move_ids.payment_state', 'account_move_ids.payment_id.is_matched')
def _compute_from_account_move_ids(self):
# Call the original method to compute default values first
super()._compute_from_account_move_ids()
# Override specific logic to prevent company-paid expenses from immediately jumping to 'Paid'
for sheet in self:
if sheet.payment_mode == 'company_account':
if sheet.account_move_ids:
moves = sheet.account_move_ids - sheet.account_move_ids.filtered('reversal_move_id')
if moves:
payments = moves.mapped('payment_id')
# Find if any linked payment is not yet matched to a bank statement
unmatched_payments = payments.filtered(lambda p: not p.is_matched)
if unmatched_payments:
# If there are unmatched payments, it should stay 'In Payment'
sheet.payment_state = 'in_payment'
else:
# If all payments are matched (or we have manual entries), it is Paid
sheet.payment_state = 'paid'