$states */ function totalsCampaignWith(int $tenantId, array $states, string $status = ClientSmsMessage::STATUS_SENT): ClientSmsCampaign { $campaign = ClientSmsCampaign::create([ 'tenant_id' => $tenantId, 'title' => 'Итог', 'body' => 'Текст рассылки', 'sender_name' => 'LIDERRA', 'source' => ClientSmsCampaign::SOURCE_MANUAL, 'status' => ClientSmsCampaign::STATUS_DONE, 'idempotency_key' => 'totals-'.uniqid(), 'segments' => 1, 'planned_count' => count($states), 'sent_count' => count($states), 'total_sms' => count($states), 'price_rub_per_sms' => '8.50', 'estimated_cost_rub' => '8.50', ]); $n = 0; foreach ($states as $state) { $n++; ClientSmsMessage::create([ 'tenant_id' => $tenantId, 'campaign_id' => $campaign->id, 'phone' => '7999'.str_pad((string) $campaign->id, 4, '0', STR_PAD_LEFT).str_pad((string) $n, 3, '0', STR_PAD_LEFT), 'provider_key' => 'mts', 'status' => $status, 'delivery_status' => $state, 'cost_rub' => '8.50', 'segments' => 1, ]); } return $campaign; } it('карточка рассылки показывает доставлено, не доставлено и ещё в пути', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $campaign = totalsCampaignWith((int) $tenant->id, [ SmsDeliveryState::DELIVERED, SmsDeliveryState::DELIVERED, SmsDeliveryState::NOT_DELIVERED, SmsDeliveryState::SENDING, null, ]); $response = $this->actingAs($user)->getJson("/api/sms/campaigns/{$campaign->id}"); $response->assertOk(); expect($response->json('delivery.delivered'))->toBe(2); expect($response->json('delivery.not_delivered'))->toBe(1); // «Ещё в пути» — это и явное `sending`, и те, кого мы ещё не спрашивали. expect($response->json('delivery.on_the_way'))->toBe(2); }); it('список рассылок несёт итог по КАЖДОЙ — человек видит его не открывая карточку', function () { // 🔴 Рассылок в списке намеренно ДВЕ и с разными числами: со списком из одной // штуки этот тест не отличал бы «итог по своей рассылке» от «итог по первой в // списке» — и не покраснел бы на такой подмене вовсе (урок В-219). $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $first = totalsCampaignWith((int) $tenant->id, [SmsDeliveryState::DELIVERED, SmsDeliveryState::NOT_DELIVERED]); $second = totalsCampaignWith((int) $tenant->id, [ SmsDeliveryState::DELIVERED, SmsDeliveryState::DELIVERED, SmsDeliveryState::DELIVERED, SmsDeliveryState::SENDING, ]); $response = $this->actingAs($user)->getJson('/api/sms/campaigns'); $response->assertOk(); // Список идёт от новых к старым: сначала вторая рассылка, потом первая. $rows = collect($response->json('campaigns'))->keyBy('id'); expect($rows[$first->id]['delivery']['delivered'])->toBe(1); expect($rows[$first->id]['delivery']['not_delivered'])->toBe(1); expect($rows[$second->id]['delivery']['delivered'])->toBe(3); expect($rows[$second->id]['delivery']['on_the_way'])->toBe(1); }); it('«оператор не отправил вовсе» считается отдельно от «не доставлено»', function () { // Это разные события, и разговор с оператором по ним разный (В-212): за // «не отправил вовсе» клиент платить не должен тем более. Свалить их в одну // кучу значило бы потерять повод для этого разговора. $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $campaign = totalsCampaignWith((int) $tenant->id, [ SmsDeliveryState::NOT_SENT, SmsDeliveryState::NOT_DELIVERED, ]); $response = $this->actingAs($user)->getJson("/api/sms/campaigns/{$campaign->id}"); $response->assertOk(); expect($response->json('delivery.not_sent'))->toBe(1); expect($response->json('delivery.not_delivered'))->toBe(1); }); it('пробные сообщения песочницы в итог не идут', function () { // За `fake_sent` никто никуда не ехал и денег не платил — ровно так же их не // считает месячный объём (`ClientSmsVolumeCounter`). Посчитай мы их «ещё в пути», // рассылка в песочнице никогда не стала бы окончательной. $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $campaign = totalsCampaignWith( (int) $tenant->id, [null, SmsDeliveryState::DELIVERED], ClientSmsMessage::STATUS_FAKE_SENT, ); $response = $this->actingAs($user)->getJson("/api/sms/campaigns/{$campaign->id}"); $response->assertOk(); expect($response->json('delivery.on_the_way'))->toBe(0); expect($response->json('delivery.delivered'))->toBe(0); }); it('итог соседней рассылки в карточку не подмешивается', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $mine = totalsCampaignWith((int) $tenant->id, [SmsDeliveryState::DELIVERED]); totalsCampaignWith((int) $tenant->id, [ SmsDeliveryState::DELIVERED, SmsDeliveryState::DELIVERED, SmsDeliveryState::DELIVERED, ]); $response = $this->actingAs($user)->getJson("/api/sms/campaigns/{$mine->id}"); $response->assertOk(); expect($response->json('delivery.delivered'))->toBe(1); });