Magento – Automatic Customer Group change based on VAT-ID: Force Magento to check and display message when customer gets to checkout page

customer-groupmagento-1.8taxvalidationvat

I've been scratching my head over this specific problem for few days now. Let's start with basics:

I have 3 Tax Rules:

1. Standard Domestic

  • Name: 21%
  • Customer Tax Class: VAT Standard 21%
  • Product Tax Classes: Taxable Goods, Shipping
  • Tax Rates: VAT Czech, VAT Slovakia, VAT Poland (but all set up to 21% cause we're selling from Czech Republic).
  • Priority: 0
  • Sorting: 0

2. Intra-European Union with UE-VAT Valid Verfication

  • Name: 0%
  • Customer Tax Class: VAT UE – Zero %
  • Product Tax Classes: Taxable Goods, Shipping
  • Tax Rates: VAT UE-PL, VAT UE-SK
  • Priority: 0
  • Sorting: 0

3. Intra-European Union with UE-VAT INVALID VERIFICATION (Bad VAT ID or VEIS Server unavailable)

  • Name: 21% ERROR
  • Customer Tax Class: VAT Standard – 21% VATUE VALIDATION ERROR, VAT Standard – 21% VATUE INVALID ID,
  • Product Tax Classes: Taxable Goods, Shipping
  • Tax Rates: VAT Czech, VAT Slovakia, VAT Poland
  • Priority: 0
  • Sorting: 0

And I have 4 customer groups:

  1. VAT Payer
  2. VAT UE 0%
  3. VAT UE – Validation Error
  4. VAT UE – Invalid ID

Create New Account Options

Create New Account Options

Registration is completely disabled in shop. Only administrator can add anything about customer to the database. Same goes for editing accounts. Simply put: customer can only make orders.

Now, when customer i created from an Administrator Panel, the VAT ID is being validated and customer is being saved into correct customer group.

I've made a 'hack' in templates files (/template/checkout/onepage.phtml, /template/checkout/cart.phtml, template/customer/account/dashboard.phtml) which looks like this:

    <?php if(Mage::getSingleton('customer/session')->isLoggedIn()){
  // Get group Id
  $groupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
  //Get customer Group name
  $group = Mage::getModel('customer/group')->load($groupId);
  echo $group->getCode();} ?>

So I could see what happening with customer group.
Now when that customer is browsing shop – everything's fine – prices are with tax set to 0% from group VATUE-0%. In account dashboard my hack is displaying the right customer group : 22 VAT UE 0% (22 is ID).

But when that customer goes into Cart or Checkout page:
"VAT UE – VALIDATION ERROR", so I've thought maybe the soap's messing something up…but no luck – simples VIES script is checking real vat ids in correct way on these pages.

I've found some topic on MagentoCommerce board, where people said to edit /code/local/Mage/Customer/Helper/Data.php around line 617 into:

protected function _createVatNumberValidationSoapClient($trace = false) {
        $options = array( 'soap_version'=>SOAP_1_1,
            'exceptions'=>true,
            'trace'=>1,
            'cache_wsdl'=> WSDL_CACHE_NONE,
            'user_agent' => 'Mozilla',
            'proxy_port' => 80);
        return new SoapClient(self::VAT_VALIDATION_WSDL_URL, $options); }

But without no luck either. So I've started to checking WSDL urls, even tried to connect by a proxy – no luck (still backend is validating, but after customer going into checkout the customergroup is somehow changed into validation error [while in backend still appearing as VAT UE 0%

Do you have any ideas is it Magento Core Related Bug or is it just something with misconfiguration? Oh I've almost forgot: Magento 1.8.1.0

P.S. Shouldn't Magento display frontend message while validating VAT-ID on checkout page? (for curious look into: public function getVatValidationUserMessage($customerAddress, $customerGroupAutoAssignDisabled, $validationResult))

Forward thanks for any help! I hope I've put in here every information that's necessary to descripe this particular problem.

Have a nice day everyone!
Tadeusz

EDIT

Okay, Validation's working 100% (well not 100% but it's process requirements that need to be as they are) now but there are still some flaws with the VAT Validation Message.

It's added to customer session only after placing order which's caused by a function checkVatNumber() – which take place after choosing Billing Address on checkout.

So the function getVatValidationUserMessage() is really adding that message into customer session but it's displayed after placing order – because message block can not be refreshed without leaving page.

So I'm thinking – if there's possibility to run those functions but before loading whole Checkout page – so it would add that message straighly into Checkout Page. Honestly [Edit: I do know, default setting of Magento is that you can have multiple Billing Addresses, were some of them may be VAT 0 rate, and some of them maybe domestic:
Example: Someone has left his country, made a new firm abroad, but got back into his country and made a firm in his country of origin – so he's got two firms but based on one account in Magento.]

But the main problem's, that he'll see prices in catalog based on his last order!

New questions based on this all things:

  1. Is it possible to make Magento checkVatNumber() before loading Checkout page so the $message is displayed right after opening Checkout Page?

  2. If upper is not possible, how to make some Ajax/Json checking in session for new messages and then append to bodyHTML without page refreshing?

EDIT2

Right now message is added to session and displayed to customer, but requires Checkout/onepage to be refreshed to display it – that's caused by Magento message utilizing system (it's init to layout on page request as far as I understand it).

