command: sed -n '1,240p' tests/Feature/Storefront/OrderViewsTest.php

aggregated_output:
<?php

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Livewire\Storefront\Account\Orders\Index as AccountOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as AccountOrderShow;
use App\Livewire\Storefront\Checkout\Confirmation;
use App\Livewire\Storefront\Checkout\Show as CheckoutShow;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\Store;
use App\Services\CartService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

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

function orderViewsStore(): Store
{
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    app()->instance('current_store', $store);

    return $store;
}

function orderViewsVariant(Store $store): ProductVariant
{
    $product = Product::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('handle', 'classic-cotton-t-shirt')
        ->firstOrFail();

    return ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->oldest('position')
        ->firstOrFail();
}

function orderViewsShippingRate(Store $store): ShippingRate
{
    return ShippingRate::withoutGlobalScopes()
        ->whereHas('zone', fn ($query) => $query->withoutGlobalScopes()->where('store_id', $store->getKey()))
        ->where('name', 'Standard Shipping')
        ->firstOrFail();
}

test('checkout page places an order and redirects to confirmation', function () {
    $store = orderViewsStore();
    $variant = orderViewsVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    $component = Livewire::test(CheckoutShow::class)
        ->set('email', 'buyer@example.test')
        ->set('shippingAddress.first_name', 'Test')
        ->set('shippingAddress.last_name', 'Buyer')
        ->set('shippingAddress.address1', 'Main Street 1')
        ->set('shippingAddress.city', 'Berlin')
        ->set('shippingAddress.country', 'DE')
        ->set('shippingAddress.postal_code', '10115')
        ->call('saveAddress')
        ->set('selectedShippingRateId', orderViewsShippingRate($store)->getKey())
        ->call('selectShippingMethod')
        ->set('paymentMethod', 'credit_card')
        ->call('selectPaymentMethod')
        ->set('cardNumber', '4242 4242 4242 4242')
        ->call('placeOrder');

    $order = Order::withoutGlobalScopes()->firstOrFail();

    $component->assertRedirect(route('checkout.confirmation', $order));

    expect($order->email)->toBe('buyer@example.test')
        ->and($order->lines)->toHaveCount(1)
        ->and($cart->refresh()->status)->toBe(CartStatus::Converted)
        ->and(session('last_order_id'))->toBe($order->getKey())
        ->and(session('cart_id'))->toBeNull();
});

test('checkout page surfaces payment failures and releases reservations', function () {
    $store = orderViewsStore();
    $variant = orderViewsVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    Livewire::test(CheckoutShow::class)
        ->set('email', 'buyer@example.test')
        ->set('shippingAddress.first_name', 'Test')
        ->set('shippingAddress.last_name', 'Buyer')
        ->set('shippingAddress.address1', 'Main Street 1')
        ->set('shippingAddress.city', 'Berlin')
        ->set('shippingAddress.country', 'DE')
        ->set('shippingAddress.postal_code', '10115')
        ->call('saveAddress')
        ->set('selectedShippingRateId', orderViewsShippingRate($store)->getKey())
        ->call('selectShippingMethod')
        ->set('paymentMethod', 'credit_card')
        ->call('selectPaymentMethod')
        ->set('cardNumber', '4000 0000 0000 0002')
        ->call('placeOrder')
        ->assertHasErrors('cardNumber')
        ->assertSet('step', 'payment');

    $checkout = Checkout::withoutGlobalScopes()->where('cart_id', $cart->getKey())->firstOrFail();
    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect(Order::withoutGlobalScopes()->count())->toBe(0)
        ->and($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($inventory->quantity_reserved)->toBe(0);
});

test('order confirmation is visible only for the session order or customer order', function () {
    $store = orderViewsStore();
    $customer = Customer::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $otherCustomer = Customer::factory()->create(['store_id' => $store->getKey()]);
    $order = Order::factory()->forCustomer($customer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $customer->getKey(),
        'email' => $customer->email,
    ]);

    session(['last_order_id' => $order->getKey()]);

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertSee($order->order_number);

    session()->forget('last_order_id');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertStatus(404);

    $this->actingAs($otherCustomer, 'customer');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertStatus(404);

    $this->actingAs($customer, 'customer');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertSee($order->order_number);
});

test('customer account lists and shows customer orders', function () {
    $store = orderViewsStore();
    $customer = Customer::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $otherCustomer = Customer::factory()->create(['store_id' => $store->getKey()]);
    $order = Order::factory()->forCustomer($customer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $customer->getKey(),
        'order_number' => '#7777',
    ]);
    $otherOrder = Order::factory()->forCustomer($otherCustomer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $otherCustomer->getKey(),
        'order_number' => '#8888',
    ]);
    OrderLine::factory()->create([
        'order_id' => $order->getKey(),
        'title_snapshot' => 'Classic Cotton T-Shirt',
    ]);

    $this->actingAs($customer, 'customer');

    Livewire::test(AccountOrdersIndex::class)
        ->assertSee('#7777')
        ->assertDontSee('#8888');

    Livewire::test(AccountOrderShow::class, ['order' => $order])
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('#7777');

    Livewire::test(AccountOrderShow::class, ['order' => $otherOrder])
        ->assertStatus(404);
});


command: sed -n '1,340p' tests/Feature/Orders/OrderServiceTest.php

OrderServiceTest.php

type: read

aggregated_output:
<?php

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Enums\DiscountType;
use App\Enums\DiscountValueType;
use App\Enums\FinancialStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentStatus;
use App\Events\OrderCreated;
use App\Events\OrderPaid;
use App\Exceptions\PaymentFailedException;
use App\Models\Checkout;
use App\Models\Discount;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\Payment;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\StoreSettings;
use App\Models\TaxSettings;
use App\Services\CartService;
use App\Services\CheckoutService;
use App\Services\PricingEngine;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;

uses(RefreshDatabase::class);

function orderCompletionStore(int $start = 1001): Store
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    StoreSettings::query()->create([
        'store_id' => $store->getKey(),
        'settings_json' => [
            'order_number_prefix' => '#',
            'order_number_start' => $start,
        ],
    ]);

    TaxSettings::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'mode' => 'manual',
        'provider' => 'none',
        'prices_include_tax' => false,
        'config_json' => ['default_rate_bps' => 0, 'shipping_taxable' => false],
    ]);

    return $store;
}

function orderCompletionVariant(Store $store, int $price = 2500, int $stock = 10): ProductVariant
{
    $product = Product::factory()
        ->withDefaultVariant($price)
        ->create(['store_id' => $store->getKey()]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();

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

    return $variant->refresh();
}

function orderCompletionShippingRate(Store $store): ShippingRate
{
    $zone = ShippingZone::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('name', 'Germany')
        ->first();

    if (! $zone instanceof ShippingZone) {
        $zone = ShippingZone::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'name' => 'Germany',
            'countries_json' => ['DE'],
            'regions_json' => [],
        ]);
    }

    $rate = ShippingRate::withoutGlobalScopes()
        ->where('zone_id', $zone->getKey())
        ->where('name', 'Standard')
        ->first();

    if ($rate instanceof ShippingRate) {
        return $rate;
    }

    return ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
}

/**
 * @return array{0: Checkout, 1: ProductVariant, 2: \App\Models\Cart}
 */
function orderCompletionCheckout(Store $store, string $paymentMethod = 'credit_card', ?string $discountCode = null): array
{
    $variant = orderCompletionVariant($store);
    $rate = orderCompletionShippingRate($store);
    $cart = app(CartService::class)->create($store);

    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, [
        'email' => 'buyer@example.test',
        'shipping_address' => [
            'first_name' => 'Test',
            'last_name' => 'Buyer',
            'address1' => 'Main Street 1',
            'city' => 'Berlin',
            'country' => 'DE',
            'postal_code' => '10115',
        ],
    ]);
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());

    if ($discountCode !== null) {
        $checkout->forceFill(['discount_code' => $discountCode])->save();
        app(PricingEngine::class)->calculate($checkout);
    }

    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, $paymentMethod);

    return [$checkout, $variant, $cart];
}

test('checkout completion creates a paid order and commits inventory', function () {
    $store = orderCompletionStore();
    $discount = Discount::factory()
        ->fixed(500)
        ->create([
            'store_id' => $store->getKey(),
            'code' => 'SAVE500',
        ]);
    [$checkout, $variant, $cart] = orderCompletionCheckout($store, discountCode: 'SAVE500');

    Event::fake();

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->order_number)->toBe('#1001')
        ->and($order->status)->toBe(OrderStatus::Paid)
        ->and($order->financial_status)->toBe(FinancialStatus:…1596 chars truncated…cent,
            'value_amount' => 10,
        ]);
    [$checkout] = orderCompletionCheckout($store);

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->discount_amount)->toBe(500)
        ->and($order->lines->first()->discount_allocations_json)->toBe([[
            'discount_id' => $automatic->getKey(),
            'code' => null,
            'amount' => 500,
        ]]);
});

test('checkout completion keeps explicit and automatic discount allocations separate', function () {
    $store = orderCompletionStore();
    $codeDiscount = Discount::factory()
        ->create([
            'store_id' => $store->getKey(),
            'code' => 'SAVE10',
            'value_type' => DiscountValueType::Percent,
            'value_amount' => 10,
        ]);
    $automatic = Discount::factory()
        ->create([
            'store_id' => $store->getKey(),
            'type' => DiscountType::Automatic,
            'code' => null,
            'value_type' => DiscountValueType::Percent,
            'value_amount' => 10,
        ]);
    [$checkout] = orderCompletionCheckout($store, discountCode: 'SAVE10');

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->discount_amount)->toBe(950)
        ->and($order->lines->first()->discount_allocations_json)->toBe([
            [
                'discount_id' => $codeDiscount->getKey(),
                'code' => 'SAVE10',
                'amount' => 500,
            ],
            [
                'discount_id' => $automatic->getKey(),
                'code' => null,
                'amount' => 450,
            ],
        ]);
});

test('checkout completion is idempotent for the same checkout', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store);

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);
    $sameOrder = app(CheckoutService::class)->completeCheckout($checkout->refresh(), [
        'card_number' => '4000 0000 0000 0002',
    ]);

    expect($sameOrder->is($order))->toBeTrue()
        ->and(Order::withoutGlobalScopes()->count())->toBe(1)
        ->and(Payment::query()->count())->toBe(1)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_on_hand)->toBe(8)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('bank transfer completion creates a pending order and keeps inventory reserved', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store, paymentMethod: 'bank_transfer');

    Event::fake();

    $order = app(CheckoutService::class)->completeCheckout($checkout);

    expect($order->status)->toBe(OrderStatus::Pending)
        ->and($order->financial_status)->toBe(FinancialStatus::Pending)
        ->and($order->payments->first()->status)->toBe(PaymentStatus::Pending)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::Completed);

    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect($inventory->quantity_on_hand)->toBe(10)
        ->and($inventory->quantity_reserved)->toBe(2);

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

