'Своя', 'body' => 'текст', 'created_by' => 1, 'tenant_id' => null, ]); (new SmsChargeService)->charge($campaign, '150.00'); expect($campaign->refresh()->balance_transaction_id)->toBeNull(); }); it('списывает с баланса клиента и пишет операцию', function () { $tenant = Tenant::factory()->create(['balance_rub' => '1000.00']); $campaign = SalesSmsCampaign::create([ 'title' => 'Клиентская', 'body' => 'текст', 'created_by' => 1, 'tenant_id' => $tenant->id, ]); (new SmsChargeService)->charge($campaign, '150.00'); expect((string) $tenant->refresh()->balance_rub)->toBe('850.00') ->and($campaign->refresh()->balance_transaction_id)->not->toBeNull(); $tx = BalanceTransaction::find($campaign->balance_transaction_id); expect($tx->type)->toBe(BalanceTransaction::TYPE_SMS_CHARGE) ->and($tx->amount_rub)->toBe('-150.00'); }); it('повторный запуск не списывает второй раз', function () { $tenant = Tenant::factory()->create(['balance_rub' => '1000.00']); $campaign = SalesSmsCampaign::create([ 'title' => 'Повтор', 'body' => 'текст', 'created_by' => 1, 'tenant_id' => $tenant->id, ]); $service = new SmsChargeService; $service->charge($campaign, '150.00'); $service->charge($campaign->refresh(), '150.00'); expect((string) $tenant->refresh()->balance_rub)->toBe('850.00'); }); it('не списывает второй раз, даже если пометка на кампании потерялась', function () { $tenant = Tenant::factory()->create(['balance_rub' => '1000.00']); $campaign = SalesSmsCampaign::create([ 'title' => 'Обрыв', 'body' => 'текст', 'created_by' => 1, 'tenant_id' => $tenant->id, ]); (new SmsChargeService)->charge($campaign, '150.00'); // Имитируем обрыв: деньги списаны, а пометка на кампании не доехала. $campaign->refresh()->update(['balance_transaction_id' => null]); (new SmsChargeService)->charge($campaign->refresh(), '150.00'); // Списание должно остаться ОДНО. expect((string) $tenant->refresh()->balance_rub)->toBe('850.00'); }); it('при нехватке денег не списывает ничего', function () { $tenant = Tenant::factory()->create(['balance_rub' => '10.00']); $campaign = SalesSmsCampaign::create([ 'title' => 'Бедная', 'body' => 'текст', 'created_by' => 1, 'tenant_id' => $tenant->id, ]); expect(fn () => (new SmsChargeService)->charge($campaign, '150.00')) ->toThrow(InsufficientBalanceException::class); expect((string) $tenant->refresh()->balance_rub)->toBe('10.00') ->and($campaign->refresh()->balance_transaction_id)->toBeNull(); });