command: sed -n '1,300p' app/Livewire/Storefront/Account/Auth/Register.php

aggregated_output:
<?php

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Livewire\Component;

class Register extends Component
{
    public string $name = '';

    public string $email = '';

    public string $password = '';

    public string $password_confirmation = '';

    public bool $marketing_opt_in = false;

    public int $storeId;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function register(): void
    {
        $store = Store::query()->findOrFail($this->storeId);

        app()->instance('current_store', $store);

        $validated = $this->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('customers', 'email')->where('store_id', $store->getKey()),
            ],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
            'marketing_opt_in' => ['boolean'],
        ]);

        $customer = Customer::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'name' => $validated['name'],
            'email' => $validated['email'],
            'password' => $validated['password'],
            'marketing_opt_in' => $validated['marketing_opt_in'],
        ]);

        Auth::guard('customer')->login($customer);

        if (request()->hasSession()) {
            request()->session()->regenerate();
        }

        $this->redirectRoute('account.dashboard', navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.register')
            ->layout('layouts.auth');
    }
}


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

namespace App\Livewire\Storefront\Account\Auth;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Livewire\Component;

class Register extends Component
{
    public string $name = '';

    public string $email = '';

    public string $password = '';

    public string $password_confirmation = '';

    public bool $marketing_opt_in = false;

    public int $storeId;

    public function mount(): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $this->storeId = $store->getKey();
    }

    public function register(): void
    {
        $store = Store::query()->findOrFail($this->storeId);

        app()->instance('current_store', $store);

        $validated = $this->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('customers', 'email')->where('store_id', $store->getKey()),
            ],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
            'marketing_opt_in' => ['boolean'],
        ]);

        $customer = Customer::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            'name' => $validated['name'],
            'email' => $validated['email'],
            'password' => $validated['password'],
            'marketing_opt_in' => $validated['marketing_opt_in'],
        ]);

        Auth::guard('customer')->login($customer);

        if (request()->hasSession()) {
            request()->session()->regenerate();
        }

        $this->redirectRoute('account.dashboard', navigate: true);
    }

    public function render(): mixed
    {
        return view('livewire.storefront.account.auth.register')
            ->layout('layouts.auth');
    }
}


output:
Chunk ID: 45ad0c
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 347
Output:

    <x-auth-header :title="__('Log in')" :description="__('Access your orders and saved addresses')" />

    <form wire:submit="login" class="flex flex-col gap-6">
        <flux:input
            wire:model="email"
            :label="__('Email address')"
            type="email"
            required
            autofocus
            autocomplete="email"
            placeholder="customer@acme.test"
        />

        <flux:input
            wire:model="password"
            :label="__('Password')"
            type="password"
            required
            autocomplete="current-password"
            :placeholder="__('Password')"
            viewable
        />

            <flux:link :href="route('customer.password.request')" wire:navigate>{{ __('Forgot your password?') }}</flux:link>

        <flux:checkbox wire:model="remember" :label="__('Remember me')" />

        <flux:button variant="primary" type="submit" class="w-full" data-test="customer-login-button">
            {{ __('Log in') }}
        </flux:button>
    </form>

        {{ __('New customer?') }}
        <flux:link :href="route('account.register')" wire:navigate>{{ __('Create an account') }}</flux:link>


command: sed -n '1,300p' resources/views/livewire/storefront/account/auth/register.blade.php

register.blade.php

type: read

aggregated_output:
    <x-auth-header :title="__('Create an account')" :description="__('Save your details for faster checkout')" />

    <form wire:submit="register" class="flex flex-col gap-6">
        <flux:input
            wire:model="name"
            :label="__('Name')"
            type="text"
            required
            autofocus
            autocomplete="name"
        />

        <flux:input
            wire:model="email"
            :label="__('Email address')"
            type="email"
            required
            autocomplete="email"
            placeholder="customer@acme.test"
        />

        <flux:input
            wire:model="password"
            :label="__('Password')"
            type="password"
            required
            autocomplete="new-password"
            viewable
        />

        <flux:input
            wire:model="password_confirmation"
            :label="__('Confirm password')"
            type="password"
            required
            autocomplete="new-password"
            viewable
        />

        <flux:checkbox wire:model="marketing_opt_in" :label="__('Email me about new products and offers')" />

        <flux:button variant="primary" type="submit" class="w-full" data-test="customer-register-button">
            {{ __('Create account') }}
        </flux:button>
    </form>

        {{ __('Already have an account?') }}
        <flux:link :href="route('account.login')" wire:navigate>{{ __('Log in') }}</flux:link>

status: completed


output:
Chunk ID: 16ecf4
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 403
Output:

    <x-auth-header :title="__('Create an account')" :description="__('Save your details for faster checkout')" />

    <form wire:submit="register" class="flex flex-col gap-6">
        <flux:input
            wire:model="name"
            :label="__('Name')"
            type="text"
            required
            autofocus
            autocomplete="name"
        />

        <flux:input
            wire:model="email"
            :label="__('Email address')"
            type="email"
            required
            autocomplete="email"
            placeholder="customer@acme.test"
        />

        <flux:input
            wire:model="password"
            :label="__('Password')"
            type="password"
            required
            autocomplete="new-password"
            viewable
        />

        <flux:input
            wire:model="password_confirmation"
            :label="__('Confirm password')"
            type="password"
            required
            autocomplete="new-password"
            viewable
        />

        <flux:checkbox wire:model="marketing_opt_in" :label="__('Email me about new products and offers')" />

        <flux:button variant="primary" type="submit" class="w-full" data-test="customer-register-button">
            {{ __('Create account') }}
        </flux:button>
    </form>

        {{ __('Already have an account?') }}
        <flux:link :href="route('account.login')" wire:navigate>{{ __('Log in') }}</flux:link>


command: sed -n '1,260p' tests/Feature/Foundation/CustomerAuthTest.php

CustomerAuthTest.php

aggregated_output:
<?php

use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Models\Customer;
use App\Models\Store;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Livewire\Livewire;

uses(RefreshDatabase::class);

test('customer authentication is scoped to the current store', function () {
    $firstStore = Store::factory()->create();
    $secondStore = Store::factory()->create();

    Customer::factory()->create([
        'store_id' => $firstStore->getKey(),
        'email' => 'same@example.test',
        'password' => 'first-password',
    ]);

    Customer::factory()->create([
        'store_id' => $secondStore->getKey(),
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]);

    app()->instance('current_store', $firstStore);

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'first-password',
    ]))->toBeTrue();

    Auth::guard('customer')->logout();

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]))->toBeFalse();

    app()->instance('current_store', $secondStore);

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]))->toBeTrue();
});

test('customer login component authenticates within the resolved store', function () {
    $store = Store::factory()->create();
    $customer = Customer::factory()->create([
        'store_id' => $store->getKey(),
        'email' => 'customer@example.test',
        'password' => 'password',
    ]);

    app()->instance('current_store', $store);

    Livewire::test(CustomerLogin::class)
        ->set('email', $customer->email)
        ->set('password', 'password')
        ->call('login')
        ->assertHasNoErrors()
        ->assertRedirect(route('account.dashboard', absolute: false));

    $this->assertAuthenticatedAs($customer, 'customer');
});

test('customer registration is unique per store', function () {
    $store = Store::factory()->create();

    app()->instance('current_store', $store);

    Livewire::test(CustomerRegister::class)
        ->set('name', 'Jane Doe')
        ->set('email', 'jane@example.test')
        ->set('password', 'password')
        ->set('password_confirmation', 'password')
        ->set('marketing_opt_in', true)
        ->call('register')
        ->assertHasNoErrors()
        ->assertRedirect(route('account.dashboard', absolute: false));

    expect(Customer::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('email', 'jane@example.test')
        ->exists())->toBeTrue();

    Livewire::test(CustomerRegister::class)
        ->set('name', 'Jane Doe')
        ->set('email', 'jane@example.test')
        ->set('password', 'password')
        ->set('password_confirmation', 'password')
        ->call('register')
        ->assertHasErrors(['email']);
});


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

