PayPal Sandbox “UTF-8 email addresses are not currently supported”

This is probably very clearly stated in the directions but it made me a little nuts because I was working in Safari and Chrome at the same time. One was logged in to my developer account and the other to … nothing.

So it turns out that when you are testing you must be signed into your development account (for example, in another tab) before you can use your test buyer. Shouldn’t I have known this? I probably did already know it, and just forgot, it’s not often that I go back to revisit the Sandbox.

Hope it helps if you’re having trouble!

Magento API: Select Orders by Date Range

Here’s snippet of code I was able to use to get all of yesterday’s orders. You can see more variations for the use of DateTime here. I also wrote a front end to allow a selection of dates, but you can figure that out. This was the hard part to me. How the heck do I pass the from and to dates to Magento’s sales_order.list call?

Also note that Magento internally store dates and times in UTC. So I have to convert to that offset to get my orders in my local time. time_local_to_utc is a little function I wrote to do that. Conversely, time_utc_to_local converts it back. (Code later in this post).

Remember, much of the code I publish here is very specific for a particular implementation. This code is designed to be able to pull back all payment information into a spreadsheet for an accounting department. This is not a generic solution to a generic Magento problem. Rather, I intended this to help other folks get a start on pulling back orders by date!

$day = new DateTime();
$day->modify( "-1 day" );
 
$fromDate = $day->format("Y-m-d 00:00:00");
$toDate = $day->format("Y-m-d 23:59:59" );
 
$utc_from=time_local_to_utc($fromDate);
$utc_to=time_local_to_utc($toDate);
 
$proxy = new SoapClient('YOURSITE/api/soap/?wsdl');
$sessionId = $proxy->login('YUOUR_LOGIN', 'YOUR_PASS');
$order_headers = $proxy->call($sessionId, 'sales_order.list',
        array(
            array(
                'created_at'=>
                    array(
                        'from'=>$utc_from,
                        'to'=>$utc_to
                    )
                )
            )
        );
$howManyOrders = count($order_headers);

Here are the 2 time functions. They could certainly be made more general and really should be refactored (pass in “to” and “from” zones…), but you get the idea. And maybe there’s something to be said for the inline main code being simple to read.

function
time_local_to_utc($date) {
    $dt = new DateTime($date, new DateTimeZone("America/New_York"));
    $dt->setTimezone(new DateTimeZone("UTC"));
    return( $dt->format("Y-m-d H:i:s") );
}
 
function
time_utc_to_local($date) {
    $dt = new DateTime($date, new DateTimeZone("UTC"));
    $dt->setTimezone(new DateTimeZone("America/New_York"));
    return( $dt->format("Y-m-d H:i:s") );
}

Magento and jQuery: Ajax Add to Cart Button

Introduction

This post describes adding an Ajax add-to-cart feature on my Magento’s product view page. This was an interesting exercise, and I learned a lot from a number of different sources. I combined their collected wisdom, and applied it as described here. Some of that wisdom was my own. You’ll need to bring in jQuery and jQuery UI as described in my previous post, Magento and jQuery.

Goal

Provide add to cart button that will give us the familiar ajax modal feel while it’s working, and then let us know it’s added the item. Then, present the user with the option of staying on the current page, or proceeding to the checkout page.

Prep Work I: Reflect the Correct number of Items in “My Cart”

In order for our work to correctly update the “My Cart” link in the header, I needed to add identification information to that section. You can see in the highlighted lines of code from my template/page/html/header.phtml. I applied a style to the whole thing in case the designers wanted to improve its appearance. And then I added div around only the number itself:

template/page/html/header.phtml

<div class="up-top-cart-status">
    <a href="<?php echo $this->getUrl('checkout/cart'); ?>"><img src="<?php echo $this->getSkinUrl(); ?>images/cart-icon.png" alt="Cart" />My Order
        <?php
    $cart = Mage::getModel('checkout/cart')->getQuote()->getData();
    $cart_qty = (!empty($cart['items_qty'])) ? $cart['items_qty'] : 0;
    printf('(<div style="display:inline" id="up-top-number-in-cart">%d</div> Items)', $cart_qty);
          ?>
     </a>
</div>

Prep Work II: Build the php Code for the Ajax Call

This code was based on work found at iFuel Interactive’s Adding to the Cart with a jQuery Ajax Call in Magento. I’ve modified the code to use php’s json_encode() function. I believe that, as it’s php, we should work in php’s milieu instead of handcrafting the JSON ourselves.

Of special note, I am calling getSummaryCount after I’ve saved the cart. This call did not yield the correct number of items in the cart until after I’d saved it. This way, I’m able to put the current number of items into the JSON returned back to the caller.

/mxwest_atc.php

<?php
include_once 'app/Mage.php';
Mage::app();
try{
    $result = array();
    // usage /mxwest_atc.php?product_id=838qty=1

    if(!isset($_GET['sku'])) {
        $sku = '';
    }
    else {
        $sku = $_GET['sku'];
    }

    if(!isset($_GET['product_id'])) {
        $product_id = '';
    }
    else {
        $product_id = $_GET['product_id'];
    }
    if(!isset($_GET['qty'])) {
        $qty = '1';
    }
    else { 
        $qty = $_GET['qty'];
    }

    if ($sku != ""){
        $product_id = Mage::getModel('catalog/product')->getIdBySku("$sku");
        if ($product_id == '') {
            $session->addError("<strong>Product Not Added</strong>The SKU you entered ($sku) was not found.");
        }
    }

    $request = Mage::app()->getRequest();
    $product = Mage::getModel('catalog/product')->load($product_id);
    $session = Mage::getSingleton('core/session', array('name'=>'frontend'));
    $cart = Mage::helper('checkout/cart')->getCart();

    $cart->addProduct($product, $qty);

    $session->setLastAddedProductId($product->getId());
    $session->setCartWasUpdated(true);

    $cart->save();

    $items_in_cart = Mage::helper('checkout/cart')->getSummaryCount();

    $result['result']="success";
    $result['message']="Added!";
    $result['items_in_cart'] = "$items_in_cart";

    echo json_encode($result);
}
catch (Exception $e) {
    $result['result'] = 'error';
    $result['message'] =  $e->getMessage();
    echo json_encode($result);
}
?>

Add to Cart: Pulling it All Together

template/catalog/product/view/addtocart.phtml

Here, we are setting up the input fields and naming the various input elements correctly. In my case, “minimum quantity” also means “quantity multiplier.” That is, I must order a multiple of minimum quantity. If minimum quantity is 4, I must order 4, 8, 12 or so on. My code will round the order up. If you tried to order 3, I’d round you up to 4. Your code might not need this. If that’s the case, just don’t use the qtyM variables, and don’t call upFixQtyMult.

template/catalog/product/view/addtocart.phtml, Part 1 – php

Of note here is that I am uniquely identifying the qty field; this isn’t necessary when I’m using this code for only 1 item. But if this code is used multiple times on a page, I’ll need unique identifiers. “A-ha!” I here you say “- the SKU isn’t unique!” Calm down. It’s not finished yet.

The UI experience will be encapsulated in the div id dialog. The subsequent jQuery UI code will use that div to keep the user up to date on what’s happening. See line 17, highlighted.

<?php
    $_product = $this->getProduct();
    $_myProductSku = $_product->getSku();
    $_mxwMinQty = $this->getMinimalQty($_product);
?>
<?php $buttonTitle = $this->__('Add to Cart'); ?>
<?php if($_product->isSaleable()): ?>
    <div class="add-to-cart">
        <?php if(!$_product->isGrouped()): ?>
        <label for="qty"><?php echo $this->__('Qty:') ?></label>
        <input type="text" size="4" name="qty" id="qty<?=$_myProductSku?>" maxlength="4" value="<?=$_mxwMinQty?>" title="<?php echo $this->__('Qty') ?>" class="input-text qty" />
        <input type="hidden" id="qtyM<?=$_myProductSku?>" value="<?=$_mxwMinQty?>" />
        <?php endif; ?>
        <br /><a href="#"><img src="<?php echo $this->getSkinUrl(); ?>images/buy-now-btn.png" alt="Buy Now" onclick="addItemToCart('<?=$_myProductSku?>');" alt='<?=$buttonTitle ?>' /></a>
        <?php echo $this->getChildHtml('', true, true) ?>
    </div>
<div class="ui-widget" id="dialog" title="Adding to Cart"></div>

template/catalog/product/view/addtocart.phtml, Part 2 – the Javascript

jQuery here is represented by $jQ. For more details on how we arrived at that nomenclature, please see my earlier post Magento and jQuery, which explains how I brought jQuery in in its noConflict() mode. That post also describes the reasoning behind the “ui-xxx” styling – that’s what jQuery UI’s ThemeRoller produces. Again, please consult the previous post for those details.

This code is pretty straightforward. Call the mxwest_atc.php script. It will return a JSON encoded response in (duh) “response.” The fancy bit of updating the header for number of items in cart is highlighted at lines 20 and 21. (You did remember to do the work described in “Prep Work I”, above, right?). I used the variable “o” as shorthand for object. Although I generally prefer more descriptive variable names, I figured the 2 lines here were comprehensible enough that I could shorthand it.

<script type="text/javascript">
function
addItemToCart(sku) {
    $jQ("#dialog").dialog('destroy');
    $jQ("#dialog").html("<center>Adding ...<p><img src='<?=$this->getSkinUrl()?>/images/up-ajax-loader.gif'></p></center>");
    $jQ("#dialog").dialog({show: 'scale', hide: 'scale', modal: 'true'});

    var qty_id = "#qty"+sku.toString();
    var qty = $jQ(qty_id).val();

    var qtyM_id = "#qtyM"+sku.toString();
    var qtyM = $jQ(qtyM_id).val();

    qty = upFixQtyMult(parseInt(qty),parseInt(qtyM));

    var cart_parms = "sku=" + sku + "&qty=" + qty;
    var myUrl = "<?=Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);?>/mxwest_atc.php?"+cart_parms;
    var jqhxr = $jQ.ajax({ url: myUrl })
        .success( function(response){
            o = $jQ.parseJSON(response);    
            $jQ("#up-top-number-in-cart").html(o.items_in_cart);
            $jQ("#dialog").html("<span class=\"ui-icon ui-icon-info\"></span>Thanks! " + sku + " was added to your cart." );
            $jQ("#dialog").addClass("ui-state-highlight ui-corner-all");
            $jQ("#dialog").dialog({hide: 'scale',
                buttons: {
                    "Keep Shopping": function() { $jQ(this).dialog("close"); },
                    "Checkout": function() { $jQ(this).dialog("close"); window.location = "<?=Mage::getUrl('checkout/cart', array('_secure' => true));?>"; }
                }
            });
        })
        .error( function() {
            $jQ("#dialog").html("<span class=\"ui-icon ui-icon-alert\"></span>Sorry, something bad happened. " + sku + " not added.");
            $jQ("#dialog").addClass("ui-state-error ui-corner-all");
            $jQ("#dialog").dialog({ buttons: { "Ok": function() { $jQ(this).dialog("close"); } } });
        });
}
function
upFixQtyMult(qty,qtyM) {
    var m = +qtyM;
    var q = m;
    if(isNaN(qty)) return +m;
    q = +qty;
    if( q <= m ) return m;
    return +((m<=1)?q:(q+(m-(q%m))));
}
</script>

For completeness sake … let’s close that php if!

<?php endif; ?>

End Note

Hope this helps! Magento is incredibly feature-rich, but I also find it incredibly dense to penetrate. I think that much of the User Experience still needs to abstracted out of php and back into jQuery UI (or similar) to improve the User Experience. There are many parts of the code that make me scratch my head. A head full of headaches at times. Hopefully, though, I helped shed a little light on using this cantankerous rascal in a more effective way. Let me know what you think!

Magento: Prevent Entry of PO Boxes for Shipping Address

Background

Pretty simple, really. We use UPS for shipping, and UPS doesn’t deliver to P.O. Boxes. Period.

Solutions for Magento, courtesy Fontis

I found this solution at fontis for preventing P.O. Boxes in shipping addresses. They offer a solution that works perfectly well. So review that first, then come back here. You’ll see that they change up Customer/Model/Address/Abstract.php and Checkout/Model/Type/Onepage.php. They’ve got it covered over there, no sense repeating here. However, I will offer one change to their solution.

One Small Change Suggested

I’m a stickler for re-using code, and a double-stickler for never copying code, which the fontis solution calls for. So I changed the validate_pobox() function they suggested:

 
public function validate_pobox()
{
    /*
      * First, call the original 'validate()' function. No need to repeat
      * all that code, just call it! If the return is boolean 'true', all is
      * well so far. Otherwise, I get an array of $errors.
      */
    if ( ($errors = $this->validate()) == true ) {
        /*
          * If validate was OK, I have to allocate an array for $errors;
          * if validate had failed, $errors would already be an array.
          */
        $errors = array();
    }
    $helper = Mage::helper('customer');
 
    /*
      * Here's the regular expression offered up by fontis. Thank
      * goodness for that regex's make my head hurt.
      */
    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.');
    }
    if( empty($errors) ) {
        return true;
    }
    return $errors;
}