Output:
Chunk ID: d523af
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1739
Output:

            <flux:heading size="xl">Products</flux:heading>
            <flux:text class="mt-1">Manage catalog items, variants, status, and inventory.</flux:text>

        <flux:button :href="route('admin.products.create')" wire:navigate variant="primary" icon="plus">
            Add product
        </flux:button>

        <flux:input wire:model.live.debounce.300ms="search" icon="magnifying-glass" placeholder="Search products..." aria-label="Search products" />

        <flux:select wire:model.live="statusFilter" aria-label="Status filter">
            <flux:select.option value="all">All statuses</flux:select.option>
            <flux:select.option value="active">Active</flux:select.option>
            <flux:select.option value="draft">Draft</flux:select.option>
            <flux:select.option value="archived">Archived</flux:select.option>
        </flux:select>

        <flux:select wire:model.live="typeFilter" aria-label="Product type filter">
            <flux:select.option value="all">All types</flux:select.option>
            @foreach ($productTypes as $type)
                <flux:select.option value="{{ $type }}">{{ $type }}</flux:select.option>
            @endforeach
        </flux:select>

    @if (count($selectedIds) > 0)

            <flux:text>{{ count($selectedIds) }} products selected</flux:text>

                <flux:button wire:click="bulkSetActive" variant="ghost">Set active</flux:button>
                <flux:button wire:click="bulkArchive" variant="ghost">Archive</flux:button>
                <flux:button wire:click="bulkDelete" variant="danger">Delete</flux:button>

    @endif

                            <input type="checkbox" wire:click="toggleSelectAll" @checked($selectAll) aria-label="Select all visible products" class="rounded border-zinc-300 dark:border-zinc-600">

                        Product
                        Status
                        Inventory
                        Type
                        Vendor

                            <button wire:click="sortBy('updated_at')" class="font-semibold">Updated</button>

                    @forelse ($products as $product)
                        @php
                            $inventory = $product->variants->sum(fn ($variant) => $variant->inventoryItem?->quantity_on_hand ?? 0);
                            $statusColor = match ($product->status->value) {
                                'active' => 'green',
                                'archived' => 'red',
                                default => 'zinc',
                            };
                        @endphp

getKey() }}">

                                <input type="checkbox" wire:model.live="selectedIds" value="{{ $product->getKey() }}" aria-label="Select {{ $product->title }}" class="rounded border-zinc-300 dark:border-zinc-600">

                                        <flux:icon name="cube" class="size-5" />

                                            {{ $product->title }}

{{ $product->variants_count }} variants

                                <flux:badge :color="$statusColor">{{ Str::title($product->status->value) }}</flux:badge>

                            {{ $inventory }}
                            {{ $product->product_type ?: '-' }}
                            {{ $product->vendor ?: '-' }}
                            {{ $product->updated_at?->diffForHumans() }}

                    @empty

                                        <flux:icon name="cube" class="size-6" />

                                    <flux:heading size="lg">No products found</flux:heading>
                                    <flux:text>Adjust your filters or add a product.</flux:text>
                                    <flux:button :href="route('admin.products.create')" wire:navigate variant="primary">Add product</flux:button>

                    @endforelse

    {{ $products->links() }}


Output:
Chunk ID: 6b3f51
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 428
Output:
<?php

namespace App\Livewire\Admin\Inventory;

use App\Models\InventoryItem;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
use Livewire\WithPagination;

class Index extends Component
{
    use WithPagination;

    public string $search = '';

    public string $stockFilter = 'all';

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function updatedStockFilter(): void
    {
        $this->resetPage();
    }

    public function items(): LengthAwarePaginator
    {
        return InventoryItem::query()
            ->with(['variant.product'])
            ->when($this->search !== '', function (Builder $query): void {
                $search = '%'.$this->search.'%';

                $query->whereHas('variant', function (Builder $query) use ($search): void {
                    $query
                        ->where('sku', 'like', $search)
                        ->orWhereHas('product', fn (Builder $query) => $query->where('title', 'like', $search));
                });
            })
            ->when($this->stockFilter === 'low', fn (Builder $query) => $query->whereRaw('(quantity_on_hand - quantity_reserved) BETWEEN 1 AND 10'))
            ->when($this->stockFilter === 'out', fn (Builder $query) => $query->whereRaw('(quantity_on_hand - quantity_reserved) <= 0'))
            ->orderBy('quantity_on_hand')
            ->paginate(20);
    }

    public function render(): mixed
    {
        return view('livewire.admin.inventory.index', [
            'items' => $this->items(),
        ])->layout('layouts.app', [
            'title' => __('Inventory'),
        ]);
    }
}


sed -n '1,260p' resources/views/livewire/admin/inventory/index.blade.php

index.blade.php

        <flux:heading size="xl">Inventory</flux:heading>
        <flux:text class="mt-1">Review stock levels by product variant.</flux:text>

        <flux:input wire:model.live.debounce.300ms="search" icon="magnifying-glass" placeholder="Search by product or SKU..." aria-label="Search inventory" />

        <flux:select wire:model.live="stockFilter" aria-label="Stock filter">
            <flux:select.option value="all">All stock</flux:select.option>
            <flux:select.option value="low">Low stock</flux:select.option>
            <flux:select.option value="out">Out of stock</flux:select.option>
        </flux:select>

                        Product
                        SKU
                        On hand
                        Reserved
                        Available
                        Policy

                    @forelse ($items as $item)

getKey() }}">

                                variant->product) }}" class="font-medium text-zinc-950 hover:underline dark:text-white" wire:navigate>
                                    {{ $item->variant->product->title }}

                            {{ $item->variant->sku ?: '-' }}
                            {{ $item->quantity_on_hand }}
                            {{ $item->quantity_reserved }}
                            {{ $item->availableQuantity() }}

                                <flux:badge :color="$item->policy->value === 'continue' ? 'blue' : 'zinc'">{{ Str::title($item->policy->value) }}</flux:badge>

                    @empty

                            No inventory items found.

                    @endforelse

    {{ $items->links() }}


Output:
Chunk ID: 7da20a
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 780
Output:

        <flux:heading size="xl">Inventory</flux:heading>
        <flux:text class="mt-1">Review stock levels by product variant.</flux:text>

        <flux:input wire:model.live.debounce.300ms="search" icon="magnifying-glass" placeholder="Search by product or SKU..." aria-label="Search inventory" />

        <flux:select wire:model.live="stockFilter" aria-label="Stock filter">
            <flux:select.option value="all">All stock</flux:select.option>
            <flux:select.option value="low">Low stock</flux:select.option>
            <flux:select.option value="out">Out of stock</flux:select.option>
        </flux:select>

                        Product
                        SKU
                        On hand
                        Reserved
                        Available
                        Policy

                    @forelse ($items as $item)

getKey() }}">

                                variant->product) }}" class="font-medium text-zinc-950 hover:underline dark:text-white" wire:navigate>
                                    {{ $item->variant->product->title }}

                            {{ $item->variant->sku ?: '-' }}
                            {{ $item->quantity_on_hand }}
                            {{ $item->quantity_reserved }}
                            {{ $item->availableQuantity() }}

                                <flux:badge :color="$item->policy->value === 'continue' ? 'blue' : 'zinc'">{{ Str::title($item->policy->value) }}</flux:badge>

                    @empty

                            No inventory items found.

                    @endforelse

    {{ $items->links() }}


find resources/views/layouts resources/views/components -maxdepth 4 -type f | sort


sed -n '1,260p' resources/views/layouts/app.blade.php


sed -n '1,220p' resources/views/components/app-logo.blade.php


sed -n '1,260p' resources/views/layouts/app.blade.php

<x-layouts::app.sidebar :title="$title ?? null">
    <flux:main>
        {{ $slot }}
    </flux:main>
</x-layouts::app.sidebar>


Output:
Chunk ID: 14c4fc
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 236
Output:
resources/views/components/action-message.blade.php
resources/views/components/app-logo-icon.blade.php
resources/views/components/app-logo.blade.php
resources/views/components/auth-header.blade.php
resources/views/components/auth-session-status.blade.php
resources/views/components/desktop-user-menu.blade.php
resources/views/components/placeholder-pattern.blade.php
resources/views/components/settings/layout.blade.php
resources/views/components/storefront/breadcrumbs.blade.php
resources/views/components/storefront/price.blade.php
resources/views/components/storefront/product-card.blade.php
resources/views/layouts/app.blade.php
resources/views/layouts/app/header.blade.php
resources/views/layouts/app/sidebar.blade.php
resources/views/layouts/auth.blade.php
resources/views/layouts/auth/card.blade.php
resources/views/layouts/auth/simple.blade.php
resources/views/layouts/auth/split.blade.php
resources/views/layouts/storefront.blade.php


Output:
Chunk ID: 08b663
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 32
Output:
<x-layouts::app.sidebar :title="$title ?? null">
    <flux:main>
        {{ $slot }}
    </flux:main>
</x-layouts::app.sidebar>


sed -n '1,220p' resources/views/components/app-logo.blade.php

@props([
    'sidebar' => false,
])

@if($sidebar)
    <flux:sidebar.brand :name="config('app.name')" {{ $attributes }}>
        <x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
            <x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
        </x-slot>
    </flux:sidebar.brand>
@else
    <flux:brand :name="config('app.name')" {{ $attributes }}>
        <x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
            <x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
        </x-slot>
    </flux:brand>
@endif


Output:
Chunk ID: a70fb9
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 184
Output:
@props([
    'sidebar' => false,
])

@if($sidebar)
    <flux:sidebar.brand :name="config('app.name')" {{ $attributes }}>
        <x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
            <x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
        </x-slot>
    </flux:sidebar.brand>
@else
    <flux:brand :name="config('app.name')" {{ $attributes }}>
        <x-slot name="logo" class="flex aspect-square size-8 items-center justify-center rounded-md bg-accent-content text-accent-foreground">
            <x-app-logo-icon class="size-5 fill-current text-white dark:text-black" />
        </x-slot>
    </flux:brand>
@endif


sed -n '1,320p' resources/views/layouts/app/sidebar.blade.php


