command: sed -n '1,320p' tests/Feature/Checkout/CheckoutServiceTest.php

aggregated_output:
<?php

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Exceptions\UnserviceableShippingAddressException;
use App\Jobs\CleanupAbandonedCarts;
use App\Jobs\ExpireAbandonedCheckouts;
use App\Models\InventoryItem;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\TaxSettings;
use App\Services\CartService;
use App\Services\CheckoutService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

function checkoutStore(): Store
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    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 checkoutVariant(Store $store, bool $requiresShipping = true): ProductVariant
{
    $product = Product::factory()
        ->withDefaultVariant(2500)
        ->create(['store_id' => $store->getKey()]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();

    $variant->forceFill([
        'requires_shipping' => $requiresShipping,
        'weight_g' => $requiresShipping ? 500 : 0,
    ])->save();
    InventoryItem::withoutGlobalScopes()
        ->where('variant_id', $variant->getKey())
        ->update([
            'quantity_on_hand' => 10,
            'quantity_reserved' => 0,
        ]);

    return $variant->refresh();
}

function checkoutAddress(string $country = 'DE'): array
{
    return [
        'email' => 'buyer@example.test',
        'shipping_address' => [
            'first_name' => 'Test',
            'last_name' => 'Buyer',
            'address1' => 'Main Street 1',
            'city' => 'Berlin',
            'country' => $country,
            'postal_code' => '10115',
        ],
    ];
}

test('checkout service transitions through address shipping payment and expiry', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $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, checkoutAddress());
    expect($checkout->status)->toBe(CheckoutStatus::Addressed)
        ->and($checkout->email)->toBe('buyer@example.test');

    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    expect($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->shipping_method_id)->toBe($rate->getKey());

    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    expect($checkout->status)->toBe(CheckoutStatus::PaymentSelected)
        ->and($checkout->expires_at)->not->toBeNull()
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(2);

    app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    expect(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(2);

    $expired = app(CheckoutService::class)->expireCheckout($checkout);
    expect($expired->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('checkout service rejects unserviceable shipping addresses for physical carts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress('FR'));

    expect(fn () => app(CheckoutService::class)->setShippingMethod($checkout, null))
        ->toThrow(UnserviceableShippingAddressException::class);
});

test('checkout service skips shipping for digital-only carts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store, requiresShipping: false);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, null);

    expect($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->shipping_method_id)->toBeNull()
        ->and($checkout->totals_json['shipping'])->toBe(0);
});

test('expire abandoned checkouts job expires stale checkouts and releases reservations', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $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, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    $checkout->forceFill(['expires_at' => now()->subMinute()])->save();

    (new ExpireAbandonedCheckouts)->handle(app(CheckoutService::class));

    expect($checkout->refresh()->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('cleanup abandoned carts job abandons old carts and expires related checkouts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'paypal');
    $cart->forceFill(['updated_at' => now()->subDays(15)])->save();

    (new CleanupAbandonedCarts)->handle(app(CheckoutService::class));

    expect($cart->refresh()->status)->toBe(CartStatus::Abandoned)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});


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

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Cart\Show as CartShow;
use App\Livewire\Storefront\Checkout\Show as CheckoutShow;
use App\Livewire\Storefront\Products\Show as ProductShow;
use App\Models\Cart;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\InventoryItem;
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 storefrontUiStore(): Store
{
    $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();
    app()->instance('current_store', $store);

    return $store;
}

function storefrontUiVariant(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();
}

test('product detail add to cart persists a session cart', function () {
    $store = storefrontUiStore();
    $variant = storefrontUiVariant($store);

    Livewire::test(ProductShow::class, ['handle' => 'classic-cotton-t-shirt'])
        ->set('quantity', 2)
        ->call('addToCart')
        ->assertDispatched('cart-updated');

    $cart = Cart::withoutGlobalScopes()->findOrFail(session('cart_id'));

    expect($cart->store_id)->toBe($store->getKey())
        ->and($cart->lines()->withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity)->toBe(2);
});

test('cart page updates and removes line quantities', function () {
    $store = storefrontUiStore();
    $variant = storefrontUiVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    $line = app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    Livewire::test(CartShow::class)
        ->assertSee('Classic Cotton T-Shirt')
        ->call('increaseQuantity', $line->getKey())
        ->assertDispatched('cart-updated');

    expect($line->refresh()->quantity)->toBe(3);

    Livewire::test(CartShow::class)
        ->call('removeLine', $line->getKey())
        ->assertDispatched('cart-updated');

    expect($cart->lines()->withoutGlobalScopes()->count())->toBe(0);
});

test('customer login merges an existing guest cart without creating empty carts', function () {
    $store = storefrontUiStore();
    $variant = storefrontUiVariant($store);
    $customer = Customer::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('email', 'customer@acme.test')
        ->firstOrFail();
    $customerCart = app(CartService::class)->create($store, $customer);
    $guestCart = app(CartService::class)->create($store);
    session(['cart_id' => $guestCart->getKey()]);

    app(CartService::class)->addLine($customerCart, $variant->getKey(), 1);
    app(CartService::class)->addLine($guestCart, $variant->getKey(), 2);

    Livewire::test(CustomerLogin::class)
        ->set('email', 'customer@acme.test')
        ->set('password', 'password')
        ->call('login');

    expect($guestCart->refresh()->status)->toBe(CartStatus::Abandoned)
        ->and($customerCart->refresh()->lines()->withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity)->toBe(2)
        ->and(Cart::withoutGlobalScopes()->where('store_id', $store->getKey())->count())->toBe(2);
});

test('checkout page progresses through address shipping discount and payment selection', function () {
    $store = storefrontUiStore();
    $variant = storefrontUiVariant($store);
    $cart = app(CartService::class)->create($store);
    session(['cart_id' => $cart->getKey()]);
    app(CartService::class)->addLine($cart, $variant->getKey(), 2);

    $rate = ShippingRate::withoutGlobalScopes()
        ->whereHas('zone', fn ($query) => $query->withoutGlobalScopes()->where('store_id', $store->getKey()))
        ->where('name', 'Standard Shipping')
        ->firstOrFail();

    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')
        ->assertSet('step', 'shipping')
        ->set('selectedShippingRateId', $rate->getKey())
        ->call('selectShippingMethod')
        ->assertSet('step', 'payment')
        ->set('discountCode', 'SAVE10')
        ->call('applyDiscount')
        ->assertHasNoErrors()
        ->set('paymentMethod', 'credit_card')
        ->call('selectPaymentMethod')
        ->assertSet('step', 'reserved');

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

    expect($checkout->status)->toBe(CheckoutStatus::PaymentSelected)
        ->and($checkout->discount_code)->toBe('SAVE10')
        ->and($checkout->totals_json['discount'])->toBeGreaterThan(0)
        ->and($inventory->quantity_reserved)->toBe(2);
});


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

use App\Enums\CartStatus;
use App\Enums\InventoryPolicy;
use App\Exceptions\CartVersionMismatchException;
use App\Exceptions\InsufficientInventoryException;
use App\Exceptions\InvalidCartOperationException;
use App\Models\Cart;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Store;
use App\Services\CartService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

function cartServiceStore(): Store
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    return $store;
}

function cartServiceVariant(Store $store, int $price = 2500, int $stock = 20, InventoryPolicy $policy = InventoryPolicy::Deny): 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,
            'policy' => $policy,
        ]);

    return $variant->refresh();
}

test('cart service creates carts and mutates lines with version increments and price snapshots', function () {
    $store = cartServiceStore();
    $variant = cartServiceVariant($store, price: 2500, stock: 20);
    $service = app(CartService::class);
    $cart = $service->create($store);

    expect($cart->store_id)->toBe($store->getKey())
        ->and($cart->currency)->toBe('EUR')
        ->and($cart->cart_version)->toBe(1);

    $line = $service->addLine($cart, $variant->getKey(), 2, expectedVersion: 1);

    expect($line->quantity)->toBe(2)
        ->and($line->unit_price_amount)->toBe(2500)
        ->and($line->line_subtotal_amount)->toBe(5000)
        ->and($cart->refresh()->cart_version)->toBe(2);

    $service->addLine($cart, $variant->getKey(), 1, expectedVersion: 2);

    expect(Cart::withoutGlobalScopes()->find($cart->getKey())?->lines()->withoutGlobalScopes()->count())->toBe(1)
        ->and($line->refresh()->quantity)->toBe(3)
        ->and($cart->refresh()->cart_version)->toBe(3);

    $variant->forceFill(['price_amount' => 9999])->save();
    $service->updateLineQuantity($cart, $line->getKey(), 4, expectedVersion: 3);

    expect($line->refresh()->unit_price_amount)->toBe(2500)
        ->and($line->line_subtotal_amount)->toBe(10000)
        ->and($cart->refresh()->cart_version)->toBe(4);

    $service->updateLineQuantity($cart, $line->getKey(), 0, expectedVersion: 4);

    expect($cart->refresh()->cart_version)->toBe(5)
        ->and($cart->lines()->withoutGlobalScopes()->count())->toBe(0);
});