use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Models\Customer;
use App\Models\Store;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Livewire\Livewire;

uses(RefreshDatabase::class);

test('customer authentication is scoped to the current store', function () {
    $firstStore = Store::factory()->create();
    $secondStore = Store::factory()->create();

    Customer::factory()->create([
        'store_id' => $firstStore->getKey(),
        'email' => 'same@example.test',
        'password' => 'first-password',
    ]);

    Customer::factory()->create([
        'store_id' => $secondStore->getKey(),
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]);

    app()->instance('current_store', $firstStore);

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'first-password',
    ]))->toBeTrue();

    Auth::guard('customer')->logout();

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]))->toBeFalse();

    app()->instance('current_store', $secondStore);

    expect(Auth::guard('customer')->attempt([
        'email' => 'same@example.test',
        'password' => 'second-password',
    ]))->toBeTrue();
});

test('customer login component authenticates within the resolved store', function () {
    $store = Store::factory()->create();
    $customer = Customer::factory()->create([
        'store_id' => $store->getKey(),
        'email' => 'customer@example.test',
        'password' => 'password',
    ]);

    app()->instance('current_store', $store);

    Livewire::test(CustomerLogin::class)
        ->set('email', $customer->email)
        ->set('password', 'password')
        ->call('login')
        ->assertHasNoErrors()
        ->assertRedirect(route('account.dashboard', absolute: false));

    $this->assertAuthenticatedAs($customer, 'customer');
});

test('customer registration is unique per store', function () {
    $store = Store::factory()->create();

    app()->instance('current_store', $store);

    Livewire::test(CustomerRegister::class)
        ->set('name', 'Jane Doe')
        ->set('email', 'jane@example.test')
        ->set('password', 'password')
        ->set('password_confirmation', 'password')
        ->set('marketing_opt_in', true)
        ->call('register')
        ->assertHasNoErrors()
        ->assertRedirect(route('account.dashboard', absolute: false));

    expect(Customer::withoutGlobalScopes()
        ->where('store_id', $store->getKey())
        ->where('email', 'jane@example.test')
        ->exists())->toBeTrue();

    Livewire::test(CustomerRegister::class)
        ->set('name', 'Jane Doe')
        ->set('email', 'jane@example.test')
        ->set('password', 'password')
        ->set('password_confirmation', 'password')
        ->call('register')
        ->assertHasErrors(['email']);
});


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


cmd: sed -n '1,240p' database/factories/CustomerAddressFactory.php


cmd: sed -n '1,260p' database/seeders/CustomerSeeder.php


cmd: sed -n '1,220p' database/seeders/CustomerAddressSeeder.php


cmd: sed -n '1,260p' database/seeders/DatabaseSeeder.php


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

aggregated_output:
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class CustomerAddressSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
    }
}


command: sed -n '1,260p' app/Models/CustomerAddress.php

aggregated_output:
<?php

namespace App\Models;

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

class CustomerAddress extends Model
{
    /** @use HasFactory<\Database\Factories\CustomerAddressFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'customer_id',
        'label',
        'address_json',
        'is_default',
    ];

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

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


command: sed -n '1,240p' database/factories/CustomerAddressFactory.php

aggregated_output:
<?php

namespace Database\Factories;

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

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
 */
class CustomerAddressFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'customer_id' => Customer::factory(),
            'label' => fake()->randomElement(['Shipping', 'Billing', 'Home', 'Office']),
            'address_json' => [
                'first_name' => fake()->firstName(),
                'last_name' => fake()->lastName(),
                'address1' => fake()->streetAddress(),
                'address2' => null,
                'city' => fake()->city(),
                'province_code' => null,
                'country' => 'DE',
                'postal_code' => fake()->postcode(),
            ],
            'is_default' => false,
        ];
    }

    public function default(): static
    {
        return $this->state(fn (array $attributes): array => [
            'is_default' => true,
        ]);
    }
}


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

aggregated_output:
<?php

namespace Database\Seeders;

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

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

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


command: sed -n '1,260p' database/seeders/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,
            AppSeeder::class,
            UserSeeder::class,
            StoreUserSeeder::class,
            StoreSettingsSeeder::class,
            SearchSettingsSeeder::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,
            AnalyticsSeeder::class,
        ]);
    }
}


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

namespace App\Models;

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

class CustomerAddress extends Model
{
    /** @use HasFactory<\Database\Factories\CustomerAddressFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'customer_id',
        'label',
        'address_json',
        'is_default',
    ];

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

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


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

namespace Database\Factories;

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

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
 */
class CustomerAddressFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'customer_id' => Customer::factory(),
            'label' => fake()->randomElement(['Shipping', 'Billing', 'Home', 'Office']),
            'address_json' => [
                'first_name' => fake()->firstName(),
                'last_name' => fake()->lastName(),
                'address1' => fake()->streetAddress(),
                'address2' => null,
                'city' => fake()->city(),
                'province_code' => null,
                'country' => 'DE',
                'postal_code' => fake()->postcode(),
            ],
            'is_default' => false,
        ];
    }

    public function default(): static
    {
        return $this->state(fn (array $attributes): array => [
            'is_default' => true,
        ]);
    }
}


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

namespace Database\Seeders;

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

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

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


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

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class CustomerAddressSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
    }
}


output:
Chunk ID: 46cdf2
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 261
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,
            AppSeeder::class,
            UserSeeder::class,
            StoreUserSeeder::class,
            StoreSettingsSeeder::class,
            SearchSettingsSeeder::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,
            AnalyticsSeeder::class,
        ]);
    }
}


cmd: sed -n '1,340p' app/Livewire/Admin/Customers/Show.php


cmd: sed -n '1,360p' resources/views/livewire/admin/customers/show.blade.php


cmd: sed -n '1,260p' tests/Feature/Storefront/OrderViewsTest.php


cmd: sed -n '1,260p' database/factories/OrderFactory.php


cmd: sed -n '1,260p' database/factories/OrderLineFactory.php


command: sed -n '1,340p' app/Livewire/Admin/Customers/Show.php

aggregated_output:
<?php

namespace App\Livewire\Admin\Customers;

use App\Models\Customer;
use App\Models\CustomerAddress;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Locked;
use Livewire\Component;
use Livewire\WithPagination;

class Show extends Component
{
    use WithPagination;

    #[Locked]
    public int $storeId;

    #[Locked]
    public int $customerId;

    public ?int $editingAddressId = null;

    public string $addressLabel = '';

    /**
     * @var array{first_name: string, last_name: string, address1: string, address2: string, city: string, province_code: string, country: string, postal_code: string}
     */
    public array $addressJson = [
        'first_name' => '',
        'last_name' => '',
        'address1' => '',
        'address2' => '',
        'city' => '',
        'province_code' => '',
        'country' => 'DE',
        'postal_code' => '',
    ];

    public function mount(Customer $customer): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $customer = Customer::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->whereKey($customer->getKey())
            ->first();

        abort_unless($customer instanceof Customer, 404);

