Add per-customer SMS and Bird credentials to Frontdesk Integrations.
Deploy Ladill Frontdesk / deploy (push) Successful in 45s
Deploy Ladill Frontdesk / deploy (push) Successful in 45s
NotificationDispatcher sends via customer relay and skips Frontdesk wallet debit when tenant keys are configured. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -10,15 +10,17 @@ use App\Models\User;
|
||||
use App\Models\Visitor;
|
||||
use App\Models\Visit;
|
||||
use App\Notifications\FrontdeskAlertNotification;
|
||||
use App\Services\Comms\EmailService;
|
||||
use App\Services\Comms\SmsService;
|
||||
use App\Services\Messaging\CustomerEmailClient;
|
||||
use App\Services\Messaging\CustomerSmsClient;
|
||||
use App\Services\Messaging\MessagingCredentialsService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class NotificationDispatcher
|
||||
{
|
||||
public function __construct(
|
||||
protected EmailService $email,
|
||||
protected SmsService $sms,
|
||||
protected MessagingCredentialsService $credentials,
|
||||
protected CustomerEmailClient $customerEmail,
|
||||
protected CustomerSmsClient $customerSms,
|
||||
protected NotificationPreferenceService $preferences,
|
||||
protected NotificationBillingService $billing,
|
||||
) {}
|
||||
@@ -194,40 +196,94 @@ class NotificationDispatcher
|
||||
): bool {
|
||||
$notified = false;
|
||||
$reference = $visit ? 'visit-'.$visit->id.'-'.($event ?? 'alert') : 'host-'.$host->id;
|
||||
$credential = $this->credentials->forOrganization($organization);
|
||||
|
||||
if (in_array('email', $channels, true) && $host->email) {
|
||||
if (! $this->billing->canAffordEmail($organization)) {
|
||||
Log::info('Frontdesk host email skipped — insufficient wallet balance', [
|
||||
if (! $credential->hasValidBird()) {
|
||||
Log::info('Frontdesk host email skipped — Ladill Bird not connected', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} else {
|
||||
try {
|
||||
$this->email->send($host->email, $title, $message);
|
||||
if ($this->billing->chargeEmail($organization, $reference, "Host alert: {$title}")) {
|
||||
$notified = true;
|
||||
$apiKey = $credential->birdApiKey();
|
||||
if (! $apiKey) {
|
||||
Log::info('Frontdesk host email skipped — Bird credentials could not be decrypted', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} elseif (! $this->billing->canAffordEmail($organization)) {
|
||||
Log::info('Frontdesk host email skipped — insufficient wallet balance', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} else {
|
||||
try {
|
||||
$html = nl2br(e($message));
|
||||
$sent = $this->customerEmail->send(
|
||||
$apiKey,
|
||||
(string) $credential->bird_from_email,
|
||||
$credential->bird_from_name,
|
||||
(string) $host->email,
|
||||
$title,
|
||||
$html,
|
||||
$message,
|
||||
);
|
||||
|
||||
if (! $sent) {
|
||||
Log::warning('Frontdesk host email failed', [
|
||||
'host_id' => $host->id,
|
||||
'error' => $this->customerEmail->lastError(),
|
||||
]);
|
||||
} elseif ($this->billing->chargeEmail($organization, $reference, "Host alert: {$title}")) {
|
||||
$notified = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Frontdesk host email failed', ['host_id' => $host->id, 'error' => $e->getMessage()]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Frontdesk host email failed', ['host_id' => $host->id, 'error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('sms', $channels, true) && $host->phone) {
|
||||
$smsBody = "{$title}: {$message}";
|
||||
if (! $this->billing->canAffordSms($organization, $smsBody)) {
|
||||
Log::info('Frontdesk host SMS skipped — insufficient wallet balance', [
|
||||
|
||||
if (! $credential->hasValidSms()) {
|
||||
Log::info('Frontdesk host SMS skipped — Ladill SMS not connected', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} else {
|
||||
try {
|
||||
$this->sms->send($host->phone, $smsBody);
|
||||
if ($this->billing->chargeSms($organization, $smsBody, $reference, "Host SMS: {$title}")) {
|
||||
$notified = true;
|
||||
$apiKey = $credential->smsApiKey();
|
||||
if (! $apiKey) {
|
||||
Log::info('Frontdesk host SMS skipped — SMS credentials could not be decrypted', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} elseif (! $this->billing->canAffordSms($organization, $smsBody)) {
|
||||
Log::info('Frontdesk host SMS skipped — insufficient wallet balance', [
|
||||
'host_id' => $host->id,
|
||||
'organization_id' => $organization->id,
|
||||
]);
|
||||
} else {
|
||||
try {
|
||||
$sent = $this->customerSms->send(
|
||||
$apiKey,
|
||||
(string) $host->phone,
|
||||
$smsBody,
|
||||
(string) $credential->sms_sender_id,
|
||||
);
|
||||
|
||||
if (! $sent) {
|
||||
Log::warning('Frontdesk host SMS failed', [
|
||||
'host_id' => $host->id,
|
||||
'error' => $this->customerSms->lastError(),
|
||||
]);
|
||||
} elseif ($this->billing->chargeSms($organization, $smsBody, $reference, "Host SMS: {$title}")) {
|
||||
$notified = true;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Frontdesk host SMS failed', ['host_id' => $host->id, 'error' => $e->getMessage()]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Frontdesk host SMS failed', ['host_id' => $host->id, 'error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user