test('cart service rejects stale versions inactive products and insufficient stock', function () {
    $store = cartServiceStore();
    $variant = cartServiceVariant($store, stock: 2);
    $service = app(CartService::class);
    $cart = $service->create($store);

    expect(fn () => $service->addLine($cart, $variant->getKey(), 1, expectedVersion: 99))
        ->toThrow(CartVersionMismatchException::class);

    $draftProduct = Product::factory()
        ->draft()
        ->withDefaultVariant()
        ->create(['store_id' => $store->getKey()]);
    $draftVariant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $draftProduct->getKey())
        ->firstOrFail();

    expect(fn () => $service->addLine($cart, $draftVariant->getKey(), 1))
        ->toThrow(InvalidCartOperationException::class);

    expect(fn () => $service->addLine($cart, $variant->getKey(), 5))
        ->toThrow(InsufficientInventoryException::class);
});

test('cart service allows oversell for continue policy and merges guest carts into customer carts', function () {
    $store = cartServiceStore();
    $firstVariant = cartServiceVariant($store, stock: 0, policy: InventoryPolicy::Continue);
    $secondVariant = cartServiceVariant($store, stock: 10);
    $service = app(CartService::class);
    $guestCart = $service->create($store);
    $customer = Customer::factory()->create(['store_id' => $store->getKey()]);
    $customerCart = $service->create($store, $customer);

    $service->addLine($guestCart, $firstVariant->getKey(), 5);
    $service->addLine($customerCart, $firstVariant->getKey(), 2);
    $service->addLine($customerCart, $secondVariant->getKey(), 3);

    $merged = $service->mergeOnLogin($guestCart, $customerCart);

    expect($merged->lines()->withoutGlobalScopes()->where('variant_id', $firstVariant->getKey())->first()?->quantity)->toBe(5)
        ->and($merged->lines()->withoutGlobalScopes()->where('variant_id', $secondVariant->getKey())->first()?->quantity)->toBe(3)
        ->and($guestCart->refresh()->status)->toBe(CartStatus::Abandoned);
});


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

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Exceptions\UnserviceableShippingAddressException;
use App\Jobs\CleanupAbandonedCarts;
use App\Jobs\ExpireAbandonedCheckouts;
use App\Models\InventoryItem;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\TaxSettings;
use App\Services\CartService;
use App\Services\CheckoutService;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

function checkoutStore(): Store
{
    $store = Store::factory()->create();
    app()->instance('current_store', $store);

    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 checkoutVariant(Store $store, bool $requiresShipping = true): ProductVariant
{
    $product = Product::factory()
        ->withDefaultVariant(2500)
        ->create(['store_id' => $store->getKey()]);
    $variant = ProductVariant::withoutGlobalScopes()
        ->where('product_id', $product->getKey())
        ->firstOrFail();

    $variant->forceFill([
        'requires_shipping' => $requiresShipping,
        'weight_g' => $requiresShipping ? 500 : 0,
    ])->save();
    InventoryItem::withoutGlobalScopes()
        ->where('variant_id', $variant->getKey())
        ->update([
            'quantity_on_hand' => 10,
            'quantity_reserved' => 0,
        ]);

    return $variant->refresh();
}

function checkoutAddress(string $country = 'DE'): array
{
    return [
        'email' => 'buyer@example.test',
        'shipping_address' => [
            'first_name' => 'Test',
            'last_name' => 'Buyer',
            'address1' => 'Main Street 1',
            'city' => 'Berlin',
            'country' => $country,
            'postal_code' => '10115',
        ],
    ];
}

test('checkout service transitions through address shipping payment and expiry', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $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, checkoutAddress());
    expect($checkout->status)->toBe(CheckoutStatus::Addressed)
        ->and($checkout->email)->toBe('buyer@example.test');

    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    expect($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->shipping_method_id)->toBe($rate->getKey());

    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    expect($checkout->status)->toBe(CheckoutStatus::PaymentSelected)
        ->and($checkout->expires_at)->not->toBeNull()
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(2);

    app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    expect(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(2);

    $expired = app(CheckoutService::class)->expireCheckout($checkout);
    expect($expired->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('checkout service rejects unserviceable shipping addresses for physical carts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress('FR'));

    expect(fn () => app(CheckoutService::class)->setShippingMethod($checkout, null))
        ->toThrow(UnserviceableShippingAddressException::class);
});

test('checkout service skips shipping for digital-only carts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store, requiresShipping: false);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, null);

    expect($checkout->status)->toBe(CheckoutStatus::ShippingSelected)
        ->and($checkout->shipping_method_id)->toBeNull()
        ->and($checkout->totals_json['shipping'])->toBe(0);
});

test('expire abandoned checkouts job expires stale checkouts and releases reservations', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $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, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'credit_card');
    $checkout->forceFill(['expires_at' => now()->subMinute()])->save();

    (new ExpireAbandonedCheckouts)->handle(app(CheckoutService::class));

    expect($checkout->refresh()->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});

test('cleanup abandoned carts job abandons old carts and expires related checkouts', function () {
    $store = checkoutStore();
    $variant = checkoutVariant($store);
    $zone = ShippingZone::withoutGlobalScopes()->create([
        'store_id' => $store->getKey(),
        'name' => 'Germany',
        'countries_json' => ['DE'],
        'regions_json' => [],
    ]);
    $rate = ShippingRate::withoutGlobalScopes()->create([
        'zone_id' => $zone->getKey(),
        'name' => 'Standard',
        'type' => 'flat',
        'config_json' => ['amount' => 499],
        'is_active' => true,
    ]);
    $cart = app(CartService::class)->create($store);
    app(CartService::class)->addLine($cart, $variant->getKey(), 1);
    $checkout = app(CheckoutService::class)->createFromCart($cart);
    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
    $checkout = app(CheckoutService::class)->setShippingMethod($checkout, $rate->getKey());
    $checkout = app(CheckoutService::class)->selectPaymentMethod($checkout, 'paypal');
    $cart->forceFill(['updated_at' => now()->subDays(15)])->save();

    (new CleanupAbandonedCarts)->handle(app(CheckoutService::class));

    expect($cart->refresh()->status)->toBe(CartStatus::Abandoned)
        ->and($checkout->refresh()->status)->toBe(CheckoutStatus::Expired)
        ->and(InventoryItem::withoutGlobalScopes()->where('variant_id', $variant->getKey())->first()?->quantity_reserved)->toBe(0);
});


command: sed -n '1,260p' database/seeders/CartCheckoutSeeder.php

CartCheckoutSeeder.php

type: read

aggregated_output: sed: database/seeders/CartCheckoutSeeder.php: No such file or directory

status: failed


command: sed -n '1,220p' database/seeders/DatabaseSeeder.php

DatabaseSeeder.php

aggregated_output:
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call([
            OrganizationSeeder::class,
            StoreSeeder::class,
            StoreDomainSeeder::class,
            UserSeeder::class,
            StoreUserSeeder::class,
            StoreSettingsSeeder::class,
            CollectionSeeder::class,
            ProductSeeder::class,
            ThemeSeeder::class,
            ThemeFileSeeder::class,
            ThemeSettingsSeeder::class,
            PageSeeder::class,
            NavigationMenuSeeder::class,
            NavigationItemSeeder::class,
            TaxSettingsSeeder::class,
            ShippingZoneSeeder::class,
            ShippingRateSeeder::class,
            DiscountSeeder::class,
            CustomerSeeder::class,
        ]);
    }
}

status: completed


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

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        $this->call([
            OrganizationSeeder::class,
            StoreSeeder::class,
            StoreDomainSeeder::class,
            UserSeeder::class,
            StoreUserSeeder::class,
            StoreSettingsSeeder::class,
            CollectionSeeder::class,
            ProductSeeder::class,
            ThemeSeeder::class,
            ThemeFileSeeder::class,
            ThemeSettingsSeeder::class,
            PageSeeder::class,
            NavigationMenuSeeder::class,
            NavigationItemSeeder::class,
            TaxSettingsSeeder::class,
            ShippingZoneSeeder::class,
            ShippingRateSeeder::class,
            DiscountSeeder::class,
            CustomerSeeder::class,
        ]);
    }
}


output:
Chunk ID: 0ce3f9
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 18
Output:
sed: database/seeders/CartCheckoutSeeder.php: No such file or directory


cmd: sed -n '1,320p' app/Services/CartService.php


