Files
Odoo-Modules/nexa_coa_setup/scripts/test_invoices.py
gsinghpal 9c52fac9ba fix(nexa_coa_setup): default tax = 13% HST, tax repartition migration, FP pass-through
Three fixes that unblock end-to-end invoice tests on staging:

1. Switched company default sale/purchase tax from '5% GST' to '13% HST'
   (Ontario is the home province). New products auto-get 13% HST; fiscal
   positions substitute OUT to other rates per customer location.

2. Added _migrate_tax_repartition_accounts hook. The post_init archive sweep
   correctly archived legacy l10n_ca tax-tracking accounts (118100.OLD,
   231000, 232000, 233000, 118400, 118500, etc.) but active taxes still
   referenced them via repartition lines, causing invoice posting to fail
   with 'account is archived'. Hook repoints repartition to Nexa's
   consolidated 118100 (ITC) / 213100 (HST collected) / 213500 (QST
   collected) accounts.

3. Odoo 19 fiscal position behavior change: empty tax_ids now means
   'remove all taxes' (was 'pass-through' in v17/18). For ON home position
   we now add a self-mapping placeholder (13% HST -> 13% HST) so the FP
   has a non-empty tax_ids and map_tax falls through to pass-through
   semantics on the 13% HST source.

Verified with 4 invoice tests on staging:
  ON     -> 13% HST   total 113.00
  US     -> 0% GST    total 100.00 (zero-rated export)
  QC     -> 14.975%   total 114.98
  Westin -> 13% HST   total 169.50 (intercompany, RP-Associated tag)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 19:19:49 -04:00

60 lines
2.4 KiB
Python

"""Test invoices using Form to emulate UI onchange behavior."""
from odoo.tests.common import Form
import json
results = []
def test_invoice(label, partner_vals, product_name, product_cat_xmlid, price=100.0):
env.cr.execute("SAVEPOINT test")
try:
partner = env['res.partner'].search([('name', '=', partner_vals['name'])], limit=1)
if not partner:
partner = env['res.partner'].create(partner_vals)
cat = env.ref(product_cat_xmlid)
product = env['product.product'].search([('name', '=', product_name)], limit=1)
if not product:
product = env['product.product'].create({
'name': product_name, 'type': 'service',
'list_price': price, 'categ_id': cat.id,
})
with Form(env['account.move'].with_context(default_move_type='out_invoice')) as inv_form:
inv_form.partner_id = partner
with inv_form.invoice_line_ids.new() as line:
line.product_id = product
line.quantity = 1
line.price_unit = price
inv = inv_form.save()
line = inv.invoice_line_ids[0]
results.append({
'label': label,
'fiscal_position': inv.fiscal_position_id.name or '(none)',
'taxes': line.tax_ids.mapped('name'),
'income_account': f"{line.account_id.code} {line.account_id.name}",
'subtotal': inv.amount_untaxed,
'tax_total': inv.amount_tax,
'total': inv.amount_total,
'partner_tags': [c.name for c in partner.category_id],
})
finally:
env.cr.execute("ROLLBACK TO SAVEPOINT test")
test_invoice("Ontario (HST 13%)",
{'name': 'TEST CUST ON', 'country_id': env.ref('base.ca').id, 'state_id': env.ref('base.state_ca_on').id, 'customer_rank': 1},
'TEST SaaS', 'nexa_coa_setup.pc_saas', 100.0)
test_invoice("US (Zero-rated)",
{'name': 'TEST CUST US', 'country_id': env.ref('base.us').id, 'customer_rank': 1},
'TEST SaaS', 'nexa_coa_setup.pc_saas', 100.0)
test_invoice("Quebec (GST+QST)",
{'name': 'TEST CUST QC', 'country_id': env.ref('base.ca').id, 'state_id': env.ref('base.state_ca_qc').id, 'customer_rank': 1},
'TEST SaaS', 'nexa_coa_setup.pc_saas', 100.0)
test_invoice("Intercompany -> Westin",
{'name': 'Westin Healthcare Inc'},
'TEST Consulting', 'nexa_coa_setup.pc_consulting', 150.0)
for r in results:
print("---")
print(json.dumps(r, indent=2, default=str))