create(['balance_rub' => $balance]); User::factory()->create(['tenant_id' => $tenant->id]); $le = LegalEntity::create([ 'code' => 'mp_'.uniqid(), 'name' => 'ИП Лидерра', 'legal_form' => 'IP', 'inn' => '770000000099', 'is_default' => true, ]); $invoice = SaasInvoice::create([ 'tenant_id' => $tenant->id, 'legal_entity_id' => $le->id, 'invoice_number' => 'СЧ-2026-00777', 'payer_type' => 'legal', 'payer_name' => 'ООО К', 'payer_inn' => '5000000000', 'amount_net' => $amount, 'amount_total' => $amount, 'status' => SaasInvoice::STATUS_ISSUED, 'issued_at' => now(), 'expires_at' => now()->addDays(5), ]); return [$tenant, $invoice]; } it('mark-paid зачисляет баланс, ставит paid, создаёт акт и шлёт письмо', function () { Storage::fake('local'); Mail::fake(); [$tenant, $invoice] = seedPaidScenario('100.00', '1500.00'); app(InvoicePaymentService::class)->markPaid($invoice->id); $invoice->refresh(); $tenant->refresh(); expect($invoice->status)->toBe(SaasInvoice::STATUS_PAID) ->and($invoice->paid_at)->not->toBeNull() ->and((string) $tenant->balance_rub)->toBe('1600.00') ->and(SaasTransaction::where('invoice_id', $invoice->id)->where('status', 'success')->count())->toBe(1) ->and(SaasUpdDocument::where('invoice_id', $invoice->id)->count())->toBe(1); $actPath = SaasUpdDocument::where('invoice_id', $invoice->id)->value('pdf_path'); Mail::assertQueued(InvoicePaidNotification::class, fn ($mail) => $mail->actPdfPath === $actPath && count($mail->attachments()) === 1); }); it('повторный mark-paid идемпотентен — баланс не удваивается, второй акт не создаётся', function () { Storage::fake('local'); Mail::fake(); [$tenant, $invoice] = seedPaidScenario('0.00', '500.00'); $svc = app(InvoicePaymentService::class); $svc->markPaid($invoice->id); $svc->markPaid($invoice->id); $tenant->refresh(); expect((string) $tenant->balance_rub)->toBe('500.00') ->and(SaasUpdDocument::where('invoice_id', $invoice->id)->count())->toBe(1); });