fix(events): point Messaging settings at suite defaults, not API keys
Deploy Ladill Events / deploy (push) Successful in 48s
Deploy Ladill Events / deploy (push) Successful in 48s
Mirror Care: suite platform keys count as ready for attendee email/SMS; Account Messaging is primary, product Bird/SMS keys are advanced. SmsService now prefers channel=suite before customer API keys.
This commit is contained in:
@@ -154,6 +154,9 @@ class AttendeeController extends Controller
|
||||
'programme' => $programme,
|
||||
'commsModes' => $commsModes,
|
||||
'defaultCommsMode' => $commsModes[0] ?? EventCommsService::MODE_PROGRAMME,
|
||||
'messagingSettingsUrl' => function_exists('ladill_account_url')
|
||||
? ladill_account_url('/account/settings/messaging')
|
||||
: (string) config('smtp.messaging_settings_url', 'https://account.ladill.com/account/settings/messaging'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\PaymentGatewaySetting;
|
||||
use App\Models\QrSetting;
|
||||
use App\Services\Billing\BillingClient;
|
||||
use App\Services\Billing\PlatformEmailClient;
|
||||
use App\Services\Billing\PlatformSmsClient;
|
||||
use App\Services\Events\SubscriptionService;
|
||||
use App\Services\Payments\MerchantGatewayService;
|
||||
use App\Support\AccountBranding;
|
||||
@@ -86,6 +88,11 @@ class AccountController extends Controller
|
||||
'frameStyles' => QrFrameStyleCatalog::visible(),
|
||||
'gateway' => $this->gateway->settingFor($account),
|
||||
'canUsePaymentGateway' => $this->subscriptions->canUsePaymentGateway($account),
|
||||
'messagingSettingsUrl' => function_exists('ladill_account_url')
|
||||
? ladill_account_url('/account/settings/messaging')
|
||||
: (string) config('smtp.messaging_settings_url', 'https://account.ladill.com/account/settings/messaging'),
|
||||
'suiteMessagingReady' => app(PlatformEmailClient::class)->isConfigured()
|
||||
|| app(PlatformSmsClient::class)->isConfigured(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ class IntegrationsController extends Controller
|
||||
return view('qr.account.integrations', [
|
||||
'account' => $account,
|
||||
'credential' => $credentials->forOwner((string) $account->public_id),
|
||||
'messagingSettingsUrl' => function_exists('ladill_account_url')
|
||||
? ladill_account_url('/account/settings/messaging')
|
||||
: (string) config('smtp.messaging_settings_url', 'https://account.ladill.com/account/settings/messaging'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@ namespace App\Services\Billing;
|
||||
use App\Services\Messaging\CustomerSmsClient;
|
||||
use App\Services\Messaging\MessagingCredentialsService;
|
||||
|
||||
/**
|
||||
* Attendee SMS: prefer platform suite messaging (zero-config), fall back to
|
||||
* product SMS API keys when suite is unavailable.
|
||||
*/
|
||||
class SmsService
|
||||
{
|
||||
private ?string $lastError = null;
|
||||
@@ -12,6 +16,7 @@ class SmsService
|
||||
public function __construct(
|
||||
private readonly CustomerSmsClient $customer,
|
||||
private readonly MessagingCredentialsService $credentials,
|
||||
private readonly PlatformSmsClient $platformSms,
|
||||
) {}
|
||||
|
||||
public function lastError(): ?string
|
||||
@@ -19,6 +24,15 @@ class SmsService
|
||||
return $this->lastError;
|
||||
}
|
||||
|
||||
public function isConfiguredForOwner(string $ownerPublicId): bool
|
||||
{
|
||||
if ($this->platformSms->isConfigured()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->credentials->forOwner($ownerPublicId)->hasValidSms();
|
||||
}
|
||||
|
||||
public function send(string $ownerPublicId, string $to, string $message): bool
|
||||
{
|
||||
$this->lastError = null;
|
||||
@@ -37,15 +51,43 @@ class SmsService
|
||||
}
|
||||
|
||||
$credential = $this->credentials->forOwner($ownerPublicId);
|
||||
|
||||
if ($this->platformSms->isConfigured()) {
|
||||
$sender = $credential->sms_sender_id ?: null;
|
||||
$sent = $this->platformSms->send(
|
||||
$ownerPublicId,
|
||||
$phone,
|
||||
$message,
|
||||
$sender ? (string) $sender : null,
|
||||
);
|
||||
if ($sent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$suiteError = $this->platformSms->lastError();
|
||||
if ($this->tryCustomerSms($credential, $phone, $message)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->lastError = $suiteError ?: $this->lastError;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->tryCustomerSms($credential, $phone, $message);
|
||||
}
|
||||
|
||||
private function tryCustomerSms(object $credential, string $phone, string $message): bool
|
||||
{
|
||||
if (! $credential->hasValidSms()) {
|
||||
$this->lastError = 'Connect Ladill SMS in Integrations before sending attendee SMS.';
|
||||
$this->lastError = 'SMS is not available (platform SMS key missing and no product SMS credentials).';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$apiKey = $credential->smsApiKey();
|
||||
if (! $apiKey) {
|
||||
$this->lastError = 'SMS credentials could not be decrypted. Reconnect SMS in Integrations.';
|
||||
$this->lastError = 'SMS credentials could not be decrypted. Reconnect SMS under Advanced keys.';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace App\Services\Events;
|
||||
|
||||
use App\Models\QrCode;
|
||||
use App\Models\QrEventRegistration;
|
||||
use App\Services\Billing\PlatformEmailClient;
|
||||
use App\Services\Billing\PlatformSmsClient;
|
||||
use App\Services\Billing\SmsService;
|
||||
use App\Services\Messaging\MessagingCredentialsService;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -23,6 +25,8 @@ class EventCommsService
|
||||
private readonly SmsService $sms,
|
||||
private readonly MessagingCredentialsService $credentials,
|
||||
private readonly EventProgrammeService $programmes,
|
||||
private readonly PlatformEmailClient $platformEmail,
|
||||
private readonly PlatformSmsClient $platformSms,
|
||||
) {}
|
||||
|
||||
/** @return array{recipients: int, emails: int, sms: int, estimated_ghs: float, affordable: bool, integrations_error: ?string} */
|
||||
@@ -188,12 +192,15 @@ class EventCommsService
|
||||
$joinUrl,
|
||||
) !== '';
|
||||
|
||||
if ($needsEmail && ! $credential->hasValidBird()) {
|
||||
return 'Connect Ladill Bird in Integrations before sending attendee email.';
|
||||
$emailReady = $this->platformEmail->isConfigured() || $credential->hasValidBird();
|
||||
$smsReady = $this->platformSms->isConfigured() || $credential->hasValidSms();
|
||||
|
||||
if ($needsEmail && ! $emailReady) {
|
||||
return 'Email is not available yet. Bind a mailbox under Account → Messaging once platform keys are configured, or connect Bird under Advanced keys.';
|
||||
}
|
||||
|
||||
if ($needsSms && ! $credential->hasValidSms()) {
|
||||
return 'Connect Ladill SMS in Integrations before sending attendee SMS.';
|
||||
if ($needsSms && ! $smsReady) {
|
||||
return 'SMS is not available yet. Ensure platform SMS is configured on this Events instance, or connect a product SMS key under Advanced keys.';
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -227,7 +227,7 @@ class EventSpeakerInviteService
|
||||
}
|
||||
|
||||
if (! app(EventMailer::class)->isConfiguredForOwner($ownerRef)) {
|
||||
return ['ok' => false, 'error' => 'Connect Ladill Bird in Integrations before sending speaker invitations.'];
|
||||
return ['ok' => false, 'error' => 'Email is not available yet. Bind a mailbox under Account → Messaging once platform keys are configured, or connect Bird under Advanced keys.'];
|
||||
}
|
||||
|
||||
$token = (string) ($speaker['invite_token'] ?? '');
|
||||
|
||||
Reference in New Issue
Block a user