Bestand in einen Lagerplatz legen
Vier Endpunkte ändern, was ein Lagerplatz hält. Alles andere im Lager (Wareneingang, Einlagerung, Kommissionieren, Inventuren, Umlagerungen, Retouren) ruft am Ende einen davon mit einem anderen angehängten Grund auf.
Alle vier liegen unter /api/_action/p2lab-stockly/warehouse/stock/, authentifizieren sich wie jeder
Admin-API-Aufruf und sind durch dieselbe Berechtigung begrenzt:
p2lab_stockly.execute_stock_operations. Alle vier antworten {"success": true}.
POST warehouse/stock/add
Ware trifft ein. Es gibt keine Quelle; hier betritt Bestand das Gebäude.
{ "warehouseId": "0191f1…", "binLocationId": "0191f2…", "productId": "0191f3…", "quantity": 12, "comment": "Received without a purchase order", "movementType": "add", "batchNumber": "L-2411", "expiresAt": "2027-03-31T00:00:00+00:00", "handlingUnitCode": "LP-000241"}| Feld | Pflicht | Anmerkungen |
|---|---|---|
warehouseId | ja | |
productId | ja | |
quantity | ja | eine positive Zahl; die Richtung kommt vom Endpunkt, nie vom Vorzeichen |
binLocationId | nein | weglassen, und die Ware landet auf dem unassigned-Lagerplatz des Lagers |
comment | nein | freier Text, in der Historie gezeigt |
movementType | nein | add, return oder correction |
batchNumber, expiresAt | nein | zusammen kennzeichnen sie das Lot, dem die Einheiten beitreten |
handlingUnitCode | nein | der Ladungsträger, auf den die Ware gelegt wird |
POST warehouse/stock/remove
Ware geht hinaus. Es gibt kein Ziel.
{ "warehouseId": "0191f1…", "binLocationId": "0191f2…", "productId": "0191f3…", "quantity": 3, "movementType": "damage", "comment": "Crushed in handling", "batchId": "0191f4…", "cleanupEmptySource": false, "handlingUnitId": "0191f5…", "placementScoped": true}| Feld | Pflicht | Anmerkungen |
|---|---|---|
warehouseId, productId, quantity | ja | wie oben |
binLocationId | nein | weggelassen heißt der unassigned-Lagerplatz, nicht „irgendein Lagerplatz” |
movementType | nein | remove, damage, loss oder correction |
batchId | nein | aus diesem Lot ziehen, statt die Entnahmestrategie wählen zu lassen |
cleanupEmptySource | nein | die Zeile fallen lassen, wenn die Entnahme sie leert |
handlingUnitId + placementScoped | nein | genau von diesem Ladungsträger ziehen |
Ohne eine batchId werden die Einheiten Lot für Lot in der Reihenfolge verbraucht, die die Entnahmestrategie des
Lagers vorgibt, und das Journal bekommt eine Zeile je berührtem Lot: Eine Entnahme über drei Lots sind drei
Bewegungen, nicht eine.
placementScoped ist das, was „der Mitarbeiter hat die losen Einheiten genommen” von „der Mitarbeiter hat nichts
gesagt” trennt. Mit gesetzter handlingUnitId und placementScoped: true trifft die Entnahme genau diesen
Ladungsträger und keinen anderen; ohne das wird die erste gefundene Platzierung verwendet, und das kann die
falsche sein, wenn dasselbe Lot im selben Lagerplatz sowohl lose als auch auf einem Träger liegt.
POST warehouse/stock/move
Ware reist. Beide Enden bestehen, die Lagersumme ändert sich nicht.
{ "sourceWarehouseId": "0191f1…", "sourceBinLocationId": "0191f2…", "targetWarehouseId": "0191f1…", "targetBinLocationId": "0191f6…", "productId": "0191f3…", "quantity": 6, "movementType": "putaway", "purchaseOrderItemId": "0191f7…", "sourceHandlingUnitId": "0191f5…", "sourcePlacementScoped": true, "targetHandlingUnitCode": "LP-000242", "cleanupEmptySource": true}| Feld | Pflicht | Anmerkungen |
|---|---|---|
sourceWarehouseId, targetWarehouseId, productId, quantity | ja | |
sourceBinLocationId, targetBinLocationId | nein | jedes darf für den unassigned-Lagerplatz weggelassen werden |
movementType | nein | move, mapping, putaway oder putaway_undo |
batchId | nein | gezielt dieses Lot bewegen |
operationId | nein | bindet die Bewegung an einen Lagervorgang |
purchaseOrderId, purchaseOrderItemId | nein | eine Einlagerung zu einem Wareneingang |
sourceHandlingUnitId + sourcePlacementScoped | nein | von welchem Träger die Einheiten kommen |
targetHandlingUnitCode | nein | der Träger, auf dem sie landen |
cleanupEmptySource | nein | die Quellzeile fallen lassen, wenn sie sich leert |
Den ganzen Inhalt eines Ladungsträgers innerhalb eines Lagers zu bewegen verlagert den Träger; einen Teil
davon zu bewegen bricht den Träger auf, und der Rest bleibt zurück. Einen targetHandlingUnitCode zu
benennen ist der Weg, auf dem loser Bestand durch eine Bewegung palettiert wird.
Eine Bewegung, die eine purchaseOrderId oder purchaseOrderItemId benennt, leitet auch den
Einlagerungsfortschritt dieses Wareneingangs neu ab. Reine Lagerplatz-zu-Lagerplatz-Bewegungen tragen keinen
solchen Verweis und ändern außerhalb des Lagers nichts.
Quelle und Ziel dürfen nicht derselbe Lagerplatz sein, eine Bewegung von unassigned nach unassigned eingeschlossen, denn beide Enden werden vor der Prüfung auf den Lagerplatz aufgelöst.
POST warehouse/stock/map
Legt bestehenden unassigned-Bestand auf einen echten Lagerplatz im selben Lager, als mapping-Bewegung
festgehalten.
{ "warehouseId": "0191f1…", "productId": "0191f3…", "targetBinLocationId": "0191f6…", "comment": "Location mapping", "batchId": "0191f4…"}Das ist keine Bewegung mit einem schöneren Namen. Eine Bewegung verlagert Ware, die irgendwo war; eine Zuordnung hält zum ersten Mal fest, wo Ware die ganze Zeit gewesen ist, und deshalb ist es der Vorgang, den der Einrichtungsassistent verwendet. Ist der Ziel-Lagerplatz frei, behält die Zeile ihre Identität und bekommt schlicht einen Lagerplatz; belegt das Produkt diesen Lagerplatz bereits, verschmelzen die zwei Zeilen.
Eine Verlagerung über Lager hinweg ist eine Bewegung. Dieser Endpunkt arbeitet nur innerhalb eines Lagers.
Sechs häufigste Fehler
Abschnitt betitelt „Sechs häufigste Fehler“Ein unbekannter movementType wird herabgestuft, er scheitert nicht. Jeder Endpunkt nimmt seine eigene kurze
Liste entgegen und setzt für alles andere stillschweigend seine Voreinstellung ein: add für den eingehenden
Endpunkt, remove für den ausgehenden, move für den dritten. Der Aufruf gelingt, das Journal hält den falschen
Grund fest, und jeder Bericht, der nach Typ gruppiert, ist still falsch. Es gibt keinen Fehler zum Abfangen;
prüfen Sie den Wert, den Sie senden.
Die Menge ist immer positiv. Alle drei Endpunkte weisen null und negative Werte mit
P2LAB_STOCKLY__STOCK__INVALID_QUANTITY (HTTP 400) ab. Die Richtung liegt darin, welcher Endpunkt aufgerufen
wurde. Eine negative Bewegung entleerte das Ziel und blähte die Quelle auf, das genaue Gegenteil der Absicht.
Den Lagerplatz wegzulassen ist eine Entscheidung, keine Lücke. binLocationId: null heißt jedes Mal den
unassigned-Lagerplatz: auf dem Weg hinein, auf dem Weg hinaus, an beiden Enden einer Bewegung. Es heißt nie „wo
auch immer dieses Produkt gerade ist”.
Der transit-Lagerplatz ist verschlossen. Ihn als Quelle oder Ziel zu benennen wird mit
P2LAB_STOCKLY__STOCK__TRANSIT_SOURCE_NOT_ALLOWED / …_TARGET_NOT_ALLOWED (HTTP 409) abgelehnt. Ware betritt
ihn, wenn eine Umlagerung versendet wird, und verlässt ihn, wenn diese Umlagerung ankommt oder storniert wird.
Verwenden Sie stattdessen die Umlagerungs-Endpunkte.
Mehr zu entnehmen, als das Regal hält, wird abgelehnt, mit
P2LAB_STOCKLY__STOCK__INSUFFICIENT_STOCK (HTTP 422), das benennt, was angefordert und was verfügbar war; die
Menge wird nicht unbemerkt auf null begrenzt.
Eine fehlerhafte Anfrage ist eine 400, die das Feld benennt. Fehlende oder ungültige Ids und nicht numerische
Mengen antworten mit P2LAB_STOCKLY__REQUEST__INVALID und einer Meldung, die sagt, welches Feld, bevor
irgendetwas geschrieben wird.
Ladungsträger
Abschnitt betitelt „Ladungsträger“Ein Lager kann verlangen, dass Ware auf einem Ladungsträger reist. Wo diese Richtlinie gilt, wird ein add ohne
handlingUnitCode abgelehnt, und ebenso eine Bewegung, die am Ziel lose landet, es sei denn, die Bewegung trägt
einen ganzen Träger aus demselben Lager herüber, was die Richtlinie von selbst erfüllt. Die Regel wird auf dem
Server durchgesetzt, eine Integration, die den Code weglässt, umgeht sie also nicht stillschweigend.
Träger haben eigene strukturelle Vorgänge, alle unter derselben Berechtigung und alle bestandsneutral: Die Ware bleibt im Lagerplatz, nur ihr Träger ändert sich:
| Methode | Pfad | Was er tut |
|---|---|---|
POST | handling-unit/palletize | lose Einheiten in einem Lagerplatz kommen auf einen Träger |
POST | handling-unit/depalletize | das Umgekehrte |
POST | handling-unit/{huId}/nest | ein Träger wird auf einen anderen geladen |
POST | handling-unit/{huId}/unnest | wieder heruntergenommen |
POST | handling-unit/{huId}/move | der ganze Träger geht in einen anderen Lagerplatz |
GET | handling-unit/{huId}/contents | was darauf ist |
GET | handling-unit/generate-code | ein freier Code, um einen neuen Träger zu beschriften |
Im Prozess, ohne HTTP
Abschnitt betitelt „Im Prozess, ohne HTTP“Ein Plugin derselben Installation kann StockService unmittelbar aufrufen. Die Methoden spiegeln die Endpunkte
(addStock(), removeStock(), moveStock(), mapStock()) und nehmen den eigenen Context des Aufrufers
entgegen.
Zwei Dinge, die die Endpunkte für Sie erledigen und über die ein unmittelbarer Aufrufer nachdenken muss:
atomic() führt mehrere Primitive als eine Arbeitseinheit aus, für Fälle, in denen ein halb angewandtes Paar
schlimmer wäre als ein Fehlschlag: ein Urteil stempeln und die Ware bewegen, eine Inventurposition buchen
und sie platzieren. Nur Datenbankarbeit: Ein Deadlock spielt das Callable von vorn ab, alles mit einer Wirkung
außerhalb der Datenbank muss also draußen bleiben.
lockProductStockRows() ist die erste Anweisung jeder verändernden Einheit, und die Endpunkte setzen sie bereits
ab. Sie ist es, die aus der Verfügbarkeitsprüfung ein gesperrtes Lesen macht; ohne sie sehen zwei gleichzeitige
Entnahmen dieselbe Zahl, und das Journal hält mehr hinausgehende Einheiten fest, als das Regal je hielt.
Was nach dem Schreiben geschieht
Abschnitt betitelt „Was nach dem Schreiben geschieht“Der Reihe nach, innerhalb einer Transaktion:
- die Mengenzeile bewegt sich, und die Chargenaufteilung mit ihr;
- eine Journalzeile je berührtem Lot;
- die Lot-Platzierungen und das Ladungsträger-Spiegelbild folgen;
product.stockwird aus den Regalen neu berechnet;- bei einer Entnahme gibt die Vormerkung nach, wenn das Regal unter das fiel, was Bestellungen beansprucht hatten, und die Differenz wird zu einem Rückstand.
Tatsachen werden nach dem Commit veröffentlicht: p2lab_stockly.stock.moved für die Bewegung selbst und
p2lab_stockly.stock.availability_changed, wenn die Neuberechnung tatsächlich geändert hat, was verkauft werden
kann. Beide sind im Ereigniskatalog beschrieben.
Vor all dem wird BeforeStockOperationEvent außerhalb der Transaktion ausgelöst, und ein Listener darf den
ganzen Vorgang ablehnen. Siehe Policy Hooks.
- Korrekturen und Massenaufträge — zählen, befüllen, ein Lager entleeren
- Bestand lesen — fragen, bevor geschrieben wird
- Das Bestandsmodell — was diese Zeilen sind