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'); });