sed -n '1,260p' resources/views/layouts/app/header.blade.php


sed -n '1,260p' resources/views/layouts/app/header.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
    <head>
        @include('partials.head')
    </head>
    <body class="min-h-screen bg-white dark:bg-zinc-800">
        <flux:header container class="border-b border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.toggle class="lg:hidden mr-2" icon="bars-2" inset="left" />

            <x-app-logo href="{{ route('dashboard') }}" wire:navigate />

            <flux:navbar class="-mb-px max-lg:hidden">
                <flux:navbar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
                    {{ __('Dashboard') }}
                </flux:navbar.item>
            </flux:navbar>

            <flux:spacer />

            <flux:navbar class="me-1.5 space-x-0.5 rtl:space-x-reverse py-0!">
                <flux:tooltip :content="__('Search')" position="bottom">
                    <flux:navbar.item class="!h-10 [&>div>svg]:size-5" icon="magnifying-glass" href="#" :label="__('Search')" />
                </flux:tooltip>
                <flux:tooltip :content="__('Repository')" position="bottom">
                    <flux:navbar.item
                        class="h-10 max-lg:hidden [&>div>svg]:size-5"
                        icon="folder-git-2"
                        href="https://github.com/laravel/livewire-starter-kit"
                        target="_blank"
                        :label="__('Repository')"
                    />
                </flux:tooltip>
                <flux:tooltip :content="__('Documentation')" position="bottom">
                    <flux:navbar.item
                        class="h-10 max-lg:hidden [&>div>svg]:size-5"
                        icon="book-open-text"
                        href="https://laravel.com/docs/starter-kits#livewire"
                        target="_blank"
                        :label="__('Documentation')"
                    />
                </flux:tooltip>
            </flux:navbar>

            <x-desktop-user-menu />
        </flux:header>

        <!-- Mobile Menu -->
        <flux:sidebar collapsible="mobile" sticky class="lg:hidden border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.header>
                <x-app-logo :sidebar="true" href="{{ route('dashboard') }}" wire:navigate />
                <flux:sidebar.collapse class="in-data-flux-sidebar-on-desktop:not-in-data-flux-sidebar-collapsed-desktop:-mr-2" />
            </flux:sidebar.header>

            <flux:sidebar.nav>
                <flux:sidebar.group :heading="__('Platform')">
                    <flux:sidebar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
                        {{ __('Dashboard')  }}
                    </flux:sidebar.item>
                </flux:sidebar.group>
            </flux:sidebar.nav>

            <flux:spacer />

            <flux:sidebar.nav>
                <flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
                    {{ __('Repository') }}
                </flux:sidebar.item>
                <flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
                    {{ __('Documentation') }}
                </flux:sidebar.item>
            </flux:sidebar.nav>
        </flux:sidebar>

        {{ $slot }}

        @fluxScripts
    </body>
</html>


sed -n '1,320p' resources/views/layouts/app/sidebar.blade.php

<!DOCTYPE html>
getLocale()) }}" class="dark">

        @include('partials.head')

        <flux:sidebar sticky collapsible="mobile" class="border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.header>
                <x-app-logo :sidebar="true" href="{{ route('admin.dashboard') }}" wire:navigate />
                <flux:sidebar.collapse class="lg:hidden" />
            </flux:sidebar.header>

            <flux:sidebar.nav>
                <flux:sidebar.group :heading="__('Platform')" class="grid">
                    <flux:sidebar.item icon="home" :href="route('admin.dashboard')" :current="request()->routeIs('admin.dashboard')" wire:navigate>
                        {{ __('Dashboard') }}
                    </flux:sidebar.item>
                </flux:sidebar.group>

                <flux:sidebar.group :heading="__('Products')" class="grid">
                    <flux:sidebar.item icon="cube" :href="route('admin.products.index')" :current="request()->routeIs('admin.products.*')" wire:navigate>
                        {{ __('Products') }}
                    </flux:sidebar.item>

                    <flux:sidebar.item icon="rectangle-stack" :href="route('admin.collections.index')" :current="request()->routeIs('admin.collections.*')" wire:navigate>
                        {{ __('Collections') }}
                    </flux:sidebar.item>

                    <flux:sidebar.item icon="archive-box" :href="route('admin.inventory.index')" :current="request()->routeIs('admin.inventory.*')" wire:navigate>
                        {{ __('Inventory') }}
                    </flux:sidebar.item>
                </flux:sidebar.group>
            </flux:sidebar.nav>

            <flux:spacer />

            <flux:sidebar.nav>
                <flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
                    {{ __('Repository') }}
                </flux:sidebar.item>

                <flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
                    {{ __('Documentation') }}
                </flux:sidebar.item>
            </flux:sidebar.nav>

            <x-desktop-user-menu class="hidden lg:block" :name="auth()->user()->name" />
        </flux:sidebar>

        <flux:header class="lg:hidden">
            <flux:sidebar.toggle class="lg:hidden" icon="bars-2" inset="left" />

            <flux:spacer />

            <flux:dropdown position="top" align="end">
                <flux:profile
                    :initials="auth()->user()->initials()"
                    icon-trailing="chevron-down"
                />

                <flux:menu>
                    <flux:menu.radio.group>

                                <flux:avatar
                                    :name="auth()->user()->name"
                                    :initials="auth()->user()->initials()"
                                />

                                    <flux:heading class="truncate">{{ auth()->user()->name }}</flux:heading>
                                    <flux:text class="truncate">{{ auth()->user()->email }}</flux:text>

                    </flux:menu.radio.group>

                    <flux:menu.separator />

                    <flux:menu.radio.group>
                        <flux:menu.item :href="route('profile.edit')" icon="cog" wire:navigate>
                            {{ __('Settings') }}
                        </flux:menu.item>
                    </flux:menu.radio.group>

                    <flux:menu.separator />

                    <form method="POST" action="{{ route('logout') }}" class="w-full">
                        @csrf
                        <flux:menu.item
                            as="button"
                            type="submit"
                            icon="arrow-right-start-on-rectangle"
                            class="w-full cursor-pointer"
                            data-test="logout-button"
                        >
                            {{ __('Log Out') }}
                        </flux:menu.item>
                    </form>
                </flux:menu>
            </flux:dropdown>
        </flux:header>

        {{ $slot }}

        @fluxScripts


Output:
Chunk ID: 215034
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1213
Output:
<!DOCTYPE html>
getLocale()) }}" class="dark">

        @include('partials.head')

        <flux:sidebar sticky collapsible="mobile" class="border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.header>
                <x-app-logo :sidebar="true" href="{{ route('admin.dashboard') }}" wire:navigate />
                <flux:sidebar.collapse class="lg:hidden" />
            </flux:sidebar.header>

            <flux:sidebar.nav>
                <flux:sidebar.group :heading="__('Platform')" class="grid">
                    <flux:sidebar.item icon="home" :href="route('admin.dashboard')" :current="request()->routeIs('admin.dashboard')" wire:navigate>
                        {{ __('Dashboard') }}
                    </flux:sidebar.item>
                </flux:sidebar.group>

                <flux:sidebar.group :heading="__('Products')" class="grid">
                    <flux:sidebar.item icon="cube" :href="route('admin.products.index')" :current="request()->routeIs('admin.products.*')" wire:navigate>
                        {{ __('Products') }}
                    </flux:sidebar.item>

                    <flux:sidebar.item icon="rectangle-stack" :href="route('admin.collections.index')" :current="request()->routeIs('admin.collections.*')" wire:navigate>
                        {{ __('Collections') }}
                    </flux:sidebar.item>

                    <flux:sidebar.item icon="archive-box" :href="route('admin.inventory.index')" :current="request()->routeIs('admin.inventory.*')" wire:navigate>
                        {{ __('Inventory') }}
                    </flux:sidebar.item>
                </flux:sidebar.group>
            </flux:sidebar.nav>

            <flux:spacer />

            <flux:sidebar.nav>
                <flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
                    {{ __('Repository') }}
                </flux:sidebar.item>

                <flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
                    {{ __('Documentation') }}
                </flux:sidebar.item>
            </flux:sidebar.nav>

            <x-desktop-user-menu class="hidden lg:block" :name="auth()->user()->name" />
        </flux:sidebar>

        <flux:header class="lg:hidden">
            <flux:sidebar.toggle class="lg:hidden" icon="bars-2" inset="left" />

            <flux:spacer />

            <flux:dropdown position="top" align="end">
                <flux:profile
                    :initials="auth()->user()->initials()"
                    icon-trailing="chevron-down"
                />

                <flux:menu>
                    <flux:menu.radio.group>

                                <flux:avatar
                                    :name="auth()->user()->name"
                                    :initials="auth()->user()->initials()"
                                />

                                    <flux:heading class="truncate">{{ auth()->user()->name }}</flux:heading>
                                    <flux:text class="truncate">{{ auth()->user()->email }}</flux:text>

                    </flux:menu.radio.group>

                    <flux:menu.separator />

                    <flux:menu.radio.group>
                        <flux:menu.item :href="route('profile.edit')" icon="cog" wire:navigate>
                            {{ __('Settings') }}
                        </flux:menu.item>
                    </flux:menu.radio.group>

                    <flux:menu.separator />

                    <form method="POST" action="{{ route('logout') }}" class="w-full">
                        @csrf
                        <flux:menu.item
                            as="button"
                            type="submit"
                            icon="arrow-right-start-on-rectangle"
                            class="w-full cursor-pointer"
                            data-test="logout-button"
                        >
                            {{ __('Log Out') }}
                        </flux:menu.item>
                    </form>
                </flux:menu>
            </flux:dropdown>
        </flux:header>

        {{ $slot }}

        @fluxScripts


