2026-06-22 21:08:46 +03:00
|
|
|
<?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([
|
2026-06-26 19:39:38 +03:00
|
|
|
'code' => 'test_le_'.uniqid(), 'name' => 'ООО Тест', 'legal_form' => 'OOO',
|
2026-06-22 21:08:46 +03:00
|
|
|
'inn' => '7700000000',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$gw = PaymentGateway::create([
|
2026-06-26 19:39:38 +03:00
|
|
|
'code' => 'yookassa_'.uniqid(), 'name' => 'ЮKassa', 'driver' => 'yookassa',
|
2026-06-22 21:08:46 +03:00
|
|
|
'legal_entity_id' => $legalEntity->id, 'config' => '', 'is_active' => true,
|
|
|
|
|
'accepts_methods' => ['card', 'sbp'], 'min_amount_rub' => '100.00',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$fakeDriver = Mockery::mock(PaymentGatewayDriver::class);
|
2026-06-26 19:39:38 +03:00
|
|
|
// Чек 54-ФЗ обязателен на стороне магазина ЮKassa — без него платёж отклоняется
|
|
|
|
|
// 400 "Receipt is missing" (инцидент 26.06.2026). Гарантируем, что receipt передаётся.
|
2026-06-22 21:08:46 +03:00
|
|
|
$fakeDriver->shouldReceive('createPayment')->once()
|
2026-06-26 19:39:38 +03:00
|
|
|
->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';
|
|
|
|
|
})
|
2026-06-22 21:08:46 +03:00
|
|
|
->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');
|
|
|
|
|
});
|