Current File : /var/www/vinorea/modules/klaviyopsautomation/controllers/front/buildReclaim.php |
<?php
/**
* Klaviyo
*
* NOTICE OF LICENSE
*
* This source file is subject to the Commercial License
* you can't distribute, modify or sell this code
*
* DISCLAIMER
*
* Do not edit or add to this file
* If you need help please contact extensions@klaviyo.com
*
* @author Klaviyo
* @copyright Klaviyo
* @license commercial
*/
if (!defined('_PS_VERSION_')) {
exit;
}
use KlaviyoPs\Classes\KlaviyoApiWrapper;
use KlaviyoPs\Classes\KlaviyoServices\CustomerEventService;
use KlaviyoPs\Classes\KlaviyoUtils;
use KlaviyoPs\Classes\KlaviyoValue;
use KlaviyoPs\Classes\PrestashopServices\ContextService;
use KlaviyoPs\Classes\PrestashopServices\CustomerService;
use KlaviyoPs\Classes\PrestashopServices\LoggerService;
use KlaviyoPs\KlaviyoPsAjaxModuleFrontController;
use KlaviyoV3Sdk\Exception\KlaviyoException;
/**
* @property Klaviyops $module
*
* Class KlaviyoPsBuildReclaimModuleFrontController
*
* Available at /klaviyo/reclaim/build-reclaim. Fetch a cart from the db and reload it for the customer.
*/
class KlaviyoPsBuildReclaimModuleFrontController extends KlaviyoPsAjaxModuleFrontController
{
/**
* @inheritDoc
*/
protected function ajaxProcess()
{
if (!Tools::getValue('email') || !Tools::getValue('cartId')) {
$this->errors[] = 'Unable to send event, invalid email or cart ID.';
return;
}
if (
$this->sendStartedCheckoutEvent(
(int) Tools::getValue('cartId'),
Tools::getValue('email')
)
) {
$this->returnData[] = 'Sent Started Checkout event to Klaviyo.';
} else {
$this->errors[] = 'Failed to send Started Checkout event to Klaviyo.';
}
}
/**
* @inheritDoc
*/
protected function isValidRequest()
{
if (Tools::getValue('token') !== Tools::getToken()) {
$this->errors[] = 'Invalid request, token does not match.';
}
if (!filter_var(Tools::getValue('email'), FILTER_VALIDATE_EMAIL)) {
$this->errors[] = 'Invalid request, email address is not a valid email.';
}
return parent::isValidRequest();
}
// NOTE: Temporary function until we add webhooks at which point we'll use the CartPayloadService and then build
// the event app-side.
/**
* @param $cartId int
* @return bool
* @throws PrestaShopDatabaseException
* @throws PrestaShopException
*/
private function sendStartedCheckoutEvent($cartId, $email)
{
try {
/** @var KlaviyoApiWrapper $api */
$api = $this->module->getService('klaviyops.klaviyo_api_wrapper');
$shop = $this->context->shop;
$shop_id = $shop->id;
$cart = new Cart($cartId, $this->context->language->id);
$cartLineItemsArray = KlaviyoUtils::buildCartLineItemsArray($cart);
// NOTE: This hook fires on each step of the checkout process.
// Cart IDs are unique in db so we can use as $event_id.
$eventConfig = array(
'event' => '$started_checkout',
'customer_properties' => $this->buildCustomerPayload($email),
'properties' => array(
'$event_id' => $cartId,
'$service' => KlaviyoValue::SERVICE,
'integration_key' => KlaviyoValue::SERVICE,
'$value' => (float) $cart->getOrderTotal(),
'$extra' => array(
'line_items' => $cartLineItemsArray['lineItems']
),
'Language' => $this->context->language->id,
'CartID' => $cartId,
'Items' => $cartLineItemsArray['itemNames'],
'ItemCount' => $cartLineItemsArray['itemCount'],
'TotalDiscounts' => (float) number_format($this->getCartDiscountTotal($cart), 2),
'Categories' => $cartLineItemsArray['uniqueCategories'],
'Tags' => $cartLineItemsArray['uniqueTags'],
'ShopId' => $shop_id,
'ReclaimCartUrl' => KlaviyoUtils::buildReclaimCartUrl($cart),
'external_catalog_id' => KlaviyoUtils::formatKlaviyoCatalogIdentifier($shop_id, $this->context->language->id),
),
);
return $api->trackEvent($eventConfig);
} catch (Exception $e) {
/** @var LoggerService $logger */
$logger = $this->module->getService('klaviyops.prestashop_services.logger');
$logger->error("{$e->getCode()} error while sending Started Checkout event. {$e->getMessage()}");
return false;
}
}
/**
* Calculate total discount value for cart.
*
* @param $cart
* @return float
*/
private function getCartDiscountTotal($cart)
{
$discount_total = 0.0;
$cart_rules = $cart->getCartRules(CartRule::FILTER_ACTION_ALL);
foreach ($cart_rules as $rule) {
$discount_total += $rule['value_real'];
}
return $discount_total;
}
/**
* @param string $email
* @return Customer|null
*/
private function getCustomerByEmail($email)
{
$customer = new Customer();
$customer = $customer->getByEmail($email);
if (!Validate::isLoadedObject($customer)) {
return null;
}
return $customer;
}
/**
* @param string $email
* @return array
* @throws KlaviyoException
*/
private function buildCustomerPayload($email)
{
/** @var ContextService $contextService */
$contextService = $this->module->getService('klaviyops.prestashop_services.context');
/** @var CustomerService $customerService */
$customerService = $this->module->getService('klaviyops.prestashop_services.customer');
/** @var CustomerEventService $customerEventService */
$customerEventService = $this->module->getService('klaviyops.klaviyo_service.customer_event_service');
$customer = $this->getCustomerByEmail($email);
// When the customer is not connected in the checkout, he set his mail in the first step
// Then, started-checkout.js send a request to this controller with the mail
// To keep this feature in the case where the customer has not yet an account
// We need to build a normalized guest customer Object with the mail only
// Then, CustomerEventService will build "restricted" data as guest customer
if ($customer === null) {
$customer = [
'email' => $email,
];
}
$normalizedContext = $contextService->normalize(); // Current context
$normalizedCustomer = $customerService->normalize(
$customer,
$normalizedContext
);
return $customerEventService->buildPayload($normalizedCustomer);
}
}
class KlaviyoPsAutomationBuildReclaimModuleFrontController extends KlaviyoPsBuildReclaimModuleFrontController
{
}