test('payment failures release reserved inventory and allow checkout retry', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store);

    expect(fn () => app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4000 0000 0000 0002',
    ]))->toThrow(PaymentFailedException::class);

    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect(Order::withoutGlobalScopes()->count())->toBe(0)
        ->and($inventory->quantity_on_hand)->toBe(10)
        ->and($inventory->quantity_reserved)->toBe(0)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->payment_method)->toBeNull();
});

test('order numbers increment sequentially per store', function () {
    $store = orderCompletionStore(start: 5001);
    [$firstCheckout] = orderCompletionCheckout($store);
    [$secondCheckout] = orderCompletionCheckout($store);

    $firstOrder = app(CheckoutService::class)->completeCheckout($firstCheckout, [
        'card_number' => '4242 4242 4242 4242',
    ]);
    $secondOrder = app(CheckoutService::class)->completeCheckout($secondCheckout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($firstOrder->order_number)->toBe('#5001')
        ->and($secondOrder->order_number)->toBe('#5002');
});

status: completed


command: sed -n '1,220p' tests/Feature/Admin/DashboardTest.php

DashboardTest.php

aggregated_output:
<?php

use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

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

function adminDashboardStore(): Store
{
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    app()->instance('current_store', $store);

    return $store;
}

function adminDashboardUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

function adminDashboardOrder(Store $store, string $title, int $quantity, int $unitPrice, array $orderAttributes = []): Order
{
    $product = Product::factory()
        ->withDefaultVariant($unitPrice)
        ->create([
            'store_id' => $store->getKey(),
            'title' => $title,
        ]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();
    $total = $quantity * $unitPrice;
    $order = Order::factory()->paid()->create(array_merge([
        'store_id' => $store->getKey(),
        'subtotal_amount' => $total,
        'shipping_amount' => 0,
        'tax_amount' => 0,
        'total_amount' => $total,
        'placed_at' => now(),
    ], $orderAttributes));

    OrderLine::factory()->create([
        'order_id' => $order->getKey(),
        'product_id' => $product->getKey(),
        'variant_id' => $variant->getKey(),
        'title_snapshot' => $title,
        'sku_snapshot' => 'DASH-'.str($title)->slug()->upper(),
        'quantity' => $quantity,
        'unit_price_amount' => $unitPrice,
        'total_amount' => $total,
    ]);

    return $order;
}

test('admin dashboard route requires authentication and renders store scoped metrics', function (): void {
    $store = adminDashboardStore();
    adminDashboardOrder($store, 'Dashboard Jacket', 2, 2500);
    adminDashboardOrder($store, 'Dashboard Cap', 1, 2000);

    $otherStore = Store::factory()->create();
    adminDashboardOrder($otherStore, 'Other Store Product', 1, 9900);

    $this->get('/admin')->assertRedirect('/admin/login');

    $this->actingAs(adminDashboardUser())
        ->withSession(['current_store_id' => $store->getKey()])
        ->get('/admin')
        ->assertSuccessful()
        ->assertSee('Dashboard')
        ->assertSee('70.00 EUR')
        ->assertSee('Dashboard Jacket')
        ->assertDontSee('Other Store Product');
});

test('admin dashboard recalculates kpis when date range changes', function (): void {
    $store = adminDashboardStore();
    $user = adminDashboardUser();

    adminDashboardOrder($store, 'Today Product', 1, 6000);
    adminDashboardOrder($store, 'Older Product', 1, 4000, [
        'placed_at' => now()->subDays(15),
    ]);

    Livewire::actingAs($user)
        ->test(AdminDashboard::class)
        ->assertSet('ordersCount', 2)
        ->assertSet('totalSales', 10000)
        ->set('dateRange', 'today')
        ->assertSet('ordersCount', 1)
        ->assertSet('totalSales', 6000)
        ->set('dateRange', 'custom')
        ->set('customStartDate', now()->subDays(20)->toDateString())
        ->set('customEndDate', now()->subDays(10)->toDateString())
        ->assertSet('ordersCount', 1)
        ->assertSet('totalSales', 4000);
});


command: rg -n "Order::withoutGlobalScopes\(\)->count\(\)|Order::query\(\)->count\(\)|orders_count|assertDatabaseCount\('orders'|firstOrFail\(\).*Order|order_number' => '#1001|#1001|#1002|#1004|#1005" tests -S

type: search

cmd: rg -n "Order::withoutGlobalScopes\\(\\)->count\\(\\)|Order::query\\(\\)->count\\(\\)|orders_count|assertDatabaseCount\\('orders'|firstOrFail\\(\\).*Order|order_number' => '#1001|#1001|#1002|#1004|#1005" tests -S

query: Order::withoutGlobalScopes\(\)->count\(\)|Order::query\(\)->count\(\)|orders_count|assertDatabaseCount\('orders'|firstOrFail\(\).*Order|order_number' => '#1001|#1001|#1002|#1004|#1005

path: tests

aggregated_output:
tests/Feature/Analytics/AnalyticsServiceTest.php:82:        ->and($daily->orders_count)->toBe(2)
tests/Feature/Orders/OrderServiceTest.php:161:    expect($order->order_number)->toBe('#1001')
tests/Feature/Orders/OrderServiceTest.php:262:        ->and(Order::withoutGlobalScopes()->count())->toBe(1)
tests/Feature/Orders/OrderServiceTest.php:300:    expect(Order::withoutGlobalScopes()->count())->toBe(0)
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:54:            'orders_count' => 2,
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:65:            'orders_count' => 3,
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:97:        ->assertJsonPath('data.summary.orders_count', 5)
tests/Feature/Api/AdminCatalogApiTest.php:103:        ->assertJsonPath('data.0.orders_count', 1)
tests/Feature/Api/StorefrontOrderApiTest.php:110:        ->assertJsonPath('data.order_number', '#1001')
tests/Feature/Api/StorefrontOrderApiTest.php:119:        ->assertJsonPath('data.order_number', '#1001')
tests/Feature/Storefront/CustomerAccountTest.php:58:    $orders = collect(['#1001', '#1002', '#1004'])->map(fn (string $orderNumber): Order => Order::factory()
tests/Feature/Storefront/CustomerAccountTest.php:76:        ->assertSee('#1001')
tests/Feature/Storefront/CustomerAccountTest.php:77:        ->assertSee('#1002')
tests/Feature/Storefront/CustomerAccountTest.php:78:        ->assertSee('#1004');
tests/Feature/Storefront/CustomerAccountTest.php:83:        ->assertSee('#1001')
tests/Feature/Storefront/OrderViewsTest.php:121:    expect(Order::withoutGlobalScopes()->count())->toBe(0)
tests/Browser/Admin/CustomerManagementTest.php:71:        'order_number' => '#1001',
tests/Browser/Admin/CustomerManagementTest.php:150:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:54:    foreach (['#1001', '#1002', '#1004'] as $orderNumber) {
tests/Browser/Storefront/TenantIsolationTest.php:133:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:157:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:158:        ->assertSee('#1002')
tests/Browser/Storefront/TenantIsolationTest.php:159:        ->assertSee('#1004')
tests/Browser/Admin/OrderManagementTest.php:69:        orderNumber: '#1001',
tests/Browser/Admin/OrderManagementTest.php:82:        orderNumber: '#1002',
tests/Browser/Admin/OrderManagementTest.php:97:        orderNumber: '#1005',
tests/Browser/Admin/OrderManagementTest.php:234:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:242:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:243:        ->assertDontSee('#1005')
tests/Browser/Admin/OrderManagementTest.php:247:        ->assertSee('#1002')
tests/Browser/Admin/OrderManagementTest.php:252:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:253:        ->assertSee('#1005')
tests/Browser/Admin/OrderManagementTest.php:258:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:270:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:277:    adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Admin/OrderManagementTest.php:281:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:294:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:300:    adminOrderOpenOrder($this, '#1005')
tests/Browser/Admin/OrderManagementTest.php:312:    adminOrderOpenOrder($this, '#1005')
tests/Browser/Admin/OrderManagementTest.php:320:    $page = adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Admin/OrderManagementTest.php:329:    $page = adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Storefront/CustomerAccountTest.php:65:    return collect(['#1001', '#1002', '#1004'])
tests/Browser/Storefront/CustomerAccountTest.php:165:        ->assertSee('#1001')
tests/Browser/Storefront/CustomerAccountTest.php:166:        ->assertSee('#1002')
tests/Browser/Storefront/CustomerAccountTest.php:167:        ->assertSee('#1004')
tests/Browser/Storefront/CustomerAccountTest.php:181:        ->assertSee('#1001')
tests/Browser/Storefront/CheckoutTest.php:125:        ->assertSee('#1001')
tests/Browser/Storefront/CheckoutTest.php:238:        ->assertSee('#1001')


output:
Chunk ID: cb4bf9
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1754
Output:
<?php

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Livewire\Storefront\Account\Orders\Index as AccountOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as AccountOrderShow;
use App\Livewire\Storefront\Checkout\Confirmation;
use App\Livewire\Storefront\Checkout\Show as CheckoutShow;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\Store;
use App\Services\CartService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

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

function orderViewsStore(): Store
{
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    app()->instance('current_store', $store);

    return $store;
}

function orderViewsVariant(Store $store): ProductVariant
{
    $product = Product::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('handle', 'classic-cotton-t-shirt')
        ->firstOrFail();

    return ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->oldest('position')
        ->firstOrFail();
}

function orderViewsShippingRate(Store $store): ShippingRate
{
    return ShippingRate::withoutGlobalScopes()
        ->whereHas('zone', fn ($query) => $query->withoutGlobalScopes()->where('store_id', $store->getKey()))
        ->where('name', 'Standard Shipping')
        ->firstOrFail();
}

test('checkout page places an order and redirects to confirmation', function () {
    $store = orderViewsStore();
    $variant = orderViewsVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    $component = Livewire::test(CheckoutShow::class)
        ->set('email', 'buyer@example.test')
        ->set('shippingAddress.first_name', 'Test')
        ->set('shippingAddress.last_name', 'Buyer')
        ->set('shippingAddress.address1', 'Main Street 1')
        ->set('shippingAddress.city', 'Berlin')
        ->set('shippingAddress.country', 'DE')
        ->set('shippingAddress.postal_code', '10115')
        ->call('saveAddress')
        ->set('selectedShippingRateId', orderViewsShippingRate($store)->getKey())
        ->call('selectShippingMethod')
        ->set('paymentMethod', 'credit_card')
        ->call('selectPaymentMethod')
        ->set('cardNumber', '4242 4242 4242 4242')
        ->call('placeOrder');

    $order = Order::withoutGlobalScopes()->firstOrFail();

    $component->assertRedirect(route('checkout.confirmation', $order));

    expect($order->email)->toBe('buyer@example.test')
        ->and($order->lines)->toHaveCount(1)
        ->and($cart->refresh()->status)->toBe(CartStatus::Converted)
        ->and(session('last_order_id'))->toBe($order->getKey())
        ->and(session('cart_id'))->toBeNull();
});

test('checkout page surfaces payment failures and releases reservations', function () {
    $store = orderViewsStore();
    $variant = orderViewsVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    Livewire::test(CheckoutShow::class)
        ->set('email', 'buyer@example.test')
        ->set('shippingAddress.first_name', 'Test')
        ->set('shippingAddress.last_name', 'Buyer')
        ->set('shippingAddress.address1', 'Main Street 1')
        ->set('shippingAddress.city', 'Berlin')
        ->set('shippingAddress.country', 'DE')
        ->set('shippingAddress.postal_code', '10115')
        ->call('saveAddress')
        ->set('selectedShippingRateId', orderViewsShippingRate($store)->getKey())
        ->call('selectShippingMethod')
        ->set('paymentMethod', 'credit_card')
        ->call('selectPaymentMethod')
        ->set('cardNumber', '4000 0000 0000 0002')
        ->call('placeOrder')
        ->assertHasErrors('cardNumber')
        ->assertSet('step', 'payment');

    $checkout = Checkout::withoutGlobalScopes()->where('cart_id', $cart->getKey())->firstOrFail();
    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect(Order::withoutGlobalScopes()->count())->toBe(0)
        ->and($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($inventory->quantity_reserved)->toBe(0);
});

test('order confirmation is visible only for the session order or customer order', function () {
    $store = orderViewsStore();
    $customer = Customer::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $otherCustomer = Customer::factory()->create(['store_id' => $store->getKey()]);
    $order = Order::factory()->forCustomer($customer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $customer->getKey(),
        'email' => $customer->email,
    ]);

    session(['last_order_id' => $order->getKey()]);

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertSee($order->order_number);

    session()->forget('last_order_id');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertStatus(404);

    $this->actingAs($otherCustomer, 'customer');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertStatus(404);

    $this->actingAs($customer, 'customer');

    Livewire::test(Confirmation::class, ['order' => $order])
        ->assertSee($order->order_number);
});

test('customer account lists and shows customer orders', function () {
    $store = orderViewsStore();
    $customer = Customer::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $otherCustomer = Customer::factory()->create(['store_id' => $store->getKey()]);
    $order = Order::factory()->forCustomer($customer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $customer->getKey(),
        'order_number' => '#7777',
    ]);
    $otherOrder = Order::factory()->forCustomer($otherCustomer)->paid()->create([
        'store_id' => $store->getKey(),
        'customer_id' => $otherCustomer->getKey(),
        'order_number' => '#8888',
    ]);
    OrderLine::factory()->create([
        'order_id' => $order->getKey(),
        'title_snapshot' => 'Classic Cotton T-Shirt',
    ]);

    $this->actingAs($customer, 'customer');

    Livewire::test(AccountOrdersIndex::class)
        ->assertSee('#7777')
        ->assertDontSee('#8888');

    Livewire::test(AccountOrderShow::class, ['order' => $order])
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('#7777');

    Livewire::test(AccountOrderShow::class, ['order' => $otherOrder])
        ->assertStatus(404);
});


output:
Chunk ID: b195d3
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2899
Output:
<?php

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Enums\DiscountType;
use App\Enums\DiscountValueType;
use App\Enums\FinancialStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentStatus;
use App\Events\OrderCreated;
use App\Events\OrderPaid;
use App\Exceptions\PaymentFailedException;
use App\Models\Checkout;
use App\Models\Discount;
use App\Models\InventoryItem;
use App\Models\Order;
use App\Models\Payment;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\StoreSettings;
use App\Models\TaxSettings;
use App\Services\CartService;
use App\Services\CheckoutService;
use App\Services\PricingEngine;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;

uses(RefreshDatabase::class);

function orderCompletionStore(int $start = 1001): Store
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    StoreSettings::query()->create([
        'store_id' => $store->getKey(),
        'settings_json' => [
            'order_number_prefix' => '#',
            'order_number_start' => $start,
        ],
    ]);

    TaxSettings::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'mode' => 'manual',
        'provider' => 'none',
        'prices_include_tax' => false,
        'config_json' => ['default_rate_bps' => 0, 'shipping_taxable' => false],
    ]);

    return $store;
}

function orderCompletionVariant(Store $store, int $price = 2500, int $stock = 10): ProductVariant
{
    $product = Product::factory()
        ->withDefaultVariant($price)
        ->create(['store_id' => $store->getKey()]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();

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

    return $variant->refresh();
}

function orderCompletionShippingRate(Store $store): ShippingRate
{
    $zone = ShippingZone::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('name', 'Germany')
        ->first();

    if (! $zone instanceof ShippingZone) {
        $zone = ShippingZone::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'name' => 'Germany',
            'countries_json' => ['DE'],
            'regions_json' => [],
        ]);
    }

    $rate = ShippingRate::withoutGlobalScopes()
        ->where('zone_id', $zone->getKey())
        ->where('name', 'Standard')
        ->first();

    if ($rate instanceof ShippingRate) {
        return $rate;
    }

    return ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
}