        $this->storeId = $store->getKey();
        $this->customerId = $customer->getKey();
    }

    public function openAddressForm(?int $addressId = null): void
    {
        $this->editingAddressId = $addressId;

        if ($addressId) {
            $address = $this->address($addressId);
            $this->addressLabel = (string) $address->label;
            $this->addressJson = array_merge($this->emptyAddressJson(), $address->address_json ?? []);
        } else {
            $this->resetAddressForm();
        }

        $this->modal('address-form')->show();
    }

    public function saveAddress(): void
    {
        $this->validate([
            'addressLabel' => ['nullable', 'string', 'max:255'],
            'addressJson.first_name' => ['nullable', 'string', 'max:255'],
            'addressJson.last_name' => ['nullable', 'string', 'max:255'],
            'addressJson.address1' => ['required', 'string', 'max:255'],
            'addressJson.address2' => ['nullable', 'string', 'max:255'],
            'addressJson.city' => ['required', 'string', 'max:255'],
            'addressJson.province_code' => ['nullable', 'string', 'max:255'],
            'addressJson.country' => ['required', 'string', 'size:2'],
            'addressJson.postal_code' => ['required', 'string', 'max:32'],
        ]);

        $address = $this->editingAddressId
            ? $this->address($this->editingAddressId)
            : new CustomerAddress(['customer_id' => $this->customerId]);

        $address->fill([
            'label' => $this->addressLabel !== '' ? $this->addressLabel : null,
            'address_json' => $this->addressJson,
            'is_default' => $address->exists ? $address->is_default : ! $this->customer()->addresses()->exists(),
        ]);
        $address->save();

        $this->resetAddressForm();
        $this->modal('address-form')->close();
        $this->dispatch('toast', type: 'success', message: __('Address saved'));
    }

    public function deleteAddress(int $addressId): void
    {
        $address = $this->address($addressId);
        $wasDefault = $address->is_default;
        $address->delete();

        if ($wasDefault) {
            $this->setFirstAddressAsDefault();
        }

        $this->dispatch('toast', type: 'success', message: __('Address deleted'));
    }

    public function setDefaultAddress(int $addressId): void
    {
        $address = $this->address($addressId);

        DB::transaction(function () use ($address): void {
            CustomerAddress::query()
                ->where('customer_id', $this->customerId)
                ->update(['is_default' => false]);

            $address->forceFill(['is_default' => true])->save();
        });

        $this->dispatch('toast', type: 'success', message: __('Default address updated'));
    }

    public function orders(): LengthAwarePaginator
    {
        return Order::withoutGlobalScopes()
            ->where('store_id', $this->storeId)
            ->where('customer_id', $this->customerId)
            ->latest('placed_at')
            ->latest('id')
            ->paginate(10);
    }

    public function render(): mixed
    {
        $customer = $this->customer();

        return view('livewire.admin.customers.show', [
            'customer' => $customer,
            'orders' => $this->orders(),
        ])->layout('layouts.app', [
            'title' => $customer->name ?: $customer->email,
        ]);
    }

    private function customer(): Customer
    {
        return Customer::withoutGlobalScopes()
            ->with(['addresses' => fn ($query) => $query->orderByDesc('is_default')->orderBy('id')])
            ->where('store_id', $this->storeId)
            ->whereKey($this->customerId)
            ->firstOrFail();
    }

    private function address(int $addressId): CustomerAddress
    {
        return CustomerAddress::query()
            ->where('customer_id', $this->customerId)
            ->whereKey($addressId)
            ->firstOrFail();
    }

    private function setFirstAddressAsDefault(): void
    {
        $nextAddress = CustomerAddress::query()
            ->where('customer_id', $this->customerId)
            ->oldest('id')
            ->first();

        if ($nextAddress instanceof CustomerAddress) {
            $nextAddress->forceFill(['is_default' => true])->save();
        }
    }

    private function resetAddressForm(): void
    {
        $this->editingAddressId = null;
        $this->addressLabel = '';
        $this->addressJson = $this->emptyAddressJson();
    }

    /**
     * @return array{first_name: string, last_name: string, address1: string, address2: string, city: string, province_code: string, country: string, postal_code: string}
     */
    private function emptyAddressJson(): array
    {
        return [
            'first_name' => '',
            'last_name' => '',
            'address1' => '',
            'address2' => '',
            'city' => '',
            'province_code' => '',
            'country' => 'DE',
            'postal_code' => '',
        ];
    }
}


command: sed -n '1,360p' resources/views/livewire/admin/customers/show.blade.php

aggregated_output:
            <flux:heading size="xl">{{ $customer->name ?: 'Unnamed customer' }}</flux:heading>
            <flux:text class="mt-1">{{ $customer->email }}</flux:text>

        <flux:button :href="route('admin.customers.index')" wire:navigate variant="filled" icon="arrow-left">
            Customers
        </flux:button>

                <flux:heading size="lg">Customer info</flux:heading>

Name

{{ $customer->name ?: 'Unnamed customer' }}

Email

{{ $customer->email }}

Created

{{ $customer->created_at?->format('M j, Y') }}

Marketing

                            <flux:badge :color="$customer->marketing_opt_in ? 'green' : 'zinc'">
                                {{ $customer->marketing_opt_in ? 'Opted in' : 'Not opted in' }}
                            </flux:badge>

                    <flux:heading size="lg">Order history</flux:heading>

                                Order
                                Date
                                Status
                                Total

                            @forelse ($orders as $order)
                                @php
                                    $statusColor = match ($order->financial_status->value) {
                                        'paid' => 'green',
                                        'partially_refunded' => 'amber',
                                        'refunded', 'voided' => 'red',
                                        default => 'zinc',
                                    };
                                @endphp

getKey() }}">

                                            {{ $order->order_number }}

                                    {{ $order->placed_at?->format('M j, Y') }}

                                        <flux:badge :color="$statusColor">{{ Str::headline($order->financial_status->value) }}</flux:badge>

                                        <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-end" />

                            @empty

                                    No orders for this custom…610 chars truncated…

                @forelse ($customer->addresses as $address)
                    @php($addressData = $address->address_json ?? [])

getKey() }}" class="rounded-lg border border-zinc-200 p-4 dark:border-zinc-700">

{{ $address->label ?: 'Address' }}

                                    @if ($address->is_default)
                                        <flux:badge color="green">Default</flux:badge>
                                    @endif

{{ data_get($addressData, 'address1') }}

                                    @if (data_get($addressData, 'address2'))

{{ data_get($addressData, 'address2') }}

                                    @endif

{{ trim(data_get($addressData, 'postal_code').' '.data_get($addressData, 'city')) }}

{{ data_get($addressData, 'country') }}

                            <flux:button wire:click="openAddressForm({{ $address->getKey() }})" size="sm" variant="filled">Edit</flux:button>
                            @unless ($address->is_default)
                                <flux:button wire:click="setDefaultAddress({{ $address->getKey() }})" size="sm" variant="ghost">Set default</flux:button>
                            @endunless
                            <flux:button wire:click="deleteAddress({{ $address->getKey() }})" wire:confirm="Delete this address?" size="sm" variant="danger">Delete</flux:button>

                @empty

                        <flux:icon name="map-pin" class="mx-auto size-8 text-zinc-400" />
                        <flux:text class="mt-3">No addresses saved.</flux:text>

                @endforelse

    <flux:modal name="address-form" class="md:w-[32rem]">
        <form wire:submit="saveAddress" class="space-y-6">

                <flux:heading size="lg">{{ $editingAddressId ? 'Edit address' : 'Add address' }}</flux:heading>

            <flux:input wire:model="addressLabel" label="Label" placeholder="Home, Office..." />

                <flux:input wire:model="addressJson.first_name" label="First name" />
                <flux:input wire:model="addressJson.last_name" label="Last name" />

                    <flux:input wire:model="addressJson.address1" label="Address line 1" />
                    <flux:error name="addressJson.address1" />

                    <flux:input wire:model="addressJson.address2" label="Address line 2" />

                <flux:input wire:model="addressJson.city" label="City" />
                <flux:input wire:model="addressJson.province_code" label="State / Province" />
                <flux:input wire:model="addressJson.postal_code" label="Postal code" />
                <flux:select wire:model="addressJson.country" label="Country">
                    <flux:select.option value="DE">Germany</flux:select.option>
                    <flux:select.option value="US">United States</flux:select.option>
                    <flux:select.option value="GB">United Kingdom</flux:select.option>
                    <flux:select.option value="FR">France</flux:select.option>
                    <flux:select.option value="NL">Netherlands</flux:select.option>
                </flux:select>

            <flux:error name="addressJson.city" />
            <flux:error name="addressJson.postal_code" />
            <flux:error name="addressJson.country" />

                <flux:modal.close>
                    <flux:button variant="filled">Cancel</flux:button>
                </flux:modal.close>
                <flux:button type="submit" variant="primary">Save</flux:button>

        </form>
    </flux:modal>


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

