Files
portal/app/app/Http/Controllers/Api/BillingController.php
T
Дмитрий 4e4ebc567a feat(billing): topup ledger service + POST /api/billing/topup stub (E1)
BillingTopupService кредитует tenants.balance_rub (bcmath) и пишет
append-only строку balance_transactions(type='topup'). BillingController
+ route POST /api/billing/topup под [auth:sanctum, tenant]. MVP-stub:
без платёжного шлюза (ЮKassa — post-Б-1).

Sprint 2 Plan C, audit E1 (backend).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 06:46:52 +03:00

61 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\Billing\BillingTopupService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* Биллинг тенанта — кошелёк, транзакции, счета, пополнение (audit E1/E3).
*
* Все эндпоинты под middleware [auth:sanctum, tenant] (RLS-контекст).
* Отдельно от TenantChargesController (lead_charges ledger) и
* AdminBillingController (SaaS-уровневые агрегаты).
*
* E1: POST /api/billing/topup — MVP-stub пополнения (без платёжного шлюза).
* E3: GET wallet/transactions/invoices — данные для BillingView Overview.
*/
class BillingController extends Controller
{
public function __construct(
private readonly BillingTopupService $topupService,
) {}
/**
* POST /api/billing/topup — пополнить рублёвый баланс.
*
* MVP-stub: кредитует баланс немедленно (без ЮKassa — реальная оплата
* post-Б-1). Записывает append-only строку balance_transactions(topup).
*/
public function topup(Request $request): JsonResponse
{
$validated = $request->validate([
'amount_rub' => ['required', 'numeric', 'min:100', 'max:1000000', 'decimal:0,2'],
]);
/** @var User $user */
$user = $request->user();
// Нормализуем в DECIMAL-строку scale 2 для bcmath (НЕ float).
$amountRub = bcadd((string) $validated['amount_rub'], '0', 2);
$tx = $this->topupService->topup((int) $user->tenant_id, $amountRub, (int) $user->id);
return response()->json([
'transaction' => [
'id' => $tx->id,
'type' => $tx->type,
'amount_rub' => $tx->amount_rub,
'balance_rub_after' => $tx->balance_rub_after,
'created_at' => $tx->created_at,
],
'balance_rub' => $tx->balance_rub_after,
], 201);
}
}