Magento – Shipping email ignored when API sends tracking number only if custom php present

apimagento-1.9shipment-trackingshipping-methodstransactional-mail

I have played with this even further and found the issue to be even more simple that what was previously presented. Please read all to get the gist of the issue. I wish to mention here that only the inclusion of a simple "href" is even causing the same error. Here is an example of the code causing the same problem described below.

This is the entire custom email/order/shipment/track.phtml file as modified with the added usps link.

<?php $_shipment=$this->getShipment() ?>
<?php $_order=$this->getOrder() ?>
<?php if ($_shipment && $_order && $_shipment->getAllTracks()): ?>
<table cellspacing="0" cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;">
    <thead>
        <tr>
            <th align="left" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Shipped By') ?></th>
            <th align="center" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Tracking Number') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php $i=0; foreach ($_shipment->getAllTracks() as $_item): $i++ ?>
        <tr <?php echo $i%2?'bgcolor="#eeeded"':'' ?>>
            <td align="left" valign="top" style="padding:3px 9px">United States Postal Service</td>            
            <td align="center" valign="top" style="padding:3px 9px"><a href="https://tools.usps.com/go/TrackConfirmAction_input?origTrackNum=<?php echo $_item->getNumber() ?>"><?php echo $_item->getNumber() ?></a></td>     
        </tr>
    <?php endforeach ?>
    </tbody>
</table>
<?php endif; ?>

This is the original track.phtml file found in base/default.

<?php $_shipment=$this->getShipment() ?>
<?php $_order=$this->getOrder() ?>
<?php if ($_shipment && $_order && $_shipment->getAllTracks()): ?>
<table cellspacing="0" cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;">
    <thead>
        <tr>
            <th align="left" bgcolor="#d9e5ee" style="padding:3px 9px"><?php echo $this->__('Shipped By') ?></th>
            <th align="center" bgcolor="#d9e5ee" style="padding:3px 9px"><?php echo $this->__('Tracking Number') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php $i=0; foreach ($_shipment->getAllTracks() as $_item): $i++ ?>
        <tr <?php echo $i%2?'bgcolor="#eeeded"':'' ?>>
            <td align="left" valign="top" style="padding:3px 9px"><?php echo $_item->getTitle() ?></td>
            <td align="center" valign="top" style="padding:3px 9px"><?php echo $_item->getNumber() ?></td>
        </tr>
    <?php endforeach ?>
    </tbody>
</table>
<?php endif; ?>

ORIGINAL MESSAGE:

We use a transactional email template for shipping notifications sent to customers when their order has shipped. The template contains the code below to insert the track/phtml block to add the tracking number with URL in the message.

{{block type='core/template' area='frontend' template='email/order/shipment/track.phtml' shipment=$shipment order=$order}}

Inside track.phtml, we added custom php code to wrap the tracking number is a hyperlink. When entering the tracking number manually and selecting the carrier, we have no problem. The t/n arrives as an active hyperlink. The title is, of course, automatically selected when the carrier is chosen from the drop-down box.