cmd: sed -n '1,380p' app/Services/CheckoutService.php


cmd: sed -n '1,300p' app/Services/PricingEngine.php


cmd: sed -n '1,260p' app/Http/Resources/Storefront/V1/CartResource.php


cmd: sed -n '1,300p' app/Http/Resources/Storefront/V1/CheckoutResource.php


command: sed -n '1,320p' app/Services/CartService.php

aggregated_output:
<?php

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\ProductStatus;
use App\Enums\VariantStatus;
use App\Exceptions\CartVersionMismatchException;
use App\Exceptions\InvalidCartOperationException;
use App\Models\Cart;
use App\Models\CartLine;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\ProductVariant;
use App\Models\Store;
use Illuminate\Support\Facades\DB;

class CartService
{
    public function __construct(
        private readonly InventoryService $inventory,
    ) {}

    public function create(Store $store, ?Customer $customer = null): Cart
    {
        return Cart::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'customer_id' => $customer?->getKey(),
            'currency' => $store->default_currency,
            'cart_version' => 1,
            'status' => CartStatus::Active,
        ]);
    }

    public function getOrCreateForSession(Store $store, ?Customer $customer = null): Cart
    {
        $sessionCartId = session('cart_id');

        if ($customer instanceof Customer) {
            $customerCart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('customer_id', $customer->getKey())
                ->where('status', CartStatus::Active)
                ->latest('id')
                ->first() ?? $this->create($store, $customer);

            if ($sessionCartId) {
                $guestCart = Cart::withoutGlobalScopes()
                    ->where('store_id', $store->getKey())
                    ->whereNull('customer_id')
                    ->where('status', CartStatus::Active)
                    ->find($sessionCartId);

                if ($guestCart instanceof Cart && $guestCart->isNot($customerCart)) {
                    $customerCart = $this->mergeOnLogin($guestCart, $customerCart);
                }

                session()->forget('cart_id');
            }

            return $customerCart->refresh();
        }

        if ($sessionCartId) {
            $cart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->whereNull('customer_id')
                ->where('status', CartStatus::Active)
                ->find($sessionCartId);

            if ($cart instanceof Cart) {
                return $cart;
            }
        }

        $cart = $this->create($store);
        session(['cart_id' => $cart->getKey()]);

        return $cart;
    }

    public function currentForSession(Store $store, ?Customer $customer = null): ?Cart
    {
        if ($customer instanceof Customer) {
            $customerCart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('customer_id', $customer->getKey())
                ->where('status', CartStatus::Active)
                ->latest('id')
                ->first();

            if ($customerCart instanceof Cart) {
                return $customerCart;
            }
        }

        $sessionCartId = session('cart_id');

        if (! $sessionCartId) {
            return null;
        }

        return Cart::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->where('status', CartStatus::Active)
            ->where(function ($query) use ($customer): void {
                if ($customer instanceof Customer) {
                    $query
                        ->whereNull('customer_id')
                        ->orWhere('customer_id', $customer->getKey());

                    return;
                }

                $query->whereNull('customer_id');
            })
            ->find($sessionCartId);
    }

    public function addLine(Cart $cart, int $variantId, int $quantity, ?int $expectedVersion = null): CartLine
    {
        $this->assertPositiveQuantity($quantity);

        return DB::transaction(function () use ($cart, $variantId, $quantity, $expectedVersion): CartLine {
            $lockedCart = $this->freshCart($cart);
            $this->assertExpectedVersion($lockedCart, $expectedVersion);
            $this->assertCartIsActive($lockedCart);

            $variant = $this->purchasableVariant($lockedCart, $variantId);
            $line = CartLine::withoutGlobalScopes()
                ->where('cart_id', $lockedCart->getKey())
                ->where('variant_id', $variant->getKey())
                ->first();
            $newQuantity = ($line?->quantity ?? 0) + $quantity;

            $this->assertAvailable($variant->inventoryItem, $newQuantity);

            if (! $line instanceof CartLine) {
                $line = new CartLine([
                    'cart_id' => $lockedCart->getKey(),
                    'variant_id' => $variant->getKey(),
                    'unit_price_amount' => $variant->price_amount,
                ]);
            }

            $this->fillLineAmounts($line, $newQuantity, $line->unit_price_amount ?: $variant->price_amount);
            $line->save…1104 chars truncated…dCart);

            return $line->refresh();
        });
    }

    public function removeLine(Cart $cart, int $lineId, ?int $expectedVersion = null): void
    {
        DB::transaction(function () use ($cart, $lineId, $expectedVersion): void {
            $lockedCart = $this->freshCart($cart);
            $this->assertExpectedVersion($lockedCart, $expectedVersion);
            $this->assertCartIsActive($lockedCart);

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $lockedCart->getKey())
                ->whereKey($lineId)
                ->delete();

            $this->incrementVersion($lockedCart);
        });
    }

    public function mergeOnLogin(Cart $guest, Cart $customer): Cart
    {
        return DB::transaction(function () use ($guest, $customer): Cart {
            $guestCart = $this->freshCart($guest);
            $customerCart = $this->freshCart($customer);

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $guestCart->getKey())
                ->get()
                ->each(function (CartLine $guestLine) use ($customerCart): void {
                    $existingLine = CartLine::withoutGlobalScopes()
                        ->where('cart_id', $customerCart->getKey())
                        ->where('variant_id', $guestLine->variant_id)
                        ->first();

                    if ($existingLine instanceof CartLine) {
                        $quantity = max($existingLine->quantity, $guestLine->quantity);
                        $this->fillLineAmounts($existingLine, $quantity, $existingLine->unit_price_amount);
                        $existingLine->save();
                        $guestLine->delete();

                        return;
                    }

                    $guestLine->forceFill(['cart_id' => $customerCart->getKey()])->save();
                });

            $guestCart->forceFill(['status' => CartStatus::Abandoned])->save();
            $this->incrementVersion($customerCart);

            return $customerCart->refresh();
        });
    }

    private function freshCart(Cart $cart): Cart
    {
        return Cart::withoutGlobalScopes()
            ->whereKey($cart->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function purchasableVariant(Cart $cart, int $variantId): ProductVariant
    {
        $variant = ProductVariant::withoutGlobalScopes()
            ->with([
                'product' => fn ($query) => $query->withoutGlobalScopes(),
                'inventoryItem' => fn ($query) => $query->withoutGlobalScopes(),
            ])
            ->findOrFail($variantId);

        if ((int) $variant->product->store_id !== (int) $cart->store_id) {
            throw InvalidCartOperationException::because('Variant does not belong to this store.');
        }

        if ($variant->product->status !== ProductStatus::Active || $variant->product->published_at === null) {
            throw InvalidCartOperationException::because('Product is not active.');
        }

        if ($variant->status !== VariantStatus::Active) {
            throw InvalidCartOperationException::because('Variant is not active.');
        }

        if (! $variant->inventoryItem instanceof InventoryItem) {
            throw InvalidCartOperationException::because('Variant inventory is missing.');
        }

        return $variant;
    }

    private function assertAvailable(InventoryItem $item, int $quantity): void
    {
        if (! $this->inventory->checkAvailability($item, $quantity)) {
            throw \App\Exceptions\InsufficientInventoryException::forQuantity($item->availableQuantity(), $quantity);
        }
    }

    private function fillLineAmounts(CartLine $line, int $quantity, int $unitPrice): void
    {
        $subtotal = $unitPrice * $quantity;

        $line->forceFill([
            'quantity' => $quantity,
            'unit_price_amount' => $unitPrice,
            'line_subtotal_amount' => $subtotal,
            'line_discount_amount' => 0,
            'line_total_amount' => $subtotal,
        ]);
    }

    private function incrementVersion(Cart $cart): void
    {
        $cart->forceFill([
            'cart_version' => $cart->cart_version + 1,
        ])->save();
    }

    private function assertExpectedVersion(Cart $cart, ?int $expectedVersion): void
    {
        if ($expectedVersion !== null && $expectedVersion !== $cart->cart_version) {
            throw new CartVersionMismatchException($expectedVersion, $cart->cart_version);
        }
    }

    private function assertCartIsActive(Cart $cart): void
    {
        if ($cart->status !== CartStatus::Active) {
            throw InvalidCartOperationException::because('Cart is not active.');
        }
    }

    private function assertPositiveQuantity(int $quantity): void
    {
        if ($quantity <= 0) {
            throw InvalidCartOperationException::because('Cart line quantity must be greater than zero.');
        }
    }
}


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

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\ProductStatus;
use App\Enums\VariantStatus;
use App\Exceptions\CartVersionMismatchException;
use App\Exceptions\InvalidCartOperationException;
use App\Models\Cart;
use App\Models\CartLine;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\ProductVariant;
use App\Models\Store;
use Illuminate\Support\Facades\DB;

class CartService
{
    public function __construct(
        private readonly InventoryService $inventory,
    ) {}

    public function create(Store $store, ?Customer $customer = null): Cart
    {
        return Cart::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'customer_id' => $customer?->getKey(),
            'currency' => $store->default_currency,
            'cart_version' => 1,
            'status' => CartStatus::Active,
        ]);
    }

    public function getOrCreateForSession(Store $store, ?Customer $customer = null): Cart
    {
        $sessionCartId = session('cart_id');

        if ($customer instanceof Customer) {
            $customerCart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('customer_id', $customer->getKey())
                ->where('status', CartStatus::Active)
                ->latest('id')
                ->first() ?? $this->create($store, $customer);

            if ($sessionCartId) {
                $guestCart = Cart::withoutGlobalScopes()
                    ->where('store_id', $store->getKey())
                    ->whereNull('customer_id')
                    ->where('status', CartStatus::Active)
                    ->find($sessionCartId);

                if ($guestCart instanceof Cart && $guestCart->isNot($customerCart)) {
                    $customerCart = $this->mergeOnLogin($guestCart, $customerCart);
                }

                session()->forget('cart_id');
            }

            return $customerCart->refresh();
        }

        if ($sessionCartId) {
            $cart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->whereNull('customer_id')
                ->where('status', CartStatus::Active)
                ->find($sessionCartId);

            if ($cart instanceof Cart) {
                return $cart;
            }
        }

        $cart = $this->create($store);
        session(['cart_id' => $cart->getKey()]);

        return $cart;
    }

    public function currentForSession(Store $store, ?Customer $customer = null): ?Cart
    {
        if ($customer instanceof Customer) {
            $customerCart = Cart::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('customer_id', $customer->getKey())
                ->where('status', CartStatus::Active)
                ->latest('id')
                ->first();

            if ($customerCart instanceof Cart) {
                return $customerCart;
            }
        }

        $sessionCartId = session('cart_id');

        if (! $sessionCartId) {
            return null;
        }

        return Cart::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->where('status', CartStatus::Active)
            ->where(function ($query) use ($customer): void {
                if ($customer instanceof Customer) {
                    $query
                        ->whereNull('customer_id')
                        ->orWhere('customer_id', $customer->getKey());

                    return;
                }

                $query->whereNull('customer_id');
            })
            ->find($sessionCartId);
    }

    public function addLine(Cart $cart, int $variantId, int $quantity, ?int $expectedVersion = null): CartLine
    {
        $this->assertPositiveQuantity($quantity);

        return DB::transaction(function () use ($cart, $variantId, $quantity, $expectedVersion): CartLine {
            $lockedCart = $this->freshCart($cart);
            $this->assertExpectedVersion($lockedCart, $expectedVersion);
            $this->assertCartIsActive($lockedCart);

            $variant = $this->purchasableVariant($lockedCart, $variantId);
            $line = CartLine::withoutGlobalScopes()
                ->where('cart_id', $lockedCart->getKey())
                ->where('variant_id', $variant->getKey())
                ->first();
            $newQuantity = ($line?->quantity ?? 0) + $quantity;

            $this->assertAvailable($variant->inventoryItem, $newQuantity);

            if (! $line instanceof CartLine) {
                $line = new CartLine([
                    'cart_id' => $lockedCart->getKey(),
                    'variant_id' => $variant->getKey(),
                    'unit_price_amount' => $variant->price_amount,
                ]);
            }

            $this->fillLineAmounts($line, $newQuantity, $line->unit_price_amount ?: $variant->price_amount);
            $line->save();
            $this->incrementVersion($lockedCart);

            return $line->refresh();
        });
    }

    public function updateLineQuantity(Cart $cart, int $lineId, int $quantity, ?int $expectedVersion = null): ?CartLine
    {
        if ($quantity <= 0) {
            $this->removeLine($cart, $lineId, $expectedVersion);

            return null;
        }

        return DB::transaction(function () use ($cart, $lineId, $quantity, $expectedVersion): CartLine {
            $lockedCart = $this->freshCart($cart);
            $this->assertExpectedVersion($lockedCart, $expectedVersion);
            $this->assertCartIsActive($lockedCart);

            $line = CartLine::withoutGlobalScopes()
                ->where('cart_id', $lockedCart->getKey())
                ->findOrFail($lineId);
            $variant = $this->purchasableVariant($lockedCart, $line->variant_id);

            $this->assertAvailable($variant->inventoryItem, $quantity);
            $this->fillLineAmounts($line, $quantity, $line->unit_price_amount);
            $line->save();
            $this->incrementVersion($lockedCart);

            return $line->refresh();
        });
    }

    public function removeLine(Cart $cart, int $lineId, ?int $expectedVersion = null): void
    {
        DB::transaction(function () use ($cart, $lineId, $expectedVersion): void {
            $lockedCart = $this->freshCart($cart);
            $this->assertExpectedVersion($lockedCart, $expectedVersion);
            $this->assertCartIsActive($lockedCart);

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $lockedCart->getKey())
                ->whereKey($lineId)
                ->delete();

            $this->incrementVersion($lockedCart);
        });
    }

    public function mergeOnLogin(Cart $guest, Cart $customer): Cart
    {
        return DB::transaction(function () use ($guest, $customer): Cart {
            $guestCart = $this->freshCart($guest);
            $customerCart = $this->freshCart($customer);

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $guestCart->getKey())
                ->get()
                ->each(function (CartLine $guestLine) use ($customerCart): void {
                    $existingLine = CartLine::withoutGlobalScopes()
                        ->where('cart_id', $customerCart->getKey())
                        ->where('variant_id', $guestLine->variant_id)
                        ->first();

                    if ($existingLine instanceof CartLine) {
                        $quantity = max($existingLine->quantity, $guestLine->quantity);
                        $this->fillLineAmounts($existingLine, $quantity, $existingLine->unit_price_amount);
                        $existingLine->save();
                        $guestLine->delete();

                        return;
                    }

                    $guestLine->forceFill(['cart_id' => $customerCart->getKey()])->save();
                });

            $guestCart->forceFill(['status' => CartStatus::Abandoned])->save();
            $this->incrementVersion($customerCart);

            return $customerCart->refresh();
        });
    }

    private function freshCart(Cart $cart): Cart
    {
        return Cart::withoutGlobalScopes()
            ->whereKey($cart->getKey())
            ->lockForUpdate()
            ->firstOrFail();
    }

    private function purchasableVariant(Cart $cart, int $variantId): ProductVariant
    {
        $variant = ProductVariant::withoutGlobalScopes()
            ->with([
                'product' => fn ($query) => $query->withoutGlobalScopes(),
                'inventoryItem' => fn ($query) => $query->withoutGlobalScopes(),
            ])
            ->findOrFail($variantId);

        if ((int) $variant->product->store_id !== (int) $cart->store_id) {
            throw InvalidCartOperationException::because('Variant does not belong to this store.');
        }

        if ($variant->product->status !== ProductStatus::Active || $variant->product->published_at === null) {
            throw InvalidCartOperationException::because('Product is not active.');
        }

        if ($variant->status !== VariantStatus::Active) {
            throw InvalidCartOperationException::because('Variant is not active.');
        }

        if (! $variant->inventoryItem instanceof InventoryItem) {
            throw InvalidCartOperationException::because('Variant inventory is missing.');
        }

        return $variant;
    }

    private function assertAvailable(InventoryItem $item, int $quantity): void
    {
        if (! $this->inventory->checkAvailability($item, $quantity)) {
            throw \App\Exceptions\InsufficientInventoryException::forQuantity($item->availableQuantity(), $quantity);
        }
    }

    private function fillLineAmounts(CartLine $line, int $quantity, int $unitPrice): void
    {
        $subtotal = $unitPrice * $quantity;

        $line->forceFill([
            'quantity' => $quantity,
            'unit_price_amount' => $unitPrice,
            'line_subtotal_amount' => $subtotal,
            'line_discount_amount' => 0,
            'line_total_amount' => $subtotal,
        ]);
    }

    private function incrementVersion(Cart $cart): void
    {
        $cart->forceFill([
            'cart_version' => $cart->cart_version + 1,
        ])->save();
    }

    private function assertExpectedVersion(Cart $cart, ?int $expectedVersion): void
    {
        if ($expectedVersion !== null && $expectedVersion !== $cart->cart_version) {
            throw new CartVersionMismatchException($expectedVersion, $cart->cart_version);
        }
    }

    private function assertCartIsActive(Cart $cart): void
    {
        if ($cart->status !== CartStatus::Active) {
            throw InvalidCartOperationException::because('Cart is not active.');
        }
    }

    private function assertPositiveQuantity(int $quantity): void
    {
        if ($quantity <= 0) {
            throw InvalidCartOperationException::because('Cart line quantity must be greater than zero.');
        }
    }
}


