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.
Inhaltsverzeichnis
- 1. Das Datenmodell hinter mehreren Shipments
- 2. Versand aus unterschiedlichen Sources bei einer Bestellung
- 3. Der Lebenszyklus eines Shipments und der Order-Status
- 4. Frontend-Darstellung mehrerer Sendungen
- 5. Edge Case: Teilweise Rückerstattung bei Teillieferung
- 6. Zusammenspiel mit Teilfakturierung
- 7. Performance bei Bestellungen mit sehr vielen Shipments
- 8. Admin-Oberfläche und Berechtigungen für manuelles Teilversenden
- 9. Typische Fehler im Partial-Shipment-Workflow
- 10. Zusammenfassung
- 11. FAQ
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.