<?php $_shipment=$this->getShipment() ?>
<?php $_order=$this->getOrder() ?>
<?php if ($_shipment && $_order && $_shipment->getAllTracks()): ?>
<table cellspacing="0" cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;">
    <thead>
        <tr>
            <th align="left" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Shipped By') ?></th>
            <th align="center" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Tracking Number') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php $i=0; foreach ($_shipment->getAllTracks() as $_item): $i++ ?>
        <tr <?php echo $i%2?'bgcolor="#eeeded"':'' ?>>
            <td align="left" valign="top" style="padding:3px 9px"><?php echo $_item->getTitle() ?></td>
                <?php if ($_item->getCarrierCode()=='usps'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="https://tools.usps.com/go/TrackConfirmAction_input?origTrackNum=<?php echo $_item->getNumber() ?>"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getCarrierCode()=='fedex'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="http://www.fedex.com/fedextrack/index.html?tracknumbers=<?php echo $_item->getNumber() ?>"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getCarrierCode()=='ups'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="http://wwwapps.ups.com/WebTracking/track?HTMLVersion=5.0&loc=en_US&trackNums=<?php echo $_item->getNumber() ?>&track.x=Track"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getCarrierCode()=='dhl'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><?php echo $_item->getNumber() ?></td>              
                <?php else: ?>
            <td align="center" valign="top" style="padding:3px 9px"><?php echo $_item->getNumber() ?></td>
                <?php endif; ?>
                <?php endif; ?>
                <?php endif; ?>
                <?php endif; ?>     
        </tr>
    <?php endforeach ?>
    </tbody>
</table>
<?php endif; ?>

We started using a third-party shipping service called ShippingEasy. They automatically return the tracking number to Magento through an API. They also change the title, not the carrier, to contain the name ShippingEasy and a unique transaction number.

Here is the problem. For some reason, the track.phtml block is completely ignored when ShippingEasy delivers the t/n through the API. Their system properly selects the carrier as "usps." The transactional email is sent just fine, but with no tracking number and no table. So, we altered the code in track.phtml to getTitle and look for "ShippingEasy." See below.

<?php $_shipment=$this->getShipment() ?>
<?php $_order=$this->getOrder() ?>
<?php if ($_shipment && $_order && $_shipment->getAllTracks()): ?>
<table cellspacing="0" cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;">
    <thead>
        <tr>
            <th align="left" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Shipped By') ?></th>
            <th align="center" style="padding:3px 9px; background:rgb(242,248,228); border-bottom:1px solid #bebcb7;"><?php echo $this->__('Tracking Number') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php $i=0; foreach ($_shipment->getAllTracks() as $_item): $i++ ?>
        <tr <?php echo $i%2?'bgcolor="#eeeded"':'' ?>>
            <td align="left" valign="top" style="padding:3px 9px"><?php echo $_item->getTitle() ?></td>
                <?php if (strpos($_item->getTitle(), 'ShippingEasy') !== false): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="https://tools.usps.com/go/TrackConfirmAction_input?origTrackNum=<?php echo $_item->getNumber() ?>"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getTitle()=='Federal Express'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="http://www.fedex.com/fedextrack/index.html?tracknumbers=<?php echo $_item->getNumber() ?>"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getTitle()=='United Parcel Service'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><a href="http://wwwapps.ups.com/WebTracking/track?HTMLVersion=5.0&loc=en_US&trackNums=<?php echo $_item->getNumber() ?>&track.x=Track"><?php echo $_item->getNumber() ?></a></td>
                <?php else: ?>
                <?php if ($_item->getTitle()=='DHL'): ?>
            <td align="center" valign="top" style="padding:3px 9px"><?php echo $_item->getNumber() ?></td>              
                <?php else: ?>
            <td align="center" valign="top" style="padding:3px 9px"><?php echo $_item->getNumber() ?></td>
                <?php endif; ?>
                <?php endif; ?>
                <?php endif; ?>
                <?php endif; ?>     
        </tr>
    <?php endforeach ?>
    </tbody>
</table>
<?php endif; ?>

However, this still resulted in the API transfer of data from ShippingEasy to Magento to completely ignore inserting the block track.phtml in the transactional email.

Here is the odd part. If we revert to the track.phtml in base/default, the block is recognized and the t/n is transmitted. Furthermore, if we use our custom track.phtml file, we can resend the e-mail by manually clicking the button in Shipments in Order View to "Send Tracking Information" again.

One other thing. The reason the code looks for "ShippingEasy" in the title rather than an exact match is because:

  1. getCarrierCode worked manually when looking for "usps," but did not work with ShippingEasy. <?php if ($_item->getCarrierCode()=='usps'): ?>
  2. Each shipment contains the name ShippingEasy with a unique transaction number. So, we cannot look for an exact match. We were hoping that detecting the "ShippingEasy" string in the title would work.

Before you suggest it, ShippingEasy was of no help in fixing this.

To add to it, we have tested this in both 1.4.1.1 and 1.9.2.1, and the results are the same.

So, what would cause the transfer via API to completely ignore the block only when the custom php or merely the HTML href hyperlink is included in the track.phtml file? Any suggestions?

Best Answer

Maybe you run into the same issue i had. I got emails, not containing the correct updated informations.

i figured out (Magento 1.7.2) that the Email for tracking is generated even before the tracking information was saved. Normally all works fine in default, but sometimes it happened, that the email sending is generated before the tracking is generated or updated.

What i were doing is to add an additional $this->save() in app/code/core/Mage/Sales/Model/Order/Shipment.php at the function addTrack right before the return statement.

For sure i didn't do this in the core file itself, i've cloned it into app/code/local/Mage/Sales/Model/Order/Shipment.php

My addTrack looks like this now:

public function addTrack(Mage_Sales_Model_Order_Shipment_Track $track)
{
    $track->setShipment($this)
        ->setParentId($this->getId())
        ->setOrderId($this->getOrderId())
        ->setStoreId($this->getStoreId());
    if (!$track->getId()) {
        $this->getTracksCollection()->addItem($track);
    }

    /**
     * Track saving is implemented in _afterSave()
     * This enforces Mage_Core_Model_Abstract::save() not to skip _afterSave()
     */
    $this->_hasDataChanges = true;
    /**
     * Added additional $this->save(); to have the new data for shippment
     * tracking already in the Mage_Sales_Model_Order_Shipment object.
     * If this would not happen, the tracking mails generated may have old
     * or wrong data regarding carrier title.
     */
    $this->save();

    return $this;
}

EDIT 3nd May 2016: Hi Scot,

in app/code/local/Mage/Sales/Model/Order/Shipment/Api/V2.php and app/code/local/Mage/Sales/Model/Order/Shipment/Api.php i've REMOVED $shipment->sendEmail($email, ($includeComment ? $comment : '')); in the create() function at the try/catch block right after the ->save();

public function create($orderIncrementId, $itemsQty = array(), $comment = null, $email = false,
    $includeComment = false
) {
    $order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);

    /**
      * Check order existing
      */
    if (!$order->getId()) {
         $this->_fault('order_not_exists');
    }

    /**
     * Check shipment create availability
     */
    if (!$order->canShip()) {
         $this->_fault('data_invalid', Mage::helper('sales')->__('Cannot do shipment for order.'));
    }

     /* @var $shipment Mage_Sales_Model_Order_Shipment */
    $shipment = $order->prepareShipment($itemsQty);
    if ($shipment) {
        $shipment->register();
        $shipment->addComment($comment, $email && $includeComment);
        if ($email) {
            $shipment->setEmailSent(true);
        }
        $shipment->getOrder()->setIsInProcess(true);
        try {
            $transactionSave = Mage::getModel('core/resource_transaction')
                ->addObject($shipment)
                ->addObject($shipment->getOrder())
                ->save();
        } catch (Mage_Core_Exception $e) {
            $this->_fault('data_invalid', $e->getMessage());
        }
        return $shipment->getIncrementId();
    }
    return null;
}

But i've added the email send in addTrack()

public function addTrack($shipmentIncrementId, $carrier, $title, $trackNumber)
{
    $shipment = Mage::getModel('sales/order_shipment')->loadByIncrementId($shipmentIncrementId);

    /* @var $shipment Mage_Sales_Model_Order_Shipment */

    if (!$shipment->getId()) {
        $this->_fault('not_exists');
    }

    $carriers = $this->_getCarriers($shipment);

    if (!isset($carriers[$carrier])) {
        $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));
    }

    $track = Mage::getModel('sales/order_shipment_track')
                ->setNumber($trackNumber)
                ->setCarrierCode($carrier)
                ->setTitle($title);

    $shipment->addTrack($track);

    try {
        $shipment->save();
        $track->save();
        if(!$shipment->getEmailSent()) {
            $shipment->sendEmail(true, $shipment->getCommentsCollection());
            $shipment->setEmailSent(true);
            $shipment->save();
        }
    } catch (Mage_Core_Exception $e) {
        $this->_fault('data_invalid', $e->getMessage());
    }

    return $track->getId();
}

Hope i didn't mix up something again.

Related Topic