303.473.4400 / Toll Free: 888.772.0777
Select Page

Magento API Shipping Email Notification Bug (Solved) - Magento Consulting - Customer ParadigmSolving Magento API shipment notification and tracking problems

If you want to use the Magento API to handle shipment notification for your customers and add tracking numbers into the email sent to an end user, there’s a well known issue / bug.

The main issue is that when you create a shipment via the Magento API, the shipment notification email sends out before you’re able to add tracking information to the shipment.

Dozens of hours and frustrated whiteboard sessions later, we’ve come up with a way to solve this issue – without creating a module or overriding core Magento code.

Magento Bug Summary: With the Magento API, you can invoice, ship, and add tracking data to an order via the Magento API. However, when you create the shipment, the shipment notification sends before you can add tracking information to the shipment. Here’s a hack to solve this problem without creating a module or overriding core code.

Magento Version: API Version 1 on Magento Enterprise. However, this should work the same on the Magento Community Platform.

Need Help With Magento Programming? Call 303.473.4400 or visit here to have a real person contact you now >>

Preparation

When invoicing, it’s best to include all fields in the API to ensure accuracy. In this example, $orderIncrementId is equal to our Magento Order Increment ID, 1001001010. However, $orderItemId is an array of order item ids and quantities invoiced.*** This is tricky, per magento API documentation, the OrderItemId is an array as outlined in this screenshot:

Magento API Email Shipping Notification Bug

Once the API session is instantiated, we need to refine some information before creating invoices and shipments.

Some constants that are passed into this example code include the order increment ID of the order we want to mark as invoiced & shipped as well as the list of products shipped and quantities.

(static constants at head of script)

$orderIncrementId = ‘100179439’;
$productsShipped = array(‘110914’ => 2, ‘105001’ => 1, ‘114447’ => 3);
$trackingNumber = ‘1Z1234567890’;

 

Next, we need to look up the order to pull the products out of the order and match them up with what is being shipped. We need to do this so we can mark those items & quantities as invoiced and shipped, thereby handling partial or backorder situations.

// lookup order
$result = $proxy->call(
$session, ‘order.info’, $orderIncrementId
);

$orderItems = $result[‘items’];
$orderItemId = false;
foreach ($orderItems as $orderItem) {
// build array of invoiced/shipped items, not individuals
if (array_key_exists($orderItem[‘product_id’], $productShipped)) {
// create sub-array of item ID and quantity
$orderItemId[$orderItem[‘item_id’]] = $productShipped[$orderItem[‘product_id’]];
}
}

What this does is to build an array of order item ids and quantities from product ids.

The order has 2 fields, item_id and product_id. Product_id is the magento product ID, and item_id is the order’s reference to that item in the order. By referencing the orders item_id, we can adjust quantities of items invoiced, shipped, returned, or canceled.

Invoicing

One thing I like to do with this code is to place each step inside a nested try/catch block. This is good for trapping errors at each stage and handling problems more gracefully.

The first try/catch block contains our sales_order_invoice.create action.