aggregated_output:
<?php

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

uses(RefreshDatabase::class);

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

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

    return $store;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


command: sed -n '1,260p' database/factories/OrderFactory.php

aggregated_output:
<?php

namespace Database\Factories;

use App\Enums\FinancialStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Order>
 */
class OrderFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $subtotal = fake()->numberBetween(2500, 25000);
        $shipping = fake()->randomElement([0, 499, 799]);
        $tax = 0;

        return [
            'store_id' => Store::factory(),
            'checkout_id' => null,
            'customer_id' => null,
            'order_number' => '#'.fake()->unique()->numberBetween(1001, 9999),
            'payment_method' => PaymentMethod::CreditCard,
            'status' => OrderStatus::Paid,
            'financial_status' => FinancialStatus::Paid,
            'fulfillment_status' => FulfillmentStatus::Unfulfilled,
            'currency' => 'EUR',
            'subtotal_amount' => $subtotal,
            'discount_amount' => 0,
            'shipping_amount' => $shipping,
            'tax_amount' => $tax,
            'total_amount' => $subtotal + $shipping + $tax,
            'email' => fake()->safeEmail(),
            'billing_address_json' => $this->address(),
            'shipping_address_json' => $this->address(),
            'placed_at' => now(),
        ];
    }

    public function forCheckout(?Checkout $checkout = null): static
    {
        return $this->state(fn (array $attributes): array => [
            'checkout_id' => $checkout?->getKey() ?? Checkout::factory(),
        ]);
    }

    public function forCustomer(?Customer $customer = null): static
    {
        return $this->state(fn (array $attributes): array => [
            'customer_id' => $customer?->getKey() ?? Customer::factory(),
        ]);
    }

    public function paid(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Paid,
            'financial_status' => FinancialStatus::Paid,
        ]);
    }

    public function pending(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Pending,
            'financial_status' => FinancialStatus::Pending,
        ]);
    }

    public function creditCard(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::CreditCard,
        ]);
    }

    public function paypal(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::Paypal,
        ]);
    }

    public function bankTransfer(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::BankTransfer,
            'status' => OrderStatus::Pending,
            'financial_status' => FinancialStatus::Pending,
        ]);
    }

    public function cancelled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Cancelled,
            'financial_status' => FinancialStatus::Voided,
        ]);
    }

    public function partiallyFulfilled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'fulfillment_status' => FulfillmentStatus::Partial,
        ]);
    }

    public function fulfilled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Fulfilled,
            'financial_status' => FinancialStatus::Paid,
            'fulfillment_status' => FulfillmentStatus::Fulfilled,
        ]);
    }

    public function refunded(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Refunded,
            'financial_status' => FinancialStatus::Refunded,
        ]);
    }

    /**
     * @return array<string, string|null>
     */
    private function address(): array
    {
        return [
            'first_name' => fake()->firstName(),
            'last_name' => fake()->lastName(),
            'address1' => fake()->streetAddress(),
            'address2' => null,
            'city' => fake()->city(),
            'province_code' => null,
            'country' => 'DE',
            'postal_code' => fake()->postcode(),
        ];
    }
}


command: sed -n '1,260p' database/factories/OrderLineFactory.php

aggregated_output:
<?php

namespace Database\Factories;

use App\Models\Order;
use App\Models\ProductVariant;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\OrderLine>
 */
class OrderLineFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $quantity = fake()->numberBetween(1, 3);
        $unitPrice = fake()->numberBetween(1000, 10000);

        return [
            'order_id' => Order::factory(),
            'product_id' => null,
            'variant_id' => ProductVariant::factory(),
            'title_snapshot' => fake()->words(3, true),
            'sku_snapshot' => 'SKU-'.fake()->unique()->numerify('####'),
            'quantity' => $quantity,
            'unit_price_amount' => $unitPrice,
            'total_amount' => $unitPrice * $quantity,
            'tax_lines_json' => [],
            'discount_allocations_json' => [],
        ];
    }
}


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

namespace App\Livewire\Admin\Customers;

use App\Models\Customer;
use App\Models\CustomerAddress;
use App\Models\Order;
use App\Models\Store;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Locked;
use Livewire\Component;
use Livewire\WithPagination;

class Show extends Component
{
    use WithPagination;

    #[Locked]
    public int $storeId;

    #[Locked]
    public int $customerId;

    public ?int $editingAddressId = null;

    public string $addressLabel = '';

    /**
     * @var array{first_name: string, last_name: string, address1: string, address2: string, city: string, province_code: string, country: string, postal_code: string}
     */
    public array $addressJson = [
        'first_name' => '',
        'last_name' => '',
        'address1' => '',
        'address2' => '',
        'city' => '',
        'province_code' => '',
        'country' => 'DE',
        'postal_code' => '',
    ];

    public function mount(Customer $customer): void
    {
        $store = app('current_store');

        abort_unless($store instanceof Store, 404);

        $customer = Customer::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->whereKey($customer->getKey())
            ->first();

        abort_unless($customer instanceof Customer, 404);

        $this->storeId = $store->getKey();
        $this->customerId = $customer->getKey();
    }

    public function openAddressForm(?int $addressId = null): void
    {
        $this->editingAddressId = $addressId;

        if ($addressId) {
            $address = $this->address($addressId);
            $this->addressLabel = (string) $address->label;
            $this->addressJson = array_merge($this->emptyAddressJson(), $address->address_json ?? []);
        } else {
            $this->resetAddressForm();
        }

        $this->modal('address-form')->show();
    }

    public function saveAddress(): void
    {
        $this->validate([
            'addressLabel' => ['nullable', 'string', 'max:255'],
            'addressJson.first_name' => ['nullable', 'string', 'max:255'],
            'addressJson.last_name' => ['nullable', 'string', 'max:255'],
            'addressJson.address1' => ['required', 'string', 'max:255'],
            'addressJson.address2' => ['nullable', 'string', 'max:255'],
            'addressJson.city' => ['required', 'string', 'max:255'],
            'addressJson.province_code' => ['nullable', 'string', 'max:255'],
            'addressJson.country' => ['required', 'string', 'size:2'],
            'addressJson.postal_code' => ['required', 'string', 'max:32'],
        ]);

        $address = $this->editingAddressId
            ? $this->address($this->editingAddressId)
            : new CustomerAddress(['customer_id' => $this->customerId]);

        $address->fill([
            'label' => $this->addressLabel !== '' ? $this->addressLabel : null,
            'address_json' => $this->addressJson,
            'is_default' => $address->exists ? $address->is_default : ! $this->customer()->addresses()->exists(),
        ]);
        $address->save();

        $this->resetAddressForm();
        $this->modal('address-form')->close();
        $this->dispatch('toast', type: 'success', message: __('Address saved'));
    }

    public function deleteAddress(int $addressId): void
    {
        $address = $this->address($addressId);
        $wasDefault = $address->is_default;
        $address->delete();

        if ($wasDefault) {
            $this->setFirstAddressAsDefault();
        }

        $this->dispatch('toast', type: 'success', message: __('Address deleted'));
    }

    public function setDefaultAddress(int $addressId): void
    {
        $address = $this->address($addressId);

        DB::transaction(function () use ($address): void {
            CustomerAddress::query()
                ->where('customer_id', $this->customerId)
                ->update(['is_default' => false]);

            $address->forceFill(['is_default' => true])->save();
        });

        $this->dispatch('toast', type: 'success', message: __('Default address updated'));
    }

    public function orders(): LengthAwarePaginator
    {
        return Order::withoutGlobalScopes()
            ->where('store_id', $this->storeId)
            ->where('customer_id', $this->customerId)
            ->latest('placed_at')
            ->latest('id')
            ->paginate(10);
    }

    public function render(): mixed
    {
        $customer = $this->customer();

        return view('livewire.admin.customers.show', [
            'customer' => $customer,
            'orders' => $this->orders(),
        ])->layout('layouts.app', [
            'title' => $customer->name ?: $customer->email,
        ]);
    }

