Current File : /var/www/vinorea/modules/klaviyopsautomation/classes/KlaviyoServices/OrderEventService.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
*/
namespace KlaviyoPs\Classes\KlaviyoServices;
if (!defined('_PS_VERSION_')) {
exit;
}
use ArrayObject;
use Exception;
use KlaviyoV3Sdk\Exception\KlaviyoException;
use KlaviyoPs\Classes\BusinessLogicServices\OrderPayloadService;
use KlaviyoPs\Classes\KlaviyoApiWrapper;
use KlaviyoPs\Classes\KlaviyoUtils;
use KlaviyoPs\Classes\KlaviyoValue;
use KlaviyoPs\Classes\PrestashopServices\OrderService;
use KlaviyoPs\Classes\PrestashopServices\ProductService;
use Tools;
class OrderEventService
{
/**
* @var KlaviyoApiWrapper
*/
protected $klaviyoApiWrapper;
/**
* @var OrderService
*/
protected $orderService;
/**
* @var ProductService
*/
protected $productService;
/**
* @var CustomerEventService
*/
protected $customerEventService;
public function __construct(
KlaviyoApiWrapper $klaviyoApiWrapper,
OrderService $orderService,
ProductService $productService,
CustomerEventService $customerEventService
) {
$this->klaviyoApiWrapper = $klaviyoApiWrapper;
$this->orderService = $orderService;
$this->productService = $productService;
$this->customerEventService = $customerEventService;
}
/**
* Send Order event into Klaviyo in real time
*
* @param ArrayObject $order
* @return void
* @throws KlaviyoException
*/
public function track(ArrayObject $order)
{
$orderObject = $this->orderService->getObject($order);
$mappedOrderStatus = OrderPayloadService::getMappedOrderStatusValue($orderObject);
if ($mappedOrderStatus === null) {
return;
}
$customer = $this->orderService->getCustomer($order);
$orderTime = $this->orderService->getDateUpdate($order);
$this->klaviyoApiWrapper->trackEvent([
'event' => $this->buildEvent($mappedOrderStatus),
'customer_properties' => $this->buildCustomerPayload($order, $customer),
'properties' => $this->buildPayload($order),
'time' => $orderTime - 1, // -1 because we want this event before Ordered Product events
]);
}
/**
* Build properties payload for an order to send it into Klaviyo
*
* @param ArrayObject $order
* @return array
* @throws KlaviyoException
*/
public function buildPayload(ArrayObject $order)
{
$orderObject = $this->orderService->getObject($order);
$extraData = OrderPayloadService::buildPayload($orderObject);
$products = $this->orderService->getProducts($order);
return [
'$value' => $this->orderService->getOrderTotal($order),
'$event_id' => $order['id_order'],
'$currency_code' => $this->orderService->getCurrencyCode($order),
'$extra' => $extraData,
'$service' => KlaviyoValue::SERVICE,
'integration_key' => KlaviyoValue::SERVICE,
'Categories' => $this->buildCategories($order),
'ItemCount' => count($products),
'Items' => $this->buildItems($order),
'ItemsDetail' => $this->buildItemsDetail($order),
'ShopId' => $order['id_shop'],
'LanguageId' => $order['id_lang'],
'LanguageIso' => $this->orderService->getIsoLang($order),
'TotalDiscounts' => $this->orderService->getOrderTotalDiscount($order),
'DiscountCodes' => $extraData['applied_cart_rule_codes'],
'Tags' => $this->buildTags($order),
'OrderStatus' => $this->orderService->getOrderStateTitle($order),
'Shipping' => $this->buildShippingData($order),
'external_catalog_id' => KlaviyoUtils::formatKlaviyoCatalogIdentifier($order['id_shop'], $order['id_lang']),
];
}
/**
* @param ArrayObject $order
* @return string[]
*/
protected function buildCategories(ArrayObject $order)
{
$res = [];
$products = $this->orderService->getProducts($order);
foreach ($products as $productDetail) {
$res = array_merge(
$res,
$this->productService->getCategoryNames($productDetail, $order)
);
}
return Tools::arrayUnique($res);
}
/**
* @param ArrayObject $order
* @return string[]
*/
protected function buildTags(ArrayObject $order)
{
$res = [];
$products = $this->orderService->getProducts($order);
foreach ($products as $productDetail) {
$res = array_merge(
$res,
$this->productService->getTags($productDetail, $order)
);
}
return Tools::arrayUnique($res);
}
/**
* @param ArrayObject $order
* @return string[]
*/
protected function buildItems(ArrayObject $order)
{
$res = [];
$products = $this->orderService->getProducts($order);
foreach ($products as $productDetail) {
$res[] = $productDetail['product_name'];
}
return $res;
}
/**
* @param ArrayObject $order
* @return array
*/
protected function buildItemsDetail(ArrayObject $order)
{
$res = [];
$products = $this->orderService->getProducts($order);
foreach ($products as $productDetail) {
$data = [
'ProductID' => $productDetail['id_product'],
'ConstructedVariantID' => KlaviyoUtils::formatKlaviyoVariantIdentifier($productDetail['id_product'], $productDetail['id_product_attribute']),
'SKU' => $productDetail['product_reference'],
'ProductName' => $productDetail['product_name'],
'ItemPrice' => KlaviyoUtils::formatPrice($productDetail['unit_price_tax_incl']),
'RowTotal' => KlaviyoUtils::formatPrice($productDetail['total_price_tax_incl']),
'Quantity' => (int)$productDetail['product_quantity'],
'IsVirtual' => $this->productService->isVirtual($productDetail),
];
// These data allow to handle transactional email "download_product" of PrestaShop in Klaviyo
$downloadData = $this->orderService->getDownloadData(
$order,
$productDetail
);
if ($downloadData !== null) {
$data['VirtualInfo'] = [
'DownloadLink' => $downloadData['link'],
'DownloadFilename' => $downloadData['filename'],
'DownloadDeadline' => $downloadData['deadline'],
];
}
$res[] = $data;
}
return $res;
}
/**
* @param ArrayObject $order
* @return array|null
*/
protected function buildShippingData(ArrayObject $order)
{
try {
$shippingData = $this->orderService->getShippingData($order);
} catch (Exception $e) {
return null;
}
return [
'ShippingMethod' => $shippingData['carrier_name'] ?? null,
'TrackingNumber' => $shippingData['tracking_number'] ?? null,
];
}
/**
* @param string $mappedOrderStatus
* @return string
* @throws KlaviyoException must never happen
*/
protected function buildEvent($mappedOrderStatus)
{
switch ($mappedOrderStatus) {
case 'klaviyops-statuses-placed':
return 'Placed Order Transactional';
case 'klaviyops-statuses-refunded':
return 'Refunded Order Transactional';
case 'klaviyops-statuses-canceled':
return 'Cancelled Order Transactional';
case 'klaviyops-statuses-fulfilled':
return 'Fulfilled Order Transactional';
default:
throw new KlaviyoException('Mapped order status is not valid');
}
}
/**
* @return array
*/
protected function buildCustomerPayload(
ArrayObject $order,
ArrayObject $customer
) {
$currency = $this->orderService->getCurrencyCode($order);
$result = $this->customerEventService->buildPayload($customer);
if ($currency !== null) {
$result['PrestaShop Recent Order Currency'] = $currency;
}
return $result;
}
}