feat(messaging): suite-channel email/SMS and entitlement sync
Deploy Ladill Events / deploy (push) Successful in 48s

Prefer platform suite messaging (channel=suite) for attendee email, fall back
to Bird integrations; sync suite plan entitlements on subscribe/renew.
This commit is contained in:
isaacclad
2026-07-16 11:24:21 +00:00
parent b73b071cb1
commit 3d5ffa593d
8 changed files with 365 additions and 86 deletions
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use App\Services\Billing\PlatformEmailClient;
use App\Services\Billing\PlatformSmsClient;
use App\Services\Events\EventMailer;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;
class EventsSuiteMessagingTest extends TestCase
{
use RefreshDatabase;
public function test_platform_email_client_sends_channel_suite(): void
{
config([
'smtp.platform_api_key' => 'events-key',
'smtp.platform_api_url' => 'https://platform.test/api/smtp',
'smtp.from_name' => 'Ladill Events',
]);
Http::fake([
'platform.test/api/smtp/messages/send' => Http::response(['success' => true, 'path' => 'suite']),
]);
$ok = app(PlatformEmailClient::class)->send(
'usr_events_1',
'guest@example.com',
'Ticket',
'<p>Hi</p>',
'Hi',
);
$this->assertTrue($ok);
Http::assertSent(function ($request) {
$data = $request->data();
return str_contains($request->url(), '/messages/send')
&& ($data['channel'] ?? null) === 'suite'
&& $request->hasHeader('Idempotency-Key');
});
}
public function test_platform_sms_client_sends_channel_suite_without_service_id(): void
{
config([
'sms.platform_api_key' => 'events-sms-key',
'sms.platform_api_url' => 'https://platform.test/api',
]);
Http::fake([
'platform.test/api/sms/messages/send' => Http::response(['success' => true, 'path' => 'suite']),
]);
$ok = app(PlatformSmsClient::class)->send('usr_events_1', '0241234567', 'Hello');
$this->assertTrue($ok);
Http::assertSent(function ($request) {
$data = $request->data();
return str_contains($request->url(), '/sms/messages/send')
&& ($data['channel'] ?? null) === 'suite'
&& ! array_key_exists('sms_service_id', $data);
});
}
public function test_event_mailer_uses_suite_when_platform_configured(): void
{
config([
'smtp.platform_api_key' => 'events-key',
'smtp.platform_api_url' => 'https://platform.test/api/smtp',
]);
Http::fake([
'platform.test/api/smtp/messages/send' => Http::response(['success' => true]),
]);
$user = User::factory()->create(['public_id' => 'usr_mailer_suite']);
$ok = app(EventMailer::class)->send(
$user->public_id,
'speaker@example.com',
'Invite',
'<p>Join us</p>',
'Join us',
);
$this->assertTrue($ok);
$this->assertTrue(app(EventMailer::class)->isConfiguredForOwner($user->public_id));
}
public function test_billing_client_syncs_suite_entitlement(): void
{
config([
'billing.api_url' => 'https://platform.test/api/billing',
'billing.api_key' => 'events-billing',
'billing.service' => 'events',
]);
Http::fake([
'platform.test/api/billing/suite-entitlements' => Http::response([
'data' => ['app' => 'events', 'plan' => 'pro'],
'idempotent_replay' => false,
], 201),
]);
$ok = app(\App\Services\Billing\BillingClient::class)->syncSuiteEntitlement(
'usr_events_1',
'pro',
'active',
'events-pro-ref-1',
[
'period_starts_at' => now()->toIso8601String(),
'period_ends_at' => now()->addMonth()->toIso8601String(),
'source' => 'wallet_debit',
],
);
$this->assertTrue($ok);
Http::assertSent(function ($request) {
$data = $request->data();
return str_contains($request->url(), '/suite-entitlements')
&& ($data['app'] ?? null) === 'events'
&& ($data['plan'] ?? null) === 'pro';
});
}
}