/**
 * @return array{0: Checkout, 1: ProductVariant, 2: \App\Models\Cart}
 */
function orderCompletionCheckout(Store $store, string $paymentMethod = 'credit_card', ?string $discountCode = null): array
{
    $variant = orderCompletionVariant($store);
    $rate = orderCompletionShippingRate($store);
    $cart = app(CartService::class)->create($store);

    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, [
        'email' => 'buyer@example.test',
        'shipping_address' => [
            'first_name' => 'Test',
            'last_name' => 'Buyer',
            'address1' => 'Main Street 1',
            'city' => 'Berlin',
            'country' => 'DE',
            'postal_code' => '10115',
        ],
    ]);
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());

    if ($discountCode !== null) {
        $checkout->forceFill(['discount_code' => $discountCode])->save();
        app(PricingEngine::class)->calculate($checkout);
    }

    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, $paymentMethod);

    return [$checkout, $variant, $cart];
}

test('checkout completion creates a paid order and commits inventory', function () {
    $store = orderCompletionStore();
    $discount = Discount::factory()
        ->fixed(500)
        ->create([
            'store_id' => $store->getKey(),
            'code' => 'SAVE500',
        ]);
    [$checkout, $variant, $cart] = orderCompletionCheckout($store, discountCode: 'SAVE500');

    Event::fake();

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->order_number)->toBe('#1001')
        ->and($order->status)->toBe(OrderStatus::Paid)
        ->and($order->financial_status)->toBe(FinancialStatus::Paid)
        ->and($order->total_amount)->toBe(4999)
        ->and($order->lines)->toHaveCount(1)
        ->and($order->lines->first()->title_snapshot)->toContain($variant->product->title)
        ->and($order->lines->first()->discount_allocations_json)->toBe([[
            'discount_id' => $discount->getKey(),
            'code' => 'SAVE500',
            'amount' => 500,
        ]])
        ->and($order->payments)->toHaveCount(1)
        ->and($order->payments->first()->status)->toBe(PaymentStatus::Captured)
        ->and($order->payments->first()->raw_json_encrypted['success'])->toBeTrue()
        ->and($cart->refresh()->status)->toBe(CartStatus::Converted)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::Completed)
        ->and($discount->refresh()->usage_count)->toBe(1);

    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect($inventory->quantity_on_hand)->toBe(8)
        ->and($inventory->quantity_reserved)->toBe(0);

    Event::assertDispatched(OrderCreated::class, fn (OrderCreated $event): bool => $event->order->is($order));
    Event::assertDispatched(OrderPaid::class, fn (OrderPaid $event): bool => $event->order->is($order));
});

test('checkout completion attributes automatic discounts on order lines', function () {
    $store = orderCompletionStore();
    $automatic = Discount::factory()
        ->create([
            'store_id' => $store->getKey(),
            'type' => DiscountType::Automatic,
            'code' => null,
            'value_type' => DiscountValueType::Percent,
            'value_amount' => 10,
        ]);
    [$checkout] = orderCompletionCheckout($store);

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->discount_amount)->toBe(500)
        ->and($order->lines->first()->discount_allocations_json)->toBe([[
            'discount_id' => $automatic->getKey(),
            'code' => null,
            'amount' => 500,
        ]]);
});

test('checkout completion keeps explicit and automatic discount allocations separate', function () {
    $store = orderCompletionStore();
    $codeDiscount = Discount::factory()
        ->create([
            'store_id' => $store->getKey(),
            'code' => 'SAVE10',
            'value_type' => DiscountValueType::Percent,
            'value_amount' => 10,
        ]);
    $automatic = Discount::factory()
        ->create([
            'store_id' => $store->getKey(),
            'type' => DiscountType::Automatic,
            'code' => null,
            'value_type' => DiscountValueType::Percent,
            'value_amount' => 10,
        ]);
    [$checkout] = orderCompletionCheckout($store, discountCode: 'SAVE10');

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($order->discount_amount)->toBe(950)
        ->and($order->lines->first()->discount_allocations_json)->toBe([
            [
                'discount_id' => $codeDiscount->getKey(),
                'code' => 'SAVE10',
                'amount' => 500,
            ],
            [
                'discount_id' => $automatic->getKey(),
                'code' => null,
                'amount' => 450,
            ],
        ]);
});

