100 lines
4.0 KiB
PHP
100 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Sms;
|
|
|
|
use App\Models\CalendarReminder;
|
|
use App\Models\SmsCampaign;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class SmsCampaignReconciler
|
|
{
|
|
public function __construct(private readonly OvhSmsProvider $provider) {}
|
|
|
|
public function reconcile(SmsCampaign $campaign): SmsCampaign
|
|
{
|
|
try {
|
|
$messages = $this->provider->outgoing($campaign);
|
|
} catch (SmsProviderException $exception) {
|
|
Log::warning('SMS campaign verification unavailable.', [
|
|
'sms_campaign_id' => $campaign->id,
|
|
'reason' => $exception->getMessage(),
|
|
]);
|
|
|
|
return $campaign;
|
|
}
|
|
|
|
return $this->applyOutgoing($campaign, $messages);
|
|
}
|
|
|
|
/** @param array<int, array<string, mixed>> $messages */
|
|
public function applyOutgoing(SmsCampaign $campaign, array $messages): SmsCampaign
|
|
{
|
|
return DB::transaction(function () use ($campaign, $messages): SmsCampaign {
|
|
$campaign = SmsCampaign::query()->lockForUpdate()->findOrFail($campaign->id);
|
|
|
|
if (! in_array($campaign->status, ['uncertain', 'sending'], true)) {
|
|
return $campaign;
|
|
}
|
|
|
|
$byNumber = [];
|
|
foreach ($messages as $message) {
|
|
if (($message['tag'] ?? null) !== $campaign->provider_tag
|
|
|| ($message['message'] ?? null) !== $campaign->message
|
|
|| empty($message['id']) || empty($message['receiver'])) {
|
|
continue;
|
|
}
|
|
|
|
$byNumber[(string) $message['receiver']] = $message;
|
|
}
|
|
|
|
foreach ($campaign->deliveries()->whereIn('status', ['uncertain', 'queued'])->get() as $delivery) {
|
|
$message = $byNumber[$delivery->number] ?? null;
|
|
if ($message === null) {
|
|
$delivery->update(['status' => 'uncertain']);
|
|
|
|
continue;
|
|
}
|
|
|
|
// "sent" records acceptance by OVH, not delivery to the handset.
|
|
$delivery->update([
|
|
'status' => 'sent',
|
|
'provider_message_id' => (string) $message['id'],
|
|
'provider_response' => $message,
|
|
'error_message' => null,
|
|
'sent_at' => $message['sentAt'] ?? $message['creationDatetime'] ?? now(),
|
|
]);
|
|
}
|
|
|
|
$sentCount = $campaign->deliveries()->where('status', 'sent')->count();
|
|
$failedCount = $campaign->deliveries()->where('status', 'failed')->count();
|
|
$unconfirmed = $campaign->deliveries()->whereIn('status', ['uncertain', 'queued'])->exists();
|
|
$status = $unconfirmed ? 'uncertain' : ($failedCount > 0 ? ($sentCount > 0 ? 'partial' : 'failed') : 'sent');
|
|
$campaign->update([
|
|
'status' => $status,
|
|
'sent_count' => $sentCount,
|
|
'failed_count' => $failedCount,
|
|
'sent_at' => $campaign->deliveries()->where('status', 'sent')->min('sent_at'),
|
|
'response_payload' => ['verification' => 'OVH outgoing history', 'confirmed_recipients' => $sentCount],
|
|
'error_message' => $unconfirmed
|
|
? 'Certains envois restent a verifier chez OVH. Aucun renvoi automatique ; ne pas renvoyer cette campagne.'
|
|
: null,
|
|
]);
|
|
|
|
CalendarReminder::query()->where('sms_campaign_id', $campaign->id)->where('status', 'uncertain')->update([
|
|
'status' => $status === 'uncertain' ? 'uncertain' : ($sentCount > 0 ? 'sent' : 'failed'),
|
|
'last_error' => $campaign->error_message,
|
|
'sent_at' => $campaign->sent_at,
|
|
]);
|
|
|
|
Log::info('SMS campaign verified against OVH history.', [
|
|
'sms_campaign_id' => $campaign->id,
|
|
'sent_count' => $sentCount,
|
|
'status' => $status,
|
|
]);
|
|
|
|
return $campaign->fresh(['deliveries', 'user']);
|
|
});
|
|
}
|
|
}
|