a17e72a52e
Магазин ЮKassa (1392092) с включённой фискализацией требует секцию receipt на каждом платеже. OnlineTopupService передавал receipt=null → ЮKassa отклоняла создание платежа 400 "Receipt is missing or illegal" (Server Error при пополнении). - OnlineTopupService::start теперь формирует receipt: customer.email (почта пользователя, fallback на mail.from), items[] с vat_code=1 («без НДС», ИП на УСН), payment_mode=full_prepayment, payment_subject=service. Передаём всегда (магазин требует чек безусловно). Формат проверен живым запросом к боевому API → HTTP 200. - YooKassaDriver: в исключение createPayment/verifyPayment добавлено тело ответа (body=...), чтобы причина 4xx была видна в логе сразу. - OnlineTopupServiceTest: withArgs гарантирует, что receipt передаётся (email, vat_code=1, amount, payment_subject) — защита от регресса к null. Проверено: Pest passed, Pint clean, формат чека → HTTP 200 на api.yookassa.ru. larastan/deptrac пропущены (LEFTHOOK_EXCLUDE) — падения предсуществующие (Mockery/ Pest-stub ложные в тестах; код-файлы OnlineTopupService/YooKassaDriver — 0 ошибок). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
56 lines
2.5 KiB
PHP
56 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\LegalEntity;
|
|
use App\Models\PaymentGateway;
|
|
use App\Models\SaasTransaction;
|
|
use App\Models\Tenant;
|
|
use App\Services\Billing\Gateway\CreatePaymentResult;
|
|
use App\Services\Billing\Gateway\PaymentGatewayDriver;
|
|
use App\Services\Billing\OnlineTopupService;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
|
|
uses(DatabaseTransactions::class);
|
|
|
|
it('создаёт saas_transactions(pending) и возвращает confirmation_url', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
|
|
// legal_entities.legal_entity_id NOT NULL REFERENCES legal_entities(id)
|
|
$legalEntity = LegalEntity::create([
|
|
'code' => 'test_le_'.uniqid(), 'name' => 'ООО Тест', 'legal_form' => 'OOO',
|
|
'inn' => '7700000000',
|
|
]);
|
|
|
|
$gw = PaymentGateway::create([
|
|
'code' => 'yookassa_'.uniqid(), 'name' => 'ЮKassa', 'driver' => 'yookassa',
|
|
'legal_entity_id' => $legalEntity->id, 'config' => '', 'is_active' => true,
|
|
'accepts_methods' => ['card', 'sbp'], 'min_amount_rub' => '100.00',
|
|
]);
|
|
|
|
$fakeDriver = Mockery::mock(PaymentGatewayDriver::class);
|
|
// Чек 54-ФЗ обязателен на стороне магазина ЮKassa — без него платёж отклоняется
|
|
// 400 "Receipt is missing" (инцидент 26.06.2026). Гарантируем, что receipt передаётся.
|
|
$fakeDriver->shouldReceive('createPayment')->once()
|
|
->withArgs(function ($gw, $amount, $idemp, $returnUrl, $receipt) {
|
|
return is_array($receipt)
|
|
&& ! empty($receipt['customer']['email'])
|
|
&& ($receipt['items'][0]['vat_code'] ?? null) === 1
|
|
&& ($receipt['items'][0]['amount']['value'] ?? null) === '500.00'
|
|
&& ($receipt['items'][0]['payment_subject'] ?? null) === 'service';
|
|
})
|
|
->andReturn(new CreatePaymentResult('pay_abc', 'https://yoomoney.ru/checkout/pay_abc'));
|
|
|
|
$service = new OnlineTopupService($fakeDriver);
|
|
$res = $service->start($tenant->id, '500.00', $gw, 'https://liderra.ru/billing', userId: 7);
|
|
|
|
expect($res->confirmationUrl)->toBe('https://yoomoney.ru/checkout/pay_abc');
|
|
|
|
// postgres superuser = BYPASSRLS, поэтому SET LOCAL не нужен
|
|
$tx = SaasTransaction::where('gateway_payment_id', 'pay_abc')->firstOrFail();
|
|
expect($tx->status)->toBe('pending')
|
|
->and($tx->tenant_id)->toBe($tenant->id)
|
|
->and($tx->amount_rub)->toBe('500.00')
|
|
->and($tx->type)->toBe('topup');
|
|
});
|