From 935b1d02f9c3873567b0b530054fa26ce7383330 Mon Sep 17 00:00:00 2001 From: Konstantinos Arvanitakis Date: Fri, 25 Sep 2026 14:12:55 +0300 Subject: [PATCH] Feature: Adding Customer Recovery Consent to core, assigning it to the customer --- .../Events/CustomerRecoveryConsentSet.php | 25 ++++++++++++ .../Listeners/LogCustomerAccountActivity.php | 18 +++++++++ .../Services/CustomerAccountService.php | 38 +++++++++++++++++++ src/Providers/CustomerServiceProvider.php | 2 + 4 files changed, 83 insertions(+) create mode 100644 src/Customer/Events/CustomerRecoveryConsentSet.php diff --git a/src/Customer/Events/CustomerRecoveryConsentSet.php b/src/Customer/Events/CustomerRecoveryConsentSet.php new file mode 100644 index 0000000..396f7ef --- /dev/null +++ b/src/Customer/Events/CustomerRecoveryConsentSet.php @@ -0,0 +1,25 @@ +causer, ); } + + /** + * CustomerRecoveryConsentSet carries only the new value, not a + * before/after snapshot the way CustomerProfileUpdated does — but + * CustomerAccountService::setRecoveryConsent() only ever dispatches it + * once the value has actually changed, so "old" is trivially the + * opposite of $event->consent. + */ + public function handleRecoveryConsentSet(CustomerRecoveryConsentSet $event): void + { + $this->activityLog->updated( + $event->customer, + ['recovery_consent' => ! $event->consent], + ['recovery_consent' => $event->consent], + $event->causer, + ); + } } diff --git a/src/Customer/Services/CustomerAccountService.php b/src/Customer/Services/CustomerAccountService.php index 86ed31a..d97dd4e 100644 --- a/src/Customer/Services/CustomerAccountService.php +++ b/src/Customer/Services/CustomerAccountService.php @@ -13,6 +13,7 @@ use Modules\Core\Customer\Events\CustomerAddressCreated; use Modules\Core\Customer\Events\CustomerAddressDeleted; use Modules\Core\Customer\Events\CustomerAddressUpdated; use Modules\Core\Customer\Events\CustomerProfileUpdated; +use Modules\Core\Customer\Events\CustomerRecoveryConsentSet; use Modules\Core\Customer\Exceptions\AddressNotFoundException; use Modules\Core\Customer\Exceptions\OrderNotFoundException; use Modules\Core\Customer\Models\Customer; @@ -235,6 +236,43 @@ class CustomerAccountService return $customer; } + /** + * The account's standing "email me a reminder if I don't finish my + * order" opt-in — same meta shape Checkout\Services\CheckoutService:: + * setRecoveryConsent() writes on the current CART (recovery_consent, + * recovery_consent_at, recovery_consent_policy_version), written here + * onto the CUSTOMER instead, so it survives across carts/sessions as a + * standing account preference. The two are independent: opting out on + * the customer doesn't retroactively change a cart already opted in, + * and vice versa — a caller that wants both kept in sync (e.g. 3dealer + * applying a customer's standing preference to the current cart too) + * calls both services itself. + * + * A no-op (no write, no event) when $consent already matches what's + * stored — unlike updateProfile()'s address/profile writes, which + * always write and dispatch even when nothing actually changed. + */ + public function setRecoveryConsent(Authenticatable $user, bool $consent): Customer + { + $customer = $this->customerOrFail($user); + + if ((bool) data_get($customer->meta, 'recovery_consent') === $consent) { + return $customer; + } + + $customer->meta = [ + ...($customer->meta?->toArray() ?? []), + 'recovery_consent' => $consent, + 'recovery_consent_at' => $consent ? now()->toIso8601String() : null, + 'recovery_consent_policy_version' => $consent ? config('legal.privacy_policy_version') : null, + ]; + $customer->save(); + + Event::dispatch(new CustomerRecoveryConsentSet($customer, $consent, $user)); + + return $customer; + } + /** * @throws LogicException if $user has no paired Customer at all — * distinct from AddressNotFoundException/OrderNotFoundException diff --git a/src/Providers/CustomerServiceProvider.php b/src/Providers/CustomerServiceProvider.php index 96940c1..860abfd 100644 --- a/src/Providers/CustomerServiceProvider.php +++ b/src/Providers/CustomerServiceProvider.php @@ -12,6 +12,7 @@ use Modules\Core\Customer\Events\CustomerAddressCreated; use Modules\Core\Customer\Events\CustomerAddressDeleted; use Modules\Core\Customer\Events\CustomerAddressUpdated; use Modules\Core\Customer\Events\CustomerProfileUpdated; +use Modules\Core\Customer\Events\CustomerRecoveryConsentSet; use Modules\Core\Customer\Listeners\ClaimGuestOrdersOnLogin; use Modules\Core\Customer\Listeners\CreateCustomerForUser; use Modules\Core\Customer\Listeners\LogCustomerAccountActivity; @@ -43,5 +44,6 @@ class CustomerServiceProvider extends ServiceProvider Event::listen(CustomerAddressUpdated::class, [LogCustomerAccountActivity::class, 'handleAddressUpdated']); Event::listen(CustomerAddressDeleted::class, [LogCustomerAccountActivity::class, 'handleAddressDeleted']); Event::listen(CustomerProfileUpdated::class, [LogCustomerAccountActivity::class, 'handleProfileUpdated']); + Event::listen(CustomerRecoveryConsentSet::class, [LogCustomerAccountActivity::class, 'handleRecoveryConsentSet']); } }