Business Central calculates tax from Tax Area Codes and Tax Group Codes mapped across customer, vendor and item combinations. That covers straightforward percentage tax. Tiered excise levies, volume bands and non-deductible VAT need AL extension — built on event subscribers and a rate table, never on a hardcoded percentage.

Where the native matrix stops

Misconfigured tax posting groups are expensive in both directions. Under-collect and the authority assesses the shortfall against you with penalties. Over-collect and you have overcharged customers, which is a commercial problem and often a legal one.

RequirementNative Business CentralNeeds AL
Flat percentage by jurisdictionYes — Tax Area / Tax Group matrixNo
Reverse charge and zero-rated exportYes — VAT Posting SetupNo
Tiered or banded excise (volume, sugar content, weight)NoYes — rate table plus calculation subscriber
Non-deductible input VAT allocationPartialUsually — depends on localisation
Line versus header rounding per jurisdictionSingle global settingYes, where rules differ by country

Non-deductible VAT

Some input VAT cannot be reclaimed — entertainment, certain vehicles, particular categories of asset. The error to avoid is treating this as a calculation adjustment. The unclaimable portion is not VAT at all from your books' point of view: it is part of the cost of the thing you bought.

So it has to post to the expense account or capitalise into the asset, with the deductible remainder alone hitting VAT receivable. An implementation that nets it against VAT receivable produces a return that will not agree with the ledger.

Extending without breaking upgrades

The rule that matters more than any other: subscribe to events, do not modify base objects. Business Central updates continuously, and a modified base object turns each update into a merge exercise.

Codeunit 50160 Regional Tax Engine Extension.al
codeunit 50160 "Regional Tax Engine Extension"
{
    Access = Public;
    Subtype = Normal;

    [EventSubscriber(ObjectType::Table, Database::"Sales Line", 'OnAfterAssignHeaderValues', '', false, false)]
    local procedure CalculateTieredExciseTax(var SalesLine: Record "Sales Line"; SalesHeader: Record "Sales Header")
    var
        Item: Record Item;
        TaxMatrix: Record "Regional Excise Setup";
        ExciseAmount: Decimal;
    begin
        if SalesLine.Type <> SalesLine.Type::Item then
            exit;

        if not Item.Get(SalesLine."No.") then
            exit;

        // Check if item attracts special excise levy (e.g., sugary beverages, tobacco, luxury items)
        if Item."Excise Tax Group" <> '' then begin
            if TaxMatrix.Get(SalesHeader."VAT Bus. Posting Group", Item."Excise Tax Group") then begin
                if SalesLine.Quantity > TaxMatrix."Tier Threshold Qty" then
                    ExciseAmount := (SalesLine.Quantity * TaxMatrix."High Rate Per Unit")
                else
                    ExciseAmount := (SalesLine.Quantity * TaxMatrix."Base Rate Per Unit");

                // Inject Custom Excise Tax Line
                SalesLine."Excise Levy Amount" := ExciseAmount;
                SalesLine."Line Amount" := SalesLine."Line Amount" + ExciseAmount;
            end;
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales-Post", 'OnBeforePostSalesDoc', '', false, false)]
    local procedure ValidateTaxRegistrationNumber(var SalesHeader: Record "Sales Header")
    begin
        // Enforce mandatory VAT Registration validation for B2B tax-exempt orders
        if SalesHeader."VAT Bus. Posting Group" = 'B2B-EXEMPT' then begin
            if SalesHeader."VAT Registration No." = '' then
                Error('Tax Audit Error: B2B Tax-Exempt Order %1 requires a valid VAT Registration Number.', SalesHeader."No.");
        end;
    end;
}

Note what the sample does not contain: a number. Every rate is read from a setup table with an effective date, so a legislative change is a data entry task rather than a deployment.

Rounding, which is not a detail

Business Central defaults to nearest-even rounding. Whether rounding is applied per line or once on the document header changes the total on genuinely ordinary invoices, and jurisdictions differ on which is required.

Rounding rules are the most common source of a tax figure that is off by a few units on thousands of documents. Individually trivial, collectively a reconciliation nobody can close.

Controls that shorten an audit

  1. Supplementary tax ledger. Store the exact fractional amount alongside the posted rounded one, so any discrepancy can be explained rather than argued about.
  2. Registration number validation. Verify counterparty tax numbers against the relevant government portal before zero-rating a supply. Zero-rating against an invalid number is your liability, not theirs.
  3. Effective-dated rates. Every rate carries a from-date, so historical documents recalculate correctly and a rate change never rewrites the past.
  4. Periodic tie-out. The tax return total agrees to the sum of the VAT entries for the period, run as a scheduled report and not left until filing time.

What the engineering buys

A tax engine built this way turns filing from a reconstruction exercise into a report. The measurable outcome is not a percentage saved; it is that the numbers on the return come from the ledger without manual adjustment, and that an auditor asking how a figure was reached gets an answer from the system, not from a spreadsheet somebody maintains.