Problem/Motivation
Due to the sequencing of order refreshes, there are cases when a shipment item can become invalid, but Commerce FedEx attempts to create the shipment item, causing \Drupal\commerce_shipping\ShipmentItem to throw an exception. The case I discovered has to do with a Buy X / Get Y promotion.
throw new \InvalidArgumentException(sprintf('Missing required property "%s".', $required_property));
Promotions removed
Shipments removed
Shipments created
Promotions re-applied
If I have an item that is only included in an order because of the "Get" condition of my promotion, but when the promotion order processor removes that item, the quantity becomes 0. The commerce fedex packer attempts to create the shipment item, the exception is thrown, checkout is broken.
Steps to reproduce
Create a Buy X / Get Y promotion, use two different variations for the Buy and Get items, and ensure "AUTOMATICALLY ADD THE OFFER PRODUCT TO THE CART IF IT ISN'T IN IT ALREADY." checkbox.
Add the Buy variation to the cart. Note that the Get variation is also added to the cart.
Attempt to checkout. I get a big ol' exception.
Proposed resolution
The simplest thing right now is to add a simple check around https://git.drupalcode.org/project/commerce_fedex/-/blob/8.x-1.x/src/Pac...
foreach ($this->getOrderItems($order, $shipping_profile) as $order_item) {
$purchased_entity = $order_item->getPurchasedEntity();
// Ship only shippable purchasable entity types.
if (!$purchased_entity || !$purchased_entity->hasField('weight')) {
continue;
}
$quantity = $order_item->getQuantity();
// Check quantity.
if (!$quantity) {
continue;
}
$shipments[0]['items'][] = new ShipmentItem([
'order_item_id' => $order_item->id(),
'title' => $order_item->getTitle(),
'quantity' => $quantity,
'weight' => $this->getWeight($order_item)->multiply($quantity),
'declared_value' => $order_item->getUnitPrice()->multiply($quantity),
]);
}
Remaining tasks
I'll try to get a patch together tomorrow.