    private function customer(): Customer
    {
        return Customer::withoutGlobalScopes()
            ->with(['addresses' => fn ($query) => $query->orderByDesc('is_default')->orderBy('id')])
            ->where('store_id', $this->storeId)
            ->whereKey($this->customerId)
            ->firstOrFail();
    }

    private function address(int $addressId): CustomerAddress
    {
        return CustomerAddress::query()
            ->where('customer_id', $this->customerId)
            ->whereKey($addressId)
            ->firstOrFail();
    }

    private function setFirstAddressAsDefault(): void
    {
        $nextAddress = CustomerAddress::query()
            ->where('customer_id', $this->customerId)
            ->oldest('id')
            ->first();

        if ($nextAddress instanceof CustomerAddress) {
            $nextAddress->forceFill(['is_default' => true])->save();
        }
    }

    private function resetAddressForm(): void
    {
        $this->editingAddressId = null;
        $this->addressLabel = '';
        $this->addressJson = $this->emptyAddressJson();
    }

    /**
     * @return array{first_name: string, last_name: string, address1: string, address2: string, city: string, province_code: string, country: string, postal_code: string}
     */
    private function emptyAddressJson(): array
    {
        return [
            'first_name' => '',
            'last_name' => '',
            'address1' => '',
            'address2' => '',
            'city' => '',
            'province_code' => '',
            'country' => 'DE',
            'postal_code' => '',
        ];
    }
}


output:
Chunk ID: d35b6e
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2653
Output:

            <flux:heading size="xl">{{ $customer->name ?: 'Unnamed customer' }}</flux:heading>
            <flux:text class="mt-1">{{ $customer->email }}</flux:text>

        <flux:button :href="route('admin.customers.index')" wire:navigate variant="filled" icon="arrow-left">
            Customers
        </flux:button>

                <flux:heading size="lg">Customer info</flux:heading>

Name

{{ $customer->name ?: 'Unnamed customer' }}

Email

{{ $customer->email }}

Created

{{ $customer->created_at?->format('M j, Y') }}

Marketing

                            <flux:badge :color="$customer->marketing_opt_in ? 'green' : 'zinc'">
                                {{ $customer->marketing_opt_in ? 'Opted in' : 'Not opted in' }}
                            </flux:badge>

                    <flux:heading size="lg">Order history</flux:heading>

                                Order
                                Date
                                Status
                                Total

                            @forelse ($orders as $order)
                                @php
                                    $statusColor = match ($order->financial_status->value) {
                                        'paid' => 'green',
                                        'partially_refunded' => 'amber',
                                        'refunded', 'voided' => 'red',
                                        default => 'zinc',
                                    };
                                @endphp

getKey() }}">

                                            {{ $order->order_number }}

                                    {{ $order->placed_at?->format('M j, Y') }}

                                        <flux:badge :color="$statusColor">{{ Str::headline($order->financial_status->value) }}</flux:badge>

                                        <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-end" />

                            @empty

                                    No orders for this customer.

                            @endforelse

            {{ $orders->links() }}

                <flux:heading size="lg">Addresses</flux:heading>
                <flux:button wire:click="openAddressForm" variant="primary" icon="plus" size="sm">Add</flux:button>

                @forelse ($customer->addresses as $address)
                    @php($addressData = $address->address_json ?? [])

getKey() }}" class="rounded-lg border border-zinc-200 p-4 dark:border-zinc-700">

{{ $address->label ?: 'Address' }}

                                    @if ($address->is_default)
                                        <flux:badge color="green">Default</flux:badge>
                                    @endif

{{ data_get($addressData, 'address1') }}

                                    @if (data_get($addressData, 'address2'))

{{ data_get($addressData, 'address2') }}

                                    @endif

{{ trim(data_get($addressData, 'postal_code').' '.data_get($addressData, 'city')) }}

{{ data_get($addressData, 'country') }}

                            <flux:button wire:click="openAddressForm({{ $address->getKey() }})" size="sm" variant="filled">Edit</flux:button>
                            @unless ($address->is_default)
                                <flux:button wire:click="setDefaultAddress({{ $address->getKey() }})" size="sm" variant="ghost">Set default</flux:button>
                            @endunless
                            <flux:button wire:click="deleteAddress({{ $address->getKey() }})" wire:confirm="Delete this address?" size="sm" variant="danger">Delete</flux:button>

                @empty

                        <flux:icon name="map-pin" class="mx-auto size-8 text-zinc-400" />
                        <flux:text class="mt-3">No addresses saved.</flux:text>

                @endforelse

    <flux:modal name="address-form" class="md:w-[32rem]">
        <form wire:submit="saveAddress" class="space-y-6">

                <flux:heading size="lg">{{ $editingAddressId ? 'Edit address' : 'Add address' }}</flux:heading>

            <flux:input wire:model="addressLabel" label="Label" placeholder="Home, Office..." />

                <flux:input wire:model="addressJson.first_name" label="First name" />
                <flux:input wire:model="addressJson.last_name" label="Last name" />

                    <flux:input wire:model="addressJson.address1" label="Address line 1" />
                    <flux:error name="addressJson.address1" />

                    <flux:input wire:model="addressJson.address2" label="Address line 2" />

                <flux:input wire:model="addressJson.city" label="City" />
                <flux:input wire:model="addressJson.province_code" label="State / Province" />
                <flux:input wire:model="addressJson.postal_code" label="Postal code" />
                <flux:select wire:model="addressJson.country" label="Country">
                    <flux:select.option value="DE">Germany</flux:select.option>
                    <flux:select.option value="US">United States</flux:select.option>
                    <flux:select.option value="GB">United Kingdom</flux:select.option>
                    <flux:select.option value="FR">France</flux:select.option>
                    <flux:select.option value="NL">Netherlands</flux:select.option>
                </flux:select>

            <flux:error name="addressJson.city" />
            <flux:error name="addressJson.postal_code" />
            <flux:error name="addressJson.country" />

                <flux:modal.close>
                    <flux:button variant="filled">Cancel</flux:button>
                </flux:modal.close>
                <flux:button type="submit" variant="primary">Save</flux:button>

        </form>
    </flux:modal>


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

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

uses(RefreshDatabase::class);

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

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

    return $store;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

namespace Database\Factories;

use App\Enums\FinancialStatus;
use App\Enums\FulfillmentStatus;
use App\Enums\OrderStatus;
use App\Enums\PaymentMethod;
use App\Models\Checkout;
use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Order>
 */
class OrderFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $subtotal = fake()->numberBetween(2500, 25000);
        $shipping = fake()->randomElement([0, 499, 799]);
        $tax = 0;

        return [
            'store_id' => Store::factory(),
            'checkout_id' => null,
            'customer_id' => null,
            'order_number' => '#'.fake()->unique()->numberBetween(1001, 9999),
            'payment_method' => PaymentMethod::CreditCard,
            'status' => OrderStatus::Paid,
            'financial_status' => FinancialStatus::Paid,
            'fulfillment_status' => FulfillmentStatus::Unfulfilled,
            'currency' => 'EUR',
            'subtotal_amount' => $subtotal,
            'discount_amount' => 0,
            'shipping_amount' => $shipping,
            'tax_amount' => $tax,
            'total_amount' => $subtotal + $shipping + $tax,
            'email' => fake()->safeEmail(),
            'billing_address_json' => $this->address(),
            'shipping_address_json' => $this->address(),
            'placed_at' => now(),
        ];
    }

    public function forCheckout(?Checkout $checkout = null): static
    {
        return $this->state(fn (array $attributes): array => [
            'checkout_id' => $checkout?->getKey() ?? Checkout::factory(),
        ]);
    }

    public function forCustomer(?Customer $customer = null): static
    {
        return $this->state(fn (array $attributes): array => [
            'customer_id' => $customer?->getKey() ?? Customer::factory(),
        ]);
    }

    public function paid(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Paid,
            'financial_status' => FinancialStatus::Paid,
        ]);
    }

    public function pending(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Pending,
            'financial_status' => FinancialStatus::Pending,
        ]);
    }

    public function creditCard(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::CreditCard,
        ]);
    }

    public function paypal(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::Paypal,
        ]);
    }

    public function bankTransfer(): static
    {
        return $this->state(fn (array $attributes): array => [
            'payment_method' => PaymentMethod::BankTransfer,
            'status' => OrderStatus::Pending,
            'financial_status' => FinancialStatus::Pending,
        ]);
    }

    public function cancelled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Cancelled,
            'financial_status' => FinancialStatus::Voided,
        ]);
    }

    public function partiallyFulfilled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'fulfillment_status' => FulfillmentStatus::Partial,
        ]);
    }

    public function fulfilled(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Fulfilled,
            'financial_status' => FinancialStatus::Paid,
            'fulfillment_status' => FulfillmentStatus::Fulfilled,
        ]);
    }

    public function refunded(): static
    {
        return $this->state(fn (array $attributes): array => [
            'status' => OrderStatus::Refunded,
            'financial_status' => FinancialStatus::Refunded,
        ]);
    }

    /**
     * @return array<string, string|null>
     */
    private function address(): array
    {
        return [
            'first_name' => fake()->firstName(),
            'last_name' => fake()->lastName(),
            'address1' => fake()->streetAddress(),
            'address2' => null,
            'city' => fake()->city(),
            'province_code' => null,
            'country' => 'DE',
            'postal_code' => fake()->postcode(),
        ];
    }
}


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

namespace Database\Factories;

use App\Models\Order;
use App\Models\ProductVariant;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\OrderLine>
 */
class OrderLineFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $quantity = fake()->numberBetween(1, 3);
        $unitPrice = fake()->numberBetween(1000, 10000);

        return [
            'order_id' => Order::factory(),
            'product_id' => null,
            'variant_id' => ProductVariant::factory(),
            'title_snapshot' => fake()->words(3, true),
            'sku_snapshot' => 'SKU-'.fake()->unique()->numerify('####'),
            'quantity' => $quantity,
            'unit_price_amount' => $unitPrice,
            'total_amount' => $unitPrice * $quantity,
            'tax_lines_json' => [],
            'discount_allocations_json' => [],
        ];
    }
}


cmd: sed -n '1,260p' tests/Browser/Storefront/CheckoutTest.php


cmd: sed -n '1,280p' tests/Browser/Storefront/CartTest.php


cmd: sed -n '1,240p' tests/Browser/Storefront/BrowsingTest.php


cmd: sed -n '1,260p' tests/Browser/Admin/AuthenticationTest.php


command: sed -n '1,260p' tests/Browser/Storefront/CheckoutTest.php

aggregated_output:
<?php

use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Pest\Browser\Playwright\Playwright;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Playwright::setHost('shop.test');

    $this->seed(DatabaseSeeder::class);
});

afterEach(function (): void {
    Playwright::setHost(null);
});

function storefrontCheckoutHost(): array
{
    return ['host' => 'shop.test'];
}

function storefrontCheckoutStart(): mixed
{
    return visit('/products/classic-cotton-t-shirt', storefrontCheckoutHost())
        ->click('M')
        ->wait(1)
        ->click('Black')
        ->wait(1)
        ->click('Add to cart')
        ->wait(1)
        ->navigate('/cart')
        ->wait(1)
        ->click('main button:has-text("Checkout")')
        ->wait(1)
        ->assertPathIs('/checkout')
        ->assertSee('Checkout');
}

/**
 * @param  array<string, string>  $overrides
 */
function storefrontCheckoutFillAddress(mixed $page, array $overrides = []): mixed
{
    $address = [
        'email' => 'test-buyer@example.com',
        'first_name' => 'Test',
        'last_name' => 'Buyer',
        'address1' => 'Teststrasse 1',
        'city' => 'Berlin',
        'postal_code' => '10115',
        'country' => 'DE',
    ];

    $address = array_replace($address, $overrides);

    return $page
        ->fill('input[wire\\:model="email"]', $address['email'])
        ->fill('input[wire\\:model="shippingAddress.first_name"]', $address['first_name'])
        ->fill('input[wire\\:model="shippingAddress.last_name"]', $address['last_name'])
        ->fill('input[wire\\:model="shippingAddress.address1"]', $address['address1'])
        ->fill('input[wire\\:model="shippingAddress.city"]', $address['city'])
        ->fill('input[wire\\:model="shippingAddress.postal_code"]', $address['postal_code'])
        ->select('select[wire\\:model="shippingAddress.country"]', $address['country']);
}

function storefrontCheckoutSubmitAddress(mixed $page): mixed
{
    return $page
        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
        ->wait(1);
}

function storefrontCheckoutReachShipping(array $address = []): mixed
{
    return storefrontCheckoutSubmitAddress(
        storefrontCheckoutFillAddress(storefrontCheckoutStart(), $address),
    );
}

function storefrontCheckoutReachPayment(array $address = []): mixed
{
    return storefrontCheckoutReachShipping($address)
        ->click('button:has-text("Standard Shipping")')
        ->wait(1)
        ->click('button[wire\\:click="selectShippingMethod"]')
        ->wait(1)
        ->assertSee('Payment')
        ->assertSee('Pay now');
}

function storefrontCheckoutFillSuccessfulCard(mixed $page): mixed
{
    return $page
        ->fill('input[wire\\:model="cardNumber"]', '4242 4242 4242 4242')
        ->fill('input[wire\\:model="cardName"]', 'Test Buyer')
        ->fill('input[wire\\:model="cardExpiry"]', '12/28')
        ->fill('input[wire\\:model="cardCvc"]', '123');
}

function storefrontCheckoutApplyCartDiscount(string $code): mixed
{
    return visit('/products/classic-cotton-t-shirt', storefrontCheckoutHost())
        ->click('M')
        ->wait(1)
        ->click('Black')
        ->wait(1)
        ->click('Add to cart')
        ->wait(1)
        ->navigate('/cart')
        ->wait(1)
        ->fill('input[wire\\:model="discountCode"]', $code)
        ->click('button:has-text("Apply")')
        ->wait(1);
}

test('completes full checkout with credit card', function (): void {
    storefrontCheckoutFillSuccessfulCard(storefrontCheckoutReachPayment())
        ->assertSee('29.98')
        ->click('button:has-text("Pay now")')
        ->wait(2)
        ->assertPathBeginsWith('/checkout/confirmation')
        ->assertSee('Thank you')
        ->assertSee('#1001')
        ->assertNoJavaScriptErrors();
});

test('shows shipping methods based on german address', function (): void {
    storefrontCheckoutReachShipping([
        'email' => 'test@example.com',
        'first_name' => 'Hans',
        'last_name' => 'Mueller',
        'address1' => 'Berliner Str. 10',
        'city' => 'Munich',
        'postal_code' => '80331',
        'country' => 'DE',
    ])
        ->assertSee('Standard Shipping')
        ->assertSee('4.99')
        ->assertNoJavaScriptErrors();
});

test('shows international shipping methods for non german address', function (): void {
    storefrontCheckoutReachShipping([
        'email' => 'test@example.com',
        'first_name' => 'John',
        'last_name' => 'Smith',
        'address1' => '123 Main St',
        'city' => 'New York',
        'postal_code' => '10001',
        'country' => 'US',
    ])
        ->assertSee('International Shipping')
        ->assertSee('14.99')
        ->assertNoJavaScriptErrors();
});

test('applies discount during checkout', function (): void {
    $page = storefrontCheckoutApplyCartDiscount('FLAT5')
        ->assertSee('FLAT5')
        ->click('main button:has-text("Checkout")')
        ->wait(1)
        ->assertPathIs('/checkout');

    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress($page))
        ->click('button:has-text("Standard Shipping")')
        ->wait(1)
        ->click('button[wire\\:click="selectShippingMethod"]')
        ->wait(1)
        ->assertSee('FLAT5')
        ->assertSee('5.00')
        ->assertSee('24.98')
        ->assertNoJavaScriptErrors();
});

test('validates required contact email', function (): void {
    storefrontCheckoutStart()
        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
        ->wait(1)
        ->assertSee('email field is required')
        ->assertNoJavaScriptErrors();
});

test('validates required shipping address fields', function (): void {
    storefrontCheckoutStart()
        ->fill('input[wire\\:model="email"]', 'test@example.com')
        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
        ->wait(1)
        ->assertSee('first name field is required')
        ->assertSee('last name field is required')
        ->assertSee('address1 field is required')
        ->assertSee('city field is required')
        ->assertSee('postal code field is required')
        ->assertNoJavaScriptErrors();
});

test('validates invalid postal code format', function (): void {
    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress(storefrontCheckoutStart(), [
        'postal_code' => 'INVALID',
    ]))
        ->assertSee('postal code format is invalid')
        ->assertNoJavaScriptErrors();
});

test('prevents checkout with empty cart', function (): void {
    visit('/cart', storefrontCheckoutHost())
        ->assertSee('Your cart is empty')
        ->assertButtonDisabled('main button:has-text("Checkout")')
        ->assertNoJavaScriptErrors();
});

test('completes checkout with paypal', function (): void {
    storefrontCheckoutReachPayment()
        ->select('select[wire\\:model\\.live="paymentMethod"]', 'paypal')
        ->wait(1)
        ->assertSee('Pay with PayPal')
        ->click('button:has-text("Pay with PayPal")')
        ->wait(2)
        ->assertPathBeginsWith('/checkout/confirmation')
        ->assertSee('Thank you')
        ->assertSee('PayPal')
        ->assertNoJavaScriptErrors();
});

test('completes checkout with bank transfer', function (): void {
    storefrontCheckoutReachPayment()
        ->select('select[wire\\:model\\.live="paymentMethod"]', 'bank_transfer')
        ->wait(1)
        ->assertSee('bank transfer instructions')
        ->click('button:has-text("Place order")')
        ->wait(2)
        ->assertPathBeginsWith('/checkout/confirmation')
        ->assertSee('Thank you')
        ->assertSee('IBAN')
        ->assertSee('BIC')
        ->assertSee('Reference')
        ->assertSee('#1001')
        ->assertNoJavaScriptErrors();
});

test('shows error for declined credit card', function (): void {
    storefrontCheckoutReachPayment()
        ->fill('input[wire\\:model="cardNumber"]', '4000 0000 0000 0002')
        ->fill('input[wire\\:model="cardName"]', 'Test Buyer')
        ->fill('input[wire\\:model="cardExpiry"]', '12/28')
        ->fill('input[wire\\:model="cardCvc"]', '123')
        ->click('button:has-text("Pay now")')
        ->wait(2)
        ->assertPathIs('/checkout')
        ->assertSee('declined')
        ->assertNoJavaScriptErrors();
});

test('shows error for insufficient funds', function (): void {
    storefrontCheckoutReachPayment()
        ->fill('input[wire\\:model="cardNumber"]', '4000 0000 0000 9995')
        ->fill('input[wire\\:model="cardName"]', 'Test Buyer')
        ->fill('input[wire\\:model="cardExpiry"]', '12/28')
        ->fill('input[wire\\:model="cardCvc"]', '123')


command: sed -n '1,280p' tests/Browser/Storefront/CartTest.php

aggregated_output:
<?php

use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Pest\Browser\Playwright\Playwright;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Playwright::setHost('shop.test');

    $this->seed(DatabaseSeeder::class);
});

afterEach(function (): void {
    Playwright::setHost(null);
});

function storefrontCartHost(): array
{
    return ['host' => 'shop.test'];
}

function storefrontCartAddClassicTShirt(): mixed
{
    return visit('/products/classic-cotton-t-shirt', storefrontCartHost())
        ->click('M')
        ->wait(1)
        ->click('Black')
        ->wait(1)
        ->click('Add to cart')
        ->wait(1);
}

function storefrontCartPageWithClassicTShirt(): mixed
{
    return storefrontCartAddClassicTShirt()
        ->navigate('/cart')
        ->wait(1)
        ->assertSee('Your Cart')
        ->assertSee('Classic Cotton T-Shirt');
}

function storefrontCartApplyDiscount(string $code): mixed
{
    return storefrontCartPageWithClassicTShirt()
        ->fill('input[wire\\:model="discountCode"]', $code)
        ->click('button:has-text("Apply")')
        ->wait(1);
}

test('can add product to cart', function (): void {
    storefrontCartAddClassicTShirt()
        ->navigate('/cart')
        ->wait(1)
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99')
        ->assertNoJavaScriptErrors();
});

test('can view cart with added item', function (): void {
    storefrontCartPageWithClassicTShirt()
        ->assertSee('24.99')
        ->assertNoJavaScriptErrors();
});

test('can update quantity in cart', function (): void {
    storefrontCartPageWithClassicTShirt()
        ->click('main button[aria-label="Increase Classic Cotton T-Shirt quantity"]')
        ->wait(1)
        ->assertSee('2 items')
        ->assertSee('49.98')
        ->assertNoJavaScriptErrors();
});

test('can remove item from cart', function (): void {
    storefrontCartPageWithClassicTShirt()
        ->click('main button[aria-label="Remove Classic Cotton T-Shirt"]')
        ->wait(1)
        ->assertSee('Your cart is empty')
        ->assertNoJavaScriptErrors();
});

test('can add multiple different products', function (): void {
    storefrontCartAddClassicTShirt()
        ->navigate('/products/premium-slim-fit-jeans')
        ->wait(1)
        ->click('Add to cart')
        ->wait(1)
        ->navigate('/cart')
        ->wait(1)
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('Premium Slim Fit Jeans')
        ->assertNoJavaScriptErrors();
});

test('can apply valid discount code welcome ten', function (): void {
    storefrontCartApplyDiscount('WELCOME10')
        ->assertSee('WELCOME10')
        ->assertSee('Discount')
        ->assertSee('2.50')
        ->assertNoJavaScriptErrors();
});

test('shows error for invalid discount code', function (): void {
    storefrontCartApplyDiscount('INVALID')
        ->assertSee('Invalid discount code')
        ->assertNoJavaScriptErrors();
});

test('shows error for expired discount code', function (): void {
    storefrontCartApplyDiscount('EXPIRED20')
        ->assertSee('expired')
        ->assertNoJavaScriptErrors();
});

test('shows error for maxed out discount code', function (): void {
    storefrontCartApplyDiscount('MAXED')
        ->assertSee('usage limit')
        ->assertNoJavaScriptErrors();
});

test('can apply free shipping discount', function (): void {
    storefrontCartApplyDiscount('FREESHIP')
        ->assertSee('FREESHIP')
        ->assertSee('Free shipping')
        ->assertNoJavaScriptErrors();
});

test('can apply flat five discount for fixed amount off', function (): void {
    storefrontCartApplyDiscount('FLAT5')
        ->assertSee('FLAT5')
        ->assertSee('5.00')
        ->assertNoJavaScriptErrors();
});

test('shows subtotal and total in cart', function (): void {
    storefrontCartPageWithClassicTShirt()
        ->assertSee('Subtotal')
        ->assertSee('Estimated total')
        ->assertSee('24.99')
        ->assertNoJavaScriptErrors();
});


command: sed -n '1,240p' tests/Browser/Storefront/BrowsingTest.php

aggregated_output:
<?php

use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Pest\Browser\Playwright\Playwright;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    Playwright::setHost('shop.test');

    $this->seed(DatabaseSeeder::class);
});

afterEach(function (): void {
    Playwright::setHost(null);
});

function storefrontBrowsingHost(): array
{
    return ['host' => 'shop.test'];
}

test('shows featured products on home page', function (): void {
    visit('/', storefrontBrowsingHost())
        ->assertSee('Acme Fashion')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99')
        ->assertNoJavaScriptErrors();
});

test('shows collection with product grid', function (): void {
    visit('/collections/t-shirts', storefrontBrowsingHost())
        ->assertSee('T-Shirts')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertNoJavaScriptErrors();
});

