Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion resources/views/app.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Checkout · {{ config('checkout.merchant') ?: config('app.name') }}</title>
<title>Checkout · {{ config('lunar.checkout.merchant') ?: config('app.name') }}</title>

{{-- Tab icon (CheckoutTheme::favicon). The checkout is its own document,
so without this the tab shows the browser's blank globe. --}}
Expand Down
2 changes: 1 addition & 1 deletion spec/0008-checkout-ui-and-theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ from the current channel. Same seam, runtime-resolved.
**Favicon and tab title (added in run 1 of the master test plan).** `CheckoutTheme::favicon`
is a URL/path validated by the same chokepoint as `logo` and `stylesheet`, projected as
`favicon` and rendered by the root view as `<link rel="icon">`. The tab title is
"Checkout · {merchant}" from `checkout.merchant`, falling back to the app name. Without
"Checkout · {merchant}" from `lunar.checkout.merchant`, falling back to the app name. Without
either, the checkout's own document showed the browser's blank globe and a bare "Checkout".

### E. Three customisation tiers (light → heavy)
Expand Down
13 changes: 11 additions & 2 deletions src/Http/Controllers/CheckoutController.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ private function projectCheckout(CheckoutDriver $driver, CheckoutSessionModel $s

return [
'uuid' => $session->uuid,
'merchant' => config('checkout.merchant') ?: config('app.name'),
'merchant' => $this->merchant(),
'currency' => $snapshot->currencyCode,
'items' => array_map(fn (array $line): array => [
'id' => $line['identifier'],
Expand Down Expand Up @@ -451,6 +451,15 @@ private function projectCheckout(CheckoutDriver $driver, CheckoutSessionModel $s
];
}

/**
* The store name in the checkout header: the configured merchant, falling
* back to the application name. The root view's tab title reads the same.
*/
private function merchant(): string
{
return (string) (config('lunar.checkout.merchant') ?: config('app.name'));
}

/**
* The session's write/navigation endpoints the checkout Vue app (and the
* host-page express mount's JSON start response) drive it through.
Expand Down Expand Up @@ -1243,7 +1252,7 @@ public function processing(CheckoutSessionModel $session, ReconcilesCheckoutSess

return Inertia::render('Processing', [
'pollUrl' => route('lunar.checkout.processing', $session->uuid),
'merchant' => config('app.name', 'Store'),
'merchant' => $this->merchant(),
'theme' => $theme->tokens(),
'branding' => $theme->branding(),
'stylesheet' => $theme->stylesheet(),
Expand Down
4 changes: 2 additions & 2 deletions tests/Feature/CheckoutRouteTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function routeTestCart(): Cart
});

it('projects the configured merchant name into the header prop', function () {
config(['checkout.merchant' => 'Edwardes Bros']);
config(['lunar.checkout.merchant' => 'Edwardes Bros']);

// Needs lines: show() bounces a session whose cart is empty.
$cart = CheckoutCart::orderable();
Expand All @@ -114,7 +114,7 @@ function routeTestCart(): Cart
});

it('falls back to the app name when no merchant is configured', function () {
config(['checkout.merchant' => null, 'app.name' => 'Lunar Store']);
config(['lunar.checkout.merchant' => null, 'app.name' => 'Lunar Store']);

// Needs lines: show() bounces a session whose cart is empty.
$cart = CheckoutCart::orderable();
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/CheckoutThemeBrandingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
it('renders the theme favicon and the merchant name in the root view head', function () {
app()->bind(CheckoutTheme::class, fn (): CheckoutTheme => CheckoutTheme::tender()->with(favicon: '/favicon.svg'));
config()->set('checkout.merchant', 'Edwardes Bros');
config()->set('lunar.checkout.merchant', 'Edwardes Bros');

$cart = CheckoutCart::orderable();
$session = CheckoutCart::session($cart);
Expand Down
17 changes: 17 additions & 0 deletions tests/Feature/PaymentMethodAvailabilityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,23 @@ public function unavailableReason(Cart $cart): ?string
expect($registry->unavailableReasons($large))->toBe([]);
});

it('renders the checkout before any payment method is registered', function () {
$cart = CheckoutCart::orderable();
$session = CheckoutCart::session($cart);

$this->get(route('lunar.checkout.show', $session->uuid), ['X-Inertia' => 'true'])
->assertOk()
->assertJsonCount(0, 'props.checkout.paymentMethods')
->assertJsonPath('props.checkout.paymentUnavailable', []);

$this->postJson(route('lunar.checkout.pay', $session->uuid), [
'fingerprint' => CheckoutCart::fingerprint($session),
'payment_method' => 'offline',
])->assertStatus(422);

expect(Order::query()->count())->toBe(0);
});

it('projects why the payment region is empty', function () {
app(PaymentMethodRegistry::class)->add(MinimumSpendMethod::class);

Expand Down
11 changes: 11 additions & 0 deletions tests/Feature/PaymentReleaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ function pinnedSession(array $overrides = [])
expect($session->refresh()->status)->toBeInstanceOf(PaymentProcessing::class);
});

it('processing shows the same merchant name as the checkout', function () {
ReleaseTestGateway::$status = PaymentIntentStatus::Pending;
config(['lunar.checkout.merchant' => 'Edwardes Bros', 'app.name' => 'Lunar Store']);

$session = pinnedSession();

$this->get(route('lunar.checkout.processing', $session->uuid), ['X-Inertia' => 'true'])
->assertOk()
->assertJsonPath('props.merchant', 'Edwardes Bros');
});

it('processing redirects an already completed session straight to success', function () {
$session = pinnedSession();
$session->forceFill(['status' => Completed::$name, 'success_url' => 'https://store.test/thanks'])->save();
Expand Down
Loading