Add per-customer SMS and Bird Integrations for event messaging.
Deploy Ladill Events / deploy (push) Successful in 28s
Deploy Ladill Events / deploy (push) Successful in 28s
Attendee and speaker comms use encrypted tenant relay credentials and skip platform-key fallback and Bird wallet double-debit. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,8 +4,8 @@ namespace App\Services\Events;
|
||||
|
||||
use App\Models\QrCode;
|
||||
use App\Models\QrEventRegistration;
|
||||
use App\Services\Billing\BillingClient;
|
||||
use App\Services\Billing\SmsService;
|
||||
use App\Services\Messaging\MessagingCredentialsService;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class EventCommsService
|
||||
@@ -21,11 +21,11 @@ class EventCommsService
|
||||
public function __construct(
|
||||
private readonly EventEmailService $email,
|
||||
private readonly SmsService $sms,
|
||||
private readonly BillingClient $billing,
|
||||
private readonly MessagingCredentialsService $credentials,
|
||||
private readonly EventProgrammeService $programmes,
|
||||
) {}
|
||||
|
||||
/** @return array{recipients: int, emails: int, sms: int, estimated_ghs: float, affordable: bool} */
|
||||
/** @return array{recipients: int, emails: int, sms: int, estimated_ghs: float, affordable: bool, integrations_error: ?string} */
|
||||
public function preview(QrCode $event, string $mode): array
|
||||
{
|
||||
$regs = $this->confirmedRegistrations($event);
|
||||
@@ -34,14 +34,15 @@ class EventCommsService
|
||||
$smsSegments = $phones * $this->estimateSmsSegments($event, $mode);
|
||||
$estimated = round(($emails * self::EMAIL_PRICE_GHS) + ($smsSegments * self::SMS_PRICE_GHS), 2);
|
||||
$ownerRef = (string) $event->user->public_id;
|
||||
$affordable = $estimated <= 0 || $this->billing->canAfford($ownerRef, (int) round($estimated * 100));
|
||||
$integrationsError = $this->integrationsError($event, $mode, $emails, $phones);
|
||||
|
||||
return [
|
||||
'recipients' => $regs->count(),
|
||||
'emails' => $emails,
|
||||
'sms' => $phones,
|
||||
'estimated_ghs' => $estimated,
|
||||
'affordable' => $affordable,
|
||||
'affordable' => $integrationsError === null,
|
||||
'integrations_error' => $integrationsError,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ class EventCommsService
|
||||
public function send(QrCode $event, string $mode): array
|
||||
{
|
||||
$preview = $this->preview($event, $mode);
|
||||
abort_unless($preview['affordable'], 402, 'Insufficient wallet balance for this send.');
|
||||
abort_if($preview['integrations_error'] !== null, 422, $preview['integrations_error']);
|
||||
|
||||
$programme = $this->programmeFor($event);
|
||||
$eventName = $event->content()['name'] ?? $event->label;
|
||||
@@ -86,8 +87,7 @@ class EventCommsService
|
||||
|
||||
if ($reg->attendee_phone) {
|
||||
$message = $this->smsBody($reg, $eventName, $mode, $programmeUrl, $joinUrl);
|
||||
if ($message !== '') {
|
||||
$this->sms->send($ownerRef, $reg->attendee_phone, $message);
|
||||
if ($message !== '' && $this->sms->send($ownerRef, $reg->attendee_phone, $message)) {
|
||||
$texted++;
|
||||
$sent = true;
|
||||
}
|
||||
@@ -167,4 +167,35 @@ class EventCommsService
|
||||
|
||||
return max(1, (int) ceil(strlen($sample) / self::SMS_SEGMENT_CHARS));
|
||||
}
|
||||
|
||||
private function integrationsError(QrCode $event, string $mode, int $emails, int $phones): ?string
|
||||
{
|
||||
$ownerRef = (string) $event->user->public_id;
|
||||
$credential = $this->credentials->forOwner($ownerRef);
|
||||
$programmeUrl = $this->programmeFor($event)?->publicUrl();
|
||||
$joinUrl = $this->primaryJoinUrl($event);
|
||||
|
||||
$needsEmail = $emails > 0 && (
|
||||
(in_array($mode, [self::MODE_PROGRAMME, self::MODE_BOTH], true) && $programmeUrl)
|
||||
|| ($mode === self::MODE_JOIN && $joinUrl !== '')
|
||||
);
|
||||
|
||||
$needsSms = $phones > 0 && $this->smsBody(
|
||||
new QrEventRegistration(['attendee_name' => 'Guest']),
|
||||
$event->content()['name'] ?? $event->label,
|
||||
$mode,
|
||||
$programmeUrl,
|
||||
$joinUrl,
|
||||
) !== '';
|
||||
|
||||
if ($needsEmail && ! $credential->hasValidBird()) {
|
||||
return 'Connect Ladill Bird in Integrations before sending attendee email.';
|
||||
}
|
||||
|
||||
if ($needsSms && ! $credential->hasValidSms()) {
|
||||
return 'Connect Ladill SMS in Integrations before sending attendee SMS.';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user