klaviyoModule = $klaviyopsModule;
}
/**
* Handle actionCustomerAccount hooks. Includes add and update. Subscribe customer
* to the Klaviyo list selected in module settings if they subscribed, are active
* and aren't deleted.
*
* @param array $params
* @param string $event
* @return void
*/
public function handleActionCustomerAccount(array $params, $event)
{
try {
/** @var ContextService $contextService */
$contextService = $this->klaviyoModule->getService('klaviyops.prestashop_services.context');
/** @var CustomerService $customerService */
$customerService = $this->klaviyoModule->getService('klaviyops.prestashop_services.customer');
/** @var ProfileEventService $profileEventService */
$profileEventService = $this->klaviyoModule->getService('klaviyops.klaviyo_service.profile_event');
$api = new KlaviyoApiWrapper();
$customer = $this->getCustomerFromHookParams($params);
if ($customer === null) {
return;
}
$normalizedContext = $contextService->normalize(); // Current context
$normalizedCustomer = $customerService->normalize(
$customer,
$normalizedContext
);
if (
$customer->newsletter &&
$customer->active &&
!$customer->deleted &&
Configuration::get('KLAVIYO_PRIVATE_API')
) {
try {
$api->subscribeCustomer($customer->email);
} catch (KlaviyoApiException $e) {
/** @var LoggerService $logger */
$logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger');
$logger->log('error', self::ERROR_SUBSCRIBING_CUSTOMER . $customer->email);
}
}
try {
$profileEventService->track($event, $normalizedCustomer);
} catch (KlaviyoApiException $e) {
/** @var LoggerService $logger */
$logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger');
$logger->log('error', self::ERROR_UPDATING_CUSTOM_PROPERTIES . $customer->email);
}
} catch (Exception $e) {
/** @var LoggerService $logger */
$logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger');
if (Validate::isLoadedObject($customer)) {
$logger->log('error', "An error occured in handleActionCustomerAccount for customer {$customer->email}");
} else {
$logger->log('error', 'An error occured in handleActionCustomerAccount');
}
}
}
/**
* Handle actionNewsletterSubscriptionAfter hook used in the default PrestaShop
* Newsletter Subscription module.
*
* @param array $params
*/
public function handleActionNewsletterSubscription(array $params)
{
if (
$params['action'] == static::NEWSLETTER_SUBSCRIPTION &&
!$params['error'] &&
Configuration::get('KLAVIYO_PRIVATE_API')
) {
try {
$api = new KlaviyoApiWrapper();
$api->subscribeCustomer($params['email']);
} catch (KlaviyoApiException $e) {
$logger = new LoggerService();
$logger->log('error', self::ERROR_SUBSCRIBING_CUSTOMER . $params['email']);
}
}
}
/**
* Return new Webservice Resource definition to use specific management interface.
*
* @param array $resources
* @return array[]
*/
public function handleAddWebserviceResources(array $resources)
{
return [
'klaviyo' => [
'description' => 'Klaviyo custom endpoints',
'specific_management' => true,
]
];
}
/**
* Add SMS Consent to customer address form
*
* @param array $params
* @return array
*/
public function handleAdditionalCustomerAddressFields(array $params)
{
try {
if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) {
throw new KlaviyoApiException('Sync SMS Subscribers disabled');
}
$trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER');
if (!$trigger) {
throw new KlaviyoApiException('SMS Subscribe trigger not configured');
}
$idLang = (int) Context::getContext()->language->id;
$smsConsentLabel = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_CONSENT_LABEL', $idLang);
$smsConsentDisclosure = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_CONSENT_DISCLOSURE_TEXT', $idLang);
$label = "{$smsConsentLabel}
{$smsConsentDisclosure}";
$formField = new FormField();
$formField->setName('kl_sms_consent');
$formField->setType('checkbox');
$formField->setLabel($label);
$formField->setRequired(false);
return [$formField];
} catch (KlaviyoApiException $e) {
return [];
}
}
/**
* Subscribe mobile to klaviyo list
*
* @param array $params
* @return void
*/
public function handleActionSubmitCustomerAddressForm(array $params)
{
if (
!empty($params['address']) &&
is_object($params['address']) &&
Configuration::get('KLAVIYO_PRIVATE_API') &&
isset($params['address']->kl_sms_consent) &&
!empty($params['address']->kl_sms_consent)
) {
$context = Context::getContext();
if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) {
return;
}
$trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER');
if ($trigger === 'place_order') {
// Save information in cookie to be triggered after payment (place order)
$cookie = $context->cookie;
$addressFields = [
$params['address']->phone ?? '',
$params['address']->phone_mobile ?? '',
];
$addressToHash = implode('', array_map('strval', $addressFields));
$cookie->kl_sms_consent = Tools::hash($addressToHash);
return;
}
// Trigger start checkout
$mobile = $params['address']->phone_mobile ?? $params['address']->phone ?? '';
$isoCode = '';
if (!empty($params['address']->id_country)) {
$country = new Country($params['address']->id_country);
if (Validate::isLoadedObject($country)) {
$isoCode = $country->iso_code;
}
}
$attributes = ['mobile' => $mobile];
$customer = new Customer((int)$params['address']->id_customer);
if (!Validate::isLoadedObject($customer)) {
$customer = $context->customer;
}
if (Validate::isLoadedObject($customer)) {
$attributes['email'] = $customer->email;
}
$this->sendSMSConsentRequestAPI($attributes, $isoCode);
}
}
/**
* Subscribe mobile to klaviyo list (place order trigger)
*
* @param array $params
* @return void
*/
public function handleDisplayOrderConfirmation($params)
{
$cookie = Context::getContext()->cookie;
if (
!empty($params['order']) &&
Validate::isLoadedObject($params['order']) &&
Configuration::get('KLAVIYO_PRIVATE_API') &&
isset($cookie->kl_sms_consent) &&
!empty($cookie->kl_sms_consent)
) {
if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) {
return;
}
$trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER');
if ($trigger !== 'place_order') {
return;
}
// Check consent to invoice address
$consentAddress = null;
foreach (
[
$params['order']->id_address_invoice,
$params['order']->id_address_delivery
] as $idAddress
) {
$address = new Address((int)$idAddress);
if (Validate::isLoadedObject($address)) {
$addressFields = [
$address->phone ?? '',
$address->phone_mobile ?? '',
];
$addressToHash = implode('', array_map('strval', $addressFields));
$addressHash = Tools::hash($addressToHash);
if ($cookie->kl_sms_consent === $addressHash) {
$consentAddress = $address;
break;
}
}
}
// Get mobile on invoice address
if (is_null($consentAddress)) {
return;
}
$mobile = $address->phone_mobile ?? $address->phone ?? '';
$isoCode = '';
if (!empty($address->id_country)) {
$country = new Country($address->id_country);
if (Validate::isLoadedObject($country)) {
$isoCode = $country->iso_code;
}
}
$attributes = ['mobile' => $mobile];
$customer = new Customer((int)$params['order']->id_customer);
if (Validate::isLoadedObject($customer)) {
$attributes['email'] = $customer->email;
}
$this->sendSMSConsentRequestAPI($attributes, $isoCode);
}
}
/**
* Extract Customer object from hook params.
*
* @param array $hookParams
* @return Customer|null
*/
private function getCustomerFromHookParams(array $hookParams)
{
if (isset($hookParams['customer']) && $hookParams['customer'] instanceof CustomerCore) {
return $hookParams['customer'];
}
if (isset($hookParams['newCustomer']) && $hookParams['newCustomer'] instanceof CustomerCore) {
return $hookParams['newCustomer'];
}
return null;
}
/**
* Subscribe mobile to a list
*
* @param array $address
* @param string $isoCode
* @return void
*/
private function sendSMSConsentRequestAPI($address = [], $isoCode = '')
{
if (empty($address) || !is_array($address)) {
return;
}
if (empty($address['mobile'])) {
return;
}
try {
$address['mobile'] = KlaviyoUtils::formatPhone($address['mobile'], $isoCode);
$api = new KlaviyoApiWrapper();
$api->subscribeSMSCustomer($address);
} catch (KlaviyoApiException $e) {
$logger = new LoggerService();
$logger->log('error', self::ERROR_SUBSCRIBING_SMS_CUSTOMER . $address['mobile']);
}
}
}