Output:
Chunk ID: 590f83
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 896
Output:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="dark">
    <head>
        @include('partials.head')
    </head>
    <body class="min-h-screen bg-white dark:bg-zinc-800">
        <flux:header container class="border-b border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.toggle class="lg:hidden mr-2" icon="bars-2" inset="left" />

            <x-app-logo href="{{ route('dashboard') }}" wire:navigate />

            <flux:navbar class="-mb-px max-lg:hidden">
                <flux:navbar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
                    {{ __('Dashboard') }}
                </flux:navbar.item>
            </flux:navbar>

            <flux:spacer />

            <flux:navbar class="me-1.5 space-x-0.5 rtl:space-x-reverse py-0!">
                <flux:tooltip :content="__('Search')" position="bottom">
                    <flux:navbar.item class="!h-10 [&>div>svg]:size-5" icon="magnifying-glass" href="#" :label="__('Search')" />
                </flux:tooltip>
                <flux:tooltip :content="__('Repository')" position="bottom">
                    <flux:navbar.item
                        class="h-10 max-lg:hidden [&>div>svg]:size-5"
                        icon="folder-git-2"
                        href="https://github.com/laravel/livewire-starter-kit"
                        target="_blank"
                        :label="__('Repository')"
                    />
                </flux:tooltip>
                <flux:tooltip :content="__('Documentation')" position="bottom">
                    <flux:navbar.item
                        class="h-10 max-lg:hidden [&>div>svg]:size-5"
                        icon="book-open-text"
                        href="https://laravel.com/docs/starter-kits#livewire"
                        target="_blank"
                        :label="__('Documentation')"
                    />
                </flux:tooltip>
            </flux:navbar>

            <x-desktop-user-menu />
        </flux:header>

        <!-- Mobile Menu -->
        <flux:sidebar collapsible="mobile" sticky class="lg:hidden border-e border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">
            <flux:sidebar.header>
                <x-app-logo :sidebar="true" href="{{ route('dashboard') }}" wire:navigate />
                <flux:sidebar.collapse class="in-data-flux-sidebar-on-desktop:not-in-data-flux-sidebar-collapsed-desktop:-mr-2" />
            </flux:sidebar.header>

            <flux:sidebar.nav>
                <flux:sidebar.group :heading="__('Platform')">
                    <flux:sidebar.item icon="layout-grid" :href="route('dashboard')" :current="request()->routeIs('dashboard')" wire:navigate>
                        {{ __('Dashboard')  }}
                    </flux:sidebar.item>
                </flux:sidebar.group>
            </flux:sidebar.nav>

            <flux:spacer />

            <flux:sidebar.nav>
                <flux:sidebar.item icon="folder-git-2" href="https://github.com/laravel/livewire-starter-kit" target="_blank">
                    {{ __('Repository') }}
                </flux:sidebar.item>
                <flux:sidebar.item icon="book-open-text" href="https://laravel.com/docs/starter-kits#livewire" target="_blank">
                    {{ __('Documentation') }}
                </flux:sidebar.item>
            </flux:sidebar.nav>
        </flux:sidebar>

        {{ $slot }}

        @fluxScripts
    </body>
</html>


sed -n '1,260p' app/Services/OrderService.php


sed -n '1,260p' app/Services/RefundService.php


sed -n '1,300p' app/Services/FulfillmentService.php


ls app/Enums && sed -n '1,220p' app/Enums/FinancialStatus.php && sed -n '1,220p' app/Enums/FulfillmentStatus.php && sed -n '1,220p' app/Enums/OrderStatus.php


sed -n '1,260p' app/Services/OrderService.php

<?php

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Enums\FinancialStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Enums\PaymentStatus;
use App\Events\OrderCancelled;
use App\Events\OrderCreated;
use App\Events\OrderPaid;
use App\Exceptions\InvalidCheckoutTransitionException;
use App\Exceptions\InvalidOrderOperationException;
use App\Exceptions\PaymentFailedException;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\Discount;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\ProductOptionValue;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Models\StoreSettings;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use ValueError;

class OrderService
{
    public function __construct(
        private readonly PaymentService $payments,
        private readonly InventoryService $inventory,
        private readonly PricingEngine $pricing,
        private readonly FulfillmentService $fulfillments,
    ) {}