command: sed -n '1,380p' app/Services/CheckoutService.php

aggregated_output:
<?php

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Exceptions\InvalidCheckoutTransitionException;
use App\Exceptions\UnserviceableShippingAddressException;
use App\Models\Cart;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\ShippingRate;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use RuntimeException;

class CheckoutService
{
    public function __construct(
        private readonly InventoryService $inventory,
        private readonly ShippingCalculator $shipping,
        private readonly PricingEngine $pricing,
    ) {}

    public function createFromCart(Cart $cart, ?Customer $customer = null): Checkout
    {
        $cart = Cart::withoutGlobalScopes()->findOrFail($cart->getKey());

        if ($cart->status !== CartStatus::Active) {
            throw InvalidCheckoutTransitionException::because('Checkout can only start from an active cart.');
        }

        if (! CartLine::withoutGlobalScopes()->where('cart_id', $cart->getKey())->exists()) {
            throw InvalidCheckoutTransitionException::because('Checkout cannot start from an empty cart.');
        }

        return Checkout::withoutGlobalScopes()->create([
            'store_id' => $cart->store_id,
            'cart_id' => $cart->getKey(),
            'customer_id' => $customer?->getKey() ?? $cart->customer_id,
            'status' => CheckoutStatus::Started,
        ]);
    }

    /**
     * @param  array<string, mixed>  $addressData
     */
    public function setAddress(Checkout $checkout, array $addressData): Checkout
    {
        return DB::transaction(function () use ($checkout, $addressData): Checkout {
            $checkout = $this->freshCheckout($checkout);
            $this->assertStatus($checkout, [CheckoutStatus::Started, CheckoutStatus::Addressed]);

            $email = (string) data_get($addressData, 'email');
            $shippingAddress = data_get($addressData, 'shipping_address', $addressData);

            Validator::make([
                'email' => $email,
                'shipping_address' => $shippingAddress,
            ], [
                'email' => ['required', 'email'],
                'shipping_address.first_name' => ['required', 'string'],
                'shipping_address.last_name' => ['required', 'string'],
                'shipping_address.address1' => ['required', 'string'],
                'shipping_address.city' => ['required', 'string'],
                'shipping_address.country' => ['required', 'string', 'size:2'],
                'shipping_address.postal_code' => ['required', 'string'],
            ])->validate();

            $checkout->forceFill([
                'email' => $email,
                'shipping_address_json' => $shippingAddress,
                'billing_address_json' => data_get($addressData, 'billing_address', $shippingAddress),
                'status' => CheckoutStatus::Addressed,
            ])->save();

            $this->pricing->calculate($checkout);

            return $checkout->refresh();
        });
    }

    public function setShippingMethod(Checkout $checkout, ?int $shippingRateId): Checkout
    {
        return DB::transaction(function () use ($checkout, $shippingRateId): Checkout {
            $checkout = $this->freshCheckout($checkout);
            $this->assertStatus($checkout, [CheckoutStatus::Addressed, CheckoutStatus::ShippingSelected]);

            if (! $this->shipping->requiresShipping($checkout->cart)) {
                $checkout->forceFill([
                    'shipping_method_id' => null,
                    'status' => CheckoutStatus::ShippingSelected,
                ])->save();

                $this->pricing->calculate($checkout);

                return $checkout->refresh();
            }

            $availableRates = $this->shipping->getAvailableRates($checkout->store, $checkout->shipping_address_json ?? []);

            if ($availableRates->isEmpty()) {
                throw UnserviceableShippingAddressException::forAddress();
            }

            $rate = $availableRates->firstWhere('id', $shippingRateId);

            if (! $rate instanceof ShippingRate) {
                throw InvalidCheckoutTransitionException::because('Selected shipping rate is not available for this address.');
            }

            $checkout->forceFill([
                'shipping_method_id' => $rate->getKey(),
                'status' => CheckoutStatus::ShippingSelected,
            ])->save();

            $this->pricing->calculate($checkout);

            return $checkout->refresh();
        });
    }

    public function selectPaymentMethod(Checkout $checkout, string $paymentMethod): Checkout
    {
        return DB::transaction(function () use ($checkout, $paymentMethod): Checkout {
            $checkout = $this->freshCheckout($checkout);

            if ($checkout->status === CheckoutStatus::PaymentSelected) {
                return $checkout;
            }

            $this->assertStatus($checkout, [CheckoutStatus::ShippingSelected]);

            if (! in_array($paymentMethod, ['credit_card', 'paypal', 'bank_transfer'], true)) {
                throw InvalidCheckoutTransitionException::because('Payment method is invalid.');
            }

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

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $checkout->cart_id)
                ->get()
                ->each(function (CartLine $line): void {
                    $inventory = InventoryItem::withoutGlobalScopes()
                        ->where('variant_id', $line->variant_id)
                        ->firstOrFail();

                    $this->inventory->reserve($inventory, $line->quantity);
                });

            $checkout->forceFill([
                'payment_method' => $paymentMethod,
                'status' => CheckoutStatus::PaymentSelected,
                'expires_at' => now()->addDay(),
            ])->save();

            return $checkout->refresh();
        });
    }

    public function expireCheckout(Checkout $checkout): Checkout
    {
        return DB::transaction(function () use ($checkout): Checkout {
            $checkout = $this->freshCheckout($checkout);

            if (in_array($checkout->status, [CheckoutStatus::Completed, CheckoutStatus::Expired], true)) {
                return $checkout;
            }

            if ($checkout->status === CheckoutStatus::PaymentSelected) {
                CartLine::withoutGlobalScopes()
                    ->where('cart_id', $checkout->cart_id)
                    ->get()
                    ->each(function (CartLine $line): void {
                        $inventory = InventoryItem::withoutGlobalScopes()
                            ->where('variant_id', $line->variant_id)
                            ->firstOrFail();

                        $this->inventory->release($inventory, $line->quantity);
                    });
            }

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

            return $checkout->refresh();
        });
    }

    public function completeCheckout(Checkout $checkout, array $paymentMethodData = []): never
    {
        throw new RuntimeException('Order creation is implemented in the payments and orders phase.');
    }

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

    /**
     * @param  array<int, CheckoutStatus>  $allowed
     */
    private function assertStatus(Checkout $checkout, array $allowed): void
    {
        if (! in_array($checkout->status, $allowed, true)) {
            throw InvalidCheckoutTransitionException::because("Checkout cannot transition from {$checkout->status->value}.");
        }
    }
}


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

namespace App\Services;

use App\Enums\CartStatus;
use App\Enums\CheckoutStatus;
use App\Exceptions\InvalidCheckoutTransitionException;
use App\Exceptions\UnserviceableShippingAddressException;
use App\Models\Cart;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\InventoryItem;
use App\Models\ShippingRate;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use RuntimeException;

class CheckoutService
{
    public function __construct(
        private readonly InventoryService $inventory,
        private readonly ShippingCalculator $shipping,
        private readonly PricingEngine $pricing,
    ) {}

    public function createFromCart(Cart $cart, ?Customer $customer = null): Checkout
    {
        $cart = Cart::withoutGlobalScopes()->findOrFail($cart->getKey());

        if ($cart->status !== CartStatus::Active) {
            throw InvalidCheckoutTransitionException::because('Checkout can only start from an active cart.');
        }

        if (! CartLine::withoutGlobalScopes()->where('cart_id', $cart->getKey())->exists()) {
            throw InvalidCheckoutTransitionException::because('Checkout cannot start from an empty cart.');
        }

        return Checkout::withoutGlobalScopes()->create([
            'store_id' => $cart->store_id,
            'cart_id' => $cart->getKey(),
            'customer_id' => $customer?->getKey() ?? $cart->customer_id,
            'status' => CheckoutStatus::Started,
        ]);
    }

    /**
     * @param  array<string, mixed>  $addressData
     */
    public function setAddress(Checkout $checkout, array $addressData): Checkout
    {
        return DB::transaction(function () use ($checkout, $addressData): Checkout {
            $checkout = $this->freshCheckout($checkout);
            $this->assertStatus($checkout, [CheckoutStatus::Started, CheckoutStatus::Addressed]);

            $email = (string) data_get($addressData, 'email');
            $shippingAddress = data_get($addressData, 'shipping_address', $addressData);

            Validator::make([
                'email' => $email,
                'shipping_address' => $shippingAddress,
            ], [
                'email' => ['required', 'email'],
                'shipping_address.first_name' => ['required', 'string'],
                'shipping_address.last_name' => ['required', 'string'],
                'shipping_address.address1' => ['required', 'string'],
                'shipping_address.city' => ['required', 'string'],
                'shipping_address.country' => ['required', 'string', 'size:2'],
                'shipping_address.postal_code' => ['required', 'string'],
            ])->validate();

            $checkout->forceFill([
                'email' => $email,
                'shipping_address_json' => $shippingAddress,
                'billing_address_json' => data_get($addressData, 'billing_address', $shippingAddress),
                'status' => CheckoutStatus::Addressed,
            ])->save();

            $this->pricing->calculate($checkout);

            return $checkout->refresh();
        });
    }

