Skip to content
Health
60/100
fair
  • Security25/25
    No findings
  • Activity25/25
    Last human commit 1 month ago
  • Required by5/25
    0 modules depend on it
  • Maturity5/25
    In 1 Odoo series since 18.0

Heuristic over the facts below, not an audit · How it's computed

Security findings
Grave / minor (static analysis)
Required by
0
Modules depending on it
External deps
0 pip · 0 bin
Python packages / system binaries
License
AGPL-3
No conflicts with its dependencies
Folder size
0.09 MB
Module directory on disk
Code analysis 0 migration notes 3 models 2 views 0 HTTP endpoints

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

Odoo dependencies
Python dependencies
None
System dependencies
None
Required by
None

Code analysis

Extracted from the source by best-effort static analysis (no code is executed); details may be incomplete.

Views touched 2

XML IDNameModelTypeStatus
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

New fields (5)
  • has_tax_distribution Boolean
    compute='_compute_has_tax_distribution' store=True
  • tax_amount Monetary
    precompute=False
  • tax_amount_currency Monetary
    precompute=False
  • tax_line_ids One2many → hr.expense.tax.line
    comodel_name='hr.expense.tax.line' copy=True inverse_name='expense_id' string='Tax Distribution Lines'
  • untaxed_amount_currency Monetary
    precompute=False
Public methods (1)
  • action_submit_expenses(self)
    Validate tax distribution totals before submission.

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (8)
  • base_amount_currency Monetary
    currency_field='currency_id' required=True string='Base Amount (Tax Excl.)'
  • company_id Many2one
    related='expense_id.company_id' store=True
  • currency_id Many2one
    related='expense_id.currency_id' store=True
  • expense_id Many2one → hr.expense
    comodel_name='hr.expense' index=True ondelete='cascade' required=True string='Expense'
  • sequence Integer
    default=10
  • tax_amount_currency Monetary
    compute='_compute_amounts' currency_field='currency_id' store=True string='Tax Amount'
  • tax_ids Many2many → account.tax
    check_company=True comodel_name='account.tax' domain="[('company_id', '=', company_id), ('type_tax_use', 'in', ['purchase', 'all'])]" string='Taxes'
  • total_amount_currency Monetary
    compute='_compute_amounts' currency_field='currency_id' store=True string='Total (Tax Incl.)'
Public methods (0)

No public methods.

Loading…