Teillieferungen technisch abbilden: Partial-Shipment-Workflow in Magento 2
AI generated
M2
di.xml
Magento 2 · Fulfillment
Teillieferungen technisch abbilden
Der Partial-Shipment-Workflow in Magento 2 im Detail

Sobald eine Bestellung aus mehreren Sources bedient wird oder ein Artikel erst später verfügbar ist, entstehen mehrere Shipments zu einer einzigen Bestellung. Magento bildet das technisch sauber ab, die Tücken liegen im Detail: bei der Frontend-Darstellung, bei Teil-Rückerstattungen und bei der korrekten Zuordnung von Mengen zu Sendungen. Dieser Artikel zeigt den vollständigen Workflow von der Order-Item-Ebene bis zur Kundenansicht.

13 Min. Lesezeit Partial Shipment Order Items Multi-Source Versand Teilrückerstattung Frontend

1. Das Datenmodell hinter mehreren Shipments

Eine Bestellung in Magento besteht aus einem Order-Objekt mit mehreren Order-Items, jedes Order-Item trägt eine bestellte Menge, eine bereits versendete Menge und eine bereits fakturierte Menge als separate Zähler. Ein Shipment wiederum referenziert die Order und enthält eine eigene Liste von Shipment-Items, jedes mit einer Referenz auf das zugehörige Order-Item und der in genau diesem Shipment versendeten Menge. Diese Trennung erlaubt es, dieselbe Order-Item-Zeile über mehrere Shipments hinweg schrittweise abzuarbeiten, ohne dass die ursprüngliche Bestellzeile dupliziert werden muss.

Die entscheidende Konsistenzregel lautet, dass die Summe aller shipment_qty über alle Shipments eines Order-Items niemals die ursprünglich bestellte Menge übersteigen darf. Magento prüft das serverseitig beim Anlegen eines neuen Shipments, eigene Erweiterungen, die Shipments programmatisch erzeugen, müssen diese Prüfung jedoch selbst nachbilden, wenn sie nicht über die Standard-ShipOrderInterface-API gehen.


<?php
declare(strict_types=1);

namespace Mironsoft\PartialShipment\Model;

use Magento\Sales\Api\ShipOrderInterface;
use Magento\Sales\Api\Data\ShipmentItemCreationInterfaceFactory;
use Magento\Sales\Api\OrderRepositoryInterface;

/**
 * Creates a partial shipment for a subset of order item quantities.
 */
class CreatePartialShipment
{
    /**
     * @param OrderRepositoryInterface $orderRepository
     * @param ShipOrderInterface $shipOrder
     * @param ShipmentItemCreationInterfaceFactory $itemCreationFactory
     */
    public function __construct(
        private readonly OrderRepositoryInterface $orderRepository,
        private readonly ShipOrderInterface $shipOrder,
        private readonly ShipmentItemCreationInterfaceFactory $itemCreationFactory
    ) {
    }

    /**
     * Ships the given quantities per order item id for a single source.
     *
     * @param int $orderId
     * @param array<int, float> $qtiesByOrderItemId
     * @param string $sourceCode
     * @return int Created shipment id
     */
    public function execute(int $orderId, array $qtiesByOrderItemId, string $sourceCode): int
    {
        $items = [];
        foreach ($qtiesByOrderItemId as $orderItemId => $qty) {
            $items[] = $this->itemCreationFactory->create()
                ->setOrderItemId($orderItemId)
                ->setQty($qty);
        }
        return $this->shipOrder->execute($orderId, $items, false, false, null, [], [], [
            'source_code' => $sourceCode,
        ]);
    }
}

2. Versand aus unterschiedlichen Sources bei einer Bestellung

Bei einem MSI-Setup mit mehreren Sources kann derselbe Order-Item auf mehrere Sources aufgeteilt sein, weil der gewählte Source Selection Algorithmus die angefragte Menge nicht aus einer einzigen Source decken konnte. Für den Versand bedeutet das, dass pro Source ein eigenes Shipment angelegt werden muss, da ein einzelnes Shipment in Magento genau einer Source zugeordnet ist. Wird versucht, Mengen aus zwei Sources in ein einziges Shipment zu packen, schlägt die Quellen-Zuordnung fehl oder das Shipment wird fälschlich nur einer Source zugerechnet.

In der Praxis muss deshalb die eigene Fulfillment-Logik, etwa ein Picklisten-Export fürs Lager, konsequent pro Source-Shipment-Paar arbeiten und nicht pro Bestellung. Ein Warehouse-Management-System, das nur eine Bestellung als Ganzes kennt, aber nicht zwischen den einzelnen Source-Shipments unterscheidet, führt schnell zu doppelten Kommissionierungen oder zu vergessenen Teilmengen, die aus einer zweiten Source hätten kommen müssen.

3. Der Lebenszyklus eines Shipments und der Order-Status