So the thing that I want to do now is:
Change checkout/onepage loading so it first runs function responsible for vat validation, and then init layout and load whole page. I know that will increase loading time but it's necessary in my case…

EDIT3

I've found that function getVatValidationUserMessage() is running only on saving order (last placing order button) – that's why customer gets session message about validation only after placing order.

Luckily function checkVatNumber() is running everytime someone gets into checkout/onepage . So I'm trying to figure out, how to move VatValidationUserMessage function into checkVatNumber function.

Functions getCustomerGroupIdBasedOnVatNumber, checkVatNumber are started inside /customer/model/observer.php in public function afterAddressSave. Which's paradox…how checkvatnumber can be adding message to session (and displaying without page reload), while it's started AFTER saving address? I'm having feeling that it's some Magento-Core related bug.

EDIT 4

OK, I've made a simple hack in code/local/Mage/Customer/Helper/Data.php in public function getCustomerVatClass (around line 540):

{
        $vatClass = self::VAT_CLASS_DOMESTIC;
    } elseif ($isVatNumberValid) {
        $vatClass = self::VAT_CLASS_INTRA_UNION;
    } else {
        $vatClass = self::VAT_CLASS_INVALID;
    }

    if (!$vatValidationResult->getRequestSuccess()) {
        $vatClass = self::VAT_CLASS_ERROR;
    }

into:

{
        $vatClass = self::VAT_CLASS_DOMESTIC;
        $vatMessage='Sprzedaz krajowa';
        Mage::getSingleton('customer/session')->addNotice($customerCountryCode.$vatNumber .' '. $this->__($vatMessage));
    } elseif ($isVatNumberValid) {
        $vatClass = self::VAT_CLASS_INTRA_UNION;
        $vatMessage='Your VIES VAT Number has been verified. 0% tax rate applied.';
       Mage::getSingleton('customer/session')->addSuccess($customerCountryCode.$vatNumber .' '. $this->__($vatMessage));
    } else {
        $vatClass = self::VAT_CLASS_INVALID;
        $vatMessage='Your UE VAT Number is invalid! Please verify your account information and contact our customer support.';
        Mage::getSingleton('customer/session')->addError($customerCountryCode.$vatNumber .' '. $this->__($vatMessage));
    }

    if (!$vatValidationResult->getRequestSuccess()) {
        $vatClass = self::VAT_CLASS_ERROR;
        $vatMessage='There was an error during validation of your UE VAT Number. Probably the VIES verification services are currently unavailable. Normal tax rate has been applied.';
        Mage::getSingleton('customer/session')->addError($customerCountryCode.$vatNumber .' '. $this->__($vatMessage));
    }
    return $vatClass;
}

I thought it's working fine, but it's adding the message into customer session on each OPC step so after checkout we end up with 4-5 messages on frontend. is there a way to check if session contains same error like we want to add?

After placing order there are 7 messages displayed from customer/session but when I go with

<?php echo Mage::getSingleton('customer/session')->getMessages()->count(); ?>

But above code is counting message types so if we have one success and one warning message type we will get count equal to 2.

So now I'm thinking, how to edit below messages.phtml so it would get specific message from array? Or how to save message into session so it would be always saved into one place in array?

   <?php if($this->getMessagesBlock()->getMessageCollection()->count()): ?>
     <?php foreach($this->getMessagesBlock()->getMessageCollection()->getItems() as $message): ?>
   <div class="alert alert-<?php echo $message->getType()?> fade in">
    <a class="close" data-dismiss="alert">×</a>
    <h4 class="alert-heading">
    <?php echo $this->__('Notice!') ?></h4>
    <?php echo $message->getCode()?>
</div>
<?php endforeach;?>
<?php endif; ?>
<?php $this->getMessagesBlock()->getMessageCollection()->clear(); ?>

Best Answer

Manage this using observer using function extend.

if (Mage::getSingleton('customer/session')->isLoggedIn()){
            $customer = $observer->getEvent()->getCustomer();
            if( // vat id condition):
                    $customerHelper = Mage::helper('customer');
                    $defaultGroupId = $customerHelper->getDefaultCustomerGroupId($customer->getStore());
                    if (!$customer->getDisableAutoGroupChange() && $customer->getGroupId() != $defaultGroupId) {
                        $customer->setGroupId($defaultGroupId);
                        $customer->save();
                    }
            endif;
        }
Related Topic