fix(billing): topup save() rationale comment + cross-tenant test (Task 1 review)

Code-quality review fixups: документирующий комментарий про безопасность
Eloquent save() для bcmath-строки (расхождение с LedgerService raw-update);
cross-tenant isolation тест на /api/billing/topup; balance_rub_after в
assertDatabaseHas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-16 07:00:19 +03:00
parent 75d120e6db
commit efbc4e549a
3 changed files with 16 additions and 1 deletions
@@ -41,6 +41,10 @@ final class BillingTopupService
// bcadd — DECIMAL-точность, НЕ PHP float (паттерн LedgerService).
$newBalanceRub = bcadd((string) $tenant->balance_rub, $amountRub, 2);
// Eloquent decimal:2 cast сохраняет bcmath-строку без потери точности
// при save() (в отличие от decrement(), который требует float|int —
// именно поэтому LedgerService использует raw DB::table()->update();
// здесь же присваивание уже посчитанной строки через модель безопасно).
$tenant->balance_rub = $newBalanceRub;
$tenant->save();
+1 -1
View File
@@ -591,7 +591,7 @@ parameters:
-
message: '#^Call to an undefined method Pest\\PendingCalls\\TestCall\:\:postJson\(\)\.$#'
identifier: method.notFound
count: 7
count: 8
path: tests/Feature/Billing/TopupControllerTest.php
-
@@ -33,6 +33,7 @@ test('POST /api/billing/topup пишет строку balance_transactions с us
'user_id' => $this->user->id,
'type' => 'topup',
'amount_rub' => '100.00',
'balance_rub_after' => '600.00',
]);
});
@@ -44,6 +45,16 @@ test('POST /api/billing/topup использует bcmath-точность', fun
expect((string) $this->tenant->fresh()->balance_rub)->toBe('100.30');
});
test('POST /api/billing/topup не затрагивает баланс чужого тенанта', function () {
$otherTenant = Tenant::factory()->create(['balance_rub' => '777.00']);
$this->postJson('/api/billing/topup', ['amount_rub' => 100])->assertStatus(201);
// Топап эндпоинт не принимает tenant_id — резолвит из auth-пользователя;
// баланс чужого тенанта неприкосновенен (defense-in-depth, паттерн проекта).
expect((string) $otherTenant->fresh()->balance_rub)->toBe('777.00');
});
test('POST /api/billing/topup отклоняет сумму ниже минимума 100 ₽', function () {
$this->postJson('/api/billing/topup', ['amount_rub' => 50])
->assertStatus(422)