    public function setShippingMethod(Checkout $checkout, ?int $shippingRateId): Checkout
    {
        return DB::transaction(function () use ($checkout, $shippingRateId): Checkout {
            $checkout = $this->freshCheckout($checkout);
            $this->assertStatus($checkout, [CheckoutStatus::Addressed, CheckoutStatus::ShippingSelected]);

            if (! $this->shipping->requiresShipping($checkout->cart)) {
                $checkout->forceFill([
                    'shipping_method_id' => null,
                    'status' => CheckoutStatus::ShippingSelected,
                ])->save();

                $this->pricing->calculate($checkout);

                return $checkout->refresh();
            }

            $availableRates = $this->shipping->getAvailableRates($checkout->store, $checkout->shipping_address_json ?? []);

            if ($availableRates->isEmpty()) {
                throw UnserviceableShippingAddressException::forAddress();
            }

            $rate = $availableRates->firstWhere('id', $shippingRateId);

            if (! $rate instanceof ShippingRate) {
                throw InvalidCheckoutTransitionException::because('Selected shipping rate is not available for this address.');
            }

            $checkout->forceFill([
                'shipping_method_id' => $rate->getKey(),
                'status' => CheckoutStatus::ShippingSelected,
            ])->save();

            $this->pricing->calculate($checkout);

            return $checkout->refresh();
        });
    }

    public function selectPaymentMethod(Checkout $checkout, string $paymentMethod): Checkout
    {
        return DB::transaction(function () use ($checkout, $paymentMethod): Checkout {
            $checkout = $this->freshCheckout($checkout);

            if ($checkout->status === CheckoutStatus::PaymentSelected) {
                return $checkout;
            }

            $this->assertStatus($checkout, [CheckoutStatus::ShippingSelected]);

            if (! in_array($paymentMethod, ['credit_card', 'paypal', 'bank_transfer'], true)) {
                throw InvalidCheckoutTransitionException::because('Payment method is invalid.');
            }

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

            CartLine::withoutGlobalScopes()
                ->where('cart_id', $checkout->cart_id)
                ->get()
                ->each(function (CartLine $line): void {
                    $inventory = InventoryItem::withoutGlobalScopes()
                        ->where('variant_id', $line->variant_id)
                        ->firstOrFail();

                    $this->inventory->reserve($inventory, $line->quantity);
                });

            $checkout->forceFill([
                'payment_method' => $paymentMethod,
                'status' => CheckoutStatus::PaymentSelected,
                'expires_at' => now()->addDay(),
            ])->save();

            return $checkout->refresh();
        });
    }

    public function expireCheckout(Checkout $checkout): Checkout
    {
        return DB::transaction(function () use ($checkout): Checkout {
            $checkout = $this->freshCheckout($checkout);

            if (in_array($checkout->status, [CheckoutStatus::Completed, CheckoutStatus::Expired], true)) {
                return $checkout;
            }

            if ($checkout->status === CheckoutStatus::PaymentSelected) {
                CartLine::withoutGlobalScopes()
                    ->where('cart_id', $checkout->cart_id)
                    ->get()
                    ->each(function (CartLine $line): void {
                        $inventory = InventoryItem::withoutGlobalScopes()
                            ->where('variant_id', $line->variant_id)
                            ->firstOrFail();

                        $this->inventory->release($inventory, $line->quantity);
                    });
            }

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

            return $checkout->refresh();
        });
    }

    public function completeCheckout(Checkout $checkout, array $paymentMethodData = []): never
    {
        throw new RuntimeException('Order creation is implemented in the payments and orders phase.');
    }

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

    /**
     * @param  array<int, CheckoutStatus>  $allowed
     */
    private function assertStatus(Checkout $checkout, array $allowed): void
    {
        if (! in_array($checkout->status, $allowed, true)) {
            throw InvalidCheckoutTransitionException::because("Checkout cannot transition from {$checkout->status->value}.");
        }
    }
}


command: sed -n '1,300p' app/Services/PricingEngine.php

aggregated_output:
<?php

namespace App\Services;

use App\Exceptions\InvalidCheckoutTransitionException;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\ShippingRate;
use App\Models\TaxSettings;
use App\ValueObjects\DiscountResult;
use App\ValueObjects\PricingResult;
use Illuminate\Support\Facades\DB;

class PricingEngine
{
    public function __construct(
        private readonly DiscountService $discounts,
        private readonly ShippingCalculator $shipping,
        private readonly TaxCalculator $taxes,
    ) {}

    public function calculate(Checkout $checkout): PricingResult
    {
        return DB::transaction(function () use ($checkout): PricingResult {
            $checkout = Checkout::withoutGlobalScopes()
                ->with(['cart.lines'])
                ->whereKey($checkout->getKey())
                ->firstOrFail();
            $cart = $checkout->cart;

            $this->resetLineAmounts($checkout);

            $lines = CartLine::withoutGlobalScopes()
                ->where('cart_id', $cart->getKey())
                ->orderBy('id')
                ->get();
            $subtotal = $lines->sum('line_subtotal_amount');
            $discountResult = new DiscountResult(0, []);

            if ($checkout->discount_code) {
                $discount = $this->discounts->validate($checkout->discount_code, $checkout->store, $cart);
                $discountResult = $this->discounts->applyToCart($cart, $discount);
                $lines = CartLine::withoutGlobalScopes()
                    ->where('cart_id', $cart->getKey())
                    ->orderBy('id')
                    ->get();
            }

            $shippingAmount = $this->shippingAmount($checkout, $discountResult);
            $taxSettings = $this->taxSettings($checkout);
            $taxResult = $this->taxes->calculateForAmounts(
                $lines->pluck('line_total_amount')->map(fn (int $amount): int => $amount)->all(),
                $shippingAmount,
                $taxSettings,
                $checkout->shipping_address_json ?? [],
            );
            $discountedSubtotal = $subtotal - $discountResult->amount;
            $total = $taxSettings->prices_include_tax
                ? $discountedSubtotal + $shippingAmount
                : $discountedSubtotal + $shippingAmount + $taxResult->totalAmount;

            $result = new PricingResult(
                subtotal: $subtotal,
                discount: $discountResult->amount,
                shipping: $shippingAmount,
                taxLines: $taxResult->taxLines,
                taxTotal: $taxResult->totalAmount,
                total: $total,
                currency: $cart->currency,
            );

            $checkout->forceFill([
                'tax_provider_snapshot_json' => $taxResult->toArray(),
                'totals_json' => $result->toArray(),
            ])->save();

            return $result;
        });
    }

    private function resetLineAmounts(Checkout $checkout): void
    {
        CartLine::withoutGlobalScopes()
            ->where('cart_id', $checkout->cart_id)
            ->get()
            ->each(function (CartLine $line): void {
                $subtotal = $line->unit_price_amount * $line->quantity;

                $line->forceFill([
                    'line_subtotal_amount' => $subtotal,
                    'line_discount_amount' => 0,
                    'line_total_amount' => $subtotal,
                ])->save();
            });
    }

    private function shippingAmount(Checkout $checkout, DiscountResult $discountResult): int
    {
        if (! $this->shipping->requiresShipping($checkout->cart)) {
            return 0;
        }

        if ($checkout->shipping_method_id === null) {
            return 0;
        }

        $rate = ShippingRate::withoutGlobalScopes()->find($checkout->shipping_method_id);

        if (! $rate instanceof ShippingRate) {
            throw InvalidCheckoutTransitionException::because('Shipping rate is not available.');
        }

        $amount = $this->shipping->calculate($rate, $checkout->cart);

        if ($amount === null) {
            throw InvalidCheckoutTransitionException::because('Shipping rate is not available for this cart.');
        }

        return $discountResult->freeShipping ? 0 : $amount;
    }

    private function taxSettings(Checkout $checkout): TaxSettings
    {
        return TaxSettings::withoutGlobalScopes()
            ->where('store_id', $checkout->store_id)
            ->first() ?? new TaxSettings([
                'store_id' => $checkout->store_id,
                'mode' => 'manual',
                'provider' => 'none',
                'prices_include_tax' => false,
                'config_json' => [
                    'default_rate_bps' => 0,
                    'shipping_taxable' => false,
                ],
            ]);
    }
}


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

namespace App\Services;

use App\Exceptions\InvalidCheckoutTransitionException;
use App\Models\CartLine;
use App\Models\Checkout;
use App\Models\ShippingRate;
use App\Models\TaxSettings;
use App\ValueObjects\DiscountResult;
use App\ValueObjects\PricingResult;
use Illuminate\Support\Facades\DB;

class PricingEngine
{
    public function __construct(
        private readonly DiscountService $discounts,
        private readonly ShippingCalculator $shipping,
        private readonly TaxCalculator $taxes,
    ) {}

    public function calculate(Checkout $checkout): PricingResult
    {
        return DB::transaction(function () use ($checkout): PricingResult {
            $checkout = Checkout::withoutGlobalScopes()
                ->with(['cart.lines'])
                ->whereKey($checkout->getKey())
                ->firstOrFail();
            $cart = $checkout->cart;

            $this->resetLineAmounts($checkout);

            $lines = CartLine::withoutGlobalScopes()
                ->where('cart_id', $cart->getKey())
                ->orderBy('id')
                ->get();
            $subtotal = $lines->sum('line_subtotal_amount');
            $discountResult = new DiscountResult(0, []);

            if ($checkout->discount_code) {
                $discount = $this->discounts->validate($checkout->discount_code, $checkout->store, $cart);
                $discountResult = $this->discounts->applyToCart($cart, $discount);
                $lines = CartLine::withoutGlobalScopes()
                    ->where('cart_id', $cart->getKey())
                    ->orderBy('id')
                    ->get();
            }

            $shippingAmount = $this->shippingAmount($checkout, $discountResult);
            $taxSettings = $this->taxSettings($checkout);
            $taxResult = $this->taxes->calculateForAmounts(
                $lines->pluck('line_total_amount')->map(fn (int $amount): int => $amount)->all(),
                $shippingAmount,
                $taxSettings,
                $checkout->shipping_address_json ?? [],
            );
            $discountedSubtotal = $subtotal - $discountResult->amount;
            $total = $taxSettings->prices_include_tax
                ? $discountedSubtotal + $shippingAmount
                : $discountedSubtotal + $shippingAmount + $taxResult->totalAmount;

            $result = new PricingResult(
                subtotal: $subtotal,
                discount: $discountResult->amount,
                shipping: $shippingAmount,
                taxLines: $taxResult->taxLines,
                taxTotal: $taxResult->totalAmount,
                total: $total,
                currency: $cart->currency,
            );

            $checkout->forceFill([
                'tax_provider_snapshot_json' => $taxResult->toArray(),
                'totals_json' => $result->toArray(),
            ])->save();

            return $result;
        });
    }

    private function resetLineAmounts(Checkout $checkout): void
    {
        CartLine::withoutGlobalScopes()
            ->where('cart_id', $checkout->cart_id)
            ->get()
            ->each(function (CartLine $line): void {
                $subtotal = $line->unit_price_amount * $line->quantity;

                $line->forceFill([
                    'line_subtotal_amount' => $subtotal,
                    'line_discount_amount' => 0,
                    'line_total_amount' => $subtotal,
                ])->save();
            });
    }

    private function shippingAmount(Checkout $checkout, DiscountResult $discountResult): int
    {
        if (! $this->shipping->requiresShipping($checkout->cart)) {
            return 0;
        }

        if ($checkout->shipping_method_id === null) {
            return 0;
        }

        $rate = ShippingRate::withoutGlobalScopes()->find($checkout->shipping_method_id);

        if (! $rate instanceof ShippingRate) {
            throw InvalidCheckoutTransitionException::because('Shipping rate is not available.');
        }

        $amount = $this->shipping->calculate($rate, $checkout->cart);

        if ($amount === null) {
            throw InvalidCheckoutTransitionException::because('Shipping rate is not available for this cart.');
        }

        return $discountResult->freeShipping ? 0 : $amount;
    }

    private function taxSettings(Checkout $checkout): TaxSettings
    {
        return TaxSettings::withoutGlobalScopes()
            ->where('store_id', $checkout->store_id)
            ->first() ?? new TaxSettings([
                'store_id' => $checkout->store_id,
                'mode' => 'manual',
                'provider' => 'none',
                'prices_include_tax' => false,
                'config_json' => [
                    'default_rate_bps' => 0,
                    'shipping_taxable' => false,
                ],
            ]);
    }
}


command: sed -n '1,300p' app/Http/Resources/Storefront/V1/CheckoutResource.php

aggregated_output:
<?php

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CheckoutResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'cart_id' => $this->cart_id,
            'customer_id' => $this->customer_id,
            'status' => $this->status?->value,
            'payment_method' => $this->payment_method,
            'email' => $this->email,
            'shipping_address' => $this->shipping_address_json,
            'billing_address' => $this->billing_address_json,
            'shipping_method_id' => $this->shipping_method_id,
            'discount_code' => $this->discount_code,
            'totals' => $this->totals_json,
            'tax_provider_snapshot' => $this->tax_provider_snapshot_json,
            'available_shipping_rates' => ShippingRateResource::collection($this->whenLoaded('availableRates')),
            'cart' => new CartResource($this->whenLoaded('cart')),
            'expires_at' => $this->expires_at?->toIso8601String(),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


command: sed -n '1,260p' app/Http/Resources/Storefront/V1/CartResource.php

aggregated_output:
<?php

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CartResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        $lines = $this->whenLoaded('lines');

        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'customer_id' => $this->customer_id,
            'currency' => $this->currency,
            'status' => $this->status?->value,
            'cart_version' => $this->cart_version,
            'line_count' => $this->relationLoaded('lines') ? $this->lines->sum('quantity') : null,
            'totals' => $this->relationLoaded('lines') ? [
                'subtotal' => $this->lines->sum('line_subtotal_amount'),
                'discount' => $this->lines->sum('line_discount_amount'),
                'total' => $this->lines->sum('line_total_amount'),
                'currency' => $this->currency,
            ] : null,
            'lines' => CartLineResource::collection($lines),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


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

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CartResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        $lines = $this->whenLoaded('lines');

        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'customer_id' => $this->customer_id,
            'currency' => $this->currency,
            'status' => $this->status?->value,
            'cart_version' => $this->cart_version,
            'line_count' => $this->relationLoaded('lines') ? $this->lines->sum('quantity') : null,
            'totals' => $this->relationLoaded('lines') ? [
                'subtotal' => $this->lines->sum('line_subtotal_amount'),
                'discount' => $this->lines->sum('line_discount_amount'),
                'total' => $this->lines->sum('line_total_amount'),
                'currency' => $this->currency,
            ] : null,
            'lines' => CartLineResource::collection($lines),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


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

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CheckoutResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'cart_id' => $this->cart_id,
            'customer_id' => $this->customer_id,
            'status' => $this->status?->value,
            'payment_method' => $this->payment_method,
            'email' => $this->email,
            'shipping_address' => $this->shipping_address_json,
            'billing_address' => $this->billing_address_json,
            'shipping_method_id' => $this->shipping_method_id,
            'discount_code' => $this->discount_code,
            'totals' => $this->totals_json,
            'tax_provider_snapshot' => $this->tax_provider_snapshot_json,
            'available_shipping_rates' => ShippingRateResource::collection($this->whenLoaded('availableRates')),
            'cart' => new CartResource($this->whenLoaded('cart')),
            'expires_at' => $this->expires_at?->toIso8601String(),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


cmd: sed -n '1,240p' app/Http/Controllers/Api/Storefront/V1/CartLineController.php


