Files
preregister/app/Jobs/SyncSubscriberToMailwizz.php
bert.hausmans 7eda51f52a feat: clean Weeztix and Mailwizz when admin deletes subscriber
Run CleanupSubscriberIntegrationsService before delete: remove coupon code
in Weeztix via list+DELETE API; update Mailwizz contact to strip configured
source tag from the tag field and clear the mapped coupon field.

Extract MailwizzCheckboxlistTags and MailwizzSubscriberFormPayload for
shared sync/cleanup behaviour. Add WeeztixService list and delete helpers.

Integration failures are logged only; local delete always proceeds.
Feature tests cover Mailwizz strip+clear and Weeztix delete paths.

Made-with: Cursor
2026-04-05 11:57:16 +02:00

178 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Models\MailwizzConfig;
use App\Models\Subscriber;
use App\Services\MailwizzCheckboxlistTags;
use App\Services\MailwizzService;
use App\Services\MailwizzSubscriberFormPayload;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueueAfterCommit;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use RuntimeException;
use Throwable;
class SyncSubscriberToMailwizz implements ShouldBeUnique, ShouldQueueAfterCommit
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* Seconds before the unique lock expires if the worker dies before releasing it.
*/
public int $uniqueFor = 86400;
public int $tries = 3;
/**
* @var list<int>
*/
public array $backoff = [10, 30, 60];
public function __construct(public Subscriber $subscriber)
{
$this->onQueue('mailwizz');
}
public function uniqueId(): string
{
return (string) $this->subscriber->getKey();
}
public function handle(): void
{
try {
$this->runSync();
} catch (Throwable $e) {
Log::error('SyncSubscriberToMailwizz: integration failed; subscriber remains local (use admin resync if needed)', [
'subscriber_id' => $this->subscriber->id,
'message' => $e->getMessage(),
]);
}
}
private function runSync(): void
{
$subscriber = Subscriber::query()
->with(['preregistrationPage.mailwizzConfig'])
->find($this->subscriber->id);
if ($subscriber === null) {
return;
}
$page = $subscriber->preregistrationPage;
$config = $page?->mailwizzConfig;
if ($page === null || $config === null) {
return;
}
if (! $this->configIsComplete($config)) {
Log::warning('SyncSubscriberToMailwizz: incomplete Mailwizz config', [
'subscriber_id' => $subscriber->id,
'page_id' => $page->id,
]);
$this->fail(new RuntimeException('Incomplete Mailwizz configuration.'));
return;
}
$apiKey = $config->api_key;
if (! is_string($apiKey) || $apiKey === '') {
Log::warning('SyncSubscriberToMailwizz: missing API key', ['subscriber_id' => $subscriber->id]);
$this->fail(new RuntimeException('Mailwizz API key is missing.'));
return;
}
$service = new MailwizzService($apiKey);
$listUid = $config->list_uid;
$search = $service->searchSubscriber($listUid, $subscriber->email);
if ($search === null) {
$this->createInMailwizz($service, $subscriber, $config, $listUid);
} else {
$this->updateInMailwizz($service, $subscriber, $config, $listUid, $search['subscriber_uid']);
}
$subscriber->update([
'synced_to_mailwizz' => true,
'synced_at' => now(),
]);
}
public function failed(?Throwable $exception): void
{
Log::error('SyncSubscriberToMailwizz failed', [
'subscriber_id' => $this->subscriber->id,
'message' => $exception?->getMessage(),
]);
}
private function configIsComplete(MailwizzConfig $config): bool
{
if ($config->list_uid === '' || $config->field_email === '' || $config->field_first_name === '' || $config->field_last_name === '') {
return false;
}
if ($config->tag_field === null || $config->tag_field === '' || $config->tag_value === null || $config->tag_value === '') {
return false;
}
return true;
}
private function createInMailwizz(
MailwizzService $service,
Subscriber $subscriber,
MailwizzConfig $config,
string $listUid
): void {
$page = $subscriber->preregistrationPage;
$data = MailwizzSubscriberFormPayload::baseFields($subscriber, $config, $page->isPhoneFieldEnabledForSubscribers());
$tagField = $config->tag_field;
$tagValue = $config->tag_value;
if ($tagField !== null && $tagField !== '' && $tagValue !== null && $tagValue !== '') {
$data[$tagField] = [$tagValue];
}
$service->createSubscriber($listUid, $data);
}
private function updateInMailwizz(
MailwizzService $service,
Subscriber $subscriber,
MailwizzConfig $config,
string $listUid,
string $subscriberUid
): void {
$page = $subscriber->preregistrationPage;
$data = MailwizzSubscriberFormPayload::baseFields($subscriber, $config, $page->isPhoneFieldEnabledForSubscribers());
$tagField = $config->tag_field;
$tagValue = $config->tag_value;
if ($tagField !== null && $tagField !== '' && $tagValue !== null && $tagValue !== '') {
$full = $service->getSubscriber($listUid, $subscriberUid);
if ($full === null) {
throw new RuntimeException('Mailwizz getSubscriber returned an empty payload.');
}
$existingCsv = MailwizzCheckboxlistTags::extractCsvFromSubscriberResponse($full, $tagField);
$merged = MailwizzCheckboxlistTags::mergeValueIntoCsv($existingCsv, $tagValue);
$data[$tagField] = $merged;
}
$service->updateSubscriber($listUid, $subscriberUid, $data);
}
}