Harden per-branch billing with seat caps and mid-cycle expansion.
Deploy Ladill Frontdesk / deploy (push) Successful in 55s

Enforce billed_branches when adding or reactivating branches, charge
wallet for extra seats mid-cycle, fix Settings for Enterprise, and
cover multi-branch checkout and renewal amounts in tests.
This commit is contained in:
isaacclad
2026-07-16 08:08:10 +00:00
parent bdbf572f19
commit 59433f2b7b
8 changed files with 449 additions and 24 deletions
@@ -116,6 +116,19 @@
.
</p>
<p class="mt-2 text-xs text-slate-400">SMS host alerts bill at platform rates from your wallet.</p>
@if ($canManage)
<form method="post" action="{{ route('frontdesk.pro.expand-branches') }}" class="mt-4 space-y-2"
x-data="{ seats: {{ (int) $billedBranches + 1 }}, rate: {{ (int) $proPricePerBranchMinor }}, current: {{ (int) $billedBranches }} }">
@csrf
<label class="flex items-center justify-between gap-2 text-xs font-medium text-slate-600">
<span>Increase allotment</span>
<input type="number" name="branches" x-model.number="seats" min="{{ (int) $billedBranches + 1 }}" max="999"
class="w-20 rounded-md border-slate-300 py-1 text-center text-sm focus:border-indigo-500 focus:ring-indigo-500">
</label>
<button type="submit" class="btn-secondary w-full text-sm"
x-text="'Add seats — {{ $currency }} ' + (((Math.max(current + 1, seats) - current) * rate) / 100).toLocaleString() + ' from wallet'"></button>
</form>
@endif
@elseif ($canManage)
<form x-show="billing === 'monthly'" method="post" action="{{ route('frontdesk.pro.subscribe') }}">
@csrf
@@ -171,6 +184,19 @@
@endif
.
</p>
@if ($canManage)
<form method="post" action="{{ route('frontdesk.pro.expand-branches') }}" class="mt-4 space-y-2"
x-data="{ seats: {{ (int) $billedBranches + 1 }}, rate: {{ (int) $enterprisePricePerBranchMinor }}, current: {{ (int) $billedBranches }} }">
@csrf
<label class="flex items-center justify-between gap-2 text-xs font-medium text-slate-300">
<span>Increase allotment</span>
<input type="number" name="branches" x-model.number="seats" min="{{ (int) $billedBranches + 1 }}" max="999"
class="w-20 rounded-md border-slate-500 bg-slate-800 py-1 text-center text-sm text-white focus:border-amber-400 focus:ring-amber-400">
</label>
<button type="submit" class="w-full rounded-xl border border-amber-300/40 bg-slate-800 px-4 py-2 text-sm font-semibold text-amber-200 hover:bg-slate-700"
x-text="'Add seats — {{ $currency }} ' + (((Math.max(current + 1, seats) - current) * rate) / 100).toLocaleString() + ' from wallet'"></button>
</form>
@endif
@elseif ($canManage)
@if ($canSubscribeEnterprise)
<form x-show="billing === 'monthly'" method="post" action="{{ route('frontdesk.pro.subscribe-enterprise') }}">
@@ -8,14 +8,20 @@
<x-settings.card title="Plan & usage" description="Subscription limits and notification billing for {{ $organization->name }}.">
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<p class="text-sm leading-6 text-slate-600">
@if ($isPro)
@if ($hasPaidPlan)
<span class="font-medium text-indigo-700">{{ $plan['label'] ?? 'Pro' }}</span> unlimited kiosks, integrations, and unlimited host emails, billed per branch (SMS still billed per segment).
@if ($billedBranches > 0)
Billed for {{ $billedBranches }} {{ str('branch')->plural($billedBranches) }}
({{ $activeBranchCount }} active).
@endif
@else
<span class="font-medium text-slate-900">Free</span> one branch, one kiosk, core check-in and badges. Host alerts billed after {{ number_format($freeEmailAllowance) }} free emails per month.
@endif
</p>
@if (! $isPro)
@if (! $hasPaidPlan)
<a href="{{ route('frontdesk.pro.index') }}" class="btn-primary shrink-0 text-sm">Upgrade to Pro (GHS {{ number_format($proPriceMinor / 100, 0) }}/branch/mo)</a>
@else
<a href="{{ route('frontdesk.pro.index') }}" class="btn-secondary shrink-0 text-sm">Manage plan</a>
@endif
</div>
<dl class="mt-5 grid gap-4 border-t border-slate-100 pt-5 text-sm sm:grid-cols-2">
@@ -23,7 +29,7 @@
<dt class="text-slate-500">Host emails this month</dt>
<dd class="mt-0.5 font-semibold text-slate-900">
@if ($freeEmailAllowance === null)
{{ number_format($monthlyUsage->email_count) }} sent (unlimited on Pro)
{{ number_format($monthlyUsage->email_count) }} sent (unlimited on paid plans)
@else
{{ number_format($monthlyUsage->email_count) }} / {{ number_format($freeEmailAllowance) }} free
@endif