test('checkout completion is idempotent for the same checkout', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store);

    $order = app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4242 4242 4242 4242',
    ]);
    $sameOrder = app(CheckoutService::class)->completeCheckout($checkout->refresh(), [
        'card_number' => '4000 0000 0000 0002',
    ]);

    expect($sameOrder->is($order))->toBeTrue()
        ->and(Order::withoutGlobalScopes()->count())->toBe(1)
        ->and(Payment::query()->count())->toBe(1)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_on_hand)->toBe(8)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('bank transfer completion creates a pending order and keeps inventory reserved', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store, paymentMethod: 'bank_transfer');

    Event::fake();

    $order = app(CheckoutService::class)->completeCheckout($checkout);

    expect($order->status)->toBe(OrderStatus::Pending)
        ->and($order->financial_status)->toBe(FinancialStatus::Pending)
        ->and($order->payments->first()->status)->toBe(PaymentStatus::Pending)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::Completed);

    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect($inventory->quantity_on_hand)->toBe(10)
        ->and($inventory->quantity_reserved)->toBe(2);

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

test('payment failures release reserved inventory and allow checkout retry', function () {
    $store = orderCompletionStore();
    [$checkout, $variant] = orderCompletionCheckout($store);

    expect(fn () => app(CheckoutService::class)->completeCheckout($checkout, [
        'card_number' => '4000 0000 0000 0002',
    ]))->toThrow(PaymentFailedException::class);

    $inventory = InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->firstOrFail();

    expect(Order::withoutGlobalScopes()->count())->toBe(0)
        ->and($inventory->quantity_on_hand)->toBe(10)
        ->and($inventory->quantity_reserved)->toBe(0)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->payment_method)->toBeNull();
});

test('order numbers increment sequentially per store', function () {
    $store = orderCompletionStore(start: 5001);
    [$firstCheckout] = orderCompletionCheckout($store);
    [$secondCheckout] = orderCompletionCheckout($store);

    $firstOrder = app(CheckoutService::class)->completeCheckout($firstCheckout, [
        'card_number' => '4242 4242 4242 4242',
    ]);
    $secondOrder = app(CheckoutService::class)->completeCheckout($secondCheckout, [
        'card_number' => '4242 4242 4242 4242',
    ]);

    expect($firstOrder->order_number)->toBe('#5001')
        ->and($secondOrder->order_number)->toBe('#5002');
});


output:
Chunk ID: 2e305d
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 881
Output:
<?php

use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Models\Order;
use App\Models\OrderLine;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;

uses(RefreshDatabase::class);

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

function adminDashboardStore(): Store
{
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    app()->instance('current_store', $store);

    return $store;
}

function adminDashboardUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

function adminDashboardOrder(Store $store, string $title, int $quantity, int $unitPrice, array $orderAttributes = []): Order
{
    $product = Product::factory()
        ->withDefaultVariant($unitPrice)
        ->create([
            'store_id' => $store->getKey(),
            'title' => $title,
        ]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();
    $total = $quantity * $unitPrice;
    $order = Order::factory()->paid()->create(array_merge([
        'store_id' => $store->getKey(),
        'subtotal_amount' => $total,
        'shipping_amount' => 0,
        'tax_amount' => 0,
        'total_amount' => $total,
        'placed_at' => now(),
    ], $orderAttributes));

    OrderLine::factory()->create([
        'order_id' => $order->getKey(),
        'product_id' => $product->getKey(),
        'variant_id' => $variant->getKey(),
        'title_snapshot' => $title,
        'sku_snapshot' => 'DASH-'.str($title)->slug()->upper(),
        'quantity' => $quantity,
        'unit_price_amount' => $unitPrice,
        'total_amount' => $total,
    ]);

    return $order;
}

test('admin dashboard route requires authentication and renders store scoped metrics', function (): void {
    $store = adminDashboardStore();
    adminDashboardOrder($store, 'Dashboard Jacket', 2, 2500);
    adminDashboardOrder($store, 'Dashboard Cap', 1, 2000);

    $otherStore = Store::factory()->create();
    adminDashboardOrder($otherStore, 'Other Store Product', 1, 9900);

    $this->get('/admin')->assertRedirect('/admin/login');

    $this->actingAs(adminDashboardUser())
        ->withSession(['current_store_id' => $store->getKey()])
        ->get('/admin')
        ->assertSuccessful()
        ->assertSee('Dashboard')
        ->assertSee('70.00 EUR')
        ->assertSee('Dashboard Jacket')
        ->assertDontSee('Other Store Product');
});

test('admin dashboard recalculates kpis when date range changes', function (): void {
    $store = adminDashboardStore();
    $user = adminDashboardUser();

    adminDashboardOrder($store, 'Today Product', 1, 6000);
    adminDashboardOrder($store, 'Older Product', 1, 4000, [
        'placed_at' => now()->subDays(15),
    ]);

    Livewire::actingAs($user)
        ->test(AdminDashboard::class)
        ->assertSet('ordersCount', 2)
        ->assertSet('totalSales', 10000)
        ->set('dateRange', 'today')
        ->assertSet('ordersCount', 1)
        ->assertSet('totalSales', 6000)
        ->set('dateRange', 'custom')
        ->set('customStartDate', now()->subDays(20)->toDateString())
        ->set('customEndDate', now()->subDays(10)->toDateString())
        ->assertSet('ordersCount', 1)
        ->assertSet('totalSales', 4000);
});


output:
Chunk ID: b9676e
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1098
Output:
tests/Feature/Analytics/AnalyticsServiceTest.php:82:        ->and($daily->orders_count)->toBe(2)
tests/Feature/Orders/OrderServiceTest.php:161:    expect($order->order_number)->toBe('#1001')
tests/Feature/Orders/OrderServiceTest.php:262:        ->and(Order::withoutGlobalScopes()->count())->toBe(1)
tests/Feature/Orders/OrderServiceTest.php:300:    expect(Order::withoutGlobalScopes()->count())->toBe(0)
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:54:            'orders_count' => 2,
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:65:            'orders_count' => 3,
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:97:        ->assertJsonPath('data.summary.orders_count', 5)
tests/Feature/Api/AdminCatalogApiTest.php:103:        ->assertJsonPath('data.0.orders_count', 1)
tests/Feature/Api/StorefrontOrderApiTest.php:110:        ->assertJsonPath('data.order_number', '#1001')
tests/Feature/Api/StorefrontOrderApiTest.php:119:        ->assertJsonPath('data.order_number', '#1001')
tests/Feature/Storefront/CustomerAccountTest.php:58:    $orders = collect(['#1001', '#1002', '#1004'])->map(fn (string $orderNumber): Order => Order::factory()
tests/Feature/Storefront/CustomerAccountTest.php:76:        ->assertSee('#1001')
tests/Feature/Storefront/CustomerAccountTest.php:77:        ->assertSee('#1002')
tests/Feature/Storefront/CustomerAccountTest.php:78:        ->assertSee('#1004');
tests/Feature/Storefront/CustomerAccountTest.php:83:        ->assertSee('#1001')
tests/Feature/Storefront/OrderViewsTest.php:121:    expect(Order::withoutGlobalScopes()->count())->toBe(0)
tests/Browser/Admin/CustomerManagementTest.php:71:        'order_number' => '#1001',
tests/Browser/Admin/CustomerManagementTest.php:150:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:54:    foreach (['#1001', '#1002', '#1004'] as $orderNumber) {
tests/Browser/Storefront/TenantIsolationTest.php:133:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:157:        ->assertSee('#1001')
tests/Browser/Storefront/TenantIsolationTest.php:158:        ->assertSee('#1002')
tests/Browser/Storefront/TenantIsolationTest.php:159:        ->assertSee('#1004')
tests/Browser/Admin/OrderManagementTest.php:69:        orderNumber: '#1001',
tests/Browser/Admin/OrderManagementTest.php:82:        orderNumber: '#1002',
tests/Browser/Admin/OrderManagementTest.php:97:        orderNumber: '#1005',
tests/Browser/Admin/OrderManagementTest.php:234:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:242:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:243:        ->assertDontSee('#1005')
tests/Browser/Admin/OrderManagementTest.php:247:        ->assertSee('#1002')
tests/Browser/Admin/OrderManagementTest.php:252:        ->assertSee('#1001')
tests/Browser/Admin/OrderManagementTest.php:253:        ->assertSee('#1005')
tests/Browser/Admin/OrderManagementTest.php:258:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:270:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:277:    adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Admin/OrderManagementTest.php:281:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:294:    adminOrderOpenOrder($this, '#1001')
tests/Browser/Admin/OrderManagementTest.php:300:    adminOrderOpenOrder($this, '#1005')
tests/Browser/Admin/OrderManagementTest.php:312:    adminOrderOpenOrder($this, '#1005')
tests/Browser/Admin/OrderManagementTest.php:320:    $page = adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Admin/OrderManagementTest.php:329:    $page = adminOrderCreateFulfillmentInBrowser(adminOrderOpenOrder($this, '#1001'));
tests/Browser/Storefront/CustomerAccountTest.php:65:    return collect(['#1001', '#1002', '#1004'])
tests/Browser/Storefront/CustomerAccountTest.php:165:        ->assertSee('#1001')
tests/Browser/Storefront/CustomerAccountTest.php:166:        ->assertSee('#1002')
tests/Browser/Storefront/CustomerAccountTest.php:167:        ->assertSee('#1004')
tests/Browser/Storefront/CustomerAccountTest.php:181:        ->assertSee('#1001')
tests/Browser/Storefront/CheckoutTest.php:125:        ->assertSee('#1001')
tests/Browser/Storefront/CheckoutTest.php:238:        ->assertSee('#1001')


cmd: sed -n '1,220p' database/seeders/CustomerSeeder.php && sed -n '1,220p' database/factories/CustomerFactory.php && sed -n '1,160p' app/Models/Customer.php


command: sed -n '1,220p' database/seeders/CustomerSeeder.php && sed -n '1,220p' database/factories/CustomerFactory.php && sed -n '1,160p' app/Models/Customer.php

Customer.php

cmd: sed -n '1,160p' app/Models/Customer.php

aggregated_output:
<?php

namespace Database\Seeders;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Seeder;

class CustomerSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();

        Customer::withoutGlobalScopes()->updateOrCreate(
            [
                'store_id' => $store->getKey(),
                'email' => 'customer@acme.test',
            ],
            [
                'name' => 'John Doe',
                'password' => 'password',
                'marketing_opt_in' => true,
            ],
        );
    }
}
<?php

namespace Database\Factories;

use App\Models\Store;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Customer>
 */
class CustomerFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'store_id' => Store::factory(),
            'email' => fake()->unique()->safeEmail(),
            'password' => 'password',
            'name' => fake()->name(),
            'marketing_opt_in' => false,
        ];
    }

    public function guest(): static
    {
        return $this->state(fn (array $attributes): array => [
            'password' => null,
        ]);
    }
}
<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;