Nach jedem neuen Shipment aktualisiert Magento den Order-Status automatisch anhand der Verhältnisse zwischen bestellter und versendeter Menge über alle Order-Items hinweg. Sind alle Items vollständig versendet, wechselt die Bestellung auf Complete, ist nur ein Teil versendet, bleibt sie auf Processing mit dem zusätzlichen Hinweis Partially Shipped im Backend. Dieser Zwischenzustand ist kein eigener, in der order_status-Tabelle explizit definierter Status, sondern eine abgeleitete Anzeige, die aus dem Verhältnis der Mengen berechnet wird.

Wichtig für eigene Statuserweiterungen oder Benachrichtigungslogik ist, dass sich dieser Zwischenzustand nicht zuverlässig über ein einfaches Status-Feld abfragen lässt, sondern über einen Vergleich der Order-Item-Mengen ermittelt werden muss. Ein eigener Event-Observer auf sales_order_shipment_save_after eignet sich gut, um nach jedem neuen Shipment zu prüfen, ob die Bestellung damit vollständig oder weiterhin teilweise versendet ist, und entsprechende Kundenbenachrichtigungen auszulösen.

4. Frontend-Darstellung mehrerer Sendungen

Im Kundenkonto zeigt Magento standardmäßig eine eigene Shipment-Übersicht je Bestellung, in der jede Sendung mit ihrer Tracking-Nummer und den enthaltenen Positionen separat aufgelistet wird. Diese Ansicht funktioniert im Standard-Luma-Theme bereits korrekt, in einem Hyvä-Theme muss die entsprechende Vorlage jedoch bewusst nachgebaut werden, da Hyvä bewusst reduzierte Order-View-Templates mitbringt und die vollständige Shipment-Liste je nach Theme-Version nicht immer 1:1 übernommen wird.

Für ein gutes Kundenerlebnis sollte jede Sendung klar erkennbar mit Tracking-Link, enthaltenen Artikeln und Versanddatum dargestellt werden, statt nur eine einzelne, zusammengefasste Trackingnummer für die gesamte Bestellung anzuzeigen. Kunden, die eine Teillieferung erhalten, fragen sich sonst regelmäßig, wo der Rest ihrer Bestellung bleibt, obwohl er technisch bereits als separates, noch nicht versendetes Shipment im System vorgemerkt ist.


<div class="space-y-6" x-data="{ shipments: window.orderShipments }">
  <template x-for="shipment in shipments" :key="shipment.id">
    <div class="border rounded-lg p-4">
      <div class="flex items-center justify-between mb-2">
        <p class="font-semibold">Sendung <span x-text="shipment.number"></span></p>
        <a class="text-orange-600 text-sm" :href="shipment.trackingUrl" x-show="shipment.trackingUrl">
          Sendung verfolgen
        </a>
      </div>
      <p class="text-sm text-gray-500 mb-2" x-text="shipment.shippedAt"></p>
      <ul class="text-sm divide-y">
        <template x-for="item in shipment.items" :key="item.sku">
          <li class="py-1 flex justify-between">
            <span x-text="item.name"></span>
            <span x-text="'Menge: ' + item.qty"></span>
          </li>
        </template>
      </ul>
    </div>
  </template>
</div>

5. Edge Case: Teilweise Rückerstattung bei Teillieferung

Besonders fehleranfällig ist die Kombination aus Teillieferung und Teil-Rückerstattung. Wird ein Artikel aus dem zweiten, noch nicht versendeten Shipment storniert, bevor er das Lager verlässt, muss die Rückerstattung als Credit Memo ohne Bezug zu einem existierenden Shipment erstellt werden, da noch kein physischer Versand stattgefunden hat. Wird hingegen ein bereits versendeter Artikel zurückgeschickt, muss das Credit Memo explizit auf das zugehörige Shipment verweisen, damit die Retourenlogik weiß, welche physische Sendung betroffen ist.

Ein häufiger Fehler in eigenen Erweiterungen ist, die Rückerstattungslogik pauschal auf Order-Item-Ebene zu implementieren, ohne zwischen bereits versendeten und noch offenen Teilmengen zu unterscheiden. Das führt dazu, dass ein Kunde für einen Artikel, der noch gar nicht das Lager verlassen hat, eine Rückerstattung mit falschem Rückversand-Hinweis erhält, oder dass eine Rückerstattung für eine bereits versendete Teilmenge fälschlich als reine Stornierung ohne Retourenprozess behandelt wird.

6. Zusammenspiel mit Teilfakturierung

Analog zu Shipments kann eine Bestellung auch mehrere Invoices haben, wobei die Konfiguration steuert, ob eine Rechnung automatisch beim ersten Versand oder unabhängig davon erstellt wird. Für Teillieferungen ist die gängige Praxis, pro Shipment auch eine passende Teilrechnung über genau die versendeten Positionen und Mengen zu erstellen, statt die gesamte Bestellung sofort bei der ersten Teillieferung vollständig zu fakturieren.

