Skip to content

fix: tax net_amount and not_applicable#54687

Open
barredterra wants to merge 5 commits intofrappe:version-15-hotfixfrom
barredterra:text-net-na
Open

fix: tax net_amount and not_applicable#54687
barredterra wants to merge 5 commits intofrappe:version-15-hotfixfrom
barredterra:text-net-na

Conversation

@barredterra
Copy link
Copy Markdown
Collaborator

@barredterra barredterra commented Apr 30, 2026

Summary

Brings two related v16 behaviors to v15:

  1. Net amount per tax row (subset of fix: item wise tax details and net amounts #43372) — populates net_amount / base_net_amount on Sales / Purchase / Advance Taxes and Charges so each tax row records the taxable basis that contributed to it. The JS controller already aggregated this (fix(account): compute tax net_amount in JS controller #52630, backported as 6ad84d6 and 516ad90); the doctype field and Python-side mirror were missing.
  2. 'Not Applicable' marker on Item Tax Template Detail (feat: add support for 'not applicable' tax in item tax templates #50898) — distinguishes "0% rate applies" from "this tax does not apply to this item". Without it, listing a tax at 0% in a template still inflates that tax row's Net Amount with the item's net.

Why

Templates that enumerate every regional tax with 0% for the inapplicable ones (e.g. a "VAT 7% Only" template that lists VAT 19%: 0) cause the wrong tax-row Net Amounts when items with mixed templates appear on the same invoice. The 0% rate is ambiguous — could mean "exempt" or "applies but at zero" — and v15 currently treats it as the latter unconditionally.

Reproducer (from #50898)

Two templates: A = VAT 7% @ 7, VAT 19% @ 0 (Not Applicable); B = VAT 7% @ 0 (Not Applicable), VAT 19% @ 19. Sales Invoice with one item per template, both at rate 100.

Tax row Expected net_amount Before
VAT 7% 100.00 200.00
VAT 19% 100.00 200.00

Changes

New schema fields:

  • Sales Taxes and Charges, Purchase Taxes and Charges, Advance Taxes and Charges: net_amount, base_net_amount (Currency, read-only)
  • Item Tax Template Detail: not_applicable (Check, with read_only_depends_on on tax_rate)

Server (erpnext/controllers/taxes_and_totals.py):

  • New get_current_tax_and_net_amount() returning (net, tax). Old get_current_tax_amount() kept as a thin shim for external callers.
  • tax.net_amount accumulated in calculate_taxes; included in _set_in_company_currency and the initialize_taxes reset list.
  • _get_tax_rate, get_current_tax_fraction, get_current_tax_and_net_amount short-circuit when the rate is the NOT_APPLICABLE_TAX sentinel.

Sentinel propagation:

  • erpnext/stock/get_item_details.py: exposes NOT_APPLICABLE_TAX = "N/A"; get_item_tax_map emits the sentinel for not_applicable rows.
  • erpnext/controllers/accounts_controller.py: add_taxes_from_tax_template skips not-applicable rows.

Client (erpnext/public/js/controllers/taxes_and_totals.js):

  • Mirrors the server-side sentinel handling (_get_tax_rate, get_current_tax_fraction, get_current_tax_amount, add_taxes_from_item_tax_template).

Item Tax Template UX:

  • New checkbox on the row; toggling it forces tax_rate = 0 (UI handler + server validate).

Intentional non-changes

  • item_wise_tax_detail keeps the v15 [rate, amount] list shape — the v16 dict refactor (fix: item wise tax details and net amounts #43372 / feat!: Item Wise Tax Details Table #48692) and its migration patch are not backported. Out of scope for the basis-amount fix and would ripple into pos_invoice_merge_log, item_wise_sales_register, regional/italy/utils.py, and vat_audit_report.
  • v16-only entry points buying_controller.get_item_tax_amount and transaction_base.add_taxes_from_item_template don't exist in v15 — nothing to plumb there.
  • No data migration patch: existing tax rows will have net_amount = 0 until the parent doc is re-saved. If regulatory reports rely on this field for historical data, a one-shot replay can be added.

Test plan

  • `bench migrate` adds the four new columns on the tax tables and `not_applicable` on `Item Tax Template Detail`
  • Create the two templates from feat: add support for 'not applicable' tax in item tax templates #50898; verify `tax_rate` is forced to 0 and read-only when `Not Applicable` is checked
  • Sales Invoice with one item per template, both rate 100, two tax rows; expect `net_amount` = 100 on each tax row (not 200)
  • Re-save existing invoices and confirm `net_amount` populates without changing totals/grand total
  • Purchase Invoice with mixed templates: same expected shape
  • Inclusive-rate tax + an item with `Not Applicable`: `tax_fraction_for_current_item` excludes that item (no double-counting)
  • Existing reports (`item_wise_sales_register`, `vat_audit_report`, `regional/italy/utils.py`) still work — `item_wise_tax_detail` shape is unchanged

Summary by CodeRabbit

  • New Features

    • Added "Net Amount" and company-currency "Net Amount" columns to sales, purchase and advance tax child tables.
    • Added a "Not Applicable" checkbox on item tax template rows to mark taxes as N/A.
  • Improvements

    • Tax calculations now track per-row net amounts alongside tax amounts.
    • Non-applicable/N/A taxes are ignored across template application, validation and tax computation; their rates are set to zero.
    • UI currency labels updated to include net amount columns.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7db3680f-03f6-4966-85f4-9ac72b45305b

📥 Commits

Reviewing files that changed from the base of the PR and between b92ecce and 482a908.

📒 Files selected for processing (1)
  • erpnext/public/js/controllers/transaction.js
✅ Files skipped from review due to trivial changes (1)
  • erpnext/public/js/controllers/transaction.js

Walkthrough

Adds read-only currency fields net_amount and base_net_amount to tax child tables for Advance, Purchase, and Sales Taxes and Charges and updates their DocType metadata. Introduces not_applicable on Item Tax Template Detail and client/server logic to set tax_rate to zero and avoid creating tax rows for N/A mappings. Adds a NOT_APPLICABLE_TAX sentinel in item tax mapping and updates tax-expansion and tax-calculation code to compute and propagate per-row net_amount alongside tax_amount, preserving compatibility wrappers.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: tax net_amount and not_applicable' accurately captures the two main features being backported: net_amount fields on tax rows and not_applicable checkbox for item tax templates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

@barredterra
Copy link
Copy Markdown
Collaborator Author

barredterra commented Apr 30, 2026

Review notes

item_wise_tax_detail: missing keys vs old [0, …] rows

Skipping set_item_wise_tax for N/A means some item codes no longer appear under a tax row (instead of a [0, amount] stub). Traced core consumers:

  • VAT Audit Report already skips entries with taxes[0] == 0 for non-zero-rated items, so omitting N/A pairs aligns with that rule without relying on ambiguous 0%.
  • Item-wise Sales Register, Italy utilities, and POS merge log iterate existing keys only; absence matches “tax does not apply to this item.”

Residual risk is mostly custom code that assumed every item key exists on every tax row or treated [0, 0] placeholders specially.


Semantics of net_amount on tax rows (valuation / deduction)

In calculate_taxes, tax.net_amount and the accumulated tax_amount fields use pre–get_tax_amount_if_for_valuation_or_deduction amounts; the adjusted amount is used when building running totals (grand_total_for_current_item / set_cumulative_total). So for Valuation (and signed Deduct on buying), net_amount is “basis attributed to this row for tax math,” not “basis included in invoice total for this step.”

That’s consistent with existing total logic but it’s easy to misread when summing rows or building new reports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accounts needs-tests This PR needs automated unit-tests. stock

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant