Skip to content
intermediate Phase 50 · Order Operations

Order Processing

Order workflows, state transitions, automatic invoicing, and shipment creation

45m
0 problems
Topic Progress 0%

Order Workflow

Processing Workflow

// Standard order processing workflow
namespace Vendor\Order\Processor;

class OrderProcessor
{
    public function __construct(
        private \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
        private \Magento\Sales\Model\Service\InvoiceService $invoiceService,
        private \Magento\Sales\Model\Service\ShipmentService $shipmentService
    ) {}

    public function processOrder(int $orderId): void
    {
        $order = $this->orderRepository->get($orderId);

        // Step 1: Validate order
        $this->validateOrder($order);

        // Step 2: Process payment
        $this->processPayment($order);

        // Step 3: Create invoice (if auto-invoice enabled)
        if ($this->canAutoInvoice($order)) {
            $this->createInvoice($order);
        }

        // Step 4: Create shipment (if digital product)
        if ($this->isDigitalProduct($order)) {
            $this->createShipment($order);
        }

        // Step 5: Send notifications
        $this->sendNotifications($order);
    }
}

Workflow Steps

Step Action Condition
1 Validate Always
2 Process Payment If not already paid
3 Create Invoice Auto-invoice enabled
4 Create Shipment Digital products or auto-ship
5 Send Notifications Always

Automatic Invoicing

Auto-Invoice Configuration

// Configuration for automatic invoicing
namespace Vendor\Order\Config;

class AutoInvoiceConfig
{
    public function __construct(
        private \Magento\Framework\App\Config\ScopeConfigInterface $config
    ) {}

    public function isAutoInvoiceEnabled(): bool
    {
        return $this->config->isSetFlag(
            'sales/orders/auto_invoice',
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
        );
    }
}

Auto-Invoice Observer

namespace Vendor\Order\Observer;

class AutoInvoiceObserver implements \Magento\Framework\Event\ObserverInterface
{
    public function execute(\Magento\Framework\Event\Observer $observer): void
    {
        $order = $observer->getEvent()->getOrder();

        if ($this->canAutoInvoice($order)) {
            $this->createInvoice($order);
        }
    }

    private function canAutoInvoice(\Magento\Sales\Api\Data\OrderInterface $order): bool
    {
        return $order->canInvoice() &&
               $this->config->isAutoInvoiceEnabled() &&
               $order->getPayment()->getMethod() !== 'checkmo';
    }
}

Event Registration

<!-- etc/events.xml -->
<config>
    <event name="sales_order_place_after">
        <observer name="auto_invoice" instance="Vendor\Order\Observer\AutoInvoiceObserver"/>
    </event>
</config>

Automated Shipment Processing

Auto-Shipment for Digital Products

namespace Vendor\Order\Processor;

class DigitalShipmentProcessor
{
    public function __construct(
        private \Magento\Sales\Model\Service\ShipmentService $shipmentService,
        private \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
    ) {}

    public function processDigitalShipment(
        \Magento\Sales\Api\Data\OrderInterface $order
    ): void {
        $hasDigitalItems = false;

        foreach ($order->getItems() as $item) {
            $product = $this->productRepository->getById($item->getProductId());
            if ($product->getIsDigital()) {
                $hasDigitalItems = true;
                break;
            }
        }

        if ($hasDigitalItems) {
            $this->shipmentService->createShipment(
                $order,
                [], // All items
                [['carrier' => 'digital', 'number' => 'DIGITAL-' . $order->getIncrementId()]]
            );
        }
    }
}

Batch Processing

namespace Vendor\Order\Cron;

class BatchShipment
{
    public function execute(): void
    {
        $orders = $this->getOrdersForShipment();

        foreach ($orders as $order) {
            try {
                $this->processShipment($order);
            } catch (\Exception $e) {
                $this->logger->error(
                    'Shipment failed for order: ' . $order->getIncrementId(),
                    ['error' => $e->getMessage()]
                );
            }
        }
    }

    private function getOrdersForShipment(): array
    {
        return $this->orderCollectionFactory->create()
            ->addFieldToFilter('state', 'processing')
            ->addFieldToFilter('can_ship', 1)
            ->setPageSize(100)
            ->getItems();
    }
}

State Transition Automation

Automatic State Updates

namespace Vendor\Order\State;

class StateAutomation
{
    public function __construct(
        private \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
    ) {}

    public function updateOrderState(
        \Magento\Sales\Api\Data\OrderInterface $order
    ): void {
        $state = $this->determineState($order);

        if ($state !== $order->getState()) {
            $order->setState($state);
            $order->addStatusHistoryComment(
                sprintf('Automatic state transition to %s', $state)
            );
            $this->orderRepository->save($order);
        }
    }

    private function determineState(
        \Magento\Sales\Api\Data\OrderInterface $order
    ): string {
        // All items invoiced and shipped = complete
        if (!$order->canInvoice() && !$order->canShip()) {
            return \Magento\Sales\Model\Order::STATE_COMPLETE;
        }

        // Payment captured but items not fully processed = processing
        if ($order->getPayment()->isCaptured()) {
            return \Magento\Sales\Model\Order::STATE_PROCESSING;
        }

        // Awaiting payment = pending_payment
        if (!$order->getPayment()->isCaptured()) {
            return \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT;
        }

        return $order->getState();
    }
}

Cron-Based Processing

<!-- crontab.xml -->
<config>
    <group id="default">
        <job name="order_processing_automation" instance="Vendor\Order\Cron\ProcessOrders" method="execute">
            <schedule>*/5 * * * *</schedule>
        </job>
    </group>
</config>

Quiz

1. What triggers automatic invoicing?

Question 1 options

2. When does an order state transition to complete?

Question 2 options

3. How are digital products shipped?

Question 3 options

Flashcards

Question

Auto-invoice trigger?

Answer

sales_order_place_after event + auto_invoice config enabled

Question

Complete state condition?

Answer

All items invoiced AND shipped

Question

Digital product shipment?

Answer

Automatic with digital carrier and tracking

Question

Order processing cron?

Answer

Runs periodically to automate state transitions

Revision Notes

Key Takeaways

  • 1. Order workflows automate processing steps after placement
  • 2. Automatic invoicing triggers on order place when configured
  • 3. Digital products receive automatic shipment processing
  • 4. State transitions are determined by invoice and shipment status
  • 5. Cron jobs can automate batch order processing

Interview Tips

  • Describe the complete order processing workflow
  • Explain how automatic invoicing is triggered and configured
  • Discuss the criteria for state transitions to complete

Cheat Sheet

Order Processing:
  Place → Validate → Payment → Invoice → Ship → Notify

Auto-Invoice:
  Event: sales_order_place_after
  Config: sales/orders/auto_invoice
  Condition: canInvoice() && payment captured

State Transitions:
  canInvoice() == false && canShip() == false → complete
  payment captured → processing
  awaiting payment → pending_payment

Cron:
  Batch process orders periodically