HR Expense Tax Distribution
hr_expense_tax_distribution · OCA/hr-expense
-
Security25/25No findings
-
Activity25/25Last human commit 1 month ago
-
Required by5/250 modules depend on it
-
Maturity5/25In 1 Odoo series since 18.0
Heuristic over the facts below, not an audit · How it's computed
Description
In standard Odoo, an expense record accepts a single set of taxes applied to the full total amount. This works well when a receipt is entirely subject to one VAT rate, but breaks down for mixed receipts where different line items are taxed at different rates.
A typical example in France is a restaurant bill, where the applicable VAT rates depend on what was consumed:
- 5.5 % on food (solid items)
- 10 % on non-alcoholic beverages
- 20 % on alcoholic beverages
With the standard module, the user is forced to pick a single tax for the whole amount, which leads to an incorrect tax breakdown in the final accounting entry and, consequently, to wrong VAT reporting figures.
This module solves the problem by introducing tax distribution lines
on the hr.expense form. When an expense carries more than one tax, the
user can split the total receipt amount across as many distribution
lines as needed — one per applicable tax rate. Each line holds:
- the tax that applies to that portion of the receipt,
- the base amount (tax excluded) entered by the user,
- the tax amount and the total (tax included) computed automatically.
A validation constraint ensures that the sum of the distribution line totals equals the expense total before the expense report can be submitted.
When the expense report is posted, the accounting entry is built from
the distribution lines instead of the single tax_ids / total pair,
producing a correct and auditable VAT breakdown for each applicable
rate.
The module is fully backward compatible: expenses with a single tax or no distribution lines behave exactly as in standard Odoo.
Dependencies
Code analysis
Extracted from the source by best-effort static analysis (no code is executed); details may be incomplete.
Views touched 2
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
hr_expense_view_form_tax_distribution |
hr.expense.form.tax.distribution | hr.expense | form | Inherits hr_expense.hr_expense_view_form |
view_hr_expense_tax_line_tree |
hr.expense.tax.line.tree | hr.expense.tax.line | list | New |
HTTP endpoints 0
No HTTP endpoints found for this module.
Models touched 3
-
has_tax_distributionBooleancompute='_compute_has_tax_distribution'store=True -
tax_amountMonetaryprecompute=False -
tax_amount_currencyMonetaryprecompute=False -
tax_line_idsOne2many → hr.expense.tax.linecomodel_name='hr.expense.tax.line'copy=Trueinverse_name='expense_id'string='Tax Distribution Lines' -
untaxed_amount_currencyMonetaryprecompute=False
-
action_submit_expenses(self)Validate tax distribution totals before submission.
No new fields.
Public methods (0)No public methods.
-
base_amount_currencyMonetarycurrency_field='currency_id'required=Truestring='Base Amount (Tax Excl.)' -
company_idMany2onerelated='expense_id.company_id'store=True -
currency_idMany2onerelated='expense_id.currency_id'store=True -
expense_idMany2one → hr.expensecomodel_name='hr.expense'index=Trueondelete='cascade'required=Truestring='Expense' -
sequenceIntegerdefault=10 -
tax_amount_currencyMonetarycompute='_compute_amounts'currency_field='currency_id'store=Truestring='Tax Amount' -
tax_idsMany2many → account.taxcheck_company=Truecomodel_name='account.tax'domain="[('company_id', '=', company_id), ('type_tax_use', 'in', ['purchase', 'all'])]"string='Taxes' -
total_amount_currencyMonetarycompute='_compute_amounts'currency_field='currency_id'store=Truestring='Total (Tax Incl.)'
No public methods.
Loading…