Wird stattdessen sofort die volle Bestellsumme fakturiert, obwohl erst ein Teil versendet wurde, entsteht eine buchhalterische Diskrepanz zwischen dem tatsächlich gelieferten Warenwert und dem fakturierten Betrag, die spätestens bei einer Stornierung des noch offenen Teils zu Korrekturbuchungen führt. Für B2B-Kunden mit eigener Rechnungsprüfung ist diese Diskrepanz besonders kritisch, da eine Rechnung über nicht gelieferte Ware dort häufig automatisiert zurückgewiesen wird.

7. Performance bei Bestellungen mit sehr vielen Shipments

Bei B2B-Bestellungen mit hunderten Positionen, die über mehrere Wochen in vielen kleinen Teillieferungen versendet werden, kann die Sales-Grid-Ansicht im Backend spürbar langsamer werden, da für jede Bestellung alle zugehörigen Shipments und deren Items geladen werden müssen, um den Fortschritt korrekt anzuzeigen. Ein eigener Report, der den Versandfortschritt aggregiert vorab berechnet und cached, entlastet in solchen Fällen die Backend-Performance deutlich gegenüber einer Live-Berechnung bei jedem Seitenaufruf.

Für die Storefront-Ansicht im Kundenkonto gilt ähnliches: Werden alle Shipments einer Bestellung ungefiltert samt Items geladen, kann das bei sehr vielen Teillieferungen zu einer spürbaren Ladezeit führen. Eine Paginierung der Shipment-Liste oder ein clientseitiges Lazy-Loading für ältere Sendungen hält die initiale Ladezeit der Bestellübersicht auch bei aussergewöhnlich vielen Teillieferungen stabil.

8. Admin-Oberfläche und Berechtigungen für manuelles Teilversenden

Im Backend erlaubt die Shipment-Erstellungsmaske dem Lagerpersonal, die Menge je Position frei anzupassen, bevor ein Shipment gespeichert wird, sodass eine Teillieferung auch ohne automatisierte Fulfillment-Anbindung manuell möglich ist. Bei Mehrsource-Bestellungen zeigt die Maske zusätzlich eine Source-Auswahl je Position, über die das Personal festlegt, aus welcher Source tatsächlich versendet wird, was insbesondere dann wichtig ist, wenn die automatische Source-Auswahl aus betrieblichen Gründen manuell übersteuert werden soll.

Da ein manuell erstelltes Shipment direkte Auswirkungen auf Bestand, Rechnungsstellung und Kundenkommunikation hat, sollte der Zugriff auf diese Funktion über eine eigene ACL-Ressource abgesichert werden, statt sich auf die generische Sales-Berechtigung zu verlassen. Damit lässt sich beispielsweise regeln, dass nur ein bestimmtes Lagerteam Teillieferungen manuell anstoßen darf, während andere Rollen Bestellungen nur einsehen, aber nicht versenden können.

9. Typische Fehler im Partial-Shipment-Workflow

Der häufigste Fehler ist, eigene Fulfillment-Automatisierung auf Bestellebene statt auf Source-Shipment-Ebene zu bauen, was bei Mehrsource-Versand zu falschen Kommissionierungen führt. Ein zweiter Fehler ist die fehlende Unterscheidung zwischen bereits versendeten und noch offenen Mengen bei der Rückerstattungslogik, was zu falschen Retourenhinweisen führt. Beide Fehler fallen im Testsystem selten auf, weil dort meist einfache Ein-Source-Bestellungen getestet werden, und zeigen sich erst bei echten Multi-Source-Bestellungen in Produktion.

Ein dritter, oft übersehener Punkt ist die fehlende Anpassung eigener Hyvä-Templates für die Shipment-Übersicht. Wird die Standard-Bestellübersicht unverändert übernommen, sehen Kunden bei Teillieferungen mitunter nur eine einzige, unvollständige Trackingnummer, obwohl im Backend bereits mehrere Sendungen korrekt angelegt sind, was unnötige Support-Anfragen nach sich zieht.

Baustein Zuständigkeit Granularität Typischer Fallstrick
Order Item Bestellte, versendete, fakturierte Menge Je Bestellposition Summen über alle Shipments dürfen Bestellmenge nie übersteigen
Shipment Physische Sendung mit Tracking Je Source und Teilversand Ein Shipment gehört immer genau einer Source
Invoice Teilrechnung über versendete Positionen Je Fakturierungslauf Volle Fakturierung bei Teillieferung erzeugt Buchungsdiskrepanz
Credit Memo Rückerstattung mit oder ohne Shipment-Bezug Je Retoure oder Stornierung Fehlende Unterscheidung versendet/offen führt zu falschen Hinweisen
Frontend-Ansicht Darstellung aller Sendungen im Kundenkonto Je Bestellung, mehrere Sendungen Hyvä-Templates müssen die volle Shipment-Liste bewusst abbilden