class Customer extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\CustomerFactory> */
    use BelongsToStore, HasFactory, Notifiable;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'store_id',
        'email',
        'password',
        'name',
        'marketing_opt_in',
    ];

    /**
     * @var list<string>
     */
    protected $hidden = [
        'password_hash',
        'remember_token',
    ];

    public function getAuthPassword(): ?string
    {
        return $this->password_hash;
    }

    public function setPasswordAttribute(?string $value): void
    {
        $this->attributes['password_hash'] = $value && Hash::needsRehash($value) ? Hash::make($value) : $value;
    }

    public function getPasswordAttribute(): ?string
    {
        return $this->password_hash;
    }

    /**
     * @return HasMany<Cart, $this>
     */
    public function carts(): HasMany
    {
        return $this->hasMany(Cart::class);
    }

    /**
     * @return HasMany<Checkout, $this>
     */
    public function checkouts(): HasMany
    {
        return $this->hasMany(Checkout::class);
    }

    /**
     * @return HasMany<CustomerAddress, $this>
     */
    public function addresses(): HasMany
    {
        return $this->hasMany(CustomerAddress::class);
    }

    /**
     * @return HasMany<Order, $this>
     */
    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'marketing_opt_in' => 'bool',
        ];
    }
}


output:
Chunk ID: 211201
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 858
Output:
<?php

namespace Database\Seeders;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Seeder;

class CustomerSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();

        Customer::withoutGlobalScopes()->updateOrCreate(
            [
                'store_id' => $store->getKey(),
                'email' => 'customer@acme.test',
            ],
            [
                'name' => 'John Doe',
                'password' => 'password',
                'marketing_opt_in' => true,
            ],
        );
    }
}
<?php

namespace Database\Factories;

use App\Models\Store;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Customer>
 */
class CustomerFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'store_id' => Store::factory(),
            'email' => fake()->unique()->safeEmail(),
            'password' => 'password',
            'name' => fake()->name(),
            'marketing_opt_in' => false,
        ];
    }

    public function guest(): static
    {
        return $this->state(fn (array $attributes): array => [
            'password' => null,
        ]);
    }
}
<?php

namespace App\Models;

use App\Models\Concerns\BelongsToStore;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;

class Customer extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\CustomerFactory> */
    use BelongsToStore, HasFactory, Notifiable;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'store_id',
        'email',
        'password',
        'name',
        'marketing_opt_in',
    ];

    /**
     * @var list<string>
     */
    protected $hidden = [
        'password_hash',
        'remember_token',
    ];

    public function getAuthPassword(): ?string
    {
        return $this->password_hash;
    }

    public function setPasswordAttribute(?string $value): void
    {
        $this->attributes['password_hash'] = $value && Hash::needsRehash($value) ? Hash::make($value) : $value;
    }

    public function getPasswordAttribute(): ?string
    {
        return $this->password_hash;
    }

    /**
     * @return HasMany<Cart, $this>
     */
    public function carts(): HasMany
    {
        return $this->hasMany(Cart::class);
    }

    /**
     * @return HasMany<Checkout, $this>
     */
    public function checkouts(): HasMany
    {
        return $this->hasMany(Checkout::class);
    }

    /**
     * @return HasMany<CustomerAddress, $this>
     */
    public function addresses(): HasMany
    {
        return $this->hasMany(CustomerAddress::class);
    }

    /**
     * @return HasMany<Order, $this>
     */
    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'marketing_opt_in' => 'bool',
        ];
    }
}


cmd: sed -n '1454,1510p' specs/07-SEEDERS-AND-TEST-DATA.md && sed -n '1878,1908p' specs/07-SEEDERS-AND-TEST-DATA.md


command: sed -n '1454,1510p' specs/07-SEEDERS-AND-TEST-DATA.md && sed -n '1878,1908p' specs/07-SEEDERS-AND-TEST-DATA.md

aggregated_output:
---

### 3.12 CustomerSeeder

**Acme Fashion - 10 customers:**

| # | Email | Name | Password (plaintext) | marketing_opt_in |
|---|-------|------|----------------------|------------------|
| 1 | customer@acme.test | John Doe | password | 1 |
| 2 | jane@example.com | Jane Smith | password | 0 |
| 3 | michael@example.com | Michael Brown | password | 1 |
| 4 | sarah@example.com | Sarah Wilson | password | 0 |
| 5 | david@example.com | David Lee | password | 1 |
| 6 | emma@example.com | Emma Garcia | password | 0 |
| 7 | james@example.com | James Taylor | password | 0 |
| 8 | lisa@example.com | Lisa Anderson | password | 1 |
| 9 | robert@example.com | Robert Martinez | password | 0 |
| 10 | anna@example.com | Anna Thomas | password | 1 |

**Customer 1 (customer@acme.test) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | John Doe, Hauptstrasse 1, 10115 Berlin, DE, phone: +49 30 12345678 |
| Work | 0 | John Doe, Acme Corp, Friedrichstrasse 100, 3rd Floor, 10117 Berlin, DE, phone: +49 30 87654321 |

**Customer 2 (jane@example.com) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | Jane Smith, Schillerstrasse 45, 80336 Munich, Bavaria (BY), DE |

**Customers 3-10:** Each gets one default address with Faker-generated German addresses.

**Acme Electronics - 2 customers (tenant isolation testing):**

| # | Email | Name | Password |
|---|-------|------|----------|
| 1 | techfan@example.com | Tech Fan | password |
| 2 | gadgetlover@example.com | Gadget Lover | password |

Each has one default address with Faker-generated data.

---

### 3.13 OrderSeeder

**Acme Fashion - 15 orders:**

All orders use the customer's default shipping address (unless noted). Order numbers follow the "#NNNN" format starting from #1001.

---

**Order #1001 - Awaiting fulfillment (Credit Card)**

| Field | Value |
|-------|-------|
|-------|----------|--------|-----------|-------------|-------|---------|
| #5001 | techfan@example.com | credit_card | paid | paid | fulfilled | 121298 | Pro Laptop 512GB (119999) + USB-C Cable (1299), shipping 0 |
| #5002 | gadgetlover@example.com | credit_card | paid | paid | unfulfilled | 14999 | Wireless Headphones Black (14999), shipping 0 |
| #5003 | techfan@example.com | bank_transfer | pending | pending | unfulfilled | 4999 | Monitor Stand (4999), shipping 0, bank transfer pending |

---

### 3.14 ThemeSeeder

**Acme Fashion:**

| Field | Value |
|-------|-------|
| name | Default Theme |
| version | 1.0.0 |
| status | published |
| published_at | now |

**Theme settings (theme_settings row):**

| Setting Key | Value |
|-------------|-------|
| primary_color | #1a1a2e |
| secondary_color | #e94560 |
| font_family | Inter, sans-serif |
| hero_heading | Welcome to Acme Fashion |
| hero_subheading | Discover our curated collection of modern essentials |
| hero_cta_text | Shop New Arrivals |
| hero_cta_link | /collections/new-arrivals |
| featured_collection_handles | ["new-arrivals", "t-shirts", "sale"] |
| footer_text | 2025 Acme Fashion. All rights reserved. |


output:
Chunk ID: 7c8611
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 783
Output:
---

### 3.12 CustomerSeeder

**Acme Fashion - 10 customers:**

| # | Email | Name | Password (plaintext) | marketing_opt_in |
|---|-------|------|----------------------|------------------|
| 1 | customer@acme.test | John Doe | password | 1 |
| 2 | jane@example.com | Jane Smith | password | 0 |
| 3 | michael@example.com | Michael Brown | password | 1 |
| 4 | sarah@example.com | Sarah Wilson | password | 0 |
| 5 | david@example.com | David Lee | password | 1 |
| 6 | emma@example.com | Emma Garcia | password | 0 |
| 7 | james@example.com | James Taylor | password | 0 |
| 8 | lisa@example.com | Lisa Anderson | password | 1 |
| 9 | robert@example.com | Robert Martinez | password | 0 |
| 10 | anna@example.com | Anna Thomas | password | 1 |

**Customer 1 (customer@acme.test) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | John Doe, Hauptstrasse 1, 10115 Berlin, DE, phone: +49 30 12345678 |
| Work | 0 | John Doe, Acme Corp, Friedrichstrasse 100, 3rd Floor, 10117 Berlin, DE, phone: +49 30 87654321 |

**Customer 2 (jane@example.com) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | Jane Smith, Schillerstrasse 45, 80336 Munich, Bavaria (BY), DE |

**Customers 3-10:** Each gets one default address with Faker-generated German addresses.

**Acme Electronics - 2 customers (tenant isolation testing):**

| # | Email | Name | Password |
|---|-------|------|----------|
| 1 | techfan@example.com | Tech Fan | password |
| 2 | gadgetlover@example.com | Gadget Lover | password |

Each has one default address with Faker-generated data.

---

### 3.13 OrderSeeder

**Acme Fashion - 15 orders:**

All orders use the customer's default shipping address (unless noted). Order numbers follow the "#NNNN" format starting from #1001.

---

**Order #1001 - Awaiting fulfillment (Credit Card)**

| Field | Value |
|-------|-------|
|-------|----------|--------|-----------|-------------|-------|---------|
| #5001 | techfan@example.com | credit_card | paid | paid | fulfilled | 121298 | Pro Laptop 512GB (119999) + USB-C Cable (1299), shipping 0 |
| #5002 | gadgetlover@example.com | credit_card | paid | paid | unfulfilled | 14999 | Wireless Headphones Black (14999), shipping 0 |
| #5003 | techfan@example.com | bank_transfer | pending | pending | unfulfilled | 4999 | Monitor Stand (4999), shipping 0, bank transfer pending |

---

### 3.14 ThemeSeeder

**Acme Fashion:**

| Field | Value |
|-------|-------|
| name | Default Theme |
| version | 1.0.0 |
| status | published |
| published_at | now |

**Theme settings (theme_settings row):**

| Setting Key | Value |
|-------------|-------|
| primary_color | #1a1a2e |
| secondary_color | #e94560 |
| font_family | Inter, sans-serif |
| hero_heading | Welcome to Acme Fashion |
| hero_subheading | Discover our curated collection of modern essentials |
| hero_cta_text | Shop New Arrivals |
| hero_cta_link | /collections/new-arrivals |
| featured_collection_handles | ["new-arrivals", "t-shirts", "sale"] |
| footer_text | 2025 Acme Fashion. All rights reserved. |


