2.0.0¶
Released: TBD
Highlights¶
- Tax-rate GL accounts now drive the books. A tax rate's accounts are no longer inert placeholders — supplier and customer invoices post their ITBMS to the account configured on the rate, and customer invoices with retention now record the ITBMS the client withheld as a recoverable credit.
- Tax-account naming fixed. The confusing
accountPayable/accountReceivable/withholdingfields on a tax rate were renamed to say what they are: output tax, input tax, and a directional withholding pair.
Added¶
- Sales-side ITBMS retention posting. When a client is a withholding agent (
invoice_retention+ acodigo_retencion), the customer invoice now nets Accounts Receivable by the retained ITBMS and debits it to the rate's withholding asset account (ITBMS retenido — a recoverable credit). See Tax-Rate GL-Account Wiring. - Directional withholding accounts on
TaxRate.withholdingPayableAccountId(you withheld as agent → liability) andwithholdingAssetAccountId(withheld from you → asset) replace the singlewithholdingAccountId. - Automatic account defaults. Creating a tax rate without explicit accounts now defaults them via
get_or_create_account(output/withholding-payable →TAX_PAYABLE; input/withholding-asset →OTHER_CURRENT_ASSET). - Accounting Placeholder Audit — a documented sweep of accounting fields/enums/methods that are declared but unconsumed.
Changed¶
- Transaction-time ITBMS account sourcing. Customer-invoice and supplier-invoice ledger postings now source the tax line's GL account from the line's tax rate (
output_tax_account_id/input_tax_account_id), falling back toclient.sales_taxes_account_id/supplier.tax_account_idso lines without a rate still post. - Breaking —
TaxRateGraphQL fields renamed.accountPayableId→outputTaxAccountId,accountReceivableId→inputTaxAccountId;withholdingAccountIdremoved in favor of the pair above. Resolver fieldsaccountPayable/accountReceivable/withholding→outputTaxAccount/inputTaxAccount/withholdingPayableAccount/withholdingAssetAccount. All four account inputs are now optional on create/update.
Fixed¶
- Supplier input-tax account mis-classification. New suppliers seeded their tax account as
TAX_PAYABLE(a liability) even though purchase ITBMS is debited as a recoverable asset. It now seeds asOTHER_CURRENT_ASSET. (supplier_invoice_service.py, supplier_tabular_service.py) updateTaxRateno longer nulls configured accounts. Update only overwrites an account when a non-null value is supplied.
Migrations¶
rename_tax_rate_account_columns(down_revision = add_dates_to_items) — renamesaccount_payable_id→output_tax_account_id,account_receivable_id→input_tax_account_idontax_rates; dropswithholding_account_id; addswithholding_payable_account_id+withholding_asset_account_id(+ FKs).upgradeanddowngradeboth implemented; offline SQL verified in both directions. Data-preserving rename — no backfill required.
Frontend impact¶
- The
TaxRatetype andTaxRateCreateInput/TaxRateUpdateInputchange (breaking): accountPayableId→outputTaxAccountId,accountReceivableId→inputTaxAccountIdwithholdingAccountIdremoved →withholdingPayableAccountId+withholdingAssetAccountId- resolver fields →
outputTaxAccount/inputTaxAccount/withholdingPayableAccount/withholdingAssetAccount - all four account inputs are now optional; the backend defaults them on create, so client-side defaulting can be dropped.
Versioning notes¶
- Bumped with
uv run python scripts/bump_version.py 2.0.0 --changelog-stub. MAJOR because of the breakingTaxRateGraphQL field rename — deploy the backend and frontend together, and apply therename_tax_rate_account_columnsmigration as part of the release.