Refactor SMS campaign handling to dispatch a job for starting campaigns and update notification messages for improved user feedback.
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Filament\Pages;
|
namespace App\Filament\Pages;
|
||||||
|
|
||||||
|
use App\Jobs\StartSmsCampaignJob;
|
||||||
use App\Models\Coupon;
|
use App\Models\Coupon;
|
||||||
use App\Models\SmsCampaign;
|
|
||||||
use App\Services\SmsBroadcastService;
|
use App\Services\SmsBroadcastService;
|
||||||
use App\Services\SmsMessageAnalyzer;
|
use App\Services\SmsMessageAnalyzer;
|
||||||
use BackedEnum;
|
use BackedEnum;
|
||||||
@@ -170,53 +170,20 @@ class SendSms extends Page
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$campaign = $service->startCampaign(
|
StartSmsCampaignJob::dispatch(
|
||||||
admin: auth()->user(),
|
adminId: auth()->id(),
|
||||||
message: $data['message'],
|
message: $data['message'],
|
||||||
sendToAll: $sendToAll,
|
sendToAll: $sendToAll,
|
||||||
selectedIds: $selectedIds,
|
selectedIds: $selectedIds,
|
||||||
excludedIds: $excludedIds,
|
excludedIds: $excludedIds,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($campaign->isComplete()) {
|
|
||||||
$this->notifyCampaignFinished($campaign);
|
|
||||||
} else {
|
|
||||||
Notification::make()
|
Notification::make()
|
||||||
->title(__('filament.send_sms.notifications.queued'))
|
->title(__('filament.send_sms.notifications.submitted'))
|
||||||
->body(__('filament.send_sms.notifications.queued_body', ['count' => $campaign->recipient_count]))
|
->body(__('filament.send_sms.notifications.submitted_body', ['count' => $willReceive]))
|
||||||
->success()
|
->success()
|
||||||
->send();
|
->send();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected function notifyCampaignFinished(SmsCampaign $campaign): void
|
|
||||||
{
|
|
||||||
$campaign->refresh();
|
|
||||||
|
|
||||||
if ($campaign->failed_count > 0 && $campaign->sent_count === 0) {
|
|
||||||
Notification::make()
|
|
||||||
->title(__('filament.send_sms.notifications.failed'))
|
|
||||||
->body(__('filament.send_sms.notifications.failed_body', ['count' => $campaign->failed_count]))
|
|
||||||
->danger()
|
|
||||||
->send();
|
|
||||||
} elseif ($campaign->failed_count > 0) {
|
|
||||||
Notification::make()
|
|
||||||
->title(__('filament.send_sms.notifications.finished_with_errors'))
|
|
||||||
->body(__('filament.send_sms.notifications.finished_with_errors_body', [
|
|
||||||
'sent' => $campaign->sent_count,
|
|
||||||
'failed' => $campaign->failed_count,
|
|
||||||
'skipped' => $campaign->skipped_count,
|
|
||||||
]))
|
|
||||||
->warning()
|
|
||||||
->send();
|
|
||||||
} else {
|
|
||||||
Notification::make()
|
|
||||||
->title(__('filament.send_sms.notifications.completed'))
|
|
||||||
->body(__('filament.send_sms.notifications.completed_body', ['count' => $campaign->sent_count]))
|
|
||||||
->success()
|
|
||||||
->send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function confirmationDescription(): string
|
protected function confirmationDescription(): string
|
||||||
{
|
{
|
||||||
|
|||||||
38
app/Jobs/StartSmsCampaignJob.php
Normal file
38
app/Jobs/StartSmsCampaignJob.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\SmsBroadcastService;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Queue\Queueable;
|
||||||
|
|
||||||
|
class StartSmsCampaignJob implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, int|string> $selectedIds
|
||||||
|
* @param array<int, int|string> $excludedIds
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
public int $adminId,
|
||||||
|
public string $message,
|
||||||
|
public bool $sendToAll,
|
||||||
|
public array $selectedIds = [],
|
||||||
|
public array $excludedIds = [],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function handle(SmsBroadcastService $service): void
|
||||||
|
{
|
||||||
|
$admin = User::query()->findOrFail($this->adminId);
|
||||||
|
|
||||||
|
$service->startCampaign(
|
||||||
|
admin: $admin,
|
||||||
|
message: $this->message,
|
||||||
|
sendToAll: $this->sendToAll,
|
||||||
|
selectedIds: $this->selectedIds,
|
||||||
|
excludedIds: $this->excludedIds,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,14 +38,8 @@ return [
|
|||||||
'notifications' => [
|
'notifications' => [
|
||||||
'no_valid_recipients' => 'Dogry alyjy ýok',
|
'no_valid_recipients' => 'Dogry alyjy ýok',
|
||||||
'no_valid_recipients_body' => 'Saýlawy ýa-da aýyrmalary üýtgediň — dogry telefon belgili kupon eýesi bu habary almaz.',
|
'no_valid_recipients_body' => 'Saýlawy ýa-da aýyrmalary üýtgediň — dogry telefon belgili kupon eýesi bu habary almaz.',
|
||||||
'queued' => 'SMS kampaniýasy nobata goýuldy',
|
'submitted' => 'SMS kampaniýasy kabul edildi',
|
||||||
'queued_body' => 'Arka fonda :count alyja iberilýär.',
|
'submitted_body' => 'Arka fonda :count alyja iberilýär.',
|
||||||
'failed' => 'SMS kampaniýasy şowsuz',
|
|
||||||
'failed_body' => ':count habar iberilmedi.',
|
|
||||||
'finished_with_errors' => 'SMS kampaniýasy ýalňyşlyklar bilen tamamlandy',
|
|
||||||
'finished_with_errors_body' => 'Iberildi :sent, şowsuz :failed, geçildi :skipped.',
|
|
||||||
'completed' => 'SMS kampaniýasy tamamlandy',
|
|
||||||
'completed_body' => ':count habar üstünlikli iberildi.',
|
|
||||||
],
|
],
|
||||||
'confirmation' => ':count alyja ibermeli? :summary',
|
'confirmation' => ':count alyja ibermeli? :summary',
|
||||||
],
|
],
|
||||||
|
|||||||
64
tests/Feature/StartSmsCampaignJobTest.php
Normal file
64
tests/Feature/StartSmsCampaignJobTest.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Jobs\SendSmsToCouponJob;
|
||||||
|
use App\Jobs\StartSmsCampaignJob;
|
||||||
|
use App\Models\Coupon;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Services\SmsBroadcastService;
|
||||||
|
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||||
|
use Illuminate\Support\Facades\Bus;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class StartSmsCampaignJobTest extends TestCase
|
||||||
|
{
|
||||||
|
use LazilyRefreshDatabase;
|
||||||
|
|
||||||
|
public function test_job_is_dispatched_with_expected_payload(): void
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$admin = User::factory()->create();
|
||||||
|
$coupon = Coupon::factory()->create();
|
||||||
|
|
||||||
|
StartSmsCampaignJob::dispatch(
|
||||||
|
adminId: $admin->id,
|
||||||
|
message: 'Hello',
|
||||||
|
sendToAll: false,
|
||||||
|
selectedIds: [$coupon->id],
|
||||||
|
excludedIds: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
Queue::assertPushed(StartSmsCampaignJob::class, function (StartSmsCampaignJob $job) use ($admin, $coupon): bool {
|
||||||
|
return $job->adminId === $admin->id
|
||||||
|
&& $job->message === 'Hello'
|
||||||
|
&& $job->sendToAll === false
|
||||||
|
&& $job->selectedIds === [$coupon->id]
|
||||||
|
&& $job->excludedIds === [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_handle_starts_campaign_and_chains_send_jobs(): void
|
||||||
|
{
|
||||||
|
Bus::fake();
|
||||||
|
|
||||||
|
$admin = User::factory()->create();
|
||||||
|
$coupons = Coupon::factory()->count(2)->create();
|
||||||
|
|
||||||
|
$job = new StartSmsCampaignJob(
|
||||||
|
adminId: $admin->id,
|
||||||
|
message: 'Test broadcast',
|
||||||
|
sendToAll: false,
|
||||||
|
selectedIds: $coupons->pluck('id')->all(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$job->handle(app(SmsBroadcastService::class));
|
||||||
|
|
||||||
|
Bus::assertChained([
|
||||||
|
SendSmsToCouponJob::class,
|
||||||
|
SendSmsToCouponJob::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user