try {
echo “creating invoice rn”;
// create partial invoice for items shipping
$result = $proxy->call(
$session, ‘sales_order_invoice.create’, array(
$orderIncrementId,
$orderItemId,
‘comment’ => ”,
’email’ => false,
‘includeComment’ => false
)
);

This call will attempt to create the invoice, a couple of notes, $orderIncrementId is pulled from the constants, and the orderItemId is the array of items being marked as invoiced in this case. By including the remaining fields, even though they are optional, we can ensure proper behavior.

The comment, email, and includeComment fields normally can be used for adding comments and informing the customer.

However, we wish to control the amount of email and in this case, email and commenting is disabled. When the tracking number is added, we will add a comment and email the customer then.

Assuming this step passes the try/catch, I’ll nest another try/catch inside to proceed with creating the shipment. Otherwise, fail everything out.

Shipment
try {
echo “creating partial shipment rn”;
// create partial shipment
$shipResult = $proxy->call(
$session, ‘order_shipment.create’, array(
$orderIncrementId,
$orderItemId,
‘Creating Partial Shipment’,
0,
0,
)
);

The create shipment block is nearly identical to the create invoice step.

Again passing the order increment id, array of items being shipped and quantities.

The last three fields, comment, email, and include comment all behave the same. This does add a comment to the order, but does not inform the customer because email is set to 0 or false.

Again, assuming this try/catch block succeeds, we can proceed to adding the tracking number to this shipment.

Tracking
try {
echo “adding tracking # rn”;
// add tracking # !! need to capture shipmentIncrementId from above
$trackResult = $proxy->call(
$session, ‘sales_order_shipment.addTrack’, array(
‘shipmentIncrementId’ => $shipResult,
‘carrier’ => ‘ups’,
‘title’ => ‘tracking title’,
‘trackNumber’ => $trackNumber
)
);

The addTracking function does not allow us to include comments or notify the customer. Which is ok, we’ll handle that in the next step.

Notification
try {
echo “setting notify flagrn”;
$result = $proxy->call(
$session, ‘sales_order_shipment.addComment’, array(
”shipmentIncrementId’ => $shipResult,
‘comment’ => ‘Your order has been shipped, Here is the tracking # ‘ . $trackNumber,
’email’ => true,
‘include’ => true
)
);

Here is the Trick:

In each of the above api calls, we set email to 0, false.

We specifically do not want to email the customer at each step.

This last call allows us to notify the customer and include the tracking number via a comment.

With some creativity, you could loop through the items and quantities shipped and add them to the email as well in the comment field.

Need Help With Magento Programming? Call 303.473.4400 or visit here to have a real person contact you now >>

 

Full code:

$url = “http://mystoreurl.com/api/soap/?wsdl”;
$user = “myapiusername”;
$pass = “myapipassword”;

$proxy = new SoapClient($url);
$url = “http://mystoreurl.com/api/soap/?wsdl
$session = $proxy->login($user, $pass);
$orderIncrementId = ‘100179439’;

// by listing product IDs and quantities shipped, we can absolutely control what products are invoiced and shipped in magento
$productShipped = array(‘110914’ => 2, ‘105001’ => 1, ‘114447’ => 3);
$trackNumber = ‘1Z1234567890’;

echo “Looking up order ” . $orderIncrementId . “rn”;
// get the order_item_id by product_id and order_id
$result = $proxy->call(
$session, ‘order.info’, $orderIncrementId
);

$orderItems = $result[‘items’];
$orderItemId = false;
foreach ($orderItems as $orderItem) {
// build array of invoiced/shipped items, not individuals
if (array_key_exists($orderItem[‘product_id’], $productShipped)) {
// create sub-array of item ID and quantity
$orderItemId[$orderItem[‘item_id’]] = $productShipped[$orderItem[‘product_id’]];
}
}

// if we found the order_item_id, create partial invoice/shipment
if ($orderItemId) {
try {
echo “creating invoice rn”;
// create partial invoice for items shipping
$result = $proxy->call(
$session, ‘sales_order_invoice.create’, array(
$orderIncrementId,
$orderItemId,
‘comment’ => ”,
’email’ => false,
‘includeComment’ => false
)
);
echo “Invoice id: ” . $result . “rn”;
try {
echo “creating partial shipment rn”;
// create partial shipment
$shipResult = $proxy->call(
$session, ‘order_shipment.create’, array(
$orderIncrementId,
$orderItemId,
‘Creating Partial Shipment’,
0,
0,
)
);
echo “Shipment id: ” . $shipResult . “rn”;
try {
echo “adding tracking # rn”;
// add tracking # !! need to capture shipmentIncrementId from above
$trackResult = $proxy->call(
$session, ‘sales_order_shipment.addTrack’, array(
‘shipmentIncrementId’ => $shipResult,
‘carrier’ => ‘ups’,
‘title’ => ‘tracking title’,
‘trackNumber’ => $trackNumber
)
);
echo “Tracking result ” . $trackResult . “rn”;
try {
// add comment and send email !! need to capture shipmentIncrementId from above
// this is a hack to get around notifying customer when adding tracking information
echo “setting notify flagrn”;
$result = $proxy->call(
$session, ‘sales_order_shipment.addComment’, array(
‘shipmentIncrementId’ => $shipResult,
‘comment’ => ‘Your order has been shipped, Here is the tracking # ‘ . $trackNumber,
’email’ => true,
‘include’ => true
)
);
echo “setting notification rn”;
} catch (exception $e) {
echo “Failed to add comment & notify customer rn”;
echo “Error: ” . $e->getMessage();
echo “rn”;
}
} catch (exception $e) {
echo “Failed to add tracking Number rn”;
echo “Error: ” . $e->getMessage();
echo “rn”;
}
} catch (exception $e) {
echo “Failed to create partial shipmentrn”;
echo “Error: ” . $e->getMessage();
echo “rn”;
}
} catch (exception $e) {
echo “Could not create an invoice, either one exists already or another error occurred.rn”;
echo “Error: ” . $e->getMessage();
echo “rn”;
}
} else {
echo “could not find product_id $productId in order $orderIncrementId”;
}

 

 

Need Help With Magento Programming? Call 303.473.4400 or visit here to have a real person contact you now >>

 

Pin It on Pinterest

Share This