cmd: for f in app/Http/Requests/Api/Storefront/V1/*.php; do printf '%s\n' "$f"; sed -n '1,220p' "$f"; done


cmd: sed -n '1,240p' app/Http/Resources/Storefront/V1/CartLineResource.php


cmd: sed -n '1,220p' app/Http/Resources/Storefront/V1/ShippingRateResource.php


cmd: sed -n '1,220p' routes/api.php && sed -n '1,260p' bootstrap/app.php


command: sed -n '1,240p' app/Http/Controllers/Api/Storefront/V1/CartLineController.php

aggregated_output:
<?php

namespace App\Http\Controllers\Api\Storefront\V1;

use App\Exceptions\CartVersionMismatchException;
use App\Exceptions\InsufficientInventoryException;
use App\Exceptions\InvalidCartOperationException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Storefront\V1\StoreCartLineRequest;
use App\Http\Requests\Api\Storefront\V1\UpdateCartLineRequest;
use App\Http\Resources\Storefront\V1\CartResource;
use App\Models\Cart;
use App\Models\CartLine;
use App\Services\CartService;
use Illuminate\Http\JsonResponse;

class CartLineController extends Controller
{
    public function store(StoreCartLineRequest $request, Cart $cart, CartService $carts): CartResource|JsonResponse
    {
        try {
            $carts->addLine(
                $cart,
                (int) $request->validated('variant_id'),
                (int) $request->validated('quantity'),
                $request->validated('expected_version'),
            );

            return CartResource::make($this->loadCart($cart->refresh()));
        } catch (CartVersionMismatchException $exception) {
            return $this->versionMismatch($exception, $cart);
        } catch (InsufficientInventoryException|InvalidCartOperationException $exception) {
            return response()->json(['message' => $exception->getMessage()], 422);
        }
    }

    public function update(UpdateCartLineRequest $request, Cart $cart, CartLine $cartLine, CartService $carts): CartResource|JsonResponse
    {
        abort_unless((int) $cartLine->cart_id === (int) $cart->getKey(), 404);

        try {
            $carts->updateLineQuantity(
                $cart,
                $cartLine->getKey(),
                (int) $request->validated('quantity'),
                $request->validated('expected_version'),
            );

            return CartResource::make($this->loadCart($cart->refresh()));
        } catch (CartVersionMismatchException $exception) {
            return $this->versionMismatch($exception, $cart);
        } catch (InsufficientInventoryException|InvalidCartOperationException $exception) {
            return response()->json(['message' => $exception->getMessage()], 422);
        }
    }

    public function destroy(Cart $cart, CartLine $cartLine, CartService $carts): CartResource
    {
        abort_unless((int) $cartLine->cart_id === (int) $cart->getKey(), 404);

        $carts->removeLine($cart, $cartLine->getKey());

        return CartResource::make($this->loadCart($cart->refresh()));
    }

    private function versionMismatch(CartVersionMismatchException $exception, Cart $cart): JsonResponse
    {
        return response()->json([
            'message' => $exception->getMessage(),
            'cart' => CartResource::make($this->loadCart($cart->refresh())),
        ], 409);
    }

    private function loadCart(Cart $cart): Cart
    {
        return $cart->load([
            'lines.variant.product',
            'lines.variant.optionValues.option',
        ]);
    }
}


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

namespace App\Http\Controllers\Api\Storefront\V1;

use App\Exceptions\CartVersionMismatchException;
use App\Exceptions\InsufficientInventoryException;
use App\Exceptions\InvalidCartOperationException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Storefront\V1\StoreCartLineRequest;
use App\Http\Requests\Api\Storefront\V1\UpdateCartLineRequest;
use App\Http\Resources\Storefront\V1\CartResource;
use App\Models\Cart;
use App\Models\CartLine;
use App\Services\CartService;
use Illuminate\Http\JsonResponse;

class CartLineController extends Controller
{
    public function store(StoreCartLineRequest $request, Cart $cart, CartService $carts): CartResource|JsonResponse
    {
        try {
            $carts->addLine(
                $cart,
                (int) $request->validated('variant_id'),
                (int) $request->validated('quantity'),
                $request->validated('expected_version'),
            );

            return CartResource::make($this->loadCart($cart->refresh()));
        } catch (CartVersionMismatchException $exception) {
            return $this->versionMismatch($exception, $cart);
        } catch (InsufficientInventoryException|InvalidCartOperationException $exception) {
            return response()->json(['message' => $exception->getMessage()], 422);
        }
    }

    public function update(UpdateCartLineRequest $request, Cart $cart, CartLine $cartLine, CartService $carts): CartResource|JsonResponse
    {
        abort_unless((int) $cartLine->cart_id === (int) $cart->getKey(), 404);

        try {
            $carts->updateLineQuantity(
                $cart,
                $cartLine->getKey(),
                (int) $request->validated('quantity'),
                $request->validated('expected_version'),
            );

            return CartResource::make($this->loadCart($cart->refresh()));
        } catch (CartVersionMismatchException $exception) {
            return $this->versionMismatch($exception, $cart);
        } catch (InsufficientInventoryException|InvalidCartOperationException $exception) {
            return response()->json(['message' => $exception->getMessage()], 422);
        }
    }

    public function destroy(Cart $cart, CartLine $cartLine, CartService $carts): CartResource
    {
        abort_unless((int) $cartLine->cart_id === (int) $cart->getKey(), 404);

        $carts->removeLine($cart, $cartLine->getKey());

        return CartResource::make($this->loadCart($cart->refresh()));
    }

    private function versionMismatch(CartVersionMismatchException $exception, Cart $cart): JsonResponse
    {
        return response()->json([
            'message' => $exception->getMessage(),
            'cart' => CartResource::make($this->loadCart($cart->refresh())),
        ], 409);
    }

    private function loadCart(Cart $cart): Cart
    {
        return $cart->load([
            'lines.variant.product',
            'lines.variant.optionValues.option',
        ]);
    }
}


command: sed -n '1,240p' app/Http/Resources/Storefront/V1/CartLineResource.php

aggregated_output:
<?php

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class CartLineResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'variant_id' => $this->variant_id,
            'quantity' => $this->quantity,
            'unit_price_amount' => $this->unit_price_amount,
            'line_subtotal_amount' => $this->line_subtotal_amount,
            'line_discount_amount' => $this->line_discount_amount,
            'line_total_amount' => $this->line_total_amount,
            'product' => $this->whenLoaded('variant', fn (): ?array => $this->variant?->relationLoaded('product') ? [
                'id' => $this->variant->product?->id,
                'title' => $this->variant->product?->title,
                'handle' => $this->variant->product?->handle,
            ] : null),
            'variant' => $this->whenLoaded('variant', fn (): array => [
                'id' => $this->variant->id,
                'sku' => $this->variant->sku,
                'requires_shipping' => $this->variant->requires_shipping,
                'options' => $this->variant->relationLoaded('optionValues')
                    ? $this->variant->optionValues->map(fn ($value): array => [
                        'name' => $value->option?->name,
                        'value' => $value->value,
                    ])->values()->all()
                    : [],
            ]),
        ];
    }
}


command: sed -n '1,220p' app/Http/Resources/Storefront/V1/ShippingRateResource.php

aggregated_output:
<?php

namespace App\Http\Resources\Storefront\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class ShippingRateResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'zone_id' => $this->zone_id,
            'name' => $this->name,
            'type' => $this->type?->value,
            'amount' => $this->when($this->getAttribute('calculated_amount') !== null, $this->getAttribute('calculated_amount')),
            'config' => $this->config_json,
        ];
    }
}


command: sed -n '1,220p' routes/api.php && sed -n '1,260p' bootstrap/app.php

api.php

cmd: sed -n '1,220p' routes/api.php

app.php

cmd: sed -n '1,260p' bootstrap/app.php

aggregated_output:
<?php

use App\Http\Controllers\Api\Storefront\V1\CartController;
use App\Http\Controllers\Api\Storefront\V1\CartLineController;
use App\Http\Controllers\Api\Storefront\V1\CheckoutController;
use Illuminate\Support\Facades\Route;

Route::middleware(['store.resolve', 'throttle:api.storefront'])
    ->prefix('storefront/v1')
    ->name('api.storefront.v1.')
    ->group(function (): void {
        Route::post('carts', [CartController::class, 'store'])->name('carts.store');
        Route::get('carts/{cart}', [CartController::class, 'show'])->name('carts.show');
        Route::post('carts/{cart}/lines', [CartLineController::class, 'store'])->name('carts.lines.store');
        Route::put('carts/{cart}/lines/{cartLine}', [CartLineController::class, 'update'])->name('carts.lines.update');
        Route::delete('carts/{cart}/lines/{cartLine}', [CartLineController::class, 'destroy'])->name('carts.lines.destroy');

        Route::post('checkouts', [CheckoutController::class, 'store'])->name('checkouts.store');
        Route::get('checkouts/{checkout}', [CheckoutController::class, 'show'])->name('checkouts.show');
        Route::put('checkouts/{checkout}/address', [CheckoutController::class, 'address'])->name('checkouts.address');
        Route::put('checkouts/{checkout}/shipping-method', [CheckoutController::class, 'shippingMethod'])->name('checkouts.shipping-method');
        Route::post('checkouts/{checkout}/apply-discount', [CheckoutController::class, 'applyDiscount'])->name('checkouts.apply-discount');
        Route::put('checkouts/{checkout}/payment-method', [CheckoutController::class, 'paymentMethod'])->name('checkouts.payment-method');
    });
<?php

use App\Http\Middleware\CheckStoreRole;
use App\Http\Middleware\ResolveStore;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->alias([
            'role.check' => CheckStoreRole::class,
            'store.resolve' => ResolveStore::class,
        ]);

        $middleware->appendToGroup('storefront', [
            ResolveStore::class,
        ]);

        $middleware->appendToGroup('admin', [
            ResolveStore::class,
            CheckStoreRole::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();