From 1e7ee1454070ecaa64b471ed5d2d7be5d4d8f680 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sun, 5 Apr 2026 13:33:56 +0200 Subject: [PATCH] fix: clear Mailwizz checkboxlist tag when deleting subscriber Encode empty checkboxlist arrays as an empty scalar so multipart requests include the field. On delete, PUT only coupon and tag fields to Mailwizz after merging the tag CSV from getSubscriber. Made-with: Cursor --- .../CleanupSubscriberIntegrationsService.php | 8 ++- app/Services/MailwizzService.php | 3 +- tests/Feature/DestroySubscriberTest.php | 62 +++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/app/Services/CleanupSubscriberIntegrationsService.php b/app/Services/CleanupSubscriberIntegrationsService.php index c7ef115..ec8268a 100644 --- a/app/Services/CleanupSubscriberIntegrationsService.php +++ b/app/Services/CleanupSubscriberIntegrationsService.php @@ -104,8 +104,8 @@ final class CleanupSubscriberIntegrationsService } $subscriberUid = $search['subscriber_uid']; - $phoneEnabled = $page->isPhoneFieldEnabledForSubscribers(); - $data = MailwizzSubscriberFormPayload::baseFields($subscriber, $config, $phoneEnabled); + /** @var array $data */ + $data = []; $couponField = $config->field_coupon_code; if (is_string($couponField) && $couponField !== '') { @@ -123,6 +123,10 @@ final class CleanupSubscriberIntegrationsService $data[$tagField] = MailwizzCheckboxlistTags::removeValueFromCsv($existingCsv, $tagValue); } + if ($data === []) { + return; + } + $service->updateSubscriber($listUid, $subscriberUid, $data); } diff --git a/app/Services/MailwizzService.php b/app/Services/MailwizzService.php index d35ea1d..51c2dab 100644 --- a/app/Services/MailwizzService.php +++ b/app/Services/MailwizzService.php @@ -202,7 +202,8 @@ final class MailwizzService $out = []; foreach ($data as $key => $value) { if (is_array($value)) { - $out[$key] = $value; + // Empty arrays are omitted by Laravel's multipart encoder (no KEY[] parts), so Mailwizz never clears checkboxlist fields. + $out[$key] = $value === [] ? '' : $value; continue; } diff --git a/tests/Feature/DestroySubscriberTest.php b/tests/Feature/DestroySubscriberTest.php index 31afe22..938edbe 100644 --- a/tests/Feature/DestroySubscriberTest.php +++ b/tests/Feature/DestroySubscriberTest.php @@ -194,6 +194,68 @@ class DestroySubscriberTest extends TestCase Http::assertSentCount(3); } + public function test_delete_clears_mailwizz_checkboxlist_when_only_configured_tag_is_present(): void + { + Http::fake(function (Request $request) { + $url = $request->url(); + if (str_contains($url, 'search-by-email')) { + return Http::response(['status' => 'success', 'data' => ['subscriber_uid' => 'sub-single-tag']]); + } + if ($request->method() === 'GET' && str_contains($url, '/subscribers/sub-single-tag') && ! str_contains($url, 'search-by-email')) { + return Http::response([ + 'status' => 'success', + 'data' => [ + 'record' => [ + 'TAGS' => 'preregister-source', + 'COUPON' => 'PREREG-OLD', + ], + ], + ]); + } + if ($request->method() === 'PUT' && str_contains($url, '/subscribers/sub-single-tag')) { + $body = $request->body(); + $this->assertStringContainsString('TAGS', $body); + $this->assertStringNotContainsString('preregister-source', $body); + $this->assertStringNotContainsString('TAGS[]', $body); + $this->assertStringContainsString('COUPON', $body); + + return Http::response(['status' => 'success']); + } + + return Http::response(['status' => 'error'], 500); + }); + + $user = User::factory()->create(['role' => 'user']); + $page = $this->makePageForDestroyTest($user); + MailwizzConfig::query()->create([ + 'preregistration_page_id' => $page->id, + 'api_key' => 'fake-api-key', + 'list_uid' => 'list-uid-1', + 'list_name' => 'Main list', + 'field_email' => 'EMAIL', + 'field_first_name' => 'FNAME', + 'field_last_name' => 'LNAME', + 'field_phone' => null, + 'field_coupon_code' => 'COUPON', + 'tag_field' => 'TAGS', + 'tag_value' => 'preregister-source', + ]); + + $subscriber = Subscriber::query()->create([ + 'preregistration_page_id' => $page->id, + 'first_name' => 'Solo', + 'last_name' => 'Tag', + 'email' => 'solo-tag@example.com', + 'coupon_code' => 'PREREG-LOCAL', + ]); + + $response = $this->actingAs($user)->delete(route('admin.pages.subscribers.destroy', [$page, $subscriber])); + + $response->assertRedirect(route('admin.pages.subscribers.index', $page)); + $this->assertDatabaseMissing('subscribers', ['id' => $subscriber->id]); + Http::assertSentCount(3); + } + public function test_delete_removes_coupon_code_in_weeztix_when_configured(): void { Http::fake(function (Request $request) {