Developer notes
Overview · Installation · Configuration · Usage · FAQ
How the reverse charge is applied
Section titled “How the reverse charge is applied”The add-on never calculates VAT. It switches on CS-Cart’s own tax exemption arithmetic for one calculation of one cart:
calculate_cart_taxes_pre: the decision (Decision::forCart()) is stored in$cart['kv_vat']. When the reverse charge applies, the local$auth['tax_exempt']offn_calculate_cart_content()and$cart['user_data']['tax_exempt']are set toY(the original value is remembered).- Core then drops added taxes and, for the unit price method, takes included taxes out of the product and shipping prices.
calculate_taxes_post: for the subtotal method (where core keeps included taxes in the price for exempt customers) the add-on sets the per-producttax_summary.includedand nets the chosen shipping rate, the same way core does for the unit price method.calculate_cart_post: the cart’stax_exemptflag is restored, so nothing is saved on the customer, the profile or the order (orders.tax_exemptstays as it was).calculate_payment_taxes_pre/_post: the same for payment surcharge taxes.place_order: the decision is stored in?:kv_vat_ordersfor the order and for every Multi-Vendor sub-order.
Validation
Section titled “Validation”Countries: prefixes, normalisation, format patterns, check digits (AT, BE, DE, DK, EE, EL, FI, FR, HR, HU, IT, LU, NL, PL, PT, SE, SI, SK). Check digits only matter when VIES cannot be reached.Vies:POST https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-numberwith the store VAT number as requester (requestIdentifier= consultation number). Errors (actionSucceed: false,errorWrappers[].error) other thanINVALID_INPUTcount as “not reachable”.Hmrc: OAuth client credentials,GET /organisations/vat/check-vat-number/lookup/{vrn}[/{requester}],Accept: application/vnd.hmrc.2.0+json.Checker: cache?:kv_vat_checks(valid: setting, invalid: 1 h, outage: 10 min), per-request memo, log?:kv_vat_logfor every live lookup.
| Table | Contents |
|---|---|
?:kv_vat_checks |
Last answer per (prefix, number) with expiry |
?:kv_vat_log |
Live lookups: date, number, result, error, name, consultation number, context, user, order, company, duration |
?:kv_vat_orders |
Per order: number, buyer and store country, result, outcome, reverse charge, review flag, VIES name/address, consultation number, request date, re-check data |
The number itself is a core profile field (?:profile_fields.field_name = kv_vat_number, section C), stored by core for users and orders.
Endpoints
Section titled “Endpoints”| Dispatch | Area | Purpose |
|---|---|---|
kv_eu_vat_validation.check (GET, JSON, Cache-Control: no-store) |
Storefront | Live check: vat, country → outcome, tone, message, name, reverse_charge. 30 checks per session and hour. |
kv_eu_vat_validation.manage |
Admin | Log page |
kv_eu_vat_validation.check / recheck / recheck_order / mark_reviewed / prune (POST) |
Admin | Manual check, re-checks, review, log pruning |
Hooks used
Section titled “Hooks used”PHP: calculate_cart_taxes_pre, calculate_taxes_post, calculate_cart_post, calculate_payment_taxes_pre, calculate_payment_taxes_post, place_order, get_order_info (adds $order_info.kv_vat), get_orders (filter param kv_vat), delete_order, template_snippet_render_post (document lines), update_company (vendor numbers). All exist with the same arguments in 4.17.2 and 4.21.2.
Templates: storefront checkout:summary, checkout:checkout_totals, orders:order_total (pre), index:scripts, index:styles; admin orders:details_sidebar (pre), orders:totals_content, orders:advanced_search; classic invoices (storefront and admin mail templates) orders:invoice_customer_info, orders:invoice_company_info.
Documents (invoice, order summary)
Section titled “Documents (invoice, order summary)”The lines are appended to the bill_to and company_address snippets automatically. For a custom layout, switch Print … on invoices off and use the document variable kv_vat:
{% if kv_vat.number %}VAT number: {{ kv_vat.number }}{% endif %}{% if kv_vat.reverse_charge %}{{ kv_vat.note }} ({{ kv_vat.consultation }}){% endif %}{% if kv_vat.seller_vat %}Our VAT number: {{ kv_vat.seller_vat }}{% endif %}Fields: number, reverse_charge, note, consultation, status, seller_vat. E-mail templates can use order_info.kv_vat the same way where the order data is available.
Full page cache (4.21)
Section titled “Full page cache (4.21)”The storefront prints only static configuration (field ID, endpoint, texts). The live check is an XHR to a non-cacheable dispatch; the reverse charge lines appear only on checkout and order pages, which are never cached. No ?:storage_data writes.
Development constants
Section titled “Development constants”KV_EUVAT_VIES_URL and KV_EUVAT_HMRC_URL (in local_conf.php, localhost URLs only) point the clients at a local mock for tests.