Sklad a zásoby
Zásoba je auditovateľná kniha: každá zmena je riadok StockAdjustment a variant si ukladá stock (na sklade) a reserved (držané pre vytvorené objednávky). Dostupná zásoba je stock mínus reserved. Vstupným bodom je Shops::inventory($variant); každý zápis ide cez AdjustStockAction, ktorá v transakcii zamkne riadok variantu a o predaji či rezervácii rozhodne podľa tohto zamknutého riadku — nikdy nie podľa zastaranej kópie — takže dva nákupy si nikdy nevezmú ten istý posledný kus:
use RoundlyConsulting\Shops\Facades\Shops;
use RoundlyConsulting\Shops\Inventory\Enums\StockReason;
Shops::inventory($variant)->receive(100, ref: $purchaseOrder, note: 'PO-17'); // +100 on hand
Shops::inventory($variant)->returned(1, $order); // +1, booked against the order
Shops::inventory($variant)->adjust(-2, note: 'Stock count'); // Manual correction, either sign
Shops::inventory($variant)->adjust(-1, StockReason::Sold, $posSale); // sell one outside an order
Shops::inventory($variant)->available(); // stock - reserved
Shops::inventory($variant)->inStock(3); // boolKaždý zápis vráti riadok StockAdjustment. ref je ľubovoľný model, ktorý zmenu vysvetľuje — objednávka od dodávateľa, reklamácia, objednávka zákazníka. Vrátenie zaúčtované na Order, na ktorej variant nikdy nebol, vyhodí ForeignItemException.
Priame volanie akcie
use RoundlyConsulting\Shops\Actions\Inventory\AdjustStockAction;
// What every inventory write runs — call it directly in jobs or your own actions:
app(AdjustStockAction::class)->execute(
ProductVariant $variant,
int $delta, // signed, in the reason's direction, never 0
StockReason $reason,
?Model $reference = null, // morph, e.g. the Order or a purchase order
?string $note = null,
): StockAdjustment;Dôvody a smer
Znamienko zmeny musí zodpovedať dôvodu. Nulová zmena alebo nesprávne znamienko vyhodí InvalidQuantityException skôr, než sa čokoľvek zapíše:
| Dôvod | Znamienko | Stĺpec | Význam |
|---|---|---|---|
Received | + | stock | Tovar prijatý na sklad. |
Sold | − | stock | Predaj — pod dostupnú zásobu sledovaného variantu sa odmietne. |
Reserved | + | reserved | Držané pre vytvorenú objednávku; nikdy nevyhodí výnimku. |
Released | − | reserved | Uvoľnená rezervácia (neklesne pod nulu); nikdy nevyhodí výnimku. |
Returned | + | stock | Vrátenie od zákazníka. |
Manual | ± | stock | Ručná korekcia v ľubovoľnom smere. |
Predaj alebo rezervácia nad dostupnú zásobu sledovaného variantu vyhodí InsufficientStockException. Varianty s track_stock = false (digitálny alebo neobmedzený tovar) výnimku nikdy nevyhodia a inStock() pre ne vždy vráti true. Odovzdaný variant dostane nové stock a reserved ako čisté atribúty, takže jeho neskoršie save() nikdy neprepíše zásobu, ktorú medzitým zmenil iný request.
Rezervácie
Objednávky spravujú rezervácie automaticky — pri bežnom nákupe sa ich nedotýkate:
| Krok | Akcia | Účinok na riadok objednávky |
|---|---|---|
| Vytvorenie objednávky | ReserveStockAction | Overí každý riadok voči dostupnosti zamknutého riadku variantu (inak InsufficientStockException) a pripočíta ho k rezervácii. Jeden nedostatok vráti späť všetky rezervácie. |
| Zrušenie | ReleaseStockAction (sell: false) | Uvoľní rezerváciu — množstvo je opäť dostupné. |
| Refundácia zaplatenej objednávky | ReleaseStockAction (sell: false) | Uvoľní rezerváciu objednávky, ktorá bola zaplatená, ale nikdy nevybavená. Refundácia vybavenej objednávky zásobu nemení. |
| Vybavenie | ReleaseStockAction (sell: true) | Uvoľní rezerváciu a zaúčtuje pohyb Sold — z rezervácie sa stane predaj. |
Obe akcie sú @internal: vytvorenie objednávky rezervuje, Shops::order($order)->cancel(), fulfil() a refund() nevybavenej objednávky uvoľňujú. Pod Shops::fake() sa rátajú do vytvorenej objednávky alebo prechodu stavu, nie ako samostatné pohyby zásoby. Riadky so zmazaným variantom sa preskočia a každý záznam v knihe odkazuje na objednávku.
Skladová kniha
use RoundlyConsulting\Shops\Inventory\StockAdjustment;
StockAdjustment::query()
->where('product_variant_id', $variant->id)
->latest()
->get(); // the variant's full ledger
$adjustment->quantity; // the signed delta
$adjustment->reason; // StockReason
$adjustment->note; // ?string
$adjustment->variant; // ProductVariant
$adjustment->reference; // e.g. the Order (morph)
StockReason::Reserved->affectsReserved(); // true for Reserved and Released
StockReason::Sold->direction(); // -1Udalosti zásob
Každá úprava spustí StockAdjusted. StockRanLow sa spustí raz, keď úprava zníži dostupnú zásobu sledovaného variantu zo stavu nad shops.inventory.low_stock_threshold na prah alebo pod neho — kým zásoba zostáva nízka, znova sa nespustí. Obe udalosti sa spustia po potvrdení okolitej transakcie, takže vrátené vytvorenie objednávky nespustí nič:
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
use RoundlyConsulting\Shops\Inventory\Events\StockAdjusted;
use RoundlyConsulting\Shops\Inventory\Events\StockRanLow;
Event::listen(function (StockRanLow $event): void {
// $event->variant, $event->threshold
Notification::route('mail', '[email protected]')
->notify(new ReorderNotice($event->variant));
});
Event::listen(function (StockAdjusted $event): void {
// $event->variant, $event->adjustment
});Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.