test('can navigate from collection to product', function (): void {
    visit('/collections/t-shirts', storefrontBrowsingHost())
        ->click('a[href$="/products/classic-cotton-t-shirt"]')
        ->wait(1)
        ->assertPathIs('/products/classic-cotton-t-shirt')
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99')
        ->assertSee('Add to cart')
        ->assertNoJavaScriptErrors();
});

test('shows product detail with variant options', function (): void {
    visit('/products/classic-cotton-t-shirt', storefrontBrowsingHost())
        ->assertSee('Classic Cotton T-Shirt')
        ->assertSee('24.99')
        ->assertSee('Size')
        ->assertSee('Color')
        ->assertNoJavaScriptErrors();
});

test('shows size and color option values', function (): void {
    visit('/products/classic-cotton-t-shirt', storefrontBrowsingHost())
        ->assertSee('S')
        ->assertSee('M')
        ->assertSee('L')
        ->assertSee('XL')
        ->assertSee('Black')
        ->assertSee('White')
        ->assertSee('Navy')
        ->assertNoJavaScriptErrors();
});

test('shows sale and compare at pricing for sale product', function (): void {
    visit('/products/premium-slim-fit-jeans', storefrontBrowsingHost())
        ->assertSee('Premium Slim Fit Jeans')
        ->assertSee('79.99')
        ->assertSee('99.99')
        ->assertPresent('.line-through')
        ->assertNoJavaScriptErrors();
});

test('shows search results for valid query', function (): void {
    visit('/search?q=cotton', storefrontBrowsingHost())
        ->assertSee('Classic Cotton T-Shirt')
        ->assertNoJavaScriptErrors();
});

test('shows no results message for invalid query', function (): void {
    visit('/search?q=zznonexistentproductzz', storefrontBrowsingHost())
        ->assertSee('No products found')
        ->assertNoJavaScriptErrors();
});

test('does not show draft products on storefront collections', function (): void {
    visit('/collections', storefrontBrowsingHost())
        ->assertDontSee('Unreleased Winter Jacket')
        ->assertNoJavaScriptErrors();
});

test('does not show draft products in search results', function (): void {
    visit('/search?q=draft', storefrontBrowsingHost())
        ->assertDontSee('Unreleased Winter Jacket')
        ->assertNoJavaScriptErrors();
});

test('shows out of stock messaging for deny policy product', function (): void {
    visit('/products/limited-edition-sneakers', storefrontBrowsingHost())
        ->assertSee('Limited Edition Sneakers')
        ->assertSee('Out of stock')
        ->assertSee('Sold out')
        ->assertButtonDisabled('button:has-text("Sold out")')
        ->assertDontSee('Add to cart')
        ->assertNoJavaScriptErrors();
});

test('shows backorder messaging for continue policy product', function (): void {
    visit('/products/backorder-denim-jacket', storefrontBrowsingHost())
        ->assertSee('Backorder Denim Jacket')
        ->assertSee('Available on backorder')
        ->assertSee('Add to cart')
        ->assertButtonEnabled('button:has-text("Add to cart")')
        ->assertNoJavaScriptErrors();
});

test('shows new arrivals collection', function (): void {
    visit('/collections/new-arrivals', storefrontBrowsingHost())
        ->assertSee('New Arrivals')
        ->assertNoJavaScriptErrors();
});

test('shows static about page', function (): void {
    visit('/pages/about', storefrontBrowsingHost())
        ->assertSee('About')
        ->assertNoJavaScriptErrors();
});

test('navigates between pages using the main navigation', function (): void {
    visit('/', storefrontBrowsingHost())
        ->hover('nav[aria-label="Main navigation"] a[href$="/collections"]')
        ->click('nav[aria-label="Main navigation"] a[href$="/collections/t-shirts"]')
        ->wait(1)
        ->assertPathIs('/collections/t-shirts')
        ->assertSee('T-Shirts')
        ->assertNoJavaScriptErrors();
});


command: sed -n '1,260p' tests/Browser/Admin/AuthenticationTest.php

aggregated_output:
<?php

use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

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

function adminAuthenticationHost(): array
{
    return ['host' => 'shop.test'];
}

function adminAuthenticationLogin(): mixed
{
    return visit('/admin/login', adminAuthenticationHost())
        ->fill('input[type=email]', 'admin@acme.test')
        ->fill('input[type=password]', 'password')
        ->click('@admin-login-button')
        ->wait(1)
        ->assertPathIs('/admin')
        ->assertSee('Dashboard')
        ->assertNoJavaScriptErrors();
}

function adminAuthenticationSubmitWithoutBrowserRequired(string $email, string $password): mixed
{
    $page = visit('/admin/login', adminAuthenticationHost());

    $page->script('() => document.querySelectorAll("[required]").forEach((element) => element.removeAttribute("required"))');

    if ($email !== '') {
        $page->fill('input[type=email]', $email);
    }

    if ($password !== '') {
        $page->fill('input[type=password]', $password);
    }

    return $page->click('@admin-login-button')->wait(1);
}

test('can log in as admin', function (): void {
    adminAuthenticationLogin();
});

test('shows error for invalid credentials', function (): void {
    visit('/admin/login', adminAuthenticationHost())
        ->fill('input[type=email]', 'admin@acme.test')
        ->fill('input[type=password]', 'wrongpassword')
        ->click('@admin-login-button')
        ->wait(1)
        ->assertPathIs('/admin/login')
        ->assertSee('Invalid credentials')
        ->assertNoJavaScriptErrors();
});

test('shows error for empty email', function (): void {
    adminAuthenticationSubmitWithoutBrowserRequired('', 'password')
        ->assertPathIs('/admin/login')
        ->assertSee('email field is required')
        ->assertNoJavaScriptErrors();
});

test('shows error for empty password', function (): void {
    adminAuthenticationSubmitWithoutBrowserRequired('admin@acme.test', '')
        ->assertPathIs('/admin/login')
        ->assertSee('password field is required')
        ->assertNoJavaScriptErrors();
});

test('redirects unauthenticated users to login from dashboard', function (): void {
    visit('/admin', adminAuthenticationHost())
        ->wait(1)
        ->assertPathIs('/admin/login')
        ->assertSee('Sign in')
        ->assertNoJavaScriptErrors();
});

test('redirects unauthenticated users to login from products', function (): void {
    visit('/admin/products', adminAuthenticationHost())
        ->wait(1)
        ->assertPathIs('/admin/login')
        ->assertSee('Sign in')
        ->assertNoJavaScriptErrors();
});

test('can log out', function (): void {
    adminAuthenticationLogin()
        ->click('@sidebar-menu-button')
        ->click('button[data-test="logout-button"]:visible')
        ->wait(1)
        ->assertPathIs('/admin/login')
        ->assertSee('Sign in')
        ->assertNoJavaScriptErrors();
});

test('can navigate through admin sidebar sections', function (): void {
    $page = adminAuthenticationLogin();

    foreach ([
        '/admin/products' => 'Products',
        '/admin/orders' => 'Orders',
        '/admin/customers' => 'Customers',
        '/admin/discounts' => 'Discounts',
        '/admin/settings' => 'Store Settings',
    ] as $path => $heading) {
        $page->click("a[href$=\"{$path}\"]")
            ->wait(1)
            ->assertPathIs($path)
            ->assertSee($heading)
            ->assertNoJavaScriptErrors();
    }
});

test('can navigate to analytics from sidebar', function (): void {
    adminAuthenticationLogin()
        ->click('a[href$="/admin/analytics"]')
        ->wait(1)
        ->assertPathIs('/admin/analytics')
        ->assertSee('Analytics')
        ->assertNoJavaScriptErrors();
});

test('can navigate to themes from sidebar', function (): void {
    adminAuthenticationLogin()
        ->click('a[href$="/admin/themes"]')
        ->wait(1)
        ->assertPathIs('/admin/themes')
        ->assertSee('Themes')
        ->assertNoJavaScriptErrors();
});