Mironsoft

Magento-Entwicklung, Modul-Beratung und Systemarchitektur

Magento-Projekt, das eine zweite Meinung oder erfahrene Umsetzung braucht?

Wir entwickeln individuelle Magento-Module, beraten bei Architekturentscheidungen und übernehmen komplexe Umsetzungen, von der Service-Contract-Planung bis zum produktionsreifen Deployment.

Architektur-Beratung

Modul- und Systemarchitektur vor der Umsetzung fundiert durchdenken lassen.

Custom-Modul-Entwicklung

Individuelle Magento-Module nach Best Practices sauber umsetzen.

Code-Review & Audit

Bestehende Module auf Performance, Sicherheit und Wartbarkeit prüfen lassen.

10. Zusammenfassung

Partial-Shipment-Workflow: Das Wichtigste auf einen Blick

Ein Shipment, eine Source

Bei Mehrsource-Versand entsteht pro Source ein eigenes Shipment für dieselbe Bestellung.

Mengen-Konsistenz prüfen

Summe aller Shipment-Mengen darf die bestellte Menge je Order-Item nie übersteigen.

Rückerstattung differenzieren

Bereits versendete Mengen brauchen einen Shipment-Bezug im Credit Memo, offene Mengen nicht.

Hyvä-Templates anpassen

Vollständige Shipment-Liste im Kundenkonto muss bewusst nachgebaut werden.

11. FAQ: Partial-Shipment-Workflow: Das Wichtigste auf einen Blick

1Kann eine Bestellung mehrere Shipments haben?
Ja, jedes Order-Item trägt eine bestellte und eine bereits versendete Menge als separate Zähler. Über mehrere Shipments hinweg kann dieselbe Bestellposition schrittweise vollständig versendet werden.
2Kann ein einzelnes Shipment Positionen aus mehreren Sources enthalten?
Nein, ein Shipment ist immer genau einer Source zugeordnet. Wird eine Bestellung aus mehreren Sources bedient, entsteht pro Source ein eigenes Shipment.
3Wie erkennt man eine teilweise versendete Bestellung am Status?
Es gibt keinen eigenen, expliziten Order-Status dafür. Der Hinweis Partially Shipped ist eine abgeleitete Anzeige, die aus dem Verhältnis von bestellter zu versendeter Menge über alle Order-Items berechnet wird.
4Muss für jedes Shipment auch eine eigene Rechnung erstellt werden?
Das ist konfigurierbar, gängige Praxis ist aber eine Teilrechnung pro Shipment über genau die versendeten Positionen. Eine vollständige Fakturierung bei Teillieferung führt sonst zu buchhalterischen Diskrepanzen.
5Wie wird eine Rückerstattung für eine noch nicht versendete Position gehandhabt?
Als Credit Memo ohne Bezug zu einem existierenden Shipment, da noch kein physischer Versand stattgefunden hat. Ein Retourenprozess ist in diesem Fall nicht nötig.
6Wie wird eine Rückerstattung für eine bereits versendete Position gehandhabt?
Das Credit Memo muss explizit auf das zugehörige Shipment verweisen, damit die Retourenlogik die physische Sendung korrekt referenziert. Ohne diesen Bezug fehlt der Kontext für eine echte Retoure.
7Zeigt Hyvä standardmäßig alle Sendungen einer Bestellung an?
Nicht zwangsläufig vollständig, da Hyvä bewusst reduzierte Order-View-Templates mitbringt. Die vollständige Shipment-Liste mit Tracking-Link je Sendung muss häufig gezielt nachgebaut werden.
8Wie sollte eigene Fulfillment-Automatisierung bei Mehrsource-Versand strukturiert sein?
Konsequent auf Ebene von Source-Shipment-Paaren, nicht auf Bestellebene. Eine Automatisierung, die nur die gesamte Bestellung kennt, führt bei mehreren Sources leicht zu doppelten oder vergessenen Kommissionierungen.
9Wirkt sich eine hohe Anzahl an Teillieferungen auf die Performance aus?
Ja, sowohl im Backend-Grid als auch in der Storefront-Bestellübersicht kann das Laden aller Shipments samt Items bei sehr vielen Teillieferungen spürbar langsamer werden. Caching und Paginierung entschärfen das.
10Welcher Fehler bei Teillieferungen führt am häufigsten zu Support-Anfragen?
Eine unvollständige Frontend-Darstellung, die nur eine einzelne Trackingnummer zeigt, obwohl mehrere Sendungen existieren. Kunden vermuten dann fälschlich, ein Teil ihrer Bestellung sei verloren gegangen.