We have a single page checkout where the items are selected and addressed added before going to a cart summary page showing amount owed and tax due.

Was confused as to why certain codes were not working (checking validation against the service at https://ec.europa.eu/taxation_customs/vies/vatResponse.html) and realised the Craft Commerce submission requires the country ISO code as a prefix, eg a UK submission 166211234 needs to be GB166211234. Similarly dots and spacesm, etc need to be stripped out. Unless these are in the correct format relevant rules (eg do not add VAT if valid VAT tax record is added will not kick in).

So as a means for preparing this data thought could tap into an event to update this value. The Addresses::EVENT_BEFORE_SAVE_ADDRESS event won't work as the update cart method/action saves the address after adding the line items and relevant calculations are made.

So then looked into the LineItems::EVENT_POPULATE_LINE_ITEM event so can theoretically fetch and update the address associated with the cart/line item being saved (we are only ever adding one item to the cart at a time. If an item already exists in the cart then that is removed first.

The following code looked promising (would ideally like to limit to EU tax zone but for now assume all sales are EU):

    // get line item
    $lineItem = $event->lineItem;
    // get order
    $order = $lineItem->order;
    // get billing address
    $billingAddress = $order->billingAddressId;
    // get billing address by ID
    $address = craftCommerce::getInstance()->getAddresses()->getAddressById($billingAddress);
    // get billing address tax ID    
    $taxId = $address->businessTaxId; 
    // get billing address country ID    
    $countryId = $address->countryId;
    // get country ISO    
    $country = craftCommerce::getInstance()->getCountries()->getCountryById($countryId);
    $countryIso = $country->iso;
    // strip non-alphanumeric characters from tax ID
    $cleanTax = preg_replace("/[^A-Za-z0-9 ]/", '', $taxId);
    // specify new, ideal tax ID
    $newTax = $countryIso . $cleanTax;
    // check if tax is specified, is not already optimised if not already changed
    if ($cleanTax !== '' && strpos($cleanTax,$countryIso) === false && $address->businessTaxId != $newTax) $address->businessTaxId = $newTax;                    
    // save the new address
    craftCommerce::getInstance()->getAddresses()->saveAddress($address, false);

However, whilst this saves the new address it doesn't update the existing one.

Any thoughts? Am I doing about this completely the wrong way. Would rather than do this in the front-end JS if at all possible.



Craft Craft Commerce 3.1.12

1 Answer 1


Probably best to just update the address business tax ID if it is in the wrong format automatically for them.

Event::on(Order::class, Order::EVENT_BEFORE_SAVE, function(\craft\events\ModelEvent $event) {
    /** @var Order $order */
    $order = $event->sender;
    if ($order->getShippingAddress() && $order->getShippingAddress()->businessTaxId) {
        $newTaxId = "AU".$order->shippingAddress->businessTaxId; // transform this into the right format based on address country (if it is not already)
        $address = $order->shippingAddress;
        $address->businessTaxId = $newTaxId;
        $order->setShippingAddress($address); //  address will save when order saves.
  • Great, thanks Luke Jul 28, 2020 at 8:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.