Search code examples
shopware6

How to add a shipment (tracking code + change status to shipped) programmatically?


I want to mark an order as shipped and add the tracking code inside a Shopware 6 CLI command.

I understand that I have to create a delivery and attach the tracking code. I could do this via DAL. But I am wondering if there is a higher-level service for this? Do I have to use the state machine to change the status ? Or can this done in one step?

I have already written a test to check the tracking code:

$this->assertEquals('01234567890123', $order->get('deliveries')[0]->get('tracking_codes')[0]);

I think I can use the logic from \Shopware\Core\Checkout\Order\Api\OrderActionController::orderDeliveryStateTransition but it would require copy & paste.

EDIT For the tracking code I tried this:

        // FIXME: get the right context
        $context = Context::createDefaultContext();
        $order = $this->findOrder($orderNumber);
        /** @var \Shopware\Core\Checkout\Order\Aggregate\OrderDelivery\OrderDeliveryCollection $deliveries */
        $deliveries = $order->get('deliveries');

        if (count($deliveries) == 0) {
            throw new \LogicException('No delivery found');
        }
        if (count($deliveries) > 1) {
            throw new \LogicException('We support only 1 delivery per order');
        }

        $deliveries->first()->setTrackingCodes([$trackingCode]);
        $this->orderRepository->update([
            [
                'id' => $order->getId(),
                'deliveries' => json_decode( json_encode($deliveries), true)
            ]
        ], $context);

But I get:

1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/] Expected data to be array.
1. [/0/deliveries/0/shippingOrderAddress/salutation/translations/2fbb5fe2e29a4d70aa5854ce7ce3e20b/displayName] Dieser Wert sollte nicht leer sein.
1. [/0/deliveries/0/shippingOrderAddress/salutation/translations/2fbb5fe2e29a4d70aa5854ce7ce3e20b/letterName] Dieser Wert sollte nicht leer sein.
1. [/] Expected data to be array.

I also tried

        $this->orderRepository->update([
            [
                'id' => $order->getId(),
                'deliveries' => [
                    $deliveries->first()->getId() => [
                        'trackingCodes' => [ $trackingCode ]
                    ]
                ]
            ]
        ], $context);

Which makes more sense to my, as I just want to update the tracking code, not the full shipment.

This throws:

Shopware\Core\Framework\DataAbstractionLayer\Write\WriteException : There are 5 error(s) while writing data.

 1. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingOrderAddressId] Dieser Wert sollte nicht leer sein.
 2. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingMethodId] Dieser Wert sollte nicht leer sein.
 3. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/stateId] Dieser Wert sollte nicht leer sein.
 4. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingDateEarliest] Dieser Wert sollte nicht null sein.
 5. [/0/deliveries/9272d3693d014b25aaeadb8249ede5c2/shippingDateLatest] Dieser Wert sollte nicht null sein.

Solution

  • here is how i set an order shipped and complete

    use Shopware\Core\System\StateMachine\Aggregation\StateMachineTransition\StateMachineTransitionActions;
    use Shopware\Core\System\StateMachine\StateMachineRegistry;
    use Shopware\Core\System\StateMachine\Transition;
    
    
        private function setOrderComplete(OrderEntity $order, Context $context): void
        {
            $this->stateMachineRegistry->transition(new Transition(
                OrderDefinition::ENTITY_NAME,
                $order->getId(),
                StateMachineTransitionActions::ACTION_COMPLETE,
                'stateId'
            ), $context);
        }
    
        private function setDeliveryShipped(OrderDeliveryEntity $delivery, Context $context): void
        {
            $this->stateMachineRegistry->transition(new Transition(
                OrderDeliveryDefinition::ENTITY_NAME,
                $delivery->getId(),
                StateMachineTransitionActions::ACTION_SHIP,
                'stateId'
            ), $context);
        }