NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky
Shops for Laravel

Stav a životný cyklus objednávky

Objednávky prechádzajú stráženým stavovým automatom s týmito povolenými prechodmi:

New        → InProgress | Canceled
InProgress → Paid | Canceled
Paid       → Fulfilled | Refunded
Fulfilled  → Refunded
Canceled, Refunded   (terminal)

Stav meníte cez Shops::order($order) alebo pomocnými metódami objednávky, ktoré volajú ten istý manažér. Každý prechod sa overí pod zámkom riadku objednávky, zapíše príslušnú časovú pečiatku (in_progress_at, paid_at, fulfilled_at, canceled_at, refunded_at), objednávka sa uloží a spustia sa udalosti:

use RoundlyConsulting\Shops\Facades\Shops;
use RoundlyConsulting\Shops\Orders\Enums\Status;

Shops::order($order)->transition(Status::InProgress);   // New → InProgress
Shops::order($order)->transition(Status::Paid);         // InProgress → Paid, stamps paid_at, fires OrderPaid
Shops::order($order)->fulfil();    // Paid → Fulfilled, converts reserved stock into a sale, fires OrderFulfilled
Shops::order($order)->cancel();    // New|InProgress → Canceled, releases reserved stock, returns store credit, fires OrderCanceled
Shops::order($order)->refund();    // Paid|Fulfilled → Refunded (a Paid order's reservation is released), fires OrderRefunded

// The helpers on the order call the same manager:
$order->markInProgress();          // → InProgress
$order->markPaid();                // → Paid
$order->markFulfilled();           // → Fulfilled
$order->cancel();                  // → Canceled
$order->refund();                  // → Refunded
$order->transitionTo(Status::Paid);

Čítanie stavu

Status je enum s reťazcovými hodnotami a pomocnými metódami z enums-for-laravel:

$order->status->is(Status::Paid);                        // bool
$order->status->isIn([Status::Paid, Status::Fulfilled]); // bool
$order->status->canTransitionTo(Status::Refunded);       // bool
$order->status->allowedTransitions();                    // list<Status>
$order->status->isTerminal();                            // Canceled or Refunded
$order->status->timestampColumn();                       // e.g. 'paid_at' (null for New)

Status::options();          // select-ready options (enums-for-laravel helpers)
Status::validationRule();   // a validation rule over the values

Nepovolené prechody

use RoundlyConsulting\Shops\Facades\Shops;
use RoundlyConsulting\Shops\Orders\Exceptions\IllegalStatusTransitionException;

try {
    Shops::order($order)->refund();   // the order is still New
} catch (IllegalStatusTransitionException $e) {
    // "Cannot transition an order from [New] to [Refunded]." — nothing changed
}

Vyrovnanie skladu

Zrušenie uvoľní rezerváciu objednávky a vráti kredit, ktorý bol na ňu uplatnený; refundácia zaplatenej (ešte nevybavenej) objednávky rezerváciu tiež uvoľní; vybavenie z nej urobí predaj. Refundácia vybavenej objednávky zásobu nemení — vrátený tovar zaúčtujete cez Shops::inventory($variant)->returned($qty, $order).

Udalosti

Každý prechod spustí OrderStatusChanged (s from a to) a pre príslušné cieľové stavy aj OrderPaid, OrderFulfilled, OrderCanceled alebo OrderRefunded. Vytvorenie objednávky spúšťa OrderPlaced. Udalosti objednávky sa spustia po potvrdení okolitej transakcie, takže vrátený prechod či vytvorenie objednávky nespustí nič. Prechod, ktorý zlyhá v polovici — vybavenie, ktorého tovar sa nedá predať — tiež nič nezmení, ani riadok, ani inštanciu objednávky, ktorú držíte, takže ho na tej istej inštancii môžete zopakovať:

use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use RoundlyConsulting\Shops\Orders\Events\OrderPaid;
use RoundlyConsulting\Shops\Orders\Events\OrderStatusChanged;

Event::listen(function (OrderPaid $event): void {
    Mail::to($event->order->customer)->send(new OrderConfirmation($event->order));
});

Event::listen(function (OrderStatusChanged $event): void {
    logger()->info('Order status changed', [
        'order' => $event->order->number,
        'from' => $event->from->value,
        'to' => $event->to->value,
    ]);
});

Čísla objednávok

Predvolene je číslo dvojmiestny rok a šesťmiestne poradie, počítané za rok vrátane soft-deletnutých objednávok. Pridelí sa raz, pri prvom vložení objednávky (ak ste ho nezadali), nikdy pri načítaní:

$order = Order::create([]);
$order->number;   // e.g. "26000042" — two-digit year + six-digit sequence

Route::get('/orders/{order}', ShowOrder::class);   // orders route-bind by number

orders.number je jedinečné naprieč všetkými objednávkami. Predvolený generátor preskočí obsadené čísla; keď dva nákupy súčasne dostanú to isté číslo, index druhé vloženie odmietne a generátor sa opýta znova — najviac päťkrát, v savepointe. Explicitne zadané číslo sa nikdy nenahradí — duplikát vyhodí výnimku. Vlastnú stratégiu dodáte cez NumberGenerator:

use Illuminate\Support\Str;
use RoundlyConsulting\Shops\Orders\NumberGenerators\NumberGenerator;
use RoundlyConsulting\Shops\Orders\Order;

final class PrefixedNumberGenerator implements NumberGenerator
{
    public function generate(Order $order): string
    {
        return 'ORD-'.Str::upper(Str::random(8));
    }
}

// config/shops.php → 'orders' => ['number_generator' => PrefixedNumberGenerator::class]
use RoundlyConsulting\Shops\Orders\NumberGenerators\DefaultNumberGenerator;

// The default generator is not final — override getNextNumber(), format() or isTaken():
final class BranchNumberGenerator extends DefaultNumberGenerator
{
    protected function format(int $sequence): string
    {
        return 'A'.parent::format($sequence);   // "A26000042"
    }
}

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 kryptomien

Odoslaní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.