cmd: rg -n "product\('" database/seeders/ProductSeeder.php


command: rg -n "product\('" database/seeders/ProductSeeder.php

type: search

cmd: rg -n "product\\('" database/seeders/ProductSeeder.php

query: product\('

aggregated_output:
273:            $this->product('Classic Cotton T-Shirt', 'classic-cotton-t-shirt', 'Acme Basics', 'T-Shirts', ['new', 'popular'], ['new-arrivals', 't-shirts'], '
A timeless classic cotton t-shirt. Comfortable, breathable, and perfect for everyday wear.
', [['Size' => ['S', 'M', 'L', 'XL']], ['Color' => ['White', 'Black', 'Navy']]], ['price_amount' => 2499, 'weight_g' => 200, 'quantity_on_hand' => 15], 'ACME-CTSH'),
274:            $this->product('Premium Slim Fit Jeans', 'premium-slim-fit-jeans', 'Acme Denim', 'Pants', ['new', 'sale'], ['new-arrivals', 'pants-jeans', 'sale'], '
Slim fit jeans crafted from premium stretch denim. Comfortable all-day wear with a modern silhouette.
', [['Size' => ['28', '30', '32', '34', '36']], ['Color' => ['Blue', 'Black']]], ['price_amount' => 7999, 'compare_at_amount' => 9999, 'weight_g' => 800, 'quantity_on_hand' => 8], 'ACME-JNS'),
275:            $this->product('Organic Hoodie', 'organic-hoodie', 'Acme Basics', 'Hoodies', ['new', 'trending'], ['new-arrivals'], '
Made from 100% organic cotton. Warm, soft, and sustainably produced.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 5999, 'weight_g' => 500, 'quantity_on_hand' => 20], 'ACME-HOOD'),
276:            $this->product('Leather Belt', 'leather-belt', 'Acme Accessories', 'Accessories', ['popular'], [], '
Genuine leather belt with brushed metal buckle. A wardrobe essential.
', [['Size' => ['S/M', 'L/XL']], ['Color' => ['Brown', 'Black']]], ['price_amount' => 3499, 'weight_g' => 150, 'quantity_on_hand' => 25], 'ACME-BELT'),
277:            $this->product('Running Sneakers', 'running-sneakers', 'Acme Sport', 'Shoes', ['trending'], ['new-arrivals'], '
Lightweight running sneakers with responsive cushioning and breathable mesh upper.
', [['Size' => ['EU 38', 'EU 39', 'EU 40', 'EU 41', 'EU 42', 'EU 43', 'EU 44']], ['Color' => ['White', 'Black']]], ['price_amount' => 11999, 'weight_g' => 600, 'quantity_on_hand' => 5], 'ACME-RUN'),
278:            $this->product('Graphic Print Tee', 'graphic-print-tee', 'Acme Basics', 'T-Shirts', ['new'], ['t-shirts'], '
Bold graphic print on soft cotton. Express yourself with this statement piece.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 2999, 'weight_g' => 210, 'quantity_on_hand' => 18], 'ACME-GTEE'),
279:            $this->product('V-Neck Linen Tee', 'v-neck-linen-tee', 'Acme Basics', 'T-Shirts', ['popular'], ['t-shirts'], '
Lightweight linen blend v-neck. Perfect for warm summer days.
', [['Size' => ['S', 'M', 'L']], ['Color' => ['Beige', 'Olive', 'Sky Blue']]], ['price_amount' => 3499, 'weight_g' => 180, 'quantity_on_hand' => 12], 'ACME-VNECK'),
280:            $this->product('Striped Polo Shirt', 'striped-polo-shirt', 'Acme Basics', 'T-Shirts', ['sale'], ['t-shirts', 'sale'], '
Classic striped polo with a modern relaxed fit. Knitted collar and two-button placket.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 2799, 'compare_at_amount' => 3999, 'weight_g' => 250, 'quantity_on_hand' => 10], 'ACME-POLO'),
281:            $this->product('Cargo Pants', 'cargo-pants', 'Acme Workwear', 'Pants', ['popular'], ['pants-jeans'], '
Utility cargo pants with multiple pockets. Durable cotton twill construction.
', [['Size' => ['30', '32', '34', '36']], ['Color' => ['Khaki', 'Olive', 'Black']]], ['price_amount' => 5499, 'weight_g' => 700, 'quantity_on_hand' => 14], 'ACME-CARGO'),
282:            $this->product('Chino Shorts', 'chino-shorts', 'Acme Basics', 'Pants', ['new', 'trending'], ['pants-jeans', 'new-arrivals'], '
Tailored chino shorts. Comfortable stretch fabric with a clean silhouette.
', [['Size' => ['30', '32', '34', '36']], ['Color' => ['Navy', 'Sand']]], ['price_amount' => 3999, 'weight_g' => 350, 'quantity_on_hand' => 16], 'ACME-CHINO'),
283:            $this->product('Wide Leg Trousers', 'wide-leg-trousers', 'Acme Denim', 'Pants', ['sale'], ['pants-jeans', 'sale'], '
Relaxed wide leg trousers with a high waist. Flowing drape in premium woven fabric.
', [['Size' => ['S', 'M', 'L']]], ['price_amount' => 4999, 'compare_at_amount' => 6999, 'weight_g' => 550, 'quantity_on_hand' => 7], 'ACME-WIDE'),
284:            $this->product('Wool Scarf', 'wool-scarf', 'Acme Accessories', 'Accessories', ['popular'], [], '
Warm merino wool scarf. Soft hand feel, naturally breathable and temperature regulating.
', [['Color' => ['Grey', 'Burgundy', 'Navy']]], ['price_amount' => 2999, 'weight_g' => 120, 'quantity_on_hand' => 30], 'ACME-SCARF'),
285:            $this->product('Canvas Tote Bag', 'canvas-tote-bag', 'Acme Accessories', 'Accessories', ['trending'], [], '
Heavy-duty canvas tote bag with reinforced handles. Spacious enough for daily essentials.
', [['Color' => ['Natural', 'Black']]], ['price_amount' => 1999, 'weight_g' => 300, 'quantity_on_hand' => 40], 'ACME-TOTE'),
286:            $this->product('Bucket Hat', 'bucket-hat', 'Acme Accessories', 'Accessories', ['new', 'trending'], ['new-arrivals'], '
Lightweight bucket hat for sun protection. Packable design, washed cotton twill.
', [['Size' => ['S/M', 'L/XL']], ['Color' => ['Beige', 'Black', 'Olive']]], ['price_amount' => 2499, 'weight_g' => 80, 'quantity_on_hand' => 22], 'ACME-HAT'),
287:            $this->product('Unreleased Winter Jacket', 'unreleased-winter-jacket', 'Acme Outerwear', 'Jackets', ['limited'], [], '
Upcoming winter collection piece. Insulated puffer jacket with water-resistant shell.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 14999, 'weight_g' => 900, 'quantity_on_hand' => 0], 'ACME-WINTER', 'draft', null),
288:            $this->product('Discontinued Raincoat', 'discontinued-raincoat', 'Acme Outerwear', 'Jackets', [], [], '
Lightweight waterproof raincoat. This product has been discontinued.
', [['Size' => ['M', 'L']]], ['price_amount' => 8999, 'weight_g' => 400, 'quantity_on_hand' => 3], 'ACME-RAIN', 'archived', now()->subMonths(6)),
289:            $this->product('Limited Edition Sneakers', 'limited-edition-sneakers', 'Acme Sport', 'Shoes', ['limited'], [], '
Limited edition collaboration sneakers. Once they are gone, they are gone.
', [['Size' => ['EU 40', 'EU 42', 'EU 44']]], ['price_amount' => 15999, 'weight_g' => 650, 'quantity_on_hand' => 0, 'policy' => 'deny'], 'ACME-LIMITED'),
290:            $this->product('Backorder Denim Jacket', 'backorder-denim-jacket', 'Acme Denim', 'Jackets', ['popular'], [], '
Classic denim jacket. Currently on backorder - ships within 2-3 weeks.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 9999, 'weight_g' => 750, 'quantity_on_hand' => 0, 'policy' => 'continue'], 'ACME-BACKORDER'),
291:            $this->product('Gift Card', 'gift-card', 'Acme Fashion', 'Gift Cards', ['popular'], [], '
Digital gift card delivered via email. The perfect gift when you are not sure what to choose.
', [['Amount' => ['25 EUR', '50 EUR', '100 EUR']]], ['price_amount' => 2500, 'weight_g' => 0, 'requires_shipping' => false, 'quantity_on_hand' => 9999], 'ACME-GIFT', variants: [
296:            $this->product('Cashmere Overcoat', 'cashmere-overcoat', 'Acme Premium', 'Jackets', ['limited', 'new'], ['new-arrivals'], '
Luxurious cashmere-blend overcoat. Impeccable tailoring with silk lining.
', [['Size' => ['S', 'M', 'L']], ['Color' => ['Camel', 'Charcoal']]], ['price_amount' => 49999, 'weight_g' => 1200, 'quantity_on_hand' => 3], 'ACME-COAT'),
306:            $this->product('Pro Laptop 15', 'pro-laptop-15', 'TechCorp', 'Laptops', ['featured'], ['featured'], '
Performance laptop for tenant isolation tests.
', [['Storage' => ['256GB', '512GB', '1TB']]], ['price_amount' => 99999, 'weight_g' => 1800, 'quantity_on_hand' => 10], 'TECH-LAPTOP', variants: [
311:            $this->product('Wireless Headphones', 'wireless-headphones', 'AudioMax', 'Audio', ['featured'], ['featured'], '
Wireless headphones for tenant isolation tests.
', [['Color' => ['Black', 'Silver']]], ['price_amount' => 14999, 'weight_g' => 250, 'quantity_on_hand' => 25], 'TECH-HEADPHONES'),
312:            $this->product('USB-C Cable 2m', 'usb-c-cable-2m', 'CablePro', 'Cables', ['accessories'], ['accessories'], '
Two meter USB-C cable.
', [], ['price_amount' => 1299, 'weight_g' => 50, 'quantity_on_hand' => 200], 'TECH-CABLE'),
313:            $this->product('Mechanical Keyboard', 'mechanical-keyboard', 'KeyTech', 'Peripherals', ['featured'], ['featured'], '
Mechanical keyboard with selectable switch types.
', [['Switch Type' => ['Red', 'Blue', 'Brown']]], ['price_amount' => 12999, 'weight_g' => 1100, 'quantity_on_hand' => 15], 'TECH-KEYBOARD'),
314:            $this->product('Monitor Stand', 'monitor-stand', 'DeskGear', 'Accessories', ['accessories'], ['accessories'], '
Desktop monitor stand.
', [], ['price_amount' => 4999, 'weight_g' => 2500, 'quantity_on_hand' => 30], 'TECH-STAND'),


output:
Chunk ID: 7cc807
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2222
Output:
273:            $this->product('Classic Cotton T-Shirt', 'classic-cotton-t-shirt', 'Acme Basics', 'T-Shirts', ['new', 'popular'], ['new-arrivals', 't-shirts'], '
A timeless classic cotton t-shirt. Comfortable, breathable, and perfect for everyday wear.
', [['Size' => ['S', 'M', 'L', 'XL']], ['Color' => ['White', 'Black', 'Navy']]], ['price_amount' => 2499, 'weight_g' => 200, 'quantity_on_hand' => 15], 'ACME-CTSH'),
274:            $this->product('Premium Slim Fit Jeans', 'premium-slim-fit-jeans', 'Acme Denim', 'Pants', ['new', 'sale'], ['new-arrivals', 'pants-jeans', 'sale'], '
Slim fit jeans crafted from premium stretch denim. Comfortable all-day wear with a modern silhouette.
', [['Size' => ['28', '30', '32', '34', '36']], ['Color' => ['Blue', 'Black']]], ['price_amount' => 7999, 'compare_at_amount' => 9999, 'weight_g' => 800, 'quantity_on_hand' => 8], 'ACME-JNS'),
275:            $this->product('Organic Hoodie', 'organic-hoodie', 'Acme Basics', 'Hoodies', ['new', 'trending'], ['new-arrivals'], '
Made from 100% organic cotton. Warm, soft, and sustainably produced.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 5999, 'weight_g' => 500, 'quantity_on_hand' => 20], 'ACME-HOOD'),
276:            $this->product('Leather Belt', 'leather-belt', 'Acme Accessories', 'Accessories', ['popular'], [], '
Genuine leather belt with brushed metal buckle. A wardrobe essential.
', [['Size' => ['S/M', 'L/XL']], ['Color' => ['Brown', 'Black']]], ['price_amount' => 3499, 'weight_g' => 150, 'quantity_on_hand' => 25], 'ACME-BELT'),
277:            $this->product('Running Sneakers', 'running-sneakers', 'Acme Sport', 'Shoes', ['trending'], ['new-arrivals'], '
Lightweight running sneakers with responsive cushioning and breathable mesh upper.
', [['Size' => ['EU 38', 'EU 39', 'EU 40', 'EU 41', 'EU 42', 'EU 43', 'EU 44']], ['Color' => ['White', 'Black']]], ['price_amount' => 11999, 'weight_g' => 600, 'quantity_on_hand' => 5], 'ACME-RUN'),
278:            $this->product('Graphic Print Tee', 'graphic-print-tee', 'Acme Basics', 'T-Shirts', ['new'], ['t-shirts'], '
Bold graphic print on soft cotton. Express yourself with this statement piece.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 2999, 'weight_g' => 210, 'quantity_on_hand' => 18], 'ACME-GTEE'),
279:            $this->product('V-Neck Linen Tee', 'v-neck-linen-tee', 'Acme Basics', 'T-Shirts', ['popular'], ['t-shirts'], '
Lightweight linen blend v-neck. Perfect for warm summer days.
', [['Size' => ['S', 'M', 'L']], ['Color' => ['Beige', 'Olive', 'Sky Blue']]], ['price_amount' => 3499, 'weight_g' => 180, 'quantity_on_hand' => 12], 'ACME-VNECK'),
280:            $this->product('Striped Polo Shirt', 'striped-polo-shirt', 'Acme Basics', 'T-Shirts', ['sale'], ['t-shirts', 'sale'], '
Classic striped polo with a modern relaxed fit. Knitted collar and two-button placket.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 2799, 'compare_at_amount' => 3999, 'weight_g' => 250, 'quantity_on_hand' => 10], 'ACME-POLO'),
281:            $this->product('Cargo Pants', 'cargo-pants', 'Acme Workwear', 'Pants', ['popular'], ['pants-jeans'], '
Utility cargo pants with multiple pockets. Durable cotton twill construction.
', [['Size' => ['30', '32', '34', '36']], ['Color' => ['Khaki', 'Olive', 'Black']]], ['price_amount' => 5499, 'weight_g' => 700, 'quantity_on_hand' => 14], 'ACME-CARGO'),
282:            $this->product('Chino Shorts', 'chino-shorts', 'Acme Basics', 'Pants', ['new', 'trending'], ['pants-jeans', 'new-arrivals'], '
Tailored chino shorts. Comfortable stretch fabric with a clean silhouette.
', [['Size' => ['30', '32', '34', '36']], ['Color' => ['Navy', 'Sand']]], ['price_amount' => 3999, 'weight_g' => 350, 'quantity_on_hand' => 16], 'ACME-CHINO'),
283:            $this->product('Wide Leg Trousers', 'wide-leg-trousers', 'Acme Denim', 'Pants', ['sale'], ['pants-jeans', 'sale'], '
Relaxed wide leg trousers with a high waist. Flowing drape in premium woven fabric.
', [['Size' => ['S', 'M', 'L']]], ['price_amount' => 4999, 'compare_at_amount' => 6999, 'weight_g' => 550, 'quantity_on_hand' => 7], 'ACME-WIDE'),
284:            $this->product('Wool Scarf', 'wool-scarf', 'Acme Accessories', 'Accessories', ['popular'], [], '
Warm merino wool scarf. Soft hand feel, naturally breathable and temperature regulating.
', [['Color' => ['Grey', 'Burgundy', 'Navy']]], ['price_amount' => 2999, 'weight_g' => 120, 'quantity_on_hand' => 30], 'ACME-SCARF'),
285:            $this->product('Canvas Tote Bag', 'canvas-tote-bag', 'Acme Accessories', 'Accessories', ['trending'], [], '
Heavy-duty canvas tote bag with reinforced handles. Spacious enough for daily essentials.
', [['Color' => ['Natural', 'Black']]], ['price_amount' => 1999, 'weight_g' => 300, 'quantity_on_hand' => 40], 'ACME-TOTE'),
286:            $this->product('Bucket Hat', 'bucket-hat', 'Acme Accessories', 'Accessories', ['new', 'trending'], ['new-arrivals'], '
Lightweight bucket hat for sun protection. Packable design, washed cotton twill.
', [['Size' => ['S/M', 'L/XL']], ['Color' => ['Beige', 'Black', 'Olive']]], ['price_amount' => 2499, 'weight_g' => 80, 'quantity_on_hand' => 22], 'ACME-HAT'),
287:            $this->product('Unreleased Winter Jacket', 'unreleased-winter-jacket', 'Acme Outerwear', 'Jackets', ['limited'], [], '
Upcoming winter collection piece. Insulated puffer jacket with water-resistant shell.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 14999, 'weight_g' => 900, 'quantity_on_hand' => 0], 'ACME-WINTER', 'draft', null),
288:            $this->product('Discontinued Raincoat', 'discontinued-raincoat', 'Acme Outerwear', 'Jackets', [], [], '
Lightweight waterproof raincoat. This product has been discontinued.
', [['Size' => ['M', 'L']]], ['price_amount' => 8999, 'weight_g' => 400, 'quantity_on_hand' => 3], 'ACME-RAIN', 'archived', now()->subMonths(6)),
289:            $this->product('Limited Edition Sneakers', 'limited-edition-sneakers', 'Acme Sport', 'Shoes', ['limited'], [], '
Limited edition collaboration sneakers. Once they are gone, they are gone.
', [['Size' => ['EU 40', 'EU 42', 'EU 44']]], ['price_amount' => 15999, 'weight_g' => 650, 'quantity_on_hand' => 0, 'policy' => 'deny'], 'ACME-LIMITED'),
290:            $this->product('Backorder Denim Jacket', 'backorder-denim-jacket', 'Acme Denim', 'Jackets', ['popular'], [], '
Classic denim jacket. Currently on backorder - ships within 2-3 weeks.
', [['Size' => ['S', 'M', 'L', 'XL']]], ['price_amount' => 9999, 'weight_g' => 750, 'quantity_on_hand' => 0, 'policy' => 'continue'], 'ACME-BACKORDER'),
291:            $this->product('Gift Card', 'gift-card', 'Acme Fashion', 'Gift Cards', ['popular'], [], '
Digital gift card delivered via email. The perfect gift when you are not sure what to choose.
', [['Amount' => ['25 EUR', '50 EUR', '100 EUR']]], ['price_amount' => 2500, 'weight_g' => 0, 'requires_shipping' => false, 'quantity_on_hand' => 9999], 'ACME-GIFT', variants: [
296:            $this->product('Cashmere Overcoat', 'cashmere-overcoat', 'Acme Premium', 'Jackets', ['limited', 'new'], ['new-arrivals'], '
Luxurious cashmere-blend overcoat. Impeccable tailoring with silk lining.
', [['Size' => ['S', 'M', 'L']], ['Color' => ['Camel', 'Charcoal']]], ['price_amount' => 49999, 'weight_g' => 1200, 'quantity_on_hand' => 3], 'ACME-COAT'),
306:            $this->product('Pro Laptop 15', 'pro-laptop-15', 'TechCorp', 'Laptops', ['featured'], ['featured'], '
Performance laptop for tenant isolation tests.
', [['Storage' => ['256GB', '512GB', '1TB']]], ['price_amount' => 99999, 'weight_g' => 1800, 'quantity_on_hand' => 10], 'TECH-LAPTOP', variants: [
311:            $this->product('Wireless Headphones', 'wireless-headphones', 'AudioMax', 'Audio', ['featured'], ['featured'], '
Wireless headphones for tenant isolation tests.
', [['Color' => ['Black', 'Silver']]], ['price_amount' => 14999, 'weight_g' => 250, 'quantity_on_hand' => 25], 'TECH-HEADPHONES'),
312:            $this->product('USB-C Cable 2m', 'usb-c-cable-2m', 'CablePro', 'Cables', ['accessories'], ['accessories'], '
Two meter USB-C cable.
', [], ['price_amount' => 1299, 'weight_g' => 50, 'quantity_on_hand' => 200], 'TECH-CABLE'),
313:            $this->product('Mechanical Keyboard', 'mechanical-keyboard', 'KeyTech', 'Peripherals', ['featured'], ['featured'], '
Mechanical keyboard with selectable switch types.
', [['Switch Type' => ['Red', 'Blue', 'Brown']]], ['price_amount' => 12999, 'weight_g' => 1100, 'quantity_on_hand' => 15], 'TECH-KEYBOARD'),
314:            $this->product('Monitor Stand', 'monitor-stand', 'DeskGear', 'Accessories', ['accessories'], ['accessories'], '
Desktop monitor stand.
', [], ['price_amount' => 4999, 'weight_g' => 2500, 'quantity_on_hand' => 30], 'TECH-STAND'),


cmd: sed -n '1,220p' app/Models/ProductVariant.php && sed -n '1,220p' app/Models/ProductOptionValue.php && sed -n '1,220p' app/Models/VariantOptionValue.php


command: sed -n '1,220p' app/Models/ProductVariant.php && sed -n '1,220p' app/Models/ProductOptionValue.php && sed -n '1,220p' app/Models/VariantOptionValue.php

VariantOptionValue.php

aggregated_output:
<?php

namespace App\Models;

use App\Enums\InventoryPolicy;
use App\Enums\VariantStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use RuntimeException;

class ProductVariant extends Model
{
    /** @use HasFactory<\Database\Factories\ProductVariantFactory> */
    use HasFactory;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'product_id',
        'sku',
        'barcode',
        'price_amount',
        'compare_at_amount',
        'currency',
        'weight_g',
        'requires_shipping',
        'is_default',
        'position',
        'status',
    ];

    /**
     * @var array<string, mixed>
     */
    protected $attributes = [
        'price_amount' => 0,
        'currency' => 'USD',
        'requires_shipping' => true,
        'is_default' => false,
        'position' => 0,
        'status' => 'active',
    ];

    protected static function booted(): void
    {
        static::addGlobalScope('current_store', function (Builder $builder): void {
            if (! app()->bound('current_store')) {
                return;
            }

            $store = app('current_store');

            if (! $store instanceof Store) {
                return;
            }

            $builder->whereHas('product', function (Builder $query) use ($store): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $store->getKey());
            });
        });

        static::saving(function (ProductVariant $variant): void {
            $variant->assertSkuIsUniqueForStore();
        });

        static::created(function (ProductVariant $variant): void {
            if ($variant->inventoryItem()->exists()) {
                return;
            }

            $storeId = Product::withoutGlobalScopes()
                ->whereKey($variant->product_id)
                ->value('store_id');

            if (! $storeId) {
                return;
            }

            InventoryItem::withoutGlobalScopes()->create([
                'store_id' => $storeId,
                'variant_id' => $variant->getKey(),
                'quantity_on_hand' => 0,
                'quantity_reserved' => 0,
                'policy' => InventoryPolicy::Deny,
            ]);
        });
    }

    private function assertSkuIsUniqueForStore(): void
    {
        $sku = trim((string) $this->sku);

        if ($sku === '') {
            return;
        }

        $storeId = Product::withoutGlobalScopes()
            ->whereKey($this->product_id)
            ->value('store_id');

        if ($storeId === null) {
            return;
        }

        $query = self::withoutGlobalScopes()
            ->where('sku', $sku)
            ->whereHas('product', function (Builder $query) use ($storeId): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $storeId);
            });

        if ($this->exists) {
            $query->whereKeyNot($this->getKey());
        }

        if ($query->exists()) {
            throw new RuntimeException("The SKU [{$sku}] is already used in this store.");
        }
    }

    /**
     * @return BelongsTo<Product, $this>
     */
    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }

    /**
     * @return HasOne<InventoryItem, $this>
     */
    public function inventoryItem(): HasOne
    {
        return $this->hasOne(InventoryItem::class, 'variant_id');
    }

    /**
     * @return BelongsToMany<ProductOptionValue, $this>
     */
    public function optionValues(): BelongsToMany
    {
        return $this->belongsToMany(ProductOptionValue::class, 'variant_option_values', 'variant_id', 'product_option_value_id');
    }

    public function isPurchasable(): bool
    {
        return $this->status === VariantStatus::Active;
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'price_amount' => 'integer',
            'compare_at_amount' => 'integer',
            'weight_g' => 'integer',
            'requires_shipping' => 'bool',
            'is_default' => 'bool',
            'position' => 'integer',
            'status' => VariantStatus::class,
        ];
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class ProductOptionValue extends Model
{
    /** @use HasFactory<\Database\Factories\ProductOptionValueFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'product_option_id',
        'value',
        'position',
    ];

    /**
     * @var array<string, mixed>
     */
    protected $attributes = [
        'position' => 0,
    ];

    protected static function booted(): void
    {
        static::addGlobalScope('current_store', function (Builder $builder): void {
            if (! app()->bound('current_store')) {
                return;
            }

            $store = app('current_store');

            if (! $store instanceof Store) {
                return;
            }

            $builder->whereHas('option.product', function (Builder $query) use ($store): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $store->getKey());
            });
        });
    }

    /**
     * @return BelongsTo<ProductOption, $this>
     */
    public function option(): BelongsTo
    {
        return $this->belongsTo(ProductOption::class, 'product_option_id');
    }

    /**
     * @return BelongsToMany<ProductVariant, $this>
     */
    public function variants(): BelongsToMany
    {
        return $this->belongsToMany(ProductVariant::class, 'variant_option_values', 'product_option_value_id', 'variant_id');
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'position' => 'integer',
        ];
    }
}
sed: app/Models/VariantOptionValue.php: No such file or directory

status: failed


output:
Chunk ID: 90c65c
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 1639
Output:
<?php

namespace App\Models;

use App\Enums\InventoryPolicy;
use App\Enums\VariantStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use RuntimeException;

class ProductVariant extends Model
{
    /** @use HasFactory<\Database\Factories\ProductVariantFactory> */
    use HasFactory;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'product_id',
        'sku',
        'barcode',
        'price_amount',
        'compare_at_amount',
        'currency',
        'weight_g',
        'requires_shipping',
        'is_default',
        'position',
        'status',
    ];

    /**
     * @var array<string, mixed>
     */
    protected $attributes = [
        'price_amount' => 0,
        'currency' => 'USD',
        'requires_shipping' => true,
        'is_default' => false,
        'position' => 0,
        'status' => 'active',
    ];

    protected static function booted(): void
    {
        static::addGlobalScope('current_store', function (Builder $builder): void {
            if (! app()->bound('current_store')) {
                return;
            }

            $store = app('current_store');

            if (! $store instanceof Store) {
                return;
            }

            $builder->whereHas('product', function (Builder $query) use ($store): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $store->getKey());
            });
        });

        static::saving(function (ProductVariant $variant): void {
            $variant->assertSkuIsUniqueForStore();
        });

        static::created(function (ProductVariant $variant): void {
            if ($variant->inventoryItem()->exists()) {
                return;
            }

            $storeId = Product::withoutGlobalScopes()
                ->whereKey($variant->product_id)
                ->value('store_id');

            if (! $storeId) {
                return;
            }

            InventoryItem::withoutGlobalScopes()->create([
                'store_id' => $storeId,
                'variant_id' => $variant->getKey(),
                'quantity_on_hand' => 0,
                'quantity_reserved' => 0,
                'policy' => InventoryPolicy::Deny,
            ]);
        });
    }

    private function assertSkuIsUniqueForStore(): void
    {
        $sku = trim((string) $this->sku);

        if ($sku === '') {
            return;
        }

        $storeId = Product::withoutGlobalScopes()
            ->whereKey($this->product_id)
            ->value('store_id');

        if ($storeId === null) {
            return;
        }

        $query = self::withoutGlobalScopes()
            ->where('sku', $sku)
            ->whereHas('product', function (Builder $query) use ($storeId): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $storeId);
            });

        if ($this->exists) {
            $query->whereKeyNot($this->getKey());
        }

        if ($query->exists()) {
            throw new RuntimeException("The SKU [{$sku}] is already used in this store.");
        }
    }

    /**
     * @return BelongsTo<Product, $this>
     */
    public function product(): BelongsTo
    {
        return $this->belongsTo(Product::class);
    }

    /**
     * @return HasOne<InventoryItem, $this>
     */
    public function inventoryItem(): HasOne
    {
        return $this->hasOne(InventoryItem::class, 'variant_id');
    }

    /**
     * @return BelongsToMany<ProductOptionValue, $this>
     */
    public function optionValues(): BelongsToMany
    {
        return $this->belongsToMany(ProductOptionValue::class, 'variant_option_values', 'variant_id', 'product_option_value_id');
    }

    public function isPurchasable(): bool
    {
        return $this->status === VariantStatus::Active;
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'price_amount' => 'integer',
            'compare_at_amount' => 'integer',
            'weight_g' => 'integer',
            'requires_shipping' => 'bool',
            'is_default' => 'bool',
            'position' => 'integer',
            'status' => VariantStatus::class,
        ];
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class ProductOptionValue extends Model
{
    /** @use HasFactory<\Database\Factories\ProductOptionValueFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'product_option_id',
        'value',
        'position',
    ];

    /**
     * @var array<string, mixed>
     */
    protected $attributes = [
        'position' => 0,
    ];

    protected static function booted(): void
    {
        static::addGlobalScope('current_store', function (Builder $builder): void {
            if (! app()->bound('current_store')) {
                return;
            }

            $store = app('current_store');

            if (! $store instanceof Store) {
                return;
            }

            $builder->whereHas('option.product', function (Builder $query) use ($store): void {
                $query
                    ->withoutGlobalScopes()
                    ->where('store_id', $store->getKey());
            });
        });
    }

    /**
     * @return BelongsTo<ProductOption, $this>
     */
    public function option(): BelongsTo
    {
        return $this->belongsTo(ProductOption::class, 'product_option_id');
    }

    /**
     * @return BelongsToMany<ProductVariant, $this>
     */
    public function variants(): BelongsToMany
    {
        return $this->belongsToMany(ProductVariant::class, 'variant_option_values', 'product_option_value_id', 'variant_id');
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'position' => 'integer',
        ];
    }
}
sed: app/Models/VariantOptionValue.php: No such file or directory


cmd: sed -n '1,120p' app/Models/OrderLine.php


cmd: sed -n '1,140p' app/Models/Fulfillment.php && sed -n '1,100p' app/Models/FulfillmentLine.php


cmd: ls app/Enums && for f in app/Enums/*Status.php app/Enums/PaymentMethod.php; do echo $f; sed -n '1,120p' $f; done