    /**
     * Create an order from a checkout after payment has been selected.
     *
     * @param  array<string, mixed>  $paymentMethodData
     */
    public function createFromCheckout(Checkout $checkout, array $paymentMethodData = []): Order
    {
        try {
            return DB::transaction(function () use ($checkout, $paymentMethodData): Order {
                $checkout = $this->freshCheckout($checkout);
                $existingOrder = Order::withoutGlobalScopes()
                    ->where('checkout_id', $checkout->getKey())
                    ->first();

                if ($existingOrder instanceof Order) {
                    return $existingOrder->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);
                }

                if ($checkout->status !== CheckoutStatus::PaymentSelected) {
                    throw InvalidCheckoutTransitionException::because("Checkout cannot transition from {$checkout->status->value}.");
                }

                if ($checkout->totals_json === null) {
                    $this->pricing->calculate($checkout);
                    $checkout = $this->freshCheckout($checkout);
                }

                $method = $this->paymentMethod($checkout);
                $paymentResult = $this->payments->charge($checkout, $method, $paymentMethodData);

                if (! $paymentResult->success) {
                    throw PaymentFailedException::fromResult($paymentResult);
                }

                $paidImmediately = $paymentResult->status === PaymentStatus::Captured;
                $totals = $checkout->totals_json ?? [];

                $order = Order::withoutGlobalScopes()->create([
                    'store_id' => $checkout->store_id,
                    'checkout_id' => $checkout->getKey(),
                    'customer_id' => $checkout->customer_id,
                    'order_number' => $this->nextOrderNumber($checkout->store),
                    'payment_method' => $method,
                    'status' => $paidImmediately ? OrderStatus::Paid : OrderStatus::Pending,
                    'financial_status' => $paidImmediately ? FinancialStatus::Paid : FinancialStatus::Pending,
                    'fulfillment_status' => FulfillmentStatus::Unfulfilled,
                    'currency' => (string) data_get($totals, 'currency', $checkout->cart->currency),
                    'subtotal_amount' => (int) data_get($totals, 'subtotal', 0),
                    'discount_amount' => (int) data_get($totals, 'discount', 0),
                    'shipping_amount' => (int) data_get($totals, 'shipping', 0),
                    'tax_amount' => (int) data_get($totals, 'tax', 0),
                    'total_amount' => (int) data_get($totals, 'total', 0),
                    'email' => $checkout->email,
                    'billing_address_json' => $checkout->billing_address_json,
                    'shipping_address_json' => $checkout->shipping_address_json,
                    'placed_at' => now(),
                ]);

                $this->createOrderLines($checkout, $order);

                $order->payments()->create([
                    'provider' => 'mock',
                    'method' => $method,
                    'provider_payment_id' => $paymentResult->referenceId,
                    'status' => $paymentResult->status,
                    'amount' => $order->total_amount,
                    'currency' => $order->currency,
                    'raw_json_encrypted' => $paymentResult->toArray(),
                ]);

                if ($paidImmediately) {
                    $this->commitReservedInventory($checkout);
                }

                $checkout->cart->forceFill([
                    'status' => CartStatus::Converted,
                ])->save();

                $checkout->forceFill([
                    'status' => CheckoutStatus::Completed,
                    'expires_at' => null,
                ])->save();

                $this->incrementDiscountUsage($checkout);

                if ($paidImmediately) {
                    $this->fulfillments->autoFulfillDigital($order);
                }

                $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

                event(new OrderCreated($order));

                if ($paidImmediately) {
                    event(new OrderPaid($order));
                }

                return $order;
            });
        } catch (PaymentFailedException $exception) {
            $this->releaseFailedPaymentReservation($checkout);

            throw $exception;
        }
    }

    public function confirmBankTransferPayment(Order $order): Order
    {
        return DB::transaction(function () use ($order): Order {
            $order = $this->freshOrder($order);
            $this->assertPendingBankTransfer($order);

            $order->payments()
                ->where('status', PaymentStatus::Pending->value)
                ->update(['status' => PaymentStatus::Captured->value]);

            $this->commitReservedOrderInventory($order);

            $order->forceFill([
                'status' => OrderStatus::Paid,
                'financial_status' => FinancialStatus::Paid,
            ])->save();

            $this->fulfillments->autoFulfillDigital($order);

            $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

            event(new OrderPaid($order));

            return $order;
        });
    }

    public function cancelUnpaidBankTransferOrder(Order $order): Order
    {
        return DB::transaction(function () use ($order): Order {
            $order = $this->freshOrder($order);
            $this->assertPendingBankTransfer($order);

            $this->releaseReservedOrderInventory($order);

            $order->payments()
                ->where('status', PaymentStatus::Pending->value)
                ->update(['status' => PaymentStatus::Failed->value]);

            $order->forceFill([
                'status' => OrderStatus::Cancelled,
                'financial_status' => FinancialStatus::Voided,
            ])->save();

            $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

            event(new OrderCancelled($order));

            return $order;
        });
    }

    private function freshCheckout(Checkout $checkout): Checkout
    {
        return Checkout::withoutGlobalScopes()
            ->with(['cart', 'store'])
            ->whereKey($checkout->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'store.settings'])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function paymentMethod(Checkout $checkout): PaymentMethod
    {
        try {
            return PaymentMethod::from((string) $checkout->payment_method);
        } catch (ValueError) {
            throw InvalidCheckoutTransitionException::because('Payment method is invalid.');
        }
    }

    private function nextOrderNumber(Store $store): string
    {
        $settings = StoreSettings::query()
            ->where('store_id', $store->getKey())
            ->first()
            ?->settings_json ?? [];
        $prefix = (string) data_get($settings, 'order_number_prefix', '#');
        $start = max(1, (int) data_get($settings, 'order_number_start', 1001));
        $maxExisting = Order::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->pluck('order_number')
            ->map(fn (string $orderNumber): ?int => $this->sequenceFromOrderNumber($orderNumber))
            ->filter()
            ->max();

        return $prefix.((int) max($start - 1, $maxExisting ?? 0) + 1);
    }

    private function sequenceFromOrderNumber(string $orderNumber): ?int
    {
        $digits = preg_replace('/\D+/', '', $orderNumber);

        return $digits === '' ? null : (int) $digits;
    }

    private function createOrderLines(Checkout $checkout, Order $order): void
    {
        $this->cartLines($checkout)->each(function (CartLine $line) use ($checkout, $order): void {
            $variant = $line->variant;

            $order->lines()->create([
                'product_id' => $variant?->product_id,
                'variant_id' => $variant?->getKey(),
                'title_snapshot' => $this->titleSnapshot($variant),
                'sku_snapshot' => $variant?->sku,


Output:
Chunk ID: 9b7683
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2435
Output:
<?php

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Enums\FinancialStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Enums\PaymentStatus;
use App\Events\OrderCancelled;
use App\Events\OrderCreated;
use App\Events\OrderPaid;
use App\Exceptions\InvalidCheckoutTransitionException;
use App\Exceptions\InvalidOrderOperationException;
use App\Exceptions\PaymentFailedException;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\Discount;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\ProductOptionValue;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Models\StoreSettings;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use ValueError;

class OrderService
{
    public function __construct(
        private readonly PaymentService $payments,
        private readonly InventoryService $inventory,
        private readonly PricingEngine $pricing,
        private readonly FulfillmentService $fulfillments,
    ) {}

    /**
     * Create an order from a checkout after payment has been selected.
     *
     * @param  array<string, mixed>  $paymentMethodData
     */
    public function createFromCheckout(Checkout $checkout, array $paymentMethodData = []): Order
    {
        try {
            return DB::transaction(function () use ($checkout, $paymentMethodData): Order {
                $checkout = $this->freshCheckout($checkout);
                $existingOrder = Order::withoutGlobalScopes()
                    ->where('checkout_id', $checkout->getKey())
                    ->first();

                if ($existingOrder instanceof Order) {
                    return $existingOrder->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);
                }

                if ($checkout->status !== CheckoutStatus::PaymentSelected) {
                    throw InvalidCheckoutTransitionException::because("Checkout cannot transition from {$checkout->status->value}.");
                }

                if ($checkout->totals_json === null) {
                    $this->pricing->calculate($checkout);
                    $checkout = $this->freshCheckout($checkout);
                }

                $method = $this->paymentMethod($checkout);
                $paymentResult = $this->payments->charge($checkout, $method, $paymentMethodData);

                if (! $paymentResult->success) {
                    throw PaymentFailedException::fromResult($paymentResult);
                }

                $paidImmediately = $paymentResult->status === PaymentStatus::Captured;
                $totals = $checkout->totals_json ?? [];

                $order = Order::withoutGlobalScopes()->create([
                    'store_id' => $checkout->store_id,
                    'checkout_id' => $checkout->getKey(),
                    'customer_id' => $checkout->customer_id,
                    'order_number' => $this->nextOrderNumber($checkout->store),
                    'payment_method' => $method,
                    'status' => $paidImmediately ? OrderStatus::Paid : OrderStatus::Pending,
                    'financial_status' => $paidImmediately ? FinancialStatus::Paid : FinancialStatus::Pending,
                    'fulfillment_status' => FulfillmentStatus::Unfulfilled,
                    'currency' => (string) data_get($totals, 'currency', $checkout->cart->currency),
                    'subtotal_amount' => (int) data_get($totals, 'subtotal', 0),
                    'discount_amount' => (int) data_get($totals, 'discount', 0),
                    'shipping_amount' => (int) data_get($totals, 'shipping', 0),
                    'tax_amount' => (int) data_get($totals, 'tax', 0),
                    'total_amount' => (int) data_get($totals, 'total', 0),
                    'email' => $checkout->email,
                    'billing_address_json' => $checkout->billing_address_json,
                    'shipping_address_json' => $checkout->shipping_address_json,
                    'placed_at' => now(),
                ]);

                $this->createOrderLines($checkout, $order);

                $order->payments()->create([
                    'provider' => 'mock',
                    'method' => $method,
                    'provider_payment_id' => $paymentResult->referenceId,
                    'status' => $paymentResult->status,
                    'amount' => $order->total_amount,
                    'currency' => $order->currency,
                    'raw_json_encrypted' => $paymentResult->toArray(),
                ]);

                if ($paidImmediately) {
                    $this->commitReservedInventory($checkout);
                }

                $checkout->cart->forceFill([
                    'status' => CartStatus::Converted,
                ])->save();

                $checkout->forceFill([
                    'status' => CheckoutStatus::Completed,
                    'expires_at' => null,
                ])->save();

                $this->incrementDiscountUsage($checkout);

                if ($paidImmediately) {
                    $this->fulfillments->autoFulfillDigital($order);
                }

                $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

                event(new OrderCreated($order));

                if ($paidImmediately) {
                    event(new OrderPaid($order));
                }

                return $order;
            });
        } catch (PaymentFailedException $exception) {
            $this->releaseFailedPaymentReservation($checkout);

            throw $exception;
        }
    }

    public function confirmBankTransferPayment(Order $order): Order
    {
        return DB::transaction(function () use ($order): Order {
            $order = $this->freshOrder($order);
            $this->assertPendingBankTransfer($order);

            $order->payments()
                ->where('status', PaymentStatus::Pending->value)
                ->update(['status' => PaymentStatus::Captured->value]);

            $this->commitReservedOrderInventory($order);

            $order->forceFill([
                'status' => OrderStatus::Paid,
                'financial_status' => FinancialStatus::Paid,
            ])->save();

            $this->fulfillments->autoFulfillDigital($order);

            $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

            event(new OrderPaid($order));

            return $order;
        });
    }

    public function cancelUnpaidBankTransferOrder(Order $order): Order
    {
        return DB::transaction(function () use ($order): Order {
            $order = $this->freshOrder($order);
            $this->assertPendingBankTransfer($order);

            $this->releaseReservedOrderInventory($order);

            $order->payments()
                ->where('status', PaymentStatus::Pending->value)
                ->update(['status' => PaymentStatus::Failed->value]);

            $order->forceFill([
                'status' => OrderStatus::Cancelled,
                'financial_status' => FinancialStatus::Voided,
            ])->save();

            $order = $order->refresh()->load(['lines', 'payments', 'refunds', 'fulfillments.lines']);

            event(new OrderCancelled($order));

            return $order;
        });
    }

    private function freshCheckout(Checkout $checkout): Checkout
    {
        return Checkout::withoutGlobalScopes()
            ->with(['cart', 'store'])
            ->whereKey($checkout->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'store.settings'])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function paymentMethod(Checkout $checkout): PaymentMethod
    {
        try {
            return PaymentMethod::from((string) $checkout->payment_method);
        } catch (ValueError) {
            throw InvalidCheckoutTransitionException::because('Payment method is invalid.');
        }
    }

    private function nextOrderNumber(Store $store): string
    {
        $settings = StoreSettings::query()
            ->where('store_id', $store->getKey())
            ->first()
            ?->settings_json ?? [];
        $prefix = (string) data_get($settings, 'order_number_prefix', '#');
        $start = max(1, (int) data_get($settings, 'order_number_start', 1001));
        $maxExisting = Order::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->pluck('order_number')
            ->map(fn (string $orderNumber): ?int => $this->sequenceFromOrderNumber($orderNumber))
            ->filter()
            ->max();

        return $prefix.((int) max($start - 1, $maxExisting ?? 0) + 1);
    }

    private function sequenceFromOrderNumber(string $orderNumber): ?int
    {
        $digits = preg_replace('/\D+/', '', $orderNumber);

        return $digits === '' ? null : (int) $digits;
    }

    private function createOrderLines(Checkout $checkout, Order $order): void
    {
        $this->cartLines($checkout)->each(function (CartLine $line) use ($checkout, $order): void {
            $variant = $line->variant;

            $order->lines()->create([
                'product_id' => $variant?->product_id,
                'variant_id' => $variant?->getKey(),
                'title_snapshot' => $this->titleSnapshot($variant),
                'sku_snapshot' => $variant?->sku,


sed -n '1,260p' app/Services/RefundService.php

<?php

namespace App\Services;

use App\Enums\FinancialStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentStatus;
use App\Enums\RefundStatus;
use App\Events\OrderRefunded;
use App\Exceptions\InvalidRefundOperationException;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Payment;
use App\Models\Refund;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class RefundService
{
    public function __construct(
        private readonly PaymentService $payments,
        private readonly InventoryService $inventory,
    ) {}

    /**
     * @param  array{amount?: int, lines?: array<int|string, int>, reason?: string|null, restock?: bool}  $request
     */
    public function process(Order $order, array $request = []): Refund
    {
        return DB::transaction(function () use ($order, $request): Refund {
            $order = $this->freshOrder($order);
            $payment = $this->refundablePayment($order);
            $refundable = $this->refundableAmount($order);
            $lineQuantities = $this->lineQuantities($order, $request['lines'] ?? []);
            $amount = $this->refundAmount($order, $request, $lineQuantities, $refundable);

            $result = $this->payments->refund($payment, $amount);

            if (! $result->success) {
                throw InvalidRefundOperationException::because($result->errorMessage ?? 'Refund could not be processed.');
            }

            $refund = $order->refunds()->create([
                'payment_id' => $payment->getKey(),
                'amount' => $amount,
                'reason' => data_get($request, 'reason'),
                'status' => $result->status,
                'provider_refund_id' => $result->referenceId,
            ]);

            if ((bool) data_get($request, 'restock', false)) {
                $this->restock($order, $lineQuantities);
            }

            $this->updateOrderFinancialStatus($order, $payment);

            $order = $order->refresh();
            $refund = $refund->refresh();

            event(new OrderRefunded($order, $refund));

            return $refund;
        });
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'refunds'])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function refundablePayment(Order $order): Payment
    {
        $payment = $order->payments
            ->where('status', PaymentStatus::Captured)
            ->sortByDesc('id')
            ->first();

        if (! $payment instanceof Payment) {
            throw InvalidRefundOperationException::because('Order does not have a captured payment to refund.');
        }

        return $payment;
    }

    private function refundableAmount(Order $order): int
    {
        $refunded = $order->refunds
            ->reject(fn (Refund $refund): bool => $refund->status === RefundStatus::Failed)
            ->sum('amount');

        return $order->total_amount - $refunded;
    }

    /**
     * @param  array<string, mixed>  $request
     * @param  Collection<int, int>  $lineQuantities
     */
    private function refundAmount(Order $order, array $request, Collection $lineQuantities, int $refundable): int
    {
        $amount = array_key_exists('amount', $request)
            ? (int) $request['amount']
            : ($lineQuantities->isNotEmpty() ? $this->lineRefundAmount($order, $lineQuantities) : $refundable);

        if ($amount <= 0) {
            throw InvalidRefundOperationException::because('Refund amount must be greater than zero.');
        }

        if ($amount > $refundable) {
            throw InvalidRefundOperationException::because('Refund amount exceeds the remaining refundable amount.');
        }

        return $amount;
    }

    /**
     * @param  array<int|string, int>  $lines
     * @return Collection<int, int>
     */
    private function lineQuantities(Order $order, array $lines): Collection
    {
        return collect($lines)
            ->mapWithKeys(fn (mixed $quantity, int|string $lineId): array => [(int) $lineId => (int) $quantity])
            ->filter(fn (int $quantity): bool => $quantity > 0)
            ->each(function (int $quantity, int $lineId) use ($order): void {
                $line = $order->lines->firstWhere('id', $lineId);

                if (! $line instanceof OrderLine) {
                    throw InvalidRefundOperationException::because('Refund line does not belong to this order.');
                }

                if ($quantity > $line->quantity) {
                    throw InvalidRefundOperationException::because('Refund quantity exceeds the ordered quantity.');
                }
            });
    }

    /**
     * @param  Collection<int, int>  $lineQuantities
     */
    private function lineRefundAmount(Order $order, Collection $lineQuantities): int
    {
        return $lineQuantities->reduce(function (int $total, int $quantity, int $lineId) use ($order): int {
            $line = $order->lines->firstWhere('id', $lineId);

            if (! $line instanceof OrderLine) {
                return $total;
            }

            return $total + (int) round($line->total_amount / $line->quantity * $quantity);
        }, 0);
    }

    /**
     * @param  Collection<int, int>  $lineQuantities
     */
    private function restock(Order $order, Collection $lineQuantities): void
    {
        $linesToRestock = $lineQuantities->isNotEmpty()
            ? $lineQuantities
            : $order->lines->mapWithKeys(fn (OrderLine $line): array => [$line->getKey() => $line->quantity]);

        $linesToRestock->each(function (int $quantity, int $lineId) use ($order): void {
            $line = $order->lines->firstWhere('id', $lineId);

            if (! $line instanceof OrderLine || $line->variant_id === null) {
                return;
            }

            $item = InventoryItem::withoutGlobalScopes()
                ->where('variant_id', $line->variant_id)
                ->first();

            if ($item instanceof InventoryItem) {
                $this->inventory->restock($item, $quantity);
            }
        });
    }

    private function updateOrderFinancialStatus(Order $order, Payment $payment): void
    {
        $totalRefunded = $order->refunds()
            ->where('status', '!=', RefundStatus::Failed->value)
            ->sum('amount');

        if ($totalRefunded >= $order->total_amount) {
            $order->forceFill([
                'status' => OrderStatus::Refunded,
                'financial_status' => FinancialStatus::Refunded,
            ])->save();

            $payment->forceFill([
                'status' => PaymentStatus::Refunded,
            ])->save();

            return;
        }

        $order->forceFill([
            'financial_status' => FinancialStatus::PartiallyRefunded,
        ])->save();
    }
}


Output:
Chunk ID: e42e90
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1752
Output:
<?php

namespace App\Services;

use App\Enums\FinancialStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentStatus;
use App\Enums\RefundStatus;
use App\Events\OrderRefunded;
use App\Exceptions\InvalidRefundOperationException;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Payment;
use App\Models\Refund;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class RefundService
{
    public function __construct(
        private readonly PaymentService $payments,
        private readonly InventoryService $inventory,
    ) {}

    /**
     * @param  array{amount?: int, lines?: array<int|string, int>, reason?: string|null, restock?: bool}  $request
     */
    public function process(Order $order, array $request = []): Refund
    {
        return DB::transaction(function () use ($order, $request): Refund {
            $order = $this->freshOrder($order);
            $payment = $this->refundablePayment($order);
            $refundable = $this->refundableAmount($order);
            $lineQuantities = $this->lineQuantities($order, $request['lines'] ?? []);
            $amount = $this->refundAmount($order, $request, $lineQuantities, $refundable);

            $result = $this->payments->refund($payment, $amount);

            if (! $result->success) {
                throw InvalidRefundOperationException::because($result->errorMessage ?? 'Refund could not be processed.');
            }

            $refund = $order->refunds()->create([
                'payment_id' => $payment->getKey(),
                'amount' => $amount,
                'reason' => data_get($request, 'reason'),
                'status' => $result->status,
                'provider_refund_id' => $result->referenceId,
            ]);

            if ((bool) data_get($request, 'restock', false)) {
                $this->restock($order, $lineQuantities);
            }

            $this->updateOrderFinancialStatus($order, $payment);

            $order = $order->refresh();
            $refund = $refund->refresh();

            event(new OrderRefunded($order, $refund));

            return $refund;
        });
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with(['lines', 'payments', 'refunds'])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function refundablePayment(Order $order): Payment
    {
        $payment = $order->payments
            ->where('status', PaymentStatus::Captured)
            ->sortByDesc('id')
            ->first();

        if (! $payment instanceof Payment) {
            throw InvalidRefundOperationException::because('Order does not have a captured payment to refund.');
        }

        return $payment;
    }

    private function refundableAmount(Order $order): int
    {
        $refunded = $order->refunds
            ->reject(fn (Refund $refund): bool => $refund->status === RefundStatus::Failed)
            ->sum('amount');

        return $order->total_amount - $refunded;
    }

    /**
     * @param  array<string, mixed>  $request
     * @param  Collection<int, int>  $lineQuantities
     */
    private function refundAmount(Order $order, array $request, Collection $lineQuantities, int $refundable): int
    {
        $amount = array_key_exists('amount', $request)
            ? (int) $request['amount']
            : ($lineQuantities->isNotEmpty() ? $this->lineRefundAmount($order, $lineQuantities) : $refundable);

        if ($amount <= 0) {
            throw InvalidRefundOperationException::because('Refund amount must be greater than zero.');
        }

        if ($amount > $refundable) {
            throw InvalidRefundOperationException::because('Refund amount exceeds the remaining refundable amount.');
        }

        return $amount;
    }

    /**
     * @param  array<int|string, int>  $lines
     * @return Collection<int, int>
     */
    private function lineQuantities(Order $order, array $lines): Collection
    {
        return collect($lines)
            ->mapWithKeys(fn (mixed $quantity, int|string $lineId): array => [(int) $lineId => (int) $quantity])
            ->filter(fn (int $quantity): bool => $quantity > 0)
            ->each(function (int $quantity, int $lineId) use ($order): void {
                $line = $order->lines->firstWhere('id', $lineId);

                if (! $line instanceof OrderLine) {
                    throw InvalidRefundOperationException::because('Refund line does not belong to this order.');
                }

                if ($quantity > $line->quantity) {
                    throw InvalidRefundOperationException::because('Refund quantity exceeds the ordered quantity.');
                }
            });
    }

    /**
     * @param  Collection<int, int>  $lineQuantities
     */
    private function lineRefundAmount(Order $order, Collection $lineQuantities): int
    {
        return $lineQuantities->reduce(function (int $total, int $quantity, int $lineId) use ($order): int {
            $line = $order->lines->firstWhere('id', $lineId);

            if (! $line instanceof OrderLine) {
                return $total;
            }

            return $total + (int) round($line->total_amount / $line->quantity * $quantity);
        }, 0);
    }

    /**
     * @param  Collection<int, int>  $lineQuantities
     */
    private function restock(Order $order, Collection $lineQuantities): void
    {
        $linesToRestock = $lineQuantities->isNotEmpty()
            ? $lineQuantities
            : $order->lines->mapWithKeys(fn (OrderLine $line): array => [$line->getKey() => $line->quantity]);

        $linesToRestock->each(function (int $quantity, int $lineId) use ($order): void {
            $line = $order->lines->firstWhere('id', $lineId);

            if (! $line instanceof OrderLine || $line->variant_id === null) {
                return;
            }

            $item = InventoryItem::withoutGlobalScopes()
                ->where('variant_id', $line->variant_id)
                ->first();

            if ($item instanceof InventoryItem) {
                $this->inventory->restock($item, $quantity);
            }
        });
    }

    private function updateOrderFinancialStatus(Order $order, Payment $payment): void
    {
        $totalRefunded = $order->refunds()
            ->where('status', '!=', RefundStatus::Failed->value)
            ->sum('amount');

        if ($totalRefunded >= $order->total_amount) {
            $order->forceFill([
                'status' => OrderStatus::Refunded,
                'financial_status' => FinancialStatus::Refunded,
            ])->save();

            $payment->forceFill([
                'status' => PaymentStatus::Refunded,
            ])->save();

            return;
        }

        $order->forceFill([
            'financial_status' => FinancialStatus::PartiallyRefunded,
        ])->save();
    }
}


sed -n '1,300p' app/Services/FulfillmentService.php

<?php

namespace App\Services;

use App\Enums\FinancialStatus;
use App\Enums\FulfillmentShipmentStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Events\FulfillmentCreated;
use App\Events\FulfillmentDelivered;
use App\Events\FulfillmentShipped;
use App\Exceptions\InvalidFulfillmentOperationException;
use App\Models\Fulfillment;
use App\Models\FulfillmentLine;
use App\Models\Order;
use App\Models\OrderLine;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class FulfillmentService
{
    /**
     * @param  array<int|string, int>  $lines
     * @param  array<string, mixed>  $trackingData
     */
    public function create(Order $order, array $lines, array $trackingData = []): Fulfillment
    {
        return DB::transaction(function () use ($order, $lines, $trackingData): Fulfillment {
            $order = $this->freshOrder($order);
            $this->assertCanFulfill($order);

            $requestedLines = $this->normalizeLines($lines);

            if ($requestedLines->isEmpty()) {
                throw InvalidFulfillmentOperationException::because('At least one fulfillment line is required.');
            }

            $requestedLines->each(function (int $quantity, int $lineId) use ($order): void {
                $line = $order->lines->firstWhere('id', $lineId);

                if (! $line instanceof OrderLine) {
                    throw InvalidFulfillmentOperationException::because('Fulfillment line does not belong to this order.');
                }

                $remaining = $line->quantity - $this->fulfilledQuantity($line);

                if ($quantity > $remaining) {
                    throw InvalidFulfillmentOperationException::because('Fulfillment quantity exceeds the unfulfilled quantity.');
                }
            });

            $fulfillment = Fulfillment::query()->create([
                'order_id' => $order->getKey(),
                'status' => FulfillmentShipmentStatus::Pending,
                'tracking_company' => data_get($trackingData, 'tracking_company'),
                'tracking_number' => data_get($trackingData, 'tracking_number'),
                'tracking_url' => data_get($trackingData, 'tracking_url'),
            ]);

            $requestedLines->each(function (int $quantity, int $lineId) use ($fulfillment): void {
                $fulfillment->lines()->create([
                    'order_line_id' => $lineId,
                    'quantity' => $quantity,
                ]);
            });

            $this->updateOrderFulfillmentStatus($order);

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentCreated($fulfillment));

            return $fulfillment;
        });
    }

    public function markShipped(Fulfillment $fulfillment): Fulfillment
    {
        return DB::transaction(function () use ($fulfillment): Fulfillment {
            $fulfillment = $this->freshFulfillment($fulfillment);

            if ($fulfillment->status !== FulfillmentShipmentStatus::Pending) {
                throw InvalidFulfillmentOperationException::because('Only pending fulfillments can be marked as shipped.');
            }

            $fulfillment->forceFill([
                'status' => FulfillmentShipmentStatus::Shipped,
                'shipped_at' => now(),
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentShipped($fulfillment));

            return $fulfillment;
        });
    }

    public function markDelivered(Fulfillment $fulfillment): Fulfillment
    {
        return DB::transaction(function () use ($fulfillment): Fulfillment {
            $fulfillment = $this->freshFulfillment($fulfillment);

            if ($fulfillment->status !== FulfillmentShipmentStatus::Shipped) {
                throw InvalidFulfillmentOperationException::because('Only shipped fulfillments can be marked as delivered.');
            }

            $fulfillment->forceFill([
                'status' => FulfillmentShipmentStatus::Delivered,
                'delivered_at' => now(),
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentDelivered($fulfillment));

            return $fulfillment;
        });
    }

    public function autoFulfillDigital(Order $order): ?Fulfillment
    {
        return DB::transaction(function () use ($order): ?Fulfillment {
            $order = $this->freshOrder($order);

            if ($order->fulfillments()->exists() || $order->lines->isEmpty()) {
                return null;
            }

            $allDigital = $order->lines->every(fn (OrderLine $line): bool => $line->variant?->requires_shipping === false);

            if (! $allDigital) {
                return null;
            }

            $fulfillment = Fulfillment::query()->create([
                'order_id' => $order->getKey(),
                'status' => FulfillmentShipmentStatus::Delivered,
                'shipped_at' => now(),
                'delivered_at' => now(),
            ]);

            $order->lines->each(function (OrderLine $line) use ($fulfillment): void {
                $fulfillment->lines()->create([
                    'order_line_id' => $line->getKey(),
                    'quantity' => $line->quantity,
                ]);
            });

            $order->forceFill([
                'status' => OrderStatus::Fulfilled,
                'fulfillment_status' => FulfillmentStatus::Fulfilled,
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentCreated($fulfillment));
            event(new FulfillmentDelivered($fulfillment));

            return $fulfillment;
        });
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with([
                'lines.variant' => fn ($query) => $query->withoutGlobalScopes(),
                'fulfillments.lines',
            ])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function freshFulfillment(Fulfillment $fulfillment): Fulfillment
    {
        return Fulfillment::query()
            ->with('lines.orderLine')
            ->whereKey($fulfillment->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function assertCanFulfill(Order $order): void
    {
        if (! in_array($order->financial_status, [FinancialStatus::Paid, FinancialStatus::PartiallyRefunded], true)) {
            throw InvalidFulfillmentOperationException::because('Fulfillment cannot be created until payment is confirmed.');
        }
    }

    /**
     * @param  array<int|string, int>  $lines
     * @return Collection<int, int>
     */
    private function normalizeLines(array $lines): Collection
    {
        return collect($lines)
            ->mapWithKeys(fn (mixed $quantity, int|string $lineId): array => [(int) $lineId => (int) $quantity])
            ->filter(fn (int $quantity): bool => $quantity > 0);
    }

    private function fulfilledQuantity(OrderLine $line): int
    {
        return (int) FulfillmentLine::query()
            ->where('order_line_id', $line->getKey())
            ->sum('quantity');
    }

    private function updateOrderFulfillmentStatus(Order $order): void
    {
        $allFulfilled = $order->lines->every(function (OrderLine $line): bool {
            return $this->fulfilledQuantity($line) >= $line->quantity;
        });

        $order->forceFill([
            'status' => $allFulfilled ? OrderStatus::Fulfilled : $order->status,
            'fulfillment_status' => $allFulfilled ? FulfillmentStatus::Fulfilled : FulfillmentStatus::Partial,
        ])->save();
    }
}


Output:
Chunk ID: 28f8b5
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1974
Output:
<?php

namespace App\Services;

use App\Enums\FinancialStatus;
use App\Enums\FulfillmentShipmentStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Events\FulfillmentCreated;
use App\Events\FulfillmentDelivered;
use App\Events\FulfillmentShipped;
use App\Exceptions\InvalidFulfillmentOperationException;
use App\Models\Fulfillment;
use App\Models\FulfillmentLine;
use App\Models\Order;
use App\Models\OrderLine;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class FulfillmentService
{
    /**
     * @param  array<int|string, int>  $lines
     * @param  array<string, mixed>  $trackingData
     */
    public function create(Order $order, array $lines, array $trackingData = []): Fulfillment
    {
        return DB::transaction(function () use ($order, $lines, $trackingData): Fulfillment {
            $order = $this->freshOrder($order);
            $this->assertCanFulfill($order);

            $requestedLines = $this->normalizeLines($lines);

            if ($requestedLines->isEmpty()) {
                throw InvalidFulfillmentOperationException::because('At least one fulfillment line is required.');
            }

            $requestedLines->each(function (int $quantity, int $lineId) use ($order): void {
                $line = $order->lines->firstWhere('id', $lineId);

                if (! $line instanceof OrderLine) {
                    throw InvalidFulfillmentOperationException::because('Fulfillment line does not belong to this order.');
                }

                $remaining = $line->quantity - $this->fulfilledQuantity($line);

                if ($quantity > $remaining) {
                    throw InvalidFulfillmentOperationException::because('Fulfillment quantity exceeds the unfulfilled quantity.');
                }
            });

            $fulfillment = Fulfillment::query()->create([
                'order_id' => $order->getKey(),
                'status' => FulfillmentShipmentStatus::Pending,
                'tracking_company' => data_get($trackingData, 'tracking_company'),
                'tracking_number' => data_get($trackingData, 'tracking_number'),
                'tracking_url' => data_get($trackingData, 'tracking_url'),
            ]);

            $requestedLines->each(function (int $quantity, int $lineId) use ($fulfillment): void {
                $fulfillment->lines()->create([
                    'order_line_id' => $lineId,
                    'quantity' => $quantity,
                ]);
            });

            $this->updateOrderFulfillmentStatus($order);

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentCreated($fulfillment));

            return $fulfillment;
        });
    }

    public function markShipped(Fulfillment $fulfillment): Fulfillment
    {
        return DB::transaction(function () use ($fulfillment): Fulfillment {
            $fulfillment = $this->freshFulfillment($fulfillment);

            if ($fulfillment->status !== FulfillmentShipmentStatus::Pending) {
                throw InvalidFulfillmentOperationException::because('Only pending fulfillments can be marked as shipped.');
            }

            $fulfillment->forceFill([
                'status' => FulfillmentShipmentStatus::Shipped,
                'shipped_at' => now(),
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentShipped($fulfillment));

            return $fulfillment;
        });
    }

    public function markDelivered(Fulfillment $fulfillment): Fulfillment
    {
        return DB::transaction(function () use ($fulfillment): Fulfillment {
            $fulfillment = $this->freshFulfillment($fulfillment);

            if ($fulfillment->status !== FulfillmentShipmentStatus::Shipped) {
                throw InvalidFulfillmentOperationException::because('Only shipped fulfillments can be marked as delivered.');
            }

            $fulfillment->forceFill([
                'status' => FulfillmentShipmentStatus::Delivered,
                'delivered_at' => now(),
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentDelivered($fulfillment));

            return $fulfillment;
        });
    }

    public function autoFulfillDigital(Order $order): ?Fulfillment
    {
        return DB::transaction(function () use ($order): ?Fulfillment {
            $order = $this->freshOrder($order);

            if ($order->fulfillments()->exists() || $order->lines->isEmpty()) {
                return null;
            }

            $allDigital = $order->lines->every(fn (OrderLine $line): bool => $line->variant?->requires_shipping === false);

            if (! $allDigital) {
                return null;
            }

            $fulfillment = Fulfillment::query()->create([
                'order_id' => $order->getKey(),
                'status' => FulfillmentShipmentStatus::Delivered,
                'shipped_at' => now(),
                'delivered_at' => now(),
            ]);

            $order->lines->each(function (OrderLine $line) use ($fulfillment): void {
                $fulfillment->lines()->create([
                    'order_line_id' => $line->getKey(),
                    'quantity' => $line->quantity,
                ]);
            });

            $order->forceFill([
                'status' => OrderStatus::Fulfilled,
                'fulfillment_status' => FulfillmentStatus::Fulfilled,
            ])->save();

            $fulfillment = $fulfillment->refresh()->load('lines.orderLine');

            event(new FulfillmentCreated($fulfillment));
            event(new FulfillmentDelivered($fulfillment));

            return $fulfillment;
        });
    }

    private function freshOrder(Order $order): Order
    {
        return Order::withoutGlobalScopes()
            ->with([
                'lines.variant' => fn ($query) => $query->withoutGlobalScopes(),
                'fulfillments.lines',
            ])
            ->whereKey($order->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function freshFulfillment(Fulfillment $fulfillment): Fulfillment
    {
        return Fulfillment::query()
            ->with('lines.orderLine')
            ->whereKey($fulfillment->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function assertCanFulfill(Order $order): void
    {
        if (! in_array($order->financial_status, [FinancialStatus::Paid, FinancialStatus::PartiallyRefunded], true)) {
            throw InvalidFulfillmentOperationException::because('Fulfillment cannot be created until payment is confirmed.');
        }
    }

    /**
     * @param  array<int|string, int>  $lines
     * @return Collection<int, int>
     */
    private function normalizeLines(array $lines): Collection
    {
        return collect($lines)
            ->mapWithKeys(fn (mixed $quantity, int|string $lineId): array => [(int) $lineId => (int) $quantity])
            ->filter(fn (int $quantity): bool => $quantity > 0);
    }

    private function fulfilledQuantity(OrderLine $line): int
    {
        return (int) FulfillmentLine::query()
            ->where('order_line_id', $line->getKey())
            ->sum('quantity');
    }

    private function updateOrderFulfillmentStatus(Order $order): void
    {
        $allFulfilled = $order->lines->every(function (OrderLine $line): bool {
            return $this->fulfilledQuantity($line) >= $line->quantity;
        });

        $order->forceFill([
            'status' => $allFulfilled ? OrderStatus::Fulfilled : $order->status,
            'fulfillment_status' => $allFulfilled ? FulfillmentStatus::Fulfilled : FulfillmentStatus::Partial,
        ])->save();
    }
}


ls app/Enums && sed -n '1,220p' app/Enums/FinancialStatus.php && sed -n '1,220p' app/Enums/FulfillmentStatus.php && sed -n '1,220p' app/Enums/OrderStatus.php

OrderStatus.php

CartStatus.php
CheckoutStatus.php
CollectionStatus.php
CollectionType.php
DiscountStatus.php
DiscountType.php
DiscountValueType.php
FinancialStatus.php
FulfillmentShipmentStatus.php
FulfillmentStatus.php
InventoryPolicy.php
MediaStatus.php
MediaType.php
NavigationItemType.php
OrderStatus.php
PageStatus.php
PaymentMethod.php
PaymentStatus.php
ProductStatus.php
RefundStatus.php
ShippingRateType.php
StoreDomainType.php
StoreStatus.php
StoreUserRole.php
TaxMode.php
ThemeStatus.php
VariantStatus.php
<?php

namespace App\Enums;

enum FinancialStatus: string
{
    case Pending = 'pending';
    case Authorized = 'authorized';
    case Paid = 'paid';
    case PartiallyRefunded = 'partially_refunded';
    case Refunded = 'refunded';
    case Voided = 'voided';
}
<?php

namespace App\Enums;

enum FulfillmentStatus: string
{
    case Unfulfilled = 'unfulfilled';
    case Partial = 'partial';
    case Fulfilled = 'fulfilled';
}
<?php

namespace App\Enums;

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
    case Fulfilled = 'fulfilled';
    case Cancelled = 'cancelled';
    case Refunded = 'refunded';
}


Output:
Chunk ID: 2bcccb
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 286
Output:
CartStatus.php
CheckoutStatus.php
CollectionStatus.php
CollectionType.php
DiscountStatus.php
DiscountType.php
DiscountValueType.php
FinancialStatus.php
FulfillmentShipmentStatus.php
FulfillmentStatus.php
InventoryPolicy.php
MediaStatus.php
MediaType.php
NavigationItemType.php
OrderStatus.php
PageStatus.php
PaymentMethod.php
PaymentStatus.php
ProductStatus.php
RefundStatus.php
ShippingRateType.php
StoreDomainType.php
StoreStatus.php
StoreUserRole.php
TaxMode.php
ThemeStatus.php
VariantStatus.php
<?php

namespace App\Enums;

enum FinancialStatus: string
{
    case Pending = 'pending';
    case Authorized = 'authorized';
    case Paid = 'paid';
    case PartiallyRefunded = 'partially_refunded';
    case Refunded = 'refunded';
    case Voided = 'voided';
}
<?php

namespace App\Enums;

enum FulfillmentStatus: string
{
    case Unfulfilled = 'unfulfilled';
    case Partial = 'partial';
    case Fulfilled = 'fulfilled';
}
<?php

namespace App\Enums;

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
    case Fulfilled = 'fulfilled';
    case Cancelled = 'cancelled';
    case Refunded = 'refunded';
}


sed -n '1,260p' tests/Feature/Catalog/CatalogUiTest.php


sed -n '1,240p' tests/Feature/Orders/BankTransferOrderTest.php


sed -n '1,260p' tests/Feature/Orders/FulfillmentServiceTest.php


sed -n '1,260p' tests/Feature/Orders/RefundServiceTest.php


sed -n '1,260p' tests/Feature/Catalog/CatalogUiTest.php

<?php

use App\Livewire\Admin\Collections\Form as CollectionForm;
use App\Livewire\Admin\Products\Form as ProductForm;
use App\Livewire\Admin\Products\Index as ProductIndex;
use App\Models\Collection;
use App\Models\Product;
use App\Models\Store;
use App\Models\User;
use App\Services\ProductService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

test('storefront catalog browsing routes render seeded products', function () {
    $this->withHeader('Host', 'shop.test')
        ->get('/')
        ->assertSuccessful()
        ->assertSee('Acme Fashion')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99 EUR');

    $this->withHeader('Host', 'shop.test')
        ->get('/collections/t-shirts')
        ->assertSuccessful()
        ->assertSee('T-Shirts')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertDontSee('Unreleased Winter Jacket');

    $this->withHeader('Host', 'shop.test')
        ->get('/products/classic-cotton-t-shirt')
        ->assertSuccessful()
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('Size')
        ->assertSee('Color')
        ->assertSee('Add to cart');

    $this->withHeader('Host', 'shop.test')
        ->get('/search?q=draft')
        ->assertSuccessful()
        ->assertDontSee('Unreleased Winter Jacket');
});

test('admin catalog routes require authentication and render for store admins', function () {
    $this->get('/admin/products')->assertRedirect('/admin/login');

    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();

    $this->actingAs($user)
        ->get('/admin/products')
        ->assertSuccessful()
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('Premium Slim Fit Jeans');

    $this->actingAs($user)
        ->get('/admin/collections')
        ->assertSuccessful()
        ->assertSee('Collections')
        ->assertSee('T-Shirts');

    $this->actingAs($user)
        ->get('/admin/inventory')
        ->assertSuccessful()
        ->assertSee('Inventory')
        ->assertSee('Limited Edition Sneakers');
});

test('admin product form creates edits archives and index filters products', function () {
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();
    app()->instance('current_store', $store);

    Livewire::actingAs($user)
        ->test(ProductForm::class)
        ->set('title', 'Test Product Created by E2E')
        ->set('handle', 'test-product-created-by-e2e')
        ->set('descriptionHtml', 'This product was created by the E2E test suite.')
        ->set('vendor', 'Test Vendor')
        ->set('productType', 'T-Shirts')
        ->set('variants.0.price', '29.99')
        ->set('variants.0.sku', 'E2E-TEST-001')
        ->set('variants.0.quantity', 50)
        ->call('save')
        ->assertSee('Product saved');

    $product = Product::query()->where('handle', 'test-product-created-by-e2e')->firstOrFail();

    expect($product->variants()->first()?->price_amount)->toBe(2999)
        ->and($product->variants()->first()?->inventoryItem?->quantity_on_hand)->toBe(50);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product])
        ->set('title', 'Test Product Updated')
        ->call('save')
        ->assertSee('Product saved');

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product->refresh()])
        ->set('variants.0.sku', 'ACME-CTSH-S-WHT')
        ->call('save')
        ->assertHasErrors(['variants.0.sku']);

    expect($product->refresh()->variants()->first()?->sku)->toBe('E2E-TEST-001');

    $draftProduct = app(ProductService::class)->create($store, [
        'title' => 'Draft Product With Price Later',
        'handle' => 'draft-product-with-price-later',
        'status' => 'draft',
        'variants' => [[
            'sku' => 'DRAFT-PRICE-LATER-001',
            'price_amount' => 0,
            'currency' => $store->default_currency,
            'quantity_on_hand' => 4,
            'is_default' => true,
            'position' => 0,
        ]],
    ]);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $draftProduct])
        ->set('variants.0.price', '17.50')
        ->set('status', 'active')
        ->call('save')
        ->assertSee('Product saved');

    expect($draftProduct->refresh()->status->value)->toBe('active')
        ->and($draftProduct->variants()->first()?->price_amount)->toBe(1750);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product->refresh()])
        ->set('status', 'archived')
        ->call('save')
        ->assertSee('Product saved');

    expect($product->refresh()->status->value)->toBe('archived');

    Livewire::actingAs($user)
        ->test(ProductIndex::class)
        ->set('statusFilter', 'draft')
        ->assertSee('Unreleased Winter Jacket')
        ->assertDontSee('Classic Cotton T-Shirt')
        ->set('statusFilter', 'active')
        ->set('search', 'Cotton')
        ->assertSee('Classic Cotton T-Shirt');
});

test('admin collection form creates and assigns products', function () {
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();
    $product = Product::query()->where('handle', 'classic-cotton-t-shirt')->firstOrFail();
    app()->instance('current_store', $store);

    Livewire::actingAs($user)
        ->test(CollectionForm::class)
        ->set('title', 'E2E Test Collection')
        ->set('handle', 'e2e-test-collection')
        ->set('descriptionHtml', '
Created from tests.
')
        ->call('addProduct', $product->getKey())
        ->call('save')
        ->assertSee('Collection saved');

    $collection = Collection::query()->where('handle', 'e2e-test-collection')->firstOrFail();

    expect($collection->products()->pluck('products.id')->all())->toBe([$product->getKey()]);
});


sed -n '1,240p' tests/Feature/Orders/BankTransferOrderTest.php

<?php

use App\Enums\FinancialStatus;
use App\Enums\FulfillmentShipmentStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Enums\PaymentStatus;
use App\Events\OrderCancelled;
use App\Events\OrderPaid;
use App\Jobs\CancelUnpaidBankTransferOrders;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Payment;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Models\StoreSettings;
use App\Services\OrderService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;

uses(RefreshDatabase::class);

/**
 * @return array{0: Order, 1: ProductVariant}
 */
function bankTransferOrder(bool $digital = false, int $ageDays = 1): array
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    StoreSettings::query()->create([
        'store_id' => $store->getKey(),
        'settings_json' => ['bank_transfer_cancel_days' => 7],
    ]);

    $product = Product::factory()->withDefaultVariant(2500)->create(['store_id' => $store->getKey()]);
    $variant = ProductVariant::withoutGlobalScopes()->where('product_id', $product->getKey())->firstOrFail();
    $variant->forceFill([
        'requires_shipping' => ! $digital,
        'weight_g' => $digital ? 0 : $variant->weight_g,
    ])->save();

    InventoryItem::withoutGlobalScopes()
        ->where('variant_id', $variant->getKey())
        ->update([
            'quantity_on_hand' => 10,
            'quantity_reserved' => 2,
        ]);

    $order = Order::factory()->bankTransfer()->create([
        'store_id' => $store->getKey(),
        'payment_method' => PaymentMethod::BankTransfer,
        'status' => OrderStatus::Pending,
        'financial_status' => FinancialStatus::Pending,
        'placed_at' => now()->subDays($ageDays),
        'subtotal_amount' => 5000,
        'shipping_amount' => 0,
        'tax_amount' => 0,
        'total_amount' => 5000,
    ]);
    OrderLine::factory()->create([
        'order_id' => $order->getKey(),
        'product_id' => $product->getKey(),
        'variant_id' => $variant->getKey(),
        'quantity' => 2,
        'unit_price_amount' => 2500,
        'total_amount' => 5000,
    ]);
    Payment::factory()->bankTransfer()->create([
        'order_id' => $order->getKey(),
        'amount' => 5000,
    ]);

    return [$order, $variant];
}

test('confirming bank transfer payment captures payment and commits reserved inventory', function () {
    [$order, $variant] = bankTransferOrder();

    Event::fake();

    $paidOrder = app(OrderService::class)->confirmBankTransferPayment($order);
    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect($paidOrder->status)->toBe(OrderStatus::Paid)
        ->and($paidOrder->financial_status)->toBe(FinancialStatus::Paid)
        ->and($paidOrder->payments->first()->status)->toBe(PaymentStatus::Captured)
        ->and($inventory->quantity_on_hand)->toBe(8)
        ->and($inventory->quantity_reserved)->toBe(0);

    Event::assertDispatched(OrderPaid::class);
});

test('confirming digital bank transfer payment auto-fulfills the order', function () {
    [$order] = bankTransferOrder(digital: true);

    $paidOrder = app(OrderService::class)->confirmBankTransferPayment($order);

    expect($paidOrder->status)->toBe(OrderStatus::Fulfilled)
        ->and($paidOrder->fulfillment_status)->toBe(FulfillmentStatus::Fulfilled)
        ->and($paidOrder->fulfillments)->toHaveCount(1)
        ->and($paidOrder->fulfillments->first()->status)->toBe(FulfillmentShipmentStatus::Delivered);
});

test('cancel job voids stale bank transfer orders and releases reservations', function () {
    [$oldOrder, $oldVariant] = bankTransferOrder(ageDays: 8);
    [$newOrder, $newVariant] = bankTransferOrder(ageDays: 2);

    Event::fake();

    (new CancelUnpaidBankTransferOrders)->handle(app(OrderService::class));

    $oldInventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $oldVariant->getKey())->firstOrFail();
    $newInventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $newVariant->getKey())->firstOrFail();

    expect($oldOrder->refresh()->status)->toBe(OrderStatus::Cancelled)
        ->and($oldOrder->financial_status)->toBe(FinancialStatus::Voided)
        ->and($oldOrder->payments()->first()?->status)->toBe(PaymentStatus::Failed)
        ->and($oldInventory->quantity_on_hand)->toBe(10)
        ->and($oldInventory->quantity_reserved)->toBe(0)
        ->and($newOrder->refresh()->status)->toBe(OrderStatus::Pending)
        ->and($newInventory->quantity_reserved)->toBe(2);

    Event::assertDispatched(OrderCancelled::class);
});


Output:
Chunk ID: 112330
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1549
Output:
<?php

use App\Livewire\Admin\Collections\Form as CollectionForm;
use App\Livewire\Admin\Products\Form as ProductForm;
use App\Livewire\Admin\Products\Index as ProductIndex;
use App\Models\Collection;
use App\Models\Product;
use App\Models\Store;
use App\Models\User;
use App\Services\ProductService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

test('storefront catalog browsing routes render seeded products', function () {
    $this->withHeader('Host', 'shop.test')
        ->get('/')
        ->assertSuccessful()
        ->assertSee('Acme Fashion')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99 EUR');

    $this->withHeader('Host', 'shop.test')
        ->get('/collections/t-shirts')
        ->assertSuccessful()
        ->assertSee('T-Shirts')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertDontSee('Unreleased Winter Jacket');

    $this->withHeader('Host', 'shop.test')
        ->get('/products/classic-cotton-t-shirt')
        ->assertSuccessful()
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('Size')
        ->assertSee('Color')
        ->assertSee('Add to cart');

    $this->withHeader('Host', 'shop.test')
        ->get('/search?q=draft')
        ->assertSuccessful()
        ->assertDontSee('Unreleased Winter Jacket');
});

test('admin catalog routes require authentication and render for store admins', function () {
    $this->get('/admin/products')->assertRedirect('/admin/login');

    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();

    $this->actingAs($user)
        ->get('/admin/products')
        ->assertSuccessful()
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('Premium Slim Fit Jeans');

    $this->actingAs($user)
        ->get('/admin/collections')
        ->assertSuccessful()
        ->assertSee('Collections')
        ->assertSee('T-Shirts');

    $this->actingAs($user)
        ->get('/admin/inventory')
        ->assertSuccessful()
        ->assertSee('Inventory')
        ->assertSee('Limited Edition Sneakers');
});

test('admin product form creates edits archives and index filters products', function () {
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();
    app()->instance('current_store', $store);

    Livewire::actingAs($user)
        ->test(ProductForm::class)
        ->set('title', 'Test Product Created by E2E')
        ->set('handle', 'test-product-created-by-e2e')
        ->set('descriptionHtml', 'This product was created by the E2E test suite.')
        ->set('vendor', 'Test Vendor')
        ->set('productType', 'T-Shirts')
        ->set('variants.0.price', '29.99')
        ->set('variants.0.sku', 'E2E-TEST-001')
        ->set('variants.0.quantity', 50)
        ->call('save')
        ->assertSee('Product saved');

    $product = Product::query()->where('handle', 'test-product-created-by-e2e')->firstOrFail();

    expect($product->variants()->first()?->price_amount)->toBe(2999)
        ->and($product->variants()->first()?->inventoryItem?->quantity_on_hand)->toBe(50);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product])
        ->set('title', 'Test Product Updated')
        ->call('save')
        ->assertSee('Product saved');

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product->refresh()])
        ->set('variants.0.sku', 'ACME-CTSH-S-WHT')
        ->call('save')
        ->assertHasErrors(['variants.0.sku']);

    expect($product->refresh()->variants()->first()?->sku)->toBe('E2E-TEST-001');

    $draftProduct = app(ProductService::class)->create($store, [
        'title' => 'Draft Product With Price Later',
        'handle' => 'draft-product-with-price-later',
        'status' => 'draft',
        'variants' => [[
            'sku' => 'DRAFT-PRICE-LATER-001',
            'price_amount' => 0,
            'currency' => $store->default_currency,
            'quantity_on_hand' => 4,
            'is_default' => true,
            'position' => 0,
        ]],
    ]);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $draftProduct])
        ->set('variants.0.price', '17.50')
        ->set('status', 'active')
        ->call('save')
        ->assertSee('Product saved');

    expect($draftProduct->refresh()->status->value)->toBe('active')
        ->and($draftProduct->variants()->first()?->price_amount)->toBe(1750);

    Livewire::actingAs($user)
        ->test(ProductForm::class, ['product' => $product->refresh()])
        ->set('status', 'archived')
        ->call('save')
        ->assertSee('Product saved');

    expect($product->refresh()->status->value)->toBe('archived');

    Livewire::actingAs($user)
        ->test(ProductIndex::class)
        ->set('statusFilter', 'draft')
        ->assertSee('Unreleased Winter Jacket')
        ->assertDontSee('Classic Cotton T-Shirt')
        ->set('statusFilter', 'active')
        ->set('search', 'Cotton')
        ->assertSee('Classic Cotton T-Shirt');
});

test('admin collection form creates and assigns products', function () {
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    $user = User::query()->where('email', 'admin@acme.test')->firstOrFail();
    $product = Product::query()->where('handle', 'classic-cotton-t-shirt')->firstOrFail();
    app()->instance('current_store', $store);

    Livewire::actingAs($user)
        ->test(CollectionForm::class)
        ->set('title', 'E2E Test Collection')
        ->set('handle', 'e2e-test-collection')
        ->set('descriptionHtml', '
Created from tests.
')
        ->call('addProduct', $product->getKey())
        ->call('save')
        ->assertSee('Collection saved');

    $collection = Collection::query()->where('handle', 'e2e-test-collection')->firstOrFail();

    expect($collection->products()->pluck('products.id')->all())->toBe([$product->getKey()]);
});