fix(billing): round the recurring figure the same way as the total
The note rounded VAT after aggregating while the total rounded per order, so cent-level prices made the two disagree — and a customer who spots that stops trusting every other number on the page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
9fab251fb3
commit
ac3f429958
|
|
@ -72,7 +72,9 @@
|
|||
@php
|
||||
$net = $pending->sum('amount_cents');
|
||||
$gross = $pending->sum(fn ($o) => $o->grossCents());
|
||||
$recurringNet = $pending->filter->isRecurring()->sum('amount_cents');
|
||||
// Summed from the same per-order rounding the total uses: rounding
|
||||
// after aggregating would let the two figures disagree by a cent.
|
||||
$recurringGross = $pending->filter->isRecurring()->sum(fn ($o) => $o->grossCents());
|
||||
@endphp
|
||||
<div class="space-y-1.5 border-t border-line bg-surface-2 px-5 py-3.5 text-sm">
|
||||
<div class="flex items-center justify-between text-muted">
|
||||
|
|
@ -87,11 +89,11 @@
|
|||
<span>{{ __('billing.cart.total_gross') }}</span>
|
||||
<span class="font-mono">{{ $eur($gross) }}</span>
|
||||
</div>
|
||||
@if ($recurringNet > 0)
|
||||
@if ($recurringGross > 0)
|
||||
{{-- The number that actually matters every month, kept apart
|
||||
from a one-off traffic top-up in the same cart. --}}
|
||||
<p class="pt-1 text-xs text-faint">
|
||||
{{ __('billing.cart.recurring_note', ['amount' => $eur((int) round($recurringNet * (1 + \App\Models\Order::taxRate())))]) }}
|
||||
{{ __('billing.cart.recurring_note', ['amount' => $eur($recurringGross)]) }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -132,3 +132,20 @@ it('separates what recurs from a one-off top-up', function () {
|
|||
|
||||
Livewire\Livewire::actingAs($user)->test(Billing::class)->assertSee($expected);
|
||||
});
|
||||
|
||||
it('keeps the recurring figure consistent with the total to the cent', function () {
|
||||
[$customer, $user] = cartCustomer();
|
||||
config()->set('provisioning.tax.rate_percent', 20);
|
||||
|
||||
// Cent-level prices: rounding after aggregating instead of per order makes
|
||||
// the two figures disagree, and a customer who spots that stops trusting
|
||||
// every other number on the page.
|
||||
Order::factory()->for($customer)->create(['type' => 'storage', 'amount_cents' => 3, 'status' => 'pending']);
|
||||
Order::factory()->for($customer)->create(['type' => 'storage', 'amount_cents' => 3, 'status' => 'pending']);
|
||||
|
||||
$expected = Illuminate\Support\Number::currency(0.08, in: 'EUR', locale: 'de');
|
||||
|
||||
Livewire\Livewire::actingAs($user)->test(Billing::class)
|
||||
->assertSee($expected) // total gross
|
||||
->assertSee(__('billing.cart.recurring_note', ['amount' => $expected])); // and the note
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue