Preventing PO Box shipping addresses
24 Aug 2009, by Denis Margetic
3 Comments · Posted in Magento

    Recently, I wrote a blog post about preventing PO box customer addresses being registered at checkout. Following on from that post, I was asked a rather sensible question: "is it possible to disallow PO boxes for shipping, but allow them for billing?" The answer is yes, but it does require a few more modifications to Magento.

    As mentioned in the original post, the if statements with regular expressions required to block PO boxes and locked bags are as follows:

    if (preg_match("/p\.* *o\.* *box/i", $this->getStreet(1))) {
      $errors[] = $helper->__('We cannot ship to PO boxes.');
    }

    and

    if (preg_match("/locked *bag/i", $this->getStreet(1))) {
      $errors[] = $helper->__('We cannot ship to locked bags.');
    }

    Unlike in my original post, we need to add these in a new validation function, which we will only use for validating shipping addresses. In the file:

    magento/app/code/core/Mage/Customer/Model/Address/Abstract.php

    simply make a copy of the validate() function, name it something like validate_pobox() and insert the above code as before. The result should look something like this:

    public function validate_pobox()
    {
        $errors = array();
        $helper = Mage::helper('customer');
        $this->implodeStreetAddress();
        if (!Zend_Validate::is($this->getFirstname(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter first name.');
        }
    
        if (!Zend_Validate::is($this->getLastname(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter last name.');
        }
    
        if (!Zend_Validate::is($this->getStreet(1), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter street.');
        }
      
        if (preg_match("/p\.* *o\.* *box/i", $this->getStreet(1))) { 
        	$errors[] = $helper->__('We cannot ship to PO boxes.');
        }
    
        if (preg_match("/locked *bag/i", $this->getStreet(1))) {
            $errors[] = $helper->__('We cannot ship to locked bags.');
        }
    
        if (!Zend_Validate::is($this->getCity(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter city.');
        }
    
        if (!Zend_Validate::is($this->getTelephone(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter telephone.');
        }
    
        if (!Zend_Validate::is($this->getPostcode(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter zip/postal code.');
        }
    
        if (!Zend_Validate::is($this->getCountryId(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter country.');
        }
    
        if ($this->getCountryModel()->getRegionCollection()->getSize()
               && !Zend_Validate::is($this->getRegionId(), 'NotEmpty')) {
            $errors[] = $helper->__('Please enter state/province.');
        }
    
        if (empty($errors)) {
            return true;
        }
        return $errors;
    }

    Now that we have the necessary validation function, we need to ensure that it is used instead of the default function in the checkout module. The file to be modified is this one:

    /magento/app/code/core/Mage/Checkout/Model/Type/Onepage.php

    In the Onepage.php file we need to modify three functions:

    • saveBilling
    • saveShipping
    • validateOrder

    The first function requires a small block of code to be added, while the last two just need the instance of validate() changed to validate_pobox(). To avoid ambiguities, I have attached the modified Onepage.php file. Simply download the file and search for 'TODO', as I have wrapped all three of the required changes in comments that start with the word 'TODO'.

    Finally, the standard warning about modifying core files applies here as well. Rather than directly modifying core files make copies of the affected files before modifying them and place them in the local directory.


    Magento Compatibility

    Post originally written for Magento version: 1.3.2.3
    Tested with Magento version(s): 1.3.2.3

    Comments

    Thanks for this post! It really should be a lot simpler to things like this in Magento.

    In my case, I also added a pattern check against a 2nd line of street address:

    if( preg_match("/p\.* *o\.* *box/i", $this->getStreet(1))
    || preg_match("/p\.* *o\.* *box/i", $this->getStreet(2)) )
    {
    $errors[] = $helper->__('We cannot ship to PO boxes.');
    }
    Comment by MXWest - 10 Sep 2009 2:46:30 AM
    WOW! Great write-up! Your tutorial was super-easy to follow and very thorough (especially compared to other Magento tutorials out there).

    Thanks so much! That was terrific.
    Comment by Brady - 19 May 2010 6:32:55 AM
    Is it possible to disallow PO boxes based on shipping preferences? Say, allow shipping to PO boxes if client chooses to ship through USPS, but pop up the error message if they choose UPS or FedEx shipping?
    Comment by Chris - 12 Aug 2010 1:25:58 AM
    Comments are closed for this post