Files
portal/app/tests/Feature/ClientSms/VolumeCounterTest.php
T

123 lines
5.8 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Models\ClientSmsMessage;
use App\Models\Tenant;
use App\Services\ClientSms\ClientSmsVolumeCounter;
use Carbon\CarbonImmutable;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
/**
* Строки листа 3.9 и 3.10: сколько СМС клиент отправил в этом месяце.
*
* Считаем в СМС, а НЕ в сообщениях (решение В-108): длинное письмо — это два СМС,
* и клиент платит за два. Считая сообщения, мы держали бы его на дорогой ступени
* дольше, чем обещано, а цифра на экране разошлась бы со списанными деньгами.
*
* Счётчик ОДИН на обе дороги — и рассылки, и авто-СМС (строка 3.9). Песочные
* отправки не идут в счёт вовсе (строка 3.10): за них не платят.
*
* 🪤 Граница месяца — по МОСКВЕ (В-110), а не по Гринвичу. Не путать с окном 10–20:
* там время местное у ПОЛУЧАТЕЛЯ, здесь — московское у КЛИЕНТА.
*
* Помощники с префиксом volume* — имена функций в Pest ГЛОБАЛЬНЫЕ.
* Синтетические номера 7999… — реальные НИКОГДА.
*/
uses(RefreshDatabase::class);
beforeEach(function () {
$this->tenant = Tenant::factory()->create();
});
/** Строка журнала: сколько СМС, какой статус, когда (UTC). */
function volumeMessage(int $tenantId, string $status, ?int $segments, string $atUtc, array $extra = []): ClientSmsMessage
{
$at = CarbonImmutable::parse($atUtc, 'UTC');
$message = ClientSmsMessage::create($extra + [
'tenant_id' => $tenantId,
'phone' => '79990000001',
'status' => $status,
'segments' => $segments,
'cost_rub' => '0.00',
]);
// created_at ставим отдельно: модель проставляет своё время при создании.
ClientSmsMessage::where('id', $message->id)->update(['created_at' => $at]);
return $message->refresh();
}
it('3.9 — считает СМС, а не сообщения: длинное письмо это два', function () {
Carbon::setTestNow(CarbonImmutable::parse('2026-08-10 09:00:00', 'UTC'));
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-08-02 09:00:00');
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 2, '2026-08-03 09:00:00');
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(3);
Carbon::setTestNow();
});
it('3.9 — счётчик один на обе дороги: рассылка и авто-СМС складываются', function () {
Carbon::setTestNow(CarbonImmutable::parse('2026-08-10 09:00:00', 'UTC'));
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-08-02 09:00:00');
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-08-03 09:00:00', ['deal_id' => null]);
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(2);
Carbon::setTestNow();
});
it('3.10 — песочные отправки в счёт не идут', function () {
Carbon::setTestNow(CarbonImmutable::parse('2026-08-10 09:00:00', 'UTC'));
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-08-02 09:00:00');
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_FAKE_SENT, 5, '2026-08-03 09:00:00');
// Не ушедшее — тем более не в счёт: за него не платили.
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_FAILED, 3, '2026-08-04 09:00:00');
volumeMessage($this->tenant->id, ClientSmsMessage::SKIP_OPTOUT, 3, '2026-08-05 09:00:00');
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(1);
Carbon::setTestNow();
});
it('3.9 — граница месяца по Москве: полночь 1-го числа уже новый месяц', function () {
// 31 июля 21:30 UTC — это 1 августа 00:30 в Москве, то есть УЖЕ август.
// 31 июля 20:30 UTC — это 31 июля 23:30 в Москве, то есть ещё июль.
Carbon::setTestNow(CarbonImmutable::parse('2026-08-01 06:00:00', 'UTC'));
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-07-31 20:30:00'); // июль
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-07-31 21:30:00'); // август
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(1);
Carbon::setTestNow();
});
it('3.9 — старая строка без числа СМС считается за одну (В-109)', function () {
Carbon::setTestNow(CarbonImmutable::parse('2026-08-10 09:00:00', 'UTC'));
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, null, '2026-08-02 09:00:00');
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(1);
Carbon::setTestNow();
});
it('3.9 — чужие отправки в свой счётчик не попадают', function () {
Carbon::setTestNow(CarbonImmutable::parse('2026-08-10 09:00:00', 'UTC'));
$other = Tenant::factory()->create();
volumeMessage($this->tenant->id, ClientSmsMessage::STATUS_SENT, 1, '2026-08-02 09:00:00');
volumeMessage($other->id, ClientSmsMessage::STATUS_SENT, 7, '2026-08-02 09:00:00');
expect(app(ClientSmsVolumeCounter::class)->sentThisMonth((int) $this->tenant->id))->toBe(1);
Carbon::setTestNow();
});