Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Adapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Http\HttpClient;
class BillingAdapter
{
private const BILLING_URL = 'https://billing-api.distribution.prestashop.net/v1/';
private const BILLING_PREPROD_URL = 'https://billing-api.distribution-preprod.prestashop.net/v1/';
/**
* @var string
*/
private $jwt;
/**
* @var string
*/
private $url;
/**
* @var bool
*/
private $isSandbox;
public function __construct($jwt, $isSandbox, $usePreprod)
{
$this->jwt = $jwt;
$this->isSandbox = $isSandbox;
$this->url = $usePreprod ? self::BILLING_PREPROD_URL : self::BILLING_URL;
}
public function getCurrentSubscription($shopId, $productId)
{
$httpClient = new HttpClient($this->url);
$headers = [
'Accept: application/json',
'Authorization: Bearer ' . $this->jwt,
'Content-Type: application/json',
'User-Agent : module-lib-billing v3 (' . $productId . ')',
];
if ($this->isSandbox === true) {
$headers[] = 'sandbox: true';
}
$httpClient->setHeaders($headers);
return $httpClient->get('/customers/' . $shopId . '/subscriptions/' . $productId);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Adapter;
use Configuration;
class ConfigurationAdapter
{
/**
* @var int
*/
private $shopId;
public function __construct($shopId)
{
$this->shopId = $shopId;
}
public function get($key, $idLang = null, $idShopGroup = null, $idShop = null, $default = false)
{
if ($idShop === null) {
$idShop = $this->shopId;
}
return Configuration::get($key, $idLang, $idShopGroup, $idShop, $default);
}
public function updateValue($key, $values, $html = false, $idShopGroup = null, $idShop = null)
{
if ($idShop === null) {
$idShop = $this->shopId;
}
return Configuration::updateValue($key, $values, $html, $idShopGroup, $idShop);
}
public function deleteByName($key)
{
return Configuration::deleteByName($key);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,80 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Buffer;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
class TemplateBuffer
{
/**
* @var Session
*/
private $session;
/**
* @param string $userId
*/
public function init($userId)
{
$this->session = new Session(
new MockFileSessionStorage(
\_PS_CACHE_DIR_ . '/psxmarketingwithgoogle_sessions',
'conversionaction'
)
);
$this->session->setId($userId);
$this->session->start();
register_shutdown_function([$this, 'save']);
}
/**
* add data to the buffer
*
* @param string $data
*
* @return void
*/
public function add($data)
{
$this->session->getFlashBag()->add('gtag_events', $data);
}
/**
* return buffer content and reset it
*
* @return string
*/
public function flush(): string
{
$data = '';
foreach ($this->session->getFlashBag()->get('gtag_events', []) as $message) {
$data .= $message;
}
return $data;
}
public function save(): void
{
$this->session->save();
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,232 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Builder;
use Carrier;
use Currency;
use Language;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\Carrier as DTOCarrier;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\CarrierDetail;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\CarrierTax;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\CarrierRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\CountryRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\StateRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\TaxRepository;
use RangePrice;
use RangeWeight;
class CarrierBuilder
{
/**
* @var CarrierRepository
*/
private $carrierRepository;
/**
* @var CountryRepository
*/
private $countryRepository;
/**
* @var StateRepository
*/
private $stateRepository;
/**
* @var TaxRepository
*/
private $taxRepository;
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
public function __construct(
CarrierRepository $carrierRepository,
CountryRepository $countryRepository,
StateRepository $stateRepository,
TaxRepository $taxRepository,
ConfigurationAdapter $configurationAdapter
) {
$this->carrierRepository = $carrierRepository;
$this->countryRepository = $countryRepository;
$this->stateRepository = $stateRepository;
$this->taxRepository = $taxRepository;
$this->configurationAdapter = $configurationAdapter;
}
public function buildCarriers(array $carriers, Language $lang, Currency $currency, string $weightUnit): array
{
$carrierLines = [];
foreach ($carriers as $carrier) {
$carrierLines[] = self::buildCarrier(
new Carrier($carrier['id_carrier'], $lang->id),
$currency->iso_code,
$weightUnit
);
}
$formattedCarriers = [];
/** @var DTOCarrier $carrierLine */
foreach ($carrierLines as $carrierLine) {
$formattedCarriers = array_merge($formattedCarriers, $carrierLine->jsonSerialize());
}
return $formattedCarriers;
}
public function buildCarrier(Carrier $carrier, string $currencyIsoCode, string $weightUnit): DTOCarrier
{
$carrierLine = new DTOCarrier();
$freeShippingStartsAtPrice = (float) $this->configurationAdapter->get('PS_SHIPPING_FREE_PRICE');
$freeShippingStartsAtWeight = (float) $this->configurationAdapter->get('PS_SHIPPING_FREE_WEIGHT');
$carrierLine->setFreeShippingStartsAtPrice($freeShippingStartsAtPrice);
$carrierLine->setFreeShippingStartsAtWeight($freeShippingStartsAtWeight);
$carrierLine->setShippingHandling($this->getShippingHandlePrice((bool) $carrier->shipping_handling));
$countryIsoCodes = [];
foreach ($carrier->getZones() as $zone) {
$countryIsoCodes = array_merge($countryIsoCodes, $this->countryRepository->getCountryIsoCodesByZoneId($zone['id_zone']));
}
$carrierLine
->setIdCarrier((int) $carrier->id)
->setIdReference((int) $carrier->id_reference)
->setName($carrier->name)
->setTaxesRatesGroupId((int) $carrier->getIdTaxRulesGroup())
->setUrl((string) $carrier->url)
->setActive($carrier->active)
->setDeleted($carrier->deleted)
->setDisableCarrierWhenOutOfRange((bool) $carrier->range_behavior)
->setIsModule($carrier->is_module)
->setIsFree($carrier->is_free)
->setShippingExternal($carrier->shipping_external)
->setNeedRange($carrier->need_range)
->setExternalModuleName((string) $carrier->external_module_name)
->setMaxWidth($carrier->max_width)
->setMaxHeight($carrier->max_height)
->setMaxDepth($carrier->max_depth)
->setMaxWeight($carrier->max_weight)
->setGrade($carrier->grade)
->setDelay($carrier->delay)
->setCurrency($currencyIsoCode)
->setWeightUnit($weightUnit)
->setCountryIsoCodes($countryIsoCodes);
$deliveryPriceByRanges = $this->carrierRepository->getDeliveryPriceByRange($carrier);
$carrierLine->setCarrierTaxes($this->buildCarrierTaxes($carrier));
if (!$deliveryPriceByRanges) {
return $carrierLine;
}
$carrierDetails = [];
foreach ($deliveryPriceByRanges as $deliveryPriceByRange) {
$range = $this->carrierRepository->getCarrierRange($deliveryPriceByRange);
if (!$range) {
continue;
}
foreach ($deliveryPriceByRange['zones'] as $zone) {
$carrierDetail = $this->buildCarrierDetails($carrier, $range, $zone, $deliveryPriceByRange);
if ($carrierDetail) {
$carrierDetails[] = $carrierDetail;
}
}
}
$carrierLine->setCarrierDetails($carrierDetails);
return $carrierLine;
}
/**
* @param Carrier $carrier
* @param RangeWeight|RangePrice $range
* @param array $zone
* @param array $deliveryPriceByRange
*
* @return ?CarrierDetail
*/
private function buildCarrierDetails(Carrier $carrier, $range, array $zone, array $deliveryPriceByRange)
{
$rangeTable = $carrier->getRangeTable();
$carrierDetailId = isset($deliveryPriceByRange['id_range_weight']) ? $deliveryPriceByRange['id_range_weight'] : $deliveryPriceByRange['id_range_price'];
$carrierDetail = new CarrierDetail();
$carrierDetail->setShippingMethod($rangeTable);
$carrierDetail->setCarrierDetailId($carrierDetailId);
$carrierDetail->setDelimiter1($range->delimiter1);
$carrierDetail->setDelimiter2($range->delimiter2);
$carrierDetail->setPrice($zone['price']);
$carrierDetail->setCarrierReference($carrier->id_reference);
$carrierDetail->setZoneId($zone['id_zone']);
$carrierDetail->setRangeId($range->id);
$countryIsoCodes = $this->countryRepository->getCountryIsoCodesByZoneId($zone['id_zone']);
if (!$countryIsoCodes) {
return null;
}
$carrierDetail->setCountryIsoCodes($countryIsoCodes);
$stateIsoCodes = $this->stateRepository->getStateIsoCodesByZoneId($zone['id_zone']);
$carrierDetail->setStateIsoCodes($stateIsoCodes);
return $carrierDetail;
}
/**
* @return array<CarrierTax>
*/
private function buildCarrierTaxes(Carrier $carrier): array
{
$taxRulesGroupId = (int) $carrier->getIdTaxRulesGroup();
$carrierTaxesByZone = $this->taxRepository->getCarrierTaxesByTaxRulesGroupId($taxRulesGroupId);
if (!$carrierTaxesByZone[0]['country_iso_code']) {
return [];
}
$carrierTaxesByZone = $carrierTaxesByZone[0];
$carrierTax = new CarrierTax();
$carrierTax->setCarrierReference($carrier->id_reference);
$carrierTax->setTaxRulesGroupId($taxRulesGroupId);
$carrierTax->setCountryIsoCode((string) $carrierTaxesByZone['country_iso_code']);
$carrierTax->setStateIsoCodes((string) $carrierTaxesByZone['state_iso_code']);
$carrierTax->setTaxRate($carrierTaxesByZone['rate']);
return [
$carrierTax,
];
}
private function getShippingHandlePrice(bool $shippingHandling): float
{
if ($shippingHandling) {
return (float) $this->configurationAdapter->get('PS_SHIPPING_HANDLING');
}
return 0.0;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,76 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
class EnhancedConversionToggle
{
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
public function __construct(
ConfigurationAdapter $configurationAdapter
) {
$this->configurationAdapter = $configurationAdapter;
}
public function enable(): bool
{
$snippet = base64_decode($this->configurationAdapter->get(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG
));
$alteredSnippet = (new SnippetUpdater($snippet))
->addEnhancedConversion()
->getSnippet();
return $this->configurationAdapter->updateValue(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG,
base64_encode($alteredSnippet)
) && $this->configurationAdapter->updateValue(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_ENHANCED_STATUS,
true
);
}
public function disable(): bool
{
$snippet = base64_decode($this->configurationAdapter->get(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG
));
$alteredSnippet = (new SnippetUpdater($snippet))
->removeEnhancedConversion()
->getSnippet();
return $this->configurationAdapter->updateValue(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG,
base64_encode($alteredSnippet)
) && $this->configurationAdapter->updateValue(
Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_ENHANCED_STATUS,
false
);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
class Hasher
{
/**
* @param string|null $data
*
* @return string|null
*/
public static function hash($data)
{
if (!$data) {
return null;
}
return hash('sha256', $data, false);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
use Brick\PhoneNumber\PhoneNumber;
use Brick\PhoneNumber\PhoneNumberFormat;
use Exception;
class Normalizer
{
/**
* @param string|null $data
* @param string|null $additionalNormalization
*
* @return string|null
*/
public static function normalize($data, $additionalNormalization = null)
{
if (empty($data)) {
return null;
}
$data = trim(strtolower($data));
if ($additionalNormalization === 'phone') {
return self::normalizePhoneNumber($data);
}
return $data;
}
public static function normalizePhoneNumber(string $data): string
{
$dataWithPlusAndNumbers = preg_replace('/([-\s\(\)])/', '', $data);
return preg_replace('/^(0{2})/', '+', $dataWithPlusAndNumbers);
}
/**
* @param string|null $data
* @param string $countryCode
*
* @return string|null
*/
public static function normalizeInE164($data, $countryCode)
{
if (empty($data)) {
return null;
}
try {
return PhoneNumber::parse($data, $countryCode)->format(PhoneNumberFormat::E164);
} catch (Exception $e) {
return $data;
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
class SnippetUpdater
{
/**
* @var string
*/
private $snippet;
public function __construct(
string $originalSnippet
) {
$this->snippet = $originalSnippet;
}
public function addEnhancedConversion(): self
{
$this->snippet = preg_replace("/(gtag\('config', 'AW-[0-9]+')()(\);)/im", '${1}, {\'allow_enhanced_conversions\': true}${3}', $this->snippet);
return $this;
}
public function removeEnhancedConversion(): self
{
$this->snippet = str_replace(", {'allow_enhanced_conversions': true}", '', $this->snippet);
return $this;
}
public function getSnippet(): string
{
return $this->snippet;
}
}

View File

@@ -0,0 +1,278 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
use JsonSerializable;
class UserAddressData implements JsonSerializable
{
/**
* @var string|null
*/
private $firstName;
/**
* @var string|null
*/
private $lastName;
/**
* @var string|null
*/
private $street;
/**
* @var string|null
*/
private $city;
/**
* @var string|null
*/
private $region;
/**
* @var string|null
*/
private $postalCode;
/**
* @var string|null
*/
private $country;
public function jsonSerialize(): array
{
$data = [];
if (!empty($this->firstName)) {
$data['sha256_first_name'] = $this->firstName;
}
if (!empty($this->lastName)) {
$data['sha256_last_name'] = $this->lastName;
}
if (!empty($this->street)) {
$data['street'] = $this->street;
}
if (!empty($this->city)) {
$data['city'] = $this->city;
}
if (!empty($this->region)) {
$data['region'] = $this->region;
}
if (!empty($this->postalCode)) {
$data['postal_code'] = $this->postalCode;
}
if (!empty($this->country)) {
$data['country'] = $this->country;
}
return $data;
}
/**
* @return bool
*/
public function isEmpty()
{
foreach (get_object_vars($this) as $value) {
if (!empty($value)) {
return false;
}
}
return true;
}
/**
* Get the value of firstName
*
* @return string
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* Set the value of firstName
*
* @param string|null $firstName
*
* @return self
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
/**
* Get the value of lastName
*
* @return string
*/
public function getLastName()
{
return $this->lastName;
}
/**
* Set the value of lastName
*
* @param string|null $lastName
*
* @return self
*/
public function setLastName($lastName)
{
$this->lastName = $lastName;
return $this;
}
/**
* Get the value of street
*
* @return string
*/
public function getStreet()
{
return $this->street;
}
/**
* Set the value of street
*
* @param string|null $street
*
* @return self
*/
public function setStreet($street)
{
$this->street = $street;
return $this;
}
/**
* Get the value of city
*
* @return string
*/
public function getCity()
{
return $this->city;
}
/**
* Set the value of city
*
* @param string|null $city
*
* @return self
*/
public function setCity($city)
{
$this->city = $city;
return $this;
}
/**
* Get the value of region
*
* @return string
*/
public function getRegion()
{
return $this->region;
}
/**
* Set the value of region
*
* @param string|null $region
*
* @return self
*/
public function setRegion($region)
{
$this->region = $region;
return $this;
}
/**
* Get the value of postalCode
*
* @return string
*/
public function getPostalCode()
{
return $this->postalCode;
}
/**
* Set the value of postalCode
*
* @param string|null $postalCode
*
* @return self
*/
public function setPostalCode($postalCode)
{
$this->postalCode = $postalCode;
return $this;
}
/**
* Get the value of country
*
* @return string
*/
public function getCountry()
{
return $this->country;
}
/**
* Set the value of country
*
* @param string|null $country
*
* @return self
*/
public function setCountry($country)
{
$this->country = $country;
return $this;
}
}

View File

@@ -0,0 +1,153 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
use JsonSerializable;
class UserData implements JsonSerializable
{
/**
* @var string|null
*/
private $email;
/**
* @var string|null
*/
private $phoneNumber;
/**
* @var UserAddressData|null
*/
private $address;
public function jsonSerialize(): array
{
$data = [];
if (!empty($this->email)) {
$data['sha256_email_address'] = $this->email;
}
if (!empty($this->phoneNumber)) {
$data['sha256_phone_number'] = $this->phoneNumber;
}
if (!empty($this->address) && !$this->address->isEmpty()) {
$data['address'] = $this->address;
}
return $data;
}
/**
* @return bool
*/
public function isEmpty()
{
if (!$this->address->isEmpty()) {
return false;
}
foreach (get_object_vars($this) as $var => $value) {
if ($var === 'address') {
continue;
}
if (!empty($value)) {
return false;
}
}
return true;
}
/**
* Get the value of email
*
* @return string|null
*/
public function getEmail()
{
return $this->email;
}
/**
* Set the value of email
*
* @param string|null $email
*
* @return self
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Get the value of phoneNumber
*
* @return string|null
*/
public function getPhoneNumber()
{
return $this->phoneNumber;
}
/**
* Set the value of phoneNumber
*
* @param string|null $phoneNumber
*
* @return self
*/
public function setPhoneNumber($phoneNumber)
{
$this->phoneNumber = $phoneNumber;
return $this;
}
/**
* Get the value of address
*
* @return UserAddressData|null
*/
public function getAddress()
{
return $this->address;
}
/**
* Set the value of address
*
* @param UserAddressData|null $address
*
* @return self
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Conversion;
use Address;
use Cart;
use Country;
use Customer;
use State;
class UserDataProvider
{
/**
* @var Customer
*/
private $customer;
/**
* @var Cart
*/
private $cart;
public function __construct(
Customer $customer,
Cart $cart
) {
$this->customer = $customer;
$this->cart = $cart;
}
/**
* Return the user personal details
*
* @see https://support.google.com/google-ads/answer/13258081#zippy=%2Cidentify-and-define-your-enhanced-conversions-fields
*/
public function getUserData(): UserData
{
$userData = new UserData();
$userDataAddress = new UserAddressData();
$userData->setEmail(Hasher::hash(Normalizer::normalize($this->customer->email)));
$userDataAddress->setFirstName(Hasher::hash(Normalizer::normalize($this->customer->firstname)));
$userDataAddress->setLastName(Hasher::hash(Normalizer::normalize($this->customer->lastname)));
$address = $this->getAddressFromCart();
if (!empty($address)) {
$userData->setPhoneNumber(Hasher::hash(Normalizer::normalizeInE164($address->phone ?: $address->phone_mobile, $this->getCountryIsoCodeFromAddress($address))));
$userDataAddress->setStreet(Normalizer::normalize(trim($address->address1 . ' ' . $address->address2)));
$userDataAddress->setCity(Normalizer::normalize($address->city));
$userDataAddress->setRegion(Normalizer::normalize($address->id_state ? (new State($address->id_state))->name : null));
$userDataAddress->setPostalCode(Normalizer::normalize($address->postcode));
$userDataAddress->setCountry(Normalizer::normalize($address->country));
}
$userData->setAddress($userDataAddress);
return $userData;
}
/**
* @return Address|null
*/
protected function getAddressFromCart()
{
if (!empty($this->cart->id_address_invoice)) {
return new Address($this->cart->id_address_invoice);
}
return null;
}
/**
* @return string|null
*/
protected function getCountryIsoCodeFromAddress(Address $address)
{
if (!empty($address->id_country)) {
return (new Country($address->id_country))->iso_code;
}
return null;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,551 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO;
use JsonSerializable;
class Carrier implements JsonSerializable
{
/**
* @var string
*/
private $collection = 'carriers';
/**
* @var int
*/
private $idCarrier;
/**
* @var int
*/
private $idReference;
/**
* @var int
*/
private $taxesRatesGroupId;
/**
* @var string
*/
private $name;
/**
* @var string
*/
private $url;
/**
* @var bool
*/
private $active;
/**
* @var bool
*/
private $deleted;
/**
* @var float
*/
private $shippingHandling = 0;
/**
* @var float
*/
private $freeShippingStartsAtPrice;
/**
* @var float
*/
private $freeShippingStartsAtWeight;
/**
* @var bool
*/
private $disableCarrierWhenOutOfRange;
/**
* @var bool
*/
private $isModule;
/**
* @var bool
*/
private $isFree;
/**
* @var bool
*/
private $shippingExternal;
/**
* @var bool
*/
private $needRange;
/**
* @var string
*/
private $externalModuleName;
/**
* @var float
*/
private $maxWidth;
/**
* @var float
*/
private $maxHeight;
/**
* @var float
*/
private $maxDepth;
/**
* @var float
*/
private $maxWeight;
/**
* @var int
*/
private $grade;
/**
* @var string
*/
private $delay;
/**
* @var string
*/
private $currency;
/**
* @var string
*/
private $weightUnit;
/**
* @var array
*/
private $countryIsoCodes;
/**
* @var CarrierDetail[]
*/
private $carrierDetails = [];
/**
* @var CarrierTax[]
*/
private $carrierTaxes = [];
public function getCollection(): string
{
return $this->collection;
}
public function setCollection(string $collection): Carrier
{
$this->collection = $collection;
return $this;
}
public function getIdCarrier(): int
{
return $this->idCarrier;
}
public function setIdCarrier(int $idCarrier): Carrier
{
$this->idCarrier = $idCarrier;
return $this;
}
public function getIdReference(): int
{
return $this->idReference;
}
public function setIdReference(int $idReference): Carrier
{
$this->idReference = $idReference;
return $this;
}
public function getTaxesRatesGroupId(): int
{
return $this->taxesRatesGroupId;
}
public function setTaxesRatesGroupId(int $taxesRatesGroupId): Carrier
{
$this->taxesRatesGroupId = $taxesRatesGroupId;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): Carrier
{
$this->name = $name;
return $this;
}
public function getUrl(): string
{
return $this->url;
}
public function setUrl(string $url): Carrier
{
$this->url = $url;
return $this;
}
public function isActive(): bool
{
return $this->active;
}
public function setActive(bool $active): Carrier
{
$this->active = $active;
return $this;
}
public function isDeleted(): bool
{
return $this->deleted;
}
public function setDeleted(bool $deleted): Carrier
{
$this->deleted = $deleted;
return $this;
}
public function getShippingHandling(): float
{
return $this->shippingHandling;
}
public function setShippingHandling(float $shippingHandling): Carrier
{
$this->shippingHandling = $shippingHandling;
return $this;
}
public function getFreeShippingStartsAtPrice(): float
{
return $this->freeShippingStartsAtPrice;
}
public function setFreeShippingStartsAtPrice(float $freeShippingStartsAtPrice): Carrier
{
$this->freeShippingStartsAtPrice = $freeShippingStartsAtPrice;
return $this;
}
public function getFreeShippingStartsAtWeight(): float
{
return $this->freeShippingStartsAtWeight;
}
public function setFreeShippingStartsAtWeight(float $freeShippingStartsAtWeight): Carrier
{
$this->freeShippingStartsAtWeight = $freeShippingStartsAtWeight;
return $this;
}
public function isDisableCarrierWhenOutOfRange(): bool
{
return $this->disableCarrierWhenOutOfRange;
}
public function setDisableCarrierWhenOutOfRange(bool $disableCarrierWhenOutOfRange): Carrier
{
$this->disableCarrierWhenOutOfRange = $disableCarrierWhenOutOfRange;
return $this;
}
public function isModule(): bool
{
return $this->isModule;
}
public function setIsModule(bool $isModule): Carrier
{
$this->isModule = $isModule;
return $this;
}
public function isFree(): bool
{
return $this->isFree;
}
public function setIsFree(bool $isFree): Carrier
{
$this->isFree = $isFree;
return $this;
}
public function isShippingExternal(): bool
{
return $this->shippingExternal;
}
public function setShippingExternal(bool $shippingExternal): Carrier
{
$this->shippingExternal = $shippingExternal;
return $this;
}
public function isNeedRange(): bool
{
return $this->needRange;
}
public function setNeedRange(bool $needRange): Carrier
{
$this->needRange = $needRange;
return $this;
}
public function getExternalModuleName(): string
{
return $this->externalModuleName;
}
public function setExternalModuleName(string $externalModuleName): Carrier
{
$this->externalModuleName = $externalModuleName;
return $this;
}
public function getMaxWidth(): float
{
return $this->maxWidth;
}
public function setMaxWidth(float $maxWidth): Carrier
{
$this->maxWidth = $maxWidth;
return $this;
}
public function getMaxHeight(): float
{
return $this->maxHeight;
}
public function setMaxHeight(float $maxHeight): Carrier
{
$this->maxHeight = $maxHeight;
return $this;
}
public function getMaxDepth(): float
{
return $this->maxDepth;
}
public function setMaxDepth(float $maxDepth): Carrier
{
$this->maxDepth = $maxDepth;
return $this;
}
public function getMaxWeight(): float
{
return $this->maxWeight;
}
public function setMaxWeight(float $maxWeight): Carrier
{
$this->maxWeight = $maxWeight;
return $this;
}
public function getGrade(): int
{
return $this->grade;
}
public function setGrade(int $grade): Carrier
{
$this->grade = $grade;
return $this;
}
public function getDelay(): string
{
return $this->delay;
}
public function setDelay(string $delay): Carrier
{
$this->delay = $delay;
return $this;
}
public function getCurrency(): string
{
return $this->currency;
}
public function setCurrency(string $currency): Carrier
{
$this->currency = $currency;
return $this;
}
public function getWeightUnit(): string
{
return $this->weightUnit;
}
public function setWeightUnit(string $weightUnit): Carrier
{
$this->weightUnit = $weightUnit;
return $this;
}
public function getCountryIsoCodes(): array
{
return $this->countryIsoCodes;
}
public function setCountryIsoCodes(array $countryIsoCodes): Carrier
{
$this->countryIsoCodes = $countryIsoCodes;
return $this;
}
public function getCarrierDetails(): array
{
return $this->carrierDetails;
}
public function setCarrierDetails(array $carrierDetails): Carrier
{
$this->carrierDetails = $carrierDetails;
return $this;
}
public function getCarrierTaxes(): array
{
return $this->carrierTaxes;
}
public function setCarrierTaxes(array $carrierTaxes): Carrier
{
$this->carrierTaxes = $carrierTaxes;
return $this;
}
public function jsonSerialize()
{
$return = [];
$return[] = [
'collection' => $this->getCollection(),
'id' => (string) $this->getIdReference(),
'properties' => [
'id_carrier' => (string) $this->getIdCarrier(),
'id_reference' => (string) $this->getIdReference(),
'name' => (string) $this->getName(),
'carrier_taxes_rates_group_id' => (string) $this->getTaxesRatesGroupId(),
'url' => (string) $this->getUrl(),
'active' => (bool) $this->isActive(),
'deleted' => (bool) $this->isDeleted(),
'shipping_handling' => (float) $this->getShippingHandling(),
'free_shipping_starts_at_price' => (float) $this->getFreeShippingStartsAtPrice(),
'free_shipping_starts_at_weight' => (float) $this->getFreeShippingStartsAtWeight(),
'disable_carrier_when_out_of_range' => (bool) $this->isDisableCarrierWhenOutOfRange(),
'is_module' => (bool) $this->isModule(),
'is_free' => (bool) $this->isFree(),
'shipping_external' => (bool) $this->isShippingExternal(),
'need_range' => (bool) $this->isNeedRange(),
'external_module_name' => (string) $this->getExternalModuleName(),
'max_width' => (float) $this->getMaxWidth(),
'max_height' => (float) $this->getMaxHeight(),
'max_depth' => (float) $this->getMaxDepth(),
'max_weight' => (float) $this->getMaxWeight(),
'grade' => (int) $this->getGrade(),
'delay' => (string) $this->getDelay(),
'currency' => (string) $this->getCurrency(),
'weight_unit' => (string) $this->getWeightUnit(),
'country_ids' => (string) implode(',', $this->getCountryIsoCodes()),
],
];
$carrierDetails = [];
foreach ($this->getCarrierDetails() as $carrierDetail) {
$carrierDetails[] = $carrierDetail->jsonSerialize();
}
$carrierTaxRates = [];
foreach ($this->getCarrierTaxes() as $carrierTax) {
$carrierTaxRates[] = $carrierTax->jsonSerialize();
}
return array_merge($return, $carrierDetails, $carrierTaxRates);
}
}

View File

@@ -0,0 +1,239 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO;
use JsonSerializable;
class CarrierDetail implements JsonSerializable
{
public const RANGE_BY_WEIGHT = 0;
public const RANGE_BY_PRICE = 1;
/**
* @var string
*/
private $collection = 'carrier_details';
/**
* @var string
*/
private $shippingMethod;
/**
* @var int
*/
private $carrierReference;
/**
* @var int
*/
private $carrierDetailId;
/**
* @var int
*/
private $zoneId;
/**
* @var int
*/
private $rangeId;
/**
* @var float
*/
private $delimiter1;
/**
* @var float
*/
private $delimiter2;
/**
* @var array
*/
private $countryIsoCodes;
/**
* @var array
*/
private $stateIsoCodes;
/**
* @var float
*/
private $price;
public function getCollection(): string
{
return $this->collection;
}
public function setCollection(string $collection): CarrierDetail
{
$this->collection = $collection;
return $this;
}
public function getShippingMethod(): string
{
return $this->shippingMethod;
}
public function setShippingMethod(string $shippingMethod): CarrierDetail
{
$this->shippingMethod = $shippingMethod;
return $this;
}
public function getCarrierReference(): int
{
return $this->carrierReference;
}
public function setCarrierReference(int $carrierReference): CarrierDetail
{
$this->carrierReference = $carrierReference;
return $this;
}
public function getCarrierDetailId(): int
{
return $this->carrierDetailId;
}
public function setCarrierDetailId(int $carrierDetailId): CarrierDetail
{
$this->carrierDetailId = $carrierDetailId;
return $this;
}
public function getZoneId(): int
{
return $this->zoneId;
}
public function setZoneId(int $zoneId): CarrierDetail
{
$this->zoneId = $zoneId;
return $this;
}
public function getRangeId(): int
{
return $this->rangeId;
}
public function setRangeId(int $rangeId): CarrierDetail
{
$this->rangeId = $rangeId;
return $this;
}
public function getDelimiter1(): float
{
return $this->delimiter1;
}
public function setDelimiter1(float $delimiter1): CarrierDetail
{
$this->delimiter1 = $delimiter1;
return $this;
}
public function getDelimiter2(): float
{
return $this->delimiter2;
}
public function setDelimiter2(float $delimiter2): CarrierDetail
{
$this->delimiter2 = $delimiter2;
return $this;
}
public function getCountryIsoCodes(): array
{
return $this->countryIsoCodes;
}
public function setCountryIsoCodes(array $countryIsoCodes): CarrierDetail
{
$this->countryIsoCodes = $countryIsoCodes;
return $this;
}
public function getStateIsoCodes(): array
{
return $this->stateIsoCodes;
}
public function setStateIsoCodes(array $stateIsoCodes): CarrierDetail
{
$this->stateIsoCodes = $stateIsoCodes;
return $this;
}
public function getPrice(): float
{
return $this->price;
}
public function setPrice(float $price): CarrierDetail
{
$this->price = $price;
return $this;
}
public function jsonSerialize()
{
$countryIds = implode(',', $this->getCountryIsoCodes());
$stateIds = implode(',', $this->getStateIsoCodes());
$shippingMethod = $this->getShippingMethod() === 'range_weight' ? self::RANGE_BY_WEIGHT : self::RANGE_BY_PRICE;
return [
'collection' => $this->getCollection(),
'id' => $this->getCarrierReference() . '-' . $this->getZoneId() . '-' . $shippingMethod . '-' . $this->getRangeId(),
'properties' => [
'id_reference' => (string) $this->getCarrierReference(),
'id_carrier_detail' => (string) $this->getCarrierDetailId(),
'shipping_method' => (string) $this->getShippingMethod(),
'delimiter1' => (float) $this->getDelimiter1(),
'delimiter2' => (float) $this->getDelimiter2(),
'country_ids' => (string) $countryIds,
'state_ids' => (string) $stateIds,
'price' => (float) $this->getPrice(),
],
];
}
}

View File

@@ -0,0 +1,142 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO;
use JsonSerializable;
class CarrierTax implements JsonSerializable
{
/**
* @var string
*/
private $collection = 'carrier_taxes';
/**
* @var int
*/
private $carrierReference;
/**
* @var int
*/
private $taxRulesGroupId;
/**
* @var string
*/
private $countryIsoCode;
/**
* @var string
*/
private $stateIsoCodes;
/**
* @var float
*/
private $taxRate;
public function getCollection(): string
{
return $this->collection;
}
public function setCollection(string $collection): CarrierTax
{
$this->collection = $collection;
return $this;
}
public function getCarrierReference(): int
{
return $this->carrierReference;
}
public function setCarrierReference(int $carrierReference): CarrierTax
{
$this->carrierReference = $carrierReference;
return $this;
}
public function getTaxRulesGroupId(): int
{
return $this->taxRulesGroupId;
}
public function setTaxRulesGroupId(int $taxRulesGroupId): CarrierTax
{
$this->taxRulesGroupId = $taxRulesGroupId;
return $this;
}
public function getCountryIsoCode(): string
{
return $this->countryIsoCode;
}
public function setCountryIsoCode(string $countryIsoCode): CarrierTax
{
$this->countryIsoCode = $countryIsoCode;
return $this;
}
public function getStateIsoCodes(): string
{
return $this->stateIsoCodes;
}
public function setStateIsoCodes(string $stateIsoCodes): CarrierTax
{
$this->stateIsoCodes = $stateIsoCodes;
return $this;
}
public function getTaxRate(): float
{
return $this->taxRate;
}
public function setTaxRate(float $taxRate): CarrierTax
{
$this->taxRate = $taxRate;
return $this;
}
public function jsonSerialize()
{
return [
'collection' => $this->getCollection(),
'id' => $this->getCarrierReference(),
'properties' => [
'id_reference' => (string) $this->getCarrierReference(),
'id_carrier_tax' => (string) $this->getTaxRulesGroupId(),
'country_id' => (string) $this->getCountryIsoCode(),
'state_ids' => (string) $this->getStateIsoCodes(),
'tax_rate' => (float) $this->getTaxRate(),
],
];
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO;
use JsonSerializable;
/**
* @see https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#action-data
*/
class ConversionEventData implements JsonSerializable
{
/**
* Value (i.e. revenue) associated with the event.
*
* @var string
*/
protected $value;
/**
* @var string
*/
protected $currency;
/**
* @var string
*/
protected $sendTo;
/**
* The transaction ID (e.g. T1234).
*
* @var string|null
*/
protected $transactionId;
public function jsonSerialize(): array
{
$eventData = [
'send_to' => $this->sendTo,
'value' => $this->value,
'currency' => $this->currency,
];
if ($this->transactionId) {
$eventData['transaction_id'] = $this->transactionId;
}
return $eventData;
}
/**
* @param string|int $transactionId
*
* @return self
*/
public function setTransactionId($transactionId)
{
$this->transactionId = $transactionId;
return $this;
}
/**
* Set value (i.e. revenue) associated with the event.
*
* @param string|null $value Value (i.e. revenue) associated with the event.
*
* @return self
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @param string|null $currency
*
* @return self
*/
public function setCurrency($currency)
{
$this->currency = $currency;
return $this;
}
/**
* @param string|null $sendTo
*
* @return self
*/
public function setSendTo($sendTo)
{
$this->sendTo = $sendTo;
return $this;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO\Remarketing;
use JsonSerializable;
class ProductData implements JsonSerializable
{
/**
* The product ID or SKU (e.g. P67890).
*
* @var string
*/
protected $id;
/**
* The price of a product (e.g. 29.20).
* Kept as a float
*
* @var float|null
*/
protected $price;
/**
* The quantity of a product (e.g. 2).
*
* @var int|null
*/
protected $quantity;
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'quantity' => $this->quantity,
'price' => $this->price,
];
}
/**
* Set the product ID or SKU (e.g. P67890).
*
* @param string $id The product ID or SKU (e.g. P67890).
*
* @return self
*/
public function setId(string $id)
{
$this->id = $id;
return $this;
}
/**
* Set kept as a string to avoid float issues
*
* @param float|null $price Kept as a string to avoid float issues
*
* @return self
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Set the quantity of a product (e.g. 2).
*
* @param int|null $quantity The quantity of a product (e.g. 2).
*
* @return self
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\DTO\Remarketing;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\ConversionEventData;
class PurchaseEventData extends ConversionEventData
{
/**
* @var ProductData[]
*/
protected $items;
/**
* @var int
*/
protected $awMerchandId;
/**
* @var string
*/
protected $awFeedCountry;
/**
* @var string
*/
protected $awFeedLanguage;
/**
* @var float
*/
protected $discount;
public function jsonSerialize(): array
{
return array_merge(
parent::jsonSerialize(),
[
'items' => $this->items,
'discount' => $this->discount,
'aw_merchant_id' => $this->awMerchandId,
'aw_feed_country' => $this->awFeedCountry,
'aw_feed_language' => $this->awFeedLanguage,
]
);
}
/**
* Set the value of awFeedLanguage
*
* @param string $awFeedLanguage
*
* @return self
*/
public function setAwFeedLanguage(string $awFeedLanguage)
{
$this->awFeedLanguage = $awFeedLanguage;
return $this;
}
/**
* Set the value of awMerchandId
*
* @param int $awMerchandId
*
* @return self
*/
public function setAwMerchandId(int $awMerchandId)
{
$this->awMerchandId = $awMerchandId;
return $this;
}
/**
* Set the value of awFeedCountry
*
* @param string $awFeedCountry
*
* @return self
*/
public function setAwFeedCountry(string $awFeedCountry)
{
$this->awFeedCountry = $awFeedCountry;
return $this;
}
/**
* Set the value of items
*
* @param array $items
*
* @return self
*/
public function setItems(array $items)
{
$this->items = $items;
return $this;
}
/**
* Set the value of discount
*
* @param float $discount
*
* @return self
*/
public function setDiscount(float $discount)
{
$this->discount = $discount;
return $this;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,223 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Database;
use Exception;
use Language;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\Module\PsxMarketingWithGoogle\Exception\MktgWithGoogleInstallerException;
use PrestaShop\Module\PsxMarketingWithGoogle\Handler\ErrorHandler;
use PrestaShop\Module\PsxMarketingWithGoogle\Tracker\Segment;
use PsxMarketingWithGoogle;
use Tab;
class Installer
{
public const CLASS_NAME = 'Installer';
private $module;
/**
* @var array
*/
private $errors = [];
/**
* @var Segment
*/
private $segment;
/**
* @var ErrorHandler
*/
private $errorHandler;
public function __construct(PsxMarketingWithGoogle $module, Segment $segment, ErrorHandler $errorHandler)
{
$this->module = $module;
$this->segment = $segment;
$this->errorHandler = $errorHandler;
}
/**
* @return bool
*/
public function install()
{
$this->segment->setMessage('PSX Marketing With Google installed');
$this->segment->track();
return $this->installConfiguration() &&
$this->installTabs() &&
$this->installTables();
}
/**
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* Install configuration for each shop
*
* @return bool
*/
public function installConfiguration()
{
$result = true;
foreach (\Shop::getShops(false, null, true) as $shopId) {
/* todo: remove ignore when first configuration is added to the list */
/* @phpstan-ignore-next-line */
foreach (Config::CONFIGURATION_LIST as $name => $value) {
if (false === \Configuration::hasKey((string) $name, null, null, (int) $shopId)) {
$result = $result && \Configuration::updateValue(
(string) $name,
$value,
false,
null,
(int) $shopId
);
}
}
}
return $result;
}
/**
* This method is often use to create an ajax controller
*
* @return bool
*/
public function installTabs()
{
$installTabCompleted = true;
foreach ($this->getTabs() as $tab) {
try {
$installTabCompleted = $installTabCompleted && $this->installTab(
$tab['className'],
$tab['parent'],
$tab['name'],
$tab['module'],
$tab['active'],
$tab['icon']
);
} catch (Exception $e) {
$this->errorHandler->handle(
new MktgWithGoogleInstallerException(
'Failed to install module tabs',
MktgWithGoogleInstallerException::MKTG_WITH_GOOGLE_INSTALL_EXCEPTION,
$e
),
MktgWithGoogleInstallerException::MKTG_WITH_GOOGLE_INSTALL_EXCEPTION,
false
);
$this->errors[] = sprintf($this->module->l('Failed to install %1s tab', self::CLASS_NAME), $tab['className']);
return false;
}
}
return $installTabCompleted;
}
public function installTab($className, $parent, $name, $module, $active, $icon)
{
if (Tab::getIdFromClassName($className)) {
return true;
}
$idParent = is_int($parent) ? $parent : Tab::getIdFromClassName($parent);
$moduleTab = new Tab();
$moduleTab->class_name = $className;
$moduleTab->id_parent = $idParent;
$moduleTab->module = $module;
$moduleTab->active = $active;
if (property_exists($moduleTab, 'icon')) {
$moduleTab->icon = $icon;
}
$languages = Language::getLanguages(true);
foreach ($languages as $language) {
$moduleTab->name[$language['id_lang']] = $name;
}
return $moduleTab->add();
}
public function installTables()
{
try {
include dirname(__FILE__) . '/../../sql/install.php';
} catch (\Exception $e) {
$this->errorHandler->handle(
new MktgWithGoogleInstallerException(
'Failed to install database tables',
MktgWithGoogleInstallerException::MKTG_WITH_GOOGLE_UNINSTALL_EXCEPTION,
$e
),
$e->getCode(),
false
);
$this->errors[] = $this->module->l('Failed to install database tables', self::CLASS_NAME);
return false;
}
return true;
}
private function getTabs()
{
return [
[
'className' => 'Marketing',
'parent' => 'IMPROVE',
'name' => 'Marketing',
'module' => '',
'active' => true,
'icon' => 'campaign',
],
[
'className' => 'AdminPsxMktgWithGoogleModule',
'parent' => 'Marketing',
'name' => 'Google',
'module' => $this->module->name,
'active' => true,
'icon' => '',
],
[
'className' => 'AdminAjaxPsxMktgWithGoogle',
'parent' => -1,
'name' => $this->module->name,
'module' => $this->module->name,
'active' => true,
'icon' => '',
],
];
}
}

View File

@@ -0,0 +1,154 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Database;
use Exception;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\Module\PsxMarketingWithGoogle\Exception\MktgWithGoogleInstallerException;
use PrestaShop\Module\PsxMarketingWithGoogle\Handler\ErrorHandler;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\TabRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Tracker\Segment;
class Uninstaller
{
public const CLASS_NAME = 'Uninstaller';
/**
* @var TabRepository
*/
private $tabRepository;
/**
* @var Segment
*/
private $segment;
/**
* @var ErrorHandler
*/
private $errorHandler;
public function __construct(
TabRepository $tabRepository,
Segment $segment,
ErrorHandler $errorHandler
) {
$this->tabRepository = $tabRepository;
$this->segment = $segment;
$this->errorHandler = $errorHandler;
}
/**
* @return bool
*
* @throws Exception
*/
public function uninstall()
{
$this->segment->setMessage('PS Google shopping uninstalled');
$this->segment->track();
/* todo: remove ignore when first configuration is added to the list */
/* @phpstan-ignore-next-line */
foreach (array_keys(Config::CONFIGURATION_LIST) as $name) {
\Configuration::deleteByName((string) $name);
}
return $this->uninstallTabs() && $this->uninstallTables();
}
/**
* @return bool
*
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException|Exception
*/
private function uninstallTabs()
{
$uninstallTabCompleted = true;
try {
foreach (Config::MODULE_ADMIN_CONTROLLERS as $controllerName) {
$id_tab = (int) \Tab::getIdFromClassName($controllerName);
$tab = new \Tab($id_tab);
if (\Validate::isLoadedObject($tab)) {
$uninstallTabCompleted = $uninstallTabCompleted && $tab->delete();
}
}
$uninstallTabCompleted = $uninstallTabCompleted && $this->uninstallMarketingTab();
} catch (Exception $e) {
$this->errorHandler->handle(
new MktgWithGoogleInstallerException(
'Failed to uninstall module tabs',
MktgWithGoogleInstallerException::MKTG_WITH_GOOGLE_UNINSTALL_EXCEPTION,
$e
),
$e->getCode(),
false
);
return false;
}
return $uninstallTabCompleted;
}
/**
* @return bool
*
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
private function uninstallMarketingTab()
{
$id_tab = (int) \Tab::getIdFromClassName('Marketing');
$tab = new \Tab($id_tab);
if (!\Validate::isLoadedObject($tab)) {
return true;
}
if ($this->tabRepository->hasChildren($id_tab)) {
return true;
}
return $tab->delete();
}
public function uninstallTables()
{
try {
include dirname(__FILE__) . '/../../sql/uninstall.php';
} catch (\Exception $e) {
$this->errorHandler->handle(
new MktgWithGoogleInstallerException(
'Failed to uninstall database tables',
MktgWithGoogleInstallerException::MKTG_WITH_GOOGLE_UNINSTALL_EXCEPTION,
$e
),
$e->getCode(),
false
);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,34 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Exception;
use Exception;
class ApiClientException extends Exception
{
public const REQUEST_EXCEPTION = 501;
public const GET_EXCEPTION = 502;
public const POST_EXCEPTION = 503;
public const DELETE_EXCEPTION = 504;
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Exception;
use Exception;
class MktgWithGoogleInstallerException extends Exception
{
public const MKTG_WITH_GOOGLE_INSTALL_EXCEPTION = 1;
public const MKTG_WITH_GOOGLE_UNINSTALL_EXCEPTION = 2;
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,93 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Factory;
use Configuration;
use Context;
use Currency;
class ContextFactory
{
public static function getContext()
{
return Context::getContext();
}
public static function getLanguage()
{
return Context::getContext()->language;
}
public static function getCart()
{
return Context::getContext()->cart;
}
/**
* Return the currency present in the context, or the default one
* when the context doesn't have a currency yet (i.e when user session is empty).
*
* @return Currency
*/
public static function getCurrency()
{
if (Context::getContext()->currency !== null) {
return Context::getContext()->currency;
}
return new Currency((int) Configuration::get('PS_CURRENCY_DEFAULT'));
}
public static function getCustomer()
{
return Context::getContext()->customer;
}
public static function getSmarty()
{
return Context::getContext()->smarty;
}
public static function getShop()
{
return Context::getContext()->shop;
}
public static function getController()
{
return Context::getContext()->controller;
}
public static function getCookie()
{
return Context::getContext()->cookie;
}
public static function getLink()
{
return Context::getContext()->link;
}
public static function getCountry()
{
return Context::getContext()->country;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Factory;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Env;
class ParametersFactory
{
public static function getBillingEnv()
{
return (bool) (new Env())->get('USE_BILLING_SANDBOX');
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,126 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Handler;
use Exception;
use Module;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\PsAccountsInstaller\Installer\Facade\PsAccounts;
use PsxMarketingWithGoogle;
/**
* Handle Error.
*/
class ErrorHandler
{
/**
* @var ModuleFilteredRavenClient
*/
protected $client;
/**
* @var ErrorHandler
*/
private static $instance;
public function __construct()
{
/** @var PsxMarketingWithGoogle */
$module = Module::getInstanceByName('psxmarketingwithgoogle');
$this->client = new ModuleFilteredRavenClient(
Config::PSX_MKTG_WITH_GOOGLE_SENTRY_CREDENTIALS_PHP,
[
'level' => 'warning',
'tags' => [
'php_version' => phpversion(),
'psxmarketingwithgoogle_version' => $module->version,
'prestashop_version' => _PS_VERSION_,
'psxmarketingwithgoogle_is_enabled' => \Module::isEnabled('psxmarketingwithgoogle'),
'psxmarketingwithgoogle_is_installed' => \Module::isInstalled('psxmarketingwithgoogle'),
],
'release' => "v{$module->version}",
]
);
try {
$psAccountsService = $module->getService(PsAccounts::class)->getPsAccountsService();
$this->client->user_context([
'id' => $psAccountsService->getShopUuidV4(),
]);
} catch (Exception $e) {
// Do nothing
}
// We use realpath to get errors even if module is behind a symbolic link
$this->client->setAppPath(realpath(_PS_MODULE_DIR_ . $module->name . '/'));
// - Do no not add the shop root folder, it will exclude everything even if specified in the app path.
// - Excluding vendor/ avoids errors comming from one of your libraries library when called by another module.
$this->client->setExcludedAppPaths([
realpath(_PS_MODULE_DIR_ . $module->name . '/vendor/'),
]);
$this->client->setExcludedDomains(['127.0.0.1', 'localhost', '.local']);
if (version_compare(phpversion(), '7.4.0', '>=') && version_compare(_PS_VERSION_, '1.7.8.0', '<')) {
return;
}
$this->client->install();
}
/**
* @param \Exception $error
* @param mixed $code
* @param bool|null $throw
* @param array|null $data
*
* @return void
*
* @throws \Exception
*/
public function handle($error, $code = null, $throw = true, $data = null)
{
$this->client->captureException($error, $data);
if ($code && true === $throw) {
http_response_code($code);
throw $error;
}
}
/**
* @return ErrorHandler
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new ErrorHandler();
}
return self::$instance;
}
/**
* @return void
*/
private function __clone()
{
}
}

View File

@@ -0,0 +1,126 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Handler;
use Raven_Client;
/**
* Inheritance allow us to check data generated by Raven and filter errors
* that are not related to the module.
* Raven does not filter errors by itself depending on the appPath and any
* excludedAppPaths, but declares what phase of the stack trace is outside the app.
* We use this data to allow each module filtering their own errors.
*
* IMPORTANT NOTE: This class is present is this module during the
* stabilisation phase, and will be moved later in a library.
*/
class ModuleFilteredRavenClient extends Raven_Client
{
/**
* @var string[]|null
*/
protected $excluded_domains;
public function capture($data, $stack = null, $vars = null)
{
/*
Content of $data:
array:2 [▼
"exception" => array:1 [▼
"values" => array:1 [▼
0 => array:3 [▼
"value" => "Class 'DogeInPsFacebook' not found"
"type" => "Error"
"stacktrace" => array:1 [▼
"frames" => array:4 [▼
0 => array:7 [▼
"filename" => "index.php"
"lineno" => 93
"function" => null
"pre_context" => array:5 [▶]
"context_line" => " Dispatcher::getInstance()->dispatch();"
"post_context" => array:2 [▶]
"in_app" => false
1 => array:3 [▼
[Can be defined when a subexception is set]
*/
if (!isset($data['exception']['values'][0]['stacktrace']['frames'])) {
return null;
}
if ($this->isErrorFilteredByContext()) {
return null;
}
$allowCapture = false;
foreach ($data['exception']['values'] as $errorValues) {
$allowCapture = $allowCapture || $this->isErrorInApp($errorValues);
}
if (!$allowCapture) {
return null;
}
return parent::capture($data, $stack, $vars);
}
/**
* @return self
*/
public function setExcludedDomains(array $domains)
{
$this->excluded_domains = $domains;
return $this;
}
/**
* @return bool
*/
private function isErrorInApp(array $data)
{
$atLeastOneFileIsInApp = false;
foreach ($data['stacktrace']['frames'] as $frame) {
$atLeastOneFileIsInApp = $atLeastOneFileIsInApp || ((isset($frame['in_app']) && $frame['in_app']));
}
return $atLeastOneFileIsInApp;
}
/**
* Check the conditions in which the error is thrown, so we can apply filters
*
* @return bool
*/
private function isErrorFilteredByContext()
{
if ($this->excluded_domains && !empty($_SERVER['REMOTE_ADDR'])) {
foreach ($this->excluded_domains as $domain) {
if (strpos($_SERVER['REMOTE_ADDR'], $domain) !== false) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,222 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Handler;
use Context;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Buffer\TemplateBuffer;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\Module\PsxMarketingWithGoogle\Conversion\UserDataProvider;
use PrestaShop\Module\PsxMarketingWithGoogle\Provider\CartEventDataProvider;
use PrestaShop\Module\PsxMarketingWithGoogle\Provider\PageViewEventDataProvider;
use PrestaShop\Module\PsxMarketingWithGoogle\Provider\PurchaseEventDataProvider;
use PsxMarketingWithGoogle;
class RemarketingHookHandler
{
/**
* @var ConfigurationAdapter
*/
protected $configurationAdapter;
/**
* @var TemplateBuffer
*/
protected $templateBuffer;
/**
* @var Context
*/
protected $context;
/**
* @var PsxMarketingWithGoogle
*/
protected $module;
/**
* @var bool
*/
protected $active;
/**
* @var bool
*/
protected $enhancedConversionActive;
/**
* @var array
*/
protected $conversionLabels;
public function __construct(ConfigurationAdapter $configurationAdapter, TemplateBuffer $templateBuffer, Context $context, $module)
{
$this->configurationAdapter = $configurationAdapter;
$this->templateBuffer = $templateBuffer;
$this->context = $context;
$this->module = $module;
$this->active = (bool) $this->configurationAdapter->get(Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_STATUS)
&& (bool) $this->configurationAdapter->get(Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG)
&& in_array($this->context->controller->controller_type, ['front', 'modulefront']);
$this->enhancedConversionActive = (bool) $this->configurationAdapter->get(Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_ENHANCED_STATUS);
$this->conversionLabels = json_decode($this->configurationAdapter->get(Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_CONVERSION_LABELS), true)
?: [];
if ($this->active) {
$this->templateBuffer->init($this->findIdentifierFromContext($context));
}
}
public function handleHook(string $hookName, array $data = []): string
{
if (!$this->active) {
return '';
}
switch ($hookName) {
case 'hookDisplayTop':
if (($sendTo = $this->getSendTo(Config::REMARKETING_CONVERSION_LABEL_PAGE_VIEW)) === null) {
break;
}
$eventData = $this->module->getService(PageViewEventDataProvider::class)->getEventData($sendTo);
if ($eventData === null) {
break;
}
$this->context->smarty->assign([
'eventData' => $eventData,
]);
$this->templateBuffer->add(
$this->module->display($this->module->getfilePath(), 'views/templates/hook/gtagEvent.tpl')
);
break;
case 'hookDisplayOrderConfirmation':
if (($sendTo = $this->getSendTo(Config::REMARKETING_CONVERSION_LABEL_PURCHASE)) === null) {
break;
}
$this->context->smarty->assign([
'eventData' => $this->module->getService(PurchaseEventDataProvider::class)->getEventData($sendTo, $data['order']),
]);
$this->templateBuffer->add(
$this->module->display($this->module->getfilePath(), 'views/templates/hook/gtagEvent.tpl')
);
break;
case 'hookActionCartUpdateQuantityBefore':
if ($data['operator'] !== 'up') {
break;
}
if (($sendTo = $this->getSendTo(Config::REMARKETING_CONVERSION_LABEL_ADD_TO_CART)) === null) {
break;
}
$this->context->smarty->assign([
'eventData' => $this->module->getService(CartEventDataProvider::class)->getEventData($sendTo, $data),
]);
$this->templateBuffer->add(
$this->module->display($this->module->getfilePath(), 'views/templates/hook/gtagEvent.tpl')
);
break;
}
if ($hookName === 'hookDisplayHeader') {
$snippet = base64_decode($this->configurationAdapter->get(Config::PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG));
if (!$this->enhancedConversionActive) {
return $snippet;
}
$userData = $this->module->getService(UserDataProvider::class)->getUserData();
if ($userData->isEmpty()) {
return $snippet;
}
$this->context->smarty->assign([
'userData' => $userData,
]);
return $snippet . $this->module->display($this->module->getfilePath(), 'views/templates/hook/enhancedConversions.tpl');
}
// Return the existing content in case we have a display hook
if (strpos($hookName, 'Display') === 4 && !$this->isCurrentRequestAnAjax()) {
return $this->templateBuffer->flush();
}
return '';
}
private function getSendTo($eventName)
{
if (!empty($this->conversionLabels[$eventName])) {
return $this->conversionLabels[$eventName];
}
return null;
}
/**
* @return bool
*/
private function isCurrentRequestAnAjax()
{
/*
* An ajax property is available in controllers
* when the whole page template should not be generated.
*/
if ($this->context->controller->ajax) {
return true;
}
/*
* In case the ajax property is not properly set, there is
* another check available.
*/
if ($this->context->controller->isXmlHttpRequest()) {
return true;
}
return false;
}
/**
* @return string
*/
private function findIdentifierFromContext(Context $context)
{
if (!empty($context->customer->id_guest)) {
return 'guest_' . $context->customer->id_guest;
}
if (!empty($context->cart->id)) {
return 'cart_' . $context->cart->id;
}
return '';
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,245 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\PsxMarketingWithGoogle\Http;
use RuntimeException;
class HttpClient
{
private $curl;
/** @var array<int|string,string> */
private $headers = [];
/** @var array<int|string,bool|int> */
private $options = [];
/** @var string */
private $baseUrl = '';
/**
* Constructor initializes cURL
*
* @param string $baseUrl Optional base URL for all requests
*
* @throws RuntimeException if cURL extension is not loaded
*/
public function __construct(string $baseUrl = '')
{
if (!extension_loaded('curl')) {
throw new RuntimeException('cURL extension is not loaded');
}
$this->baseUrl = rtrim($baseUrl, '/');
$this->curl = curl_init();
// Set default options
$this->setDefaultOptions();
}
/**
* Set default cURL options
*/
private function setDefaultOptions(): void
{
$this->options = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
];
}
/**
* Set custom headers for the request
*
* @param array<int|string,string> $headers
*
* @return self
*/
public function setHeaders(array $headers): self
{
$this->headers = $headers;
return $this;
}
/**
* Add a single header
*
* @param string $name
* @param string $value
*
* @return self
*/
public function addHeader(string $name, string $value): self
{
$this->headers[] = "$name: $value";
return $this;
}
/**
* Set custom cURL options
*
* @param array<string,bool|int> $options
*
* @return self
*/
public function setOptions(array $options): self
{
$this->options = $options + $this->options;
return $this;
}
/**
* Execute HTTP request
*
* @param string $method HTTP method
* @param string $url URL endpoint
* @param array<string,string|bool|int>|string|null $data Request data
*
* @return Response
*
* @throws RuntimeException on cURL errors
*/
public function request(string $method, string $url, $data = null)
{
$url = $this->baseUrl . '/' . ltrim($url, '/');
$options = $this->options + [
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => strtoupper($method),
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => $this->headers,
];
if ($data !== null) {
if (is_array($data)) {
$data = http_build_query($data);
}
if ($method === 'GET') {
/* @phpstan-ignore-next-line */
$options[CURLOPT_URL] .= '?' . $data;
} else {
$options[CURLOPT_POSTFIELDS] = $data;
}
}
curl_setopt_array($this->curl, $options);
$response = curl_exec($this->curl);
if ($response === false) {
throw new \RuntimeException(sprintf('cURL error (%s): %s', curl_errno($this->curl), curl_error($this->curl)));
}
$headerSize = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);
$httpCode = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
// Split response into headers and body
$headerStr = substr((string) $response, 0, $headerSize);
$body = substr((string) $response, $headerSize);
$error = curl_error($this->curl);
// Parse headers
$headers = [];
foreach (explode("\r\n", $headerStr) as $line) {
if (preg_match('/^([^:]+):(.+)$/', $line, $matches)) {
$headers[trim($matches[1])] = trim($matches[2]);
}
}
return new Response(
$httpCode,
$body,
$headers,
$error
);
}
/**
* Convenience method for GET requests
*
* @param string $url
* @param array<string, string> $params Query parameters
*
* @return Response
*/
public function get(string $url, array $params = [])
{
return $this->request('GET', $url, $params);
}
/**
* Convenience method for POST requests
*
* @param string $url
* @param array<string, string>|string $data
*
* @return Response
*/
public function post(string $url, $data = [])
{
return $this->request('POST', $url, $data);
}
/**
* Convenience method for PUT requests
*
* @param string $url
* @param array<string, string>|string $data
*
* @return Response
*/
public function put(string $url, $data = [])
{
return $this->request('PUT', $url, $data);
}
/**
* Convenience method for DELETE requests
*
* @param string $url
* @param array<string, string> $params
*
* @return Response
*/
public function delete(string $url, array $params = [])
{
return $this->request('DELETE', $url, $params);
}
/**
* Destructor closes cURL connection
*/
public function __destruct()
{
if ($this->curl) {
curl_close($this->curl);
}
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\PsxMarketingWithGoogle\Http;
class Response
{
/** @var int */
private $statusCode;
/** @var string */
private $body;
/** @var array<string,string> */
private $headers;
/** @var string|null */
private $error;
/**
* @param int $statusCode
* @param string $body
* @param array<string,string> $headers
* @param string|null $error
*
**/
public function __construct($statusCode, $body, $headers = [], $error = null)
{
$this->statusCode = $statusCode;
$this->body = $body;
$this->headers = $headers;
$this->error = $error;
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* @return array<string,string>
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @return string
*/
public function getBody()
{
return $this->body;
}
/**
* @return string|null
*/
public function getError()
{
return $this->error;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,124 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter;
class AttributeMapConditionOutput
{
const STRING = 'string';
const INT = 'int';
const BOOLEAN = 'boolean';
const OBJECT = 'object';
const MAP = [
AttributeType::BRAND => [
Condition::DOES_CONTAIN => [
'multiple' => true,
'type' => self::STRING,
],
Condition::DOES_NOT_CONTAIN => [
'multiple' => true,
'type' => self::STRING,
],
Condition::IS => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['value', 'id'],
],
Condition::IS_NOT => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['value', 'id'],
],
],
AttributeType::CATEGORY => [
Condition::DOES_CONTAIN => [
'multiple' => true,
'type' => self::STRING,
],
Condition::DOES_NOT_CONTAIN => [
'multiple' => true,
'type' => self::STRING,
],
Condition::IS => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['value', 'id'],
],
Condition::IS_NOT => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['value', 'id'],
],
],
AttributeType::PRICE => [
Condition::IS => [
'multiple' => false,
'type' => self::INT,
'positive' => true,
'integer' => false,
],
Condition::GREATER => [
'multiple' => false,
'type' => self::INT,
'positive' => true,
'integer' => false,
],
Condition::LOWER => [
'multiple' => false,
'type' => self::INT,
'positive' => true,
'integer' => false,
],
],
AttributeType::PRODUCT_ID => [
Condition::IS => [
'multiple' => true,
'type' => self::INT,
'positive' => true,
'integer' => true,
],
Condition::IS_NOT => [
'multiple' => true,
'type' => self::INT,
'positive' => true,
'integer' => true,
],
],
AttributeType::OUT_OF_STOCK => [
Condition::IS => [
'multiple' => false,
'type' => self::BOOLEAN,
],
],
AttributeType::FEATURE => [
Condition::IS => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['id', 'key', 'value', 'language'],
],
Condition::IS_NOT => [
'multiple' => true,
'type' => self::OBJECT,
'keys' => ['id', 'key', 'value', 'language'],
],
],
];
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter;
/**
* enum only exists from PHP 8 and the module is compliant with PHP 7.2+,
* thus cannot be used here.
*/
class AttributeType
{
const BRAND = 'brand';
const CATEGORY = 'category';
const FEATURE = 'feature';
const PRICE = 'price';
const PRODUCT_ID = 'id';
const OUT_OF_STOCK = 'out_of_stock';
public static function all()
{
return [
static::BRAND,
static::CATEGORY,
static::FEATURE,
static::PRICE,
static::PRODUCT_ID,
static::OUT_OF_STOCK,
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter;
/**
* enum only exists from PHP 8 and the module is compliant with PHP 7.2+,
* thus cannot be used here.
*/
class Condition
{
const DOES_CONTAIN = 'does_contain';
const DOES_NOT_CONTAIN = 'does_not_contain';
const GREATER = 'greater';
const LOWER = 'lower';
const IS = 'is';
const IS_NOT = 'is_not';
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
class BrandQueryBuilder implements QueryBuilderInterface
{
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
switch ($filter['condition']) {
case Condition::DOES_CONTAIN:
$queryConditions = [];
foreach ($filter['value'] as $value) {
$queryConditions[] = 'm' . $index . '.name LIKE "%' . pSQL($value) . '%"';
}
return $query->where('(' . implode(' OR ', $queryConditions) . ')');
case Condition::DOES_NOT_CONTAIN:
$queryConditions = [];
foreach ($filter['value'] as $value) {
$queryConditions[] = 'm' . $index . '.name NOT LIKE "%' . pSQL($value) . '%"';
}
return $query->where('(' . implode(' OR ', $queryConditions) . ')');
case Condition::IS:
$filteredValues = array_map(function ($item) {
return $item['value'];
}, $filter['value']);
return $query->where('m' . $index . '.name IN ("' . implode('", "', array_map('pSQL', $filteredValues)) . '")');
case Condition::IS_NOT:
$filteredValues = array_map(function ($item) {
return $item['value'];
}, $filter['value']);
return $query->where('m' . $index . '.name NOT IN ("' . implode('", "', array_map('pSQL', $filteredValues)) . '")');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
return $query->innerJoin('manufacturer', 'm' . $index, 'm' . $index . '.id_manufacturer = p.id_manufacturer')
->where('m' . $index . '.active = 1');
}
}

View File

@@ -0,0 +1,86 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use Context;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
class CategoryQueryBuilder implements QueryBuilderInterface
{
/**
* @var Context
*/
protected $context;
public function __construct(Context $context)
{
$this->context = $context;
}
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
// At the time of implementation, CloudSync gets only the default category of the product.
// We add the condition based on the default category here as well.
switch ($filter['condition']) {
case Condition::DOES_CONTAIN:
$queryConditions = [];
foreach ($filter['value'] as $value) {
$queryConditions[] = 'cl' . $index . '.name LIKE "%' . pSQL($value) . '%"';
}
return $query->where('(' . implode(' OR ', $queryConditions) . ')');
case Condition::DOES_NOT_CONTAIN:
$queryConditions = [];
foreach ($filter['value'] as $value) {
$queryConditions[] = 'cl' . $index . '.name NOT LIKE "%' . pSQL($value) . '%"';
}
return $query->where('(' . implode(' OR ', $queryConditions) . ')');
case Condition::IS:
$filteredValues = array_map(function ($item) {
return $item['id'];
}, $filter['value']);
return $query->where('c' . $index . '.id_category IN (' . implode(', ', array_map('intval', $filteredValues)) . ')');
case Condition::IS_NOT:
$filteredValues = array_map(function ($item) {
return $item['id'];
}, $filter['value']);
return $query->where('c' . $index . '.id_category NOT IN (' . implode(', ', array_map('intval', $filteredValues)) . ')');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
return $query->innerJoin('category_product', 'cp' . $index, 'cp' . $index . '.id_product = p.id_product')
->innerJoin('category', 'c' . $index, 'c' . $index . '.id_category = cp' . $index . '.id_category')
->innerJoin('category_lang', 'cl' . $index, 'c' . $index . '.id_category = cl' . $index . '.id_category')
->where('cl' . $index . '.id_lang = ' . (int) $this->context->language->id)
->where('c' . $index . '.active = 1');
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use Context;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\LanguageRepository;
class FeatureQueryBuilder implements QueryBuilderInterface
{
/**
* @var Context
*/
protected $context;
/**
* @var LanguageRepository
*/
protected $languageRepository;
/**
* @var string
*/
protected $currentLanguageIsoCode;
public function __construct(
Context $context,
LanguageRepository $languageRepository
) {
$this->context = $context;
$this->languageRepository = $languageRepository;
$this->currentLanguageIsoCode = $this->languageRepository->getIsoById(
(int) $this->context->language->id
);
}
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
$uniqueFeature = [];
foreach ($filter['value'] as $value) {
$uniqueFeature[$value['id']] = $value;
}
$uniqueFeature = array_values($uniqueFeature);
switch ($filter['condition']) {
case Condition::IS:
$queryConditions = [];
foreach ($uniqueFeature as $value) {
$queryConditions[] = 'fvl' . $index . '.value = "' . pSQL($value['value']) . '"';
}
return $query->where('fl' . $index . '.name = "' . pSQL($uniqueFeature[0]['key']) . '" AND (' . implode(' OR ', $queryConditions) . ')');
case Condition::IS_NOT:
$queryConditions = [];
foreach ($uniqueFeature as $value) {
$queryConditions[] = 'fvl' . $index . '.value <> "' . pSQL($value['value']) . '"';
}
return $query->where('fl' . $index . '.name = "' . pSQL($uniqueFeature[0]['key']) . '" AND (' . implode(' AND ', $queryConditions) . ')');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
return $query
->leftJoin('feature_product', 'fp' . $index, 'fp' . $index . '.id_product = p.id_product')
->innerJoin('feature_shop', 'fs' . $index, 'fs' . $index . '.id_feature = fp' . $index . '.id_feature')
->innerJoin('feature_lang', 'fl' . $index, 'fl' . $index . '.id_feature = fp' . $index . '.id_feature')
->innerJoin('feature_value', 'fv' . $index, 'fv' . $index . '.id_feature = fp' . $index . '.id_feature')
->innerJoin('feature_value_lang', 'fvl' . $index, '(fvl' . $index . '.id_feature_value = fv' . $index . '.id_feature_value AND fp' . $index . '.id_feature_value = fvl' . $index . '.id_feature_value AND fl' . $index . '.id_lang = fvl' . $index . '.id_lang)')
->where('fs' . $index . '.id_shop = ' . (int) $this->context->shop->id);
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
class OutOfStockQueryBuilder implements QueryBuilderInterface
{
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
if ($filter['condition'] === Condition::IS) {
return $filter['value'] ? $query->where('sa' . $index . '.quantity <= 0') : $query->where('sa' . $index . '.quantity > 0');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
return $query->innerJoin('stock_available', 'sa' . $index, 'sa' . $index . '.id_product = p.id_product');
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
class PriceQueryBuilder implements QueryBuilderInterface
{
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
switch ($filter['condition']) {
case Condition::GREATER:
return $query->where('(
p.price > ' . (float) $filter['value'] . '
OR (p.price + pa' . $index . '.price) > ' . (float) $filter['value'] . '
)');
case Condition::LOWER:
return $query->where('(
p.price < ' . (float) $filter['value'] . '
OR (p.price + pa' . $index . '.price) < ' . (float) $filter['value'] . '
)');
case Condition::IS:
return $query->where('(
p.price = ' . (float) $filter['value'] . '
OR (p.price + pa' . $index . '.price) = ' . (float) $filter['value'] . '
)');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
return $query->leftJoin('product_attribute', 'pa' . $index, 'pa' . $index . '.id_product = p.id_product');
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Condition;
class ProductIdQueryBuilder implements QueryBuilderInterface
{
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery
{
switch ($filter['condition']) {
case Condition::IS:
return $query->where('p.id_product IN (' . implode(', ', array_map('intval', $filter['value'])) . ')');
case Condition::IS_NOT:
return $query->where('p.id_product NOT IN (' . implode(', ', array_map('intval', $filter['value'])) . ')');
}
return $query;
}
public function addRelations(DbQuery $query, int $index): DbQuery
{
// Do nothing, product data is already loaded
return $query;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder;
use DbQuery;
interface QueryBuilderInterface
{
public function addWhereFromFilter(DbQuery $query, $filter, int $index): DbQuery;
public function addRelations(DbQuery $query, int $index): DbQuery;
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,300 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication;
use InvalidArgumentException;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\AttributeMapConditionOutput;
class FilterValidator
{
/**
* @throws InvalidArgumentException
*
* See https://phpstan.org/writing-php-code/phpdoc-types#general-arrays
*/
public function validate(array $filters): void
{
foreach ($filters as $index => $filter) {
if (!isset(AttributeMapConditionOutput::MAP[$filter['attribute']])) {
throw new InvalidArgumentException('Filter #' . $index . ' has no valid "attribute" field.');
}
$attributeConditions = AttributeMapConditionOutput::MAP[$filter['attribute']];
if (!isset($attributeConditions[$filter['condition']])) {
throw new InvalidArgumentException('Filter #' . $index . ' has no valid "condition" field.');
}
$conditionRequirements = $attributeConditions[$filter['condition']];
$this->hasValueCompliantWithCondition($filter, $index, $conditionRequirements);
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function hasValueCompliantWithCondition($filter, int $index, $conditionRequirements): void
{
// number of values check
if ($conditionRequirements['multiple']) {
$this->mustHaveSeveralValues($filter, $index);
} else {
$this->mustHaveOneValue($filter, $index);
}
// type check
switch ($conditionRequirements['type']) {
case AttributeMapConditionOutput::STRING:
$this->mustBeString($filter, $index, $conditionRequirements);
break;
case AttributeMapConditionOutput::INT:
$this->mustBeNumber($filter, $index, $conditionRequirements);
if ($conditionRequirements['positive']) {
$this->mustBePositiveNumber($filter, $index, $conditionRequirements);
}
if ($conditionRequirements['integer']) {
$this->mustBeInteger($filter, $index, $conditionRequirements);
}
break;
case AttributeMapConditionOutput::BOOLEAN:
$this->mustBeBoolean($filter, $index);
break;
case AttributeMapConditionOutput::OBJECT:
$this->mustBeValidObject($filter, $index, $conditionRequirements);
break;
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
*
* @return void
*/
protected function mustHaveOneValue($filter, int $index): void
{
if (!isset($filter['value'])) {
throw new InvalidArgumentException('Filter #' . $index . ' requires a "value" field.');
}
if (is_array($filter['value']) && !$this->isAssociativeArray($filter['value'])) {
throw new InvalidArgumentException('Filter #' . $index . ' is malformed, "value" field need to be one value.');
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
*
* @return void
*/
protected function mustHaveSeveralValues($filter, int $index): void
{
if (!isset($filter['value'])) {
throw new InvalidArgumentException('Filter #' . $index . ' requires a "value" field.');
}
if (!is_array($filter['value']) || $this->isAssociativeArray($filter['value'])) {
throw new InvalidArgumentException('Filter #' . $index . ' is malformed, "value" field need to be an array of value.');
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
*
* @return void
*/
protected function mustBeBoolean($filter, int $index): void
{
if (gettype($filter['value']) !== 'boolean') {
throw new InvalidArgumentException("Value of filter #$index must be a boolean, " . gettype($filter['value']) . ' provided');
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function mustBeString($filter, int $index, $conditionRequirements): void
{
$checkValueIsString = function ($value) use ($index): void {
if (!is_string($value)) {
throw new InvalidArgumentException('Value ' . $value . " of filter #$index must be a string.");
}
};
// Single Value
if ($conditionRequirements['multiple']) {
foreach ($filter['value'] as $value) {
$checkValueIsString($value);
}
} else {
$checkValueIsString($filter['value']);
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function mustBeNumber($filter, int $index, $conditionRequirements): void
{
$checkValueIsNumber = function ($value) use ($index): void {
if (!is_numeric($value)) {
throw new InvalidArgumentException('Value ' . $value . " of filter #$index must be a number.");
}
};
if ($conditionRequirements['multiple']) {
foreach ($filter['value'] as $value) {
$checkValueIsNumber($value);
}
} else {
$checkValueIsNumber($filter['value']);
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function mustBePositiveNumber($filter, int $index, $conditionRequirements): void
{
$checkValueIsPositive = function ($value) use ($index): void {
if ($value < 0) {
throw new InvalidArgumentException('Value ' . $value . " of filter #$index is not a positive number.");
}
};
if ($conditionRequirements['multiple']) {
foreach ($filter['value'] as $value) {
$checkValueIsPositive($value);
}
} else {
$checkValueIsPositive($filter['value']);
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function mustBeInteger($filter, int $index, $conditionRequirements): void
{
$checkValueIsInteger = function ($value) use ($index): void {
if (!is_int($value)) {
throw new InvalidArgumentException('Value ' . $value . " of filter #$index is not an integer.");
}
};
if ($conditionRequirements['multiple']) {
foreach ($filter['value'] as $value) {
$checkValueIsInteger($value);
}
} else {
$checkValueIsInteger($filter['value']);
}
}
/**
* @throws InvalidArgumentException
*
* @param $filter
* @param int $index
* @param $conditionRequirements
*
* @return void
*/
protected function mustBeValidObject($filter, int $index, $conditionRequirements): void
{
$checkValueIsValidObject = function ($value) use ($index, $conditionRequirements): void {
if (!$this->isAssociativeArray($value)) {
throw new InvalidArgumentException('Value ' . json_encode($value) . " of filter #$index is not an object.");
}
foreach ($conditionRequirements['keys'] as $key) {
if (!array_key_exists($key, $value)) {
throw new InvalidArgumentException('Value ' . json_encode($value) . " of filter #$index does not have the required '" . $key . '\' key.');
}
}
};
if ($conditionRequirements['multiple']) {
foreach ($filter['value'] as $value) {
$checkValueIsValidObject($value);
}
} else {
$checkValueIsValidObject($filter['value']);
}
}
/**
* @param $array
*
* @return bool
*/
protected function isAssociativeArray($array): bool
{
if (!is_array($array)) {
return false;
}
foreach (array_keys($array) as $key) {
if (!is_string($key)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication;
use Db;
use DbQuery;
class ProductEnumerator
{
/**
* @var FilterValidator
*/
protected $filterValidator;
/**
* @var QueryBuilder
*/
protected $queryBuilder;
public function __construct(
FilterValidator $filterValidator,
QueryBuilder $queryBuilder
) {
$this->filterValidator = $filterValidator;
$this->queryBuilder = $queryBuilder;
}
public function countProductsMatchingFilters(array $filters): int
{
$this->filterValidator->validate($filters);
$res = $this->execute(
$this->queryBuilder->buildQueryToCount($filters)
);
return $res[0]['total'] ?? 0;
}
public function listProductsMatchingFilters(array $filters, array $paginationParams): array
{
$this->filterValidator->validate($filters);
return $this->execute(
$this->queryBuilder->buildQueryToList($filters)
);
}
protected function execute(DbQuery $query): array
{
return Db::getInstance()->executeS($query);
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\AttributeType;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\BrandQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\CategoryQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\FeatureQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\OutOfStockQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\PriceQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\ProductIdQueryBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\FilterApplication\AttributeQueryBuilder\QueryBuilderInterface;
class QueryBuilder
{
/**
* @var int
*/
private $shopId;
/**
* @var QueryBuilderInterface[]
*/
private $builders;
public function __construct(
int $shopId,
BrandQueryBuilder $brandQueryBuilder,
CategoryQueryBuilder $categoryQueryBuilder,
FeatureQueryBuilder $featureQueryBuilder,
OutOfStockQueryBuilder $outOfStockQueryBuilder,
PriceQueryBuilder $priceQueryBuilder,
ProductIdQueryBuilder $productIdQueryBuilder
) {
$this->shopId = $shopId;
$this->builders = [
AttributeType::BRAND => $brandQueryBuilder,
AttributeType::CATEGORY => $categoryQueryBuilder,
AttributeType::FEATURE => $featureQueryBuilder,
AttributeType::OUT_OF_STOCK => $outOfStockQueryBuilder,
AttributeType::PRICE => $priceQueryBuilder,
AttributeType::PRODUCT_ID => $productIdQueryBuilder,
];
}
public function buildQueryToCount(array $filters): DbQuery
{
$query = $this->buildCommonQuery($filters);
$query->select('COUNT(DISTINCT p.id_product) as total');
return $query;
}
public function buildQueryToList(array $filters): DbQuery
{
$query = $this->buildCommonQuery($filters);
// TODO: Selection of columns seems to depend on filters.
$query->select('DISTINCT p.id_product, p.*');
return $query;
}
protected function buildCommonQuery(array $filters): DbQuery
{
$initiatedRelations = $this->initRelations();
$query = new DbQuery();
$query->from('product', 'p');
$query->innerJoin('product_shop', 'ps', 'ps.id_product = p.id_product');
$query->where('ps.id_shop = ' . (int) $this->shopId);
$query->where('ps.active = 1');
foreach ($filters as $index => $filter) {
$query = $this->builders[$filter['attribute']]->addRelations($query, $index);
$query = $this->builders[$filter['attribute']]->addWhereFromFilter($query, $filter, $index);
}
return $query;
}
private function initRelations(): array
{
$initiatedRelations = [];
foreach (AttributeType::all() as $attribute) {
$initiatedRelations[$attribute] = false;
}
return $initiatedRelations;
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Options;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\ManufacturerRepository;
class BrandOptionsProvider implements OptionsProviderInterface
{
/**
* @var ManufacturerRepository
*/
protected $manufacturerRepository;
public function __construct(
ManufacturerRepository $manufacturerRepository
) {
$this->manufacturerRepository = $manufacturerRepository;
}
public function getOptions(): array
{
return array_map(function ($brand) {
return [
'id' => $brand['id'],
'value' => $brand['name'],
];
}, $this->manufacturerRepository->getManufacturersList());
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Options;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\CategoryRepository;
class CategoryOptionsProvider implements OptionsProviderInterface
{
/**
* @var CategoryRepository
*/
protected $categoryRepository;
public function __construct(
CategoryRepository $categoryRepository
) {
$this->categoryRepository = $categoryRepository;
}
public function getOptions(): array
{
return array_map(function ($category) {
return [
'id' => $category['id'],
'value' => $category['name'],
];
}, $this->categoryRepository->getCategoriesList());
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Options;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\AttributesRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\LanguageRepository;
class FeatureOptionsProvider implements OptionsProviderInterface
{
/**
* @var AttributesRepository
*/
protected $attributeRepository;
/**
* @var LanguageRepository
*/
protected $languageRepository;
/**
* @var int
*/
private $currentLanguageId;
public function __construct(
AttributesRepository $attributeRepository,
LanguageRepository $languageRepository,
int $currentLanguageId
) {
$this->attributeRepository = $attributeRepository;
$this->languageRepository = $languageRepository;
$this->currentLanguageId = $currentLanguageId;
}
public function getOptions(): array
{
$rawData = $this->attributeRepository->getFeaturesWithLocalizedValues();
$options = [];
foreach ($rawData as $rawAttribute) {
if (!isset($options[$rawAttribute['id_feature']])) {
$options[$rawAttribute['id_feature']] = [
'id' => $rawAttribute['id_feature'],
'key' => $rawAttribute['feature_name'],
'values' => [],
];
}
if ($this->currentLanguageId === (int) $rawAttribute['id_lang']) {
$options[$rawAttribute['id_feature']]['key'] = $rawAttribute['feature_name'];
}
$options[$rawAttribute['id_feature']]['values'][] = [
'id' => $rawAttribute['id_feature_value'],
// Repeat key to ease the creation of payload when value is selected
'key' => $rawAttribute['feature_name'],
'value' => $rawAttribute['value'],
'language' => $this->languageRepository->getIsoById($rawAttribute['id_lang']),
];
}
return array_values($options);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Options;
interface OptionsProviderInterface
{
public function getOptions(): array;
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\Options;
use InvalidArgumentException;
use PrestaShop\Module\PsxMarketingWithGoogle\ProductFilter\AttributeType;
class Resolver
{
public function getProvider(string $kind): string
{
$providersList = $this->getAttributeKindsAndProviders();
if (!array_key_exists($kind, $providersList)) {
throw new InvalidArgumentException("Provided attribute kind '$kind' is not a valid value");
}
return $providersList[$kind];
}
protected function getAttributeKindsAndProviders(): array
{
return [
AttributeType::BRAND => BrandOptionsProvider::class,
AttributeType::CATEGORY => CategoryOptionsProvider::class,
AttributeType::FEATURE => FeatureOptionsProvider::class,
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,89 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use Carrier;
use Currency;
use Language;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Builder\CarrierBuilder;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\Carrier as DTOCarrier;
use RangePrice;
use RangeWeight;
class CarrierDataProvider
{
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
/**
* @var CarrierBuilder
*/
private $carrierBuilder;
public function __construct(
ConfigurationAdapter $configurationAdapter,
CarrierBuilder $carrierBuilder
) {
$this->configurationAdapter = $configurationAdapter;
$this->carrierBuilder = $carrierBuilder;
}
public function getFormattedData(): array
{
$language = new Language($this->configurationAdapter->get('PS_LANG_DEFAULT'));
$currency = new Currency($this->configurationAdapter->get('PS_CURRENCY_DEFAULT'));
$carriers = Carrier::getCarriers($language->id, false, false, false, null, Carrier::ALL_CARRIERS);
/** @var DTOCarrier[] $carrierLines */
$carrierLines = $this->carrierBuilder->buildCarriers(
$carriers,
$language,
$currency,
$this->configurationAdapter->get('PS_WEIGHT_UNIT')
);
return $carrierLines;
}
/**
* @param array $deliveryPriceByRange
*
* @return false|RangeWeight|RangePrice
*
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function getCarrierRange(array $deliveryPriceByRange)
{
if (isset($deliveryPriceByRange['id_range_weight'])) {
return new RangeWeight($deliveryPriceByRange['id_range_weight']);
}
if (isset($deliveryPriceByRange['id_range_price'])) {
return new RangePrice($deliveryPriceByRange['id_range_price']);
}
return false;
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use Context;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\ConversionEventData;
class CartEventDataProvider
{
/**
* @var Context
*/
protected $context;
public function __construct(Context $context)
{
$this->context = $context;
}
/**
* Return the items concerned by the transaction
* https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#action-data
*/
public function getEventData($sendTo, $data): ConversionEventData
{
$product = $data['product'];
$idProductAttribute = isset($data['id_product_attribute']) ? $data['id_product_attribute'] : 0;
return (new ConversionEventData())
->setSendTo($sendTo)
->setCurrency($this->context->currency->iso_code)
->setValue((string) \Product::getPriceStatic($product->id, true, $idProductAttribute, 2));
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use Context;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\ConversionEventData;
class PageViewEventDataProvider
{
/**
* @var Context
*/
protected $context;
public function __construct(Context $context)
{
$this->context = $context;
}
/**
* Return the items concerned by the transaction
* https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-ecommerce#action-data
*
* @return ConversionEventData|null
*/
public function getEventData($sendTo)
{
if ($this->context->controller instanceof \ProductControllerCore) {
/** @var \ProductControllerCore $controller */
$controller = $this->context->controller;
$product = $controller->getTemplateVarProduct();
return (new ConversionEventData())
->setSendTo($sendTo)
->setCurrency($this->context->currency->iso_code)
->setValue((string) $product['price_amount']);
}
return null;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use Context;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\Remarketing\ProductData;
class ProductDataProvider
{
/**
* @var Context
*/
protected $context;
public function __construct(Context $context)
{
$this->context = $context;
}
public function getProductDataByProductArray(array $product): ProductData
{
$productData = new ProductData();
$productData->setId(implode(
'-',
[
(int) $product['id_product'],
(int) $product['id_product_attribute'],
]
));
$productData->setPrice((float) $product['product_price_wt']);
$productData->setQuantity((int) $product['product_quantity']);
return $productData;
}
public function getProductDataByProductObject(array $params): ProductData
{
$product = $params['product'];
$productData = new ProductData();
$productData->setId(implode(
'-',
[
(int) $product->id,
(int) $params['id_product_attribute'],
]
));
$productData->setPrice($product->price);
$productData->setQuantity($params['quantity']);
return $productData;
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use Context;
use Order;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\Module\PsxMarketingWithGoogle\DTO\Remarketing\PurchaseEventData;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\CountryRepository;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\LanguageRepository;
class PurchaseEventDataProvider
{
/**
* @var ProductDataProvider
*/
protected $productDataProvider;
/**
* @var Context
*/
protected $context;
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
/**
* @var LanguageRepository
*/
private $languageRepository;
/**
* @var CountryRepository
*/
private $countryRepository;
public function __construct(
ProductDataProvider $productDataProvider,
Context $context,
ConfigurationAdapter $configurationAdapter,
LanguageRepository $languageRepository,
CountryRepository $countryRepository
) {
$this->productDataProvider = $productDataProvider;
$this->context = $context;
$this->configurationAdapter = $configurationAdapter;
$this->languageRepository = $languageRepository;
$this->countryRepository = $countryRepository;
}
/**
* Return the items concerned by the transaction
*
* @see https://support.google.com/google-ads/answer/9028614
*/
public function getEventData($sendTo, Order $order): PurchaseEventData
{
$purchaseData = new PurchaseEventData();
// Common details
$purchaseData->setSendTo($sendTo);
$purchaseData->setCurrency($this->context->currency->iso_code);
$purchaseData->setValue((string) $order->total_products_wt);
$purchaseData->setTransactionId($order->id_cart);
// CwCD Parameters
$purchaseData->setDiscount((float) $order->total_discounts_tax_incl);
$purchaseData->setAwMerchandId((int) $this->configurationAdapter->get(Config::REMARKETING_CONVERSION_MERCHANT_GMC_ID));
$purchaseData->setAwFeedCountry(
$this->countryRepository->getIsoById(
$this->context->country->id
)
);
$purchaseData->setAwFeedLanguage(
$this->languageRepository->getIsoById(
$this->context->language->id
)
);
$items = [];
foreach ($order->getCartProducts() as $product) {
$items[] = $this->productDataProvider->getProductDataByProductArray($product);
}
$purchaseData->setItems($items);
return $purchaseData;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Provider;
use DateInterval;
use DateTimeImmutable;
use DateTimeZone;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\Module\PsxMarketingWithGoogle\Repository\VerificationTagRepository;
class VerificationTagDataProvider
{
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
/**
* @var VerificationTagRepository
*/
private $verificationTagRepository;
public function __construct(
ConfigurationAdapter $configurationAdapter,
VerificationTagRepository $verificationTagRepository
) {
$this->configurationAdapter = $configurationAdapter;
$this->verificationTagRepository = $verificationTagRepository;
}
public function isUpdateRequested(): bool
{
// If GMC account is not onboarded, do nothing.
if (empty($this->configurationAdapter->get(Config::REMARKETING_CONVERSION_MERCHANT_GMC_ID))) {
return false;
}
$configuration = $this->verificationTagRepository->getConfiguration();
return !$configuration || (
(new DateTimeImmutable($configuration['date_upd'], new DateTimeZone('UTC'))) <
(new DateTimeImmutable('now', new DateTimeZone('UTC')))->sub(new DateInterval('P30D'))
);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,94 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Db;
use DbQuery;
class AttributesRepository
{
/**
* @var Context
*/
private $context;
public function __construct(Context $context)
{
$this->context = $context;
}
/**
* Get all custom attributes that are used as product features and combination of attributes.
* Data used in Product feed configuration > Attribute mapping.
*
* @return array
*/
public function getAllAttributes(): array
{
$attributes = [];
foreach ($this->getCustomAttributes() as $attr) {
$attributes[] = [
// Not the best way in terms of permances, but avoid being responsible of a whole SQL query.
'name' => array_values(array_unique((array) (new \AttributeGroupCore($attr['id_attribute_group']))->name)),
'type' => 'custom',
];
}
foreach ($this->getFeatures() as $feature) {
$attributes[] = [
// Not the best way in terms of permances, but avoid being responsible of a whole SQL query.
'name' => array_values(array_unique((array) (new \FeatureCore($feature['id_feature']))->name)),
'type' => 'feature',
];
}
return $attributes;
}
/**
* Data used for Product filters
*/
public function getFeaturesWithLocalizedValues(): array
{
$query = new DbQuery();
$query->select('f.id_feature, fvl.id_lang, fl.name AS feature_name, fvl.id_feature_value, fvl.value')
->from('feature', 'f')
->innerJoin('feature_shop', 'fs', 'fs.id_feature = f.id_feature')
->innerJoin('feature_lang', 'fl', 'fl.id_feature = f.id_feature')
->innerJoin('feature_value', 'fv', 'fv.id_feature = f.id_feature')
->innerJoin('feature_value_lang', 'fvl', 'fvl.id_feature_value = fv.id_feature_value AND fvl.id_lang = fl.id_lang')
->where('fs.id_shop = ' . (int) $this->context->shop->id);
return Db::getInstance()->executeS($query);
}
protected function getCustomAttributes(): array
{
return \AttributeGroupCore::getAttributesGroups($this->context->language->id);
}
protected function getFeatures(): array
{
return \FeatureCore::getFeatures($this->context->language->id);
}
}

View File

@@ -0,0 +1,114 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Carrier;
use RangePrice;
use RangeWeight;
class CarrierRepository
{
public function getCarriers(int $langId): array
{
$carriers = Carrier::getCarriers($langId, false, false, false, null, Carrier::ALL_CARRIERS);
$data = [];
foreach ($carriers as $key => $carrier) {
$carrierObj = new Carrier($carrier['id_carrier']);
$data[$key]['collection'] = 'carriers';
$data[$key]['id'] = $carrierObj->id;
$data[$key]['properties'] = $carrier;
$deliveryPriceByRanges = self::getDeliveryPriceByRange($carrierObj);
foreach ($deliveryPriceByRanges as $deliveryPriceByRange) {
$data[$key]['collection'] = 'carriers_details';
$data[$key]['id'] = $deliveryPriceByRange['id_range_weight'];
$data[$key]['properties'] = $deliveryPriceByRange;
}
}
return $data;
}
public function getDeliveryPriceByRange(Carrier $carrierObj): array
{
$rangeTable = $carrierObj->getRangeTable();
switch ($rangeTable) {
case 'range_weight':
return self::getCarrierByWeightRange($carrierObj);
case 'range_price':
return self::getCarrierByPriceRange($carrierObj);
default:
return [];
}
}
private function getCarrierByPriceRange(Carrier $carrierObj): array
{
$deliveryPriceByRange = Carrier::getDeliveryPriceByRanges('range_price', (int) $carrierObj->id);
$filteredRanges = [];
foreach ($deliveryPriceByRange as $range) {
$filteredRanges[$range['id_range_price']]['id_range_price'] = $range['id_range_price'];
$filteredRanges[$range['id_range_price']]['id_carrier'] = $range['id_carrier'];
$filteredRanges[$range['id_range_price']]['zones'][$range['id_zone']]['id_zone'] = $range['id_zone'];
$filteredRanges[$range['id_range_price']]['zones'][$range['id_zone']]['price'] = $range['price'];
}
return $filteredRanges;
}
private function getCarrierByWeightRange(Carrier $carrierObj): array
{
$deliveryPriceByRange = Carrier::getDeliveryPriceByRanges('range_weight', (int) $carrierObj->id);
$filteredRanges = [];
foreach ($deliveryPriceByRange as $range) {
$filteredRanges[$range['id_range_weight']]['id_range_weight'] = $range['id_range_weight'];
$filteredRanges[$range['id_range_weight']]['id_carrier'] = $range['id_carrier'];
$filteredRanges[$range['id_range_weight']]['zones'][$range['id_zone']]['id_zone'] = $range['id_zone'];
$filteredRanges[$range['id_range_weight']]['zones'][$range['id_zone']]['price'] = $range['price'];
}
return $filteredRanges;
}
/**
* @param array $deliveryPriceByRange
*
* @return false|RangeWeight|RangePrice
*
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
public function getCarrierRange(array $deliveryPriceByRange)
{
if (isset($deliveryPriceByRange['id_range_weight'])) {
return new RangeWeight($deliveryPriceByRange['id_range_weight']);
}
if (isset($deliveryPriceByRange['id_range_price'])) {
return new RangePrice($deliveryPriceByRange['id_range_price']);
}
return false;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Db;
use DbQuery;
class CategoryRepository
{
/**
* @var Context
*/
private $context;
public function __construct(Context $context)
{
$this->context = $context;
}
public function getCategoriesList(): array
{
$query = new DbQuery();
$query->select('DISTINCT c.id_category AS id, cl.name AS name')
->from('category', 'c')
->innerJoin('category_shop', 'cs', 'cs.id_category = c.id_category')
->innerJoin('category_lang', 'cl', 'cl.id_category = c.id_category')
->where('cs.id_shop = ' . (int) $this->context->shop->id)
->where('cl.id_lang = ' . (int) $this->context->language->id)
// allows you to remove the root category and the categories cannot be administered or assigned to a product.
->where('c.id_parent <> 0')
->where('c.active = 1');
return Db::getInstance()->executeS($query);
}
}

View File

@@ -0,0 +1,183 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Country;
use Db;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\Adapter\ConfigurationAdapter;
class CountryRepository
{
/**
* @var Db
*/
private $db;
/**
* @var Context
*/
private $context;
private $countryIsoCodeCache = [];
/**
* @var ConfigurationAdapter
*/
private $configurationAdapter;
private $country;
public function __construct(Db $db, Context $context, Country $country, ConfigurationAdapter $configAdapter)
{
$this->db = $db;
$this->context = $context;
$this->country = $country;
$this->configurationAdapter = $configAdapter;
}
private function getBaseQuery(): DbQuery
{
$query = new DbQuery();
$query->from('country', 'c')
->innerJoin('country_shop', 'cs', 'cs.id_country = c.id_country')
->innerJoin('country_lang', 'cl', 'cl.id_country = c.id_country')
->where('cs.id_shop = ' . (int) $this->context->shop->id)
->where('cl.id_lang = ' . (int) $this->context->language->id);
return $query;
}
public function getCountryIsoCodesByZoneId(int $zoneId, bool $active = true): array
{
$cacheKey = $zoneId . '-' . (int) $active;
if (!isset($this->countryIsoCodeCache[$cacheKey])) {
$query = $this->getBaseQuery();
$query->select('iso_code');
$query->where('id_zone = ' . (int) $zoneId);
$query->where('active = ' . (bool) $active);
$isoCodes = [];
foreach ($this->db->executeS($query) as $country) {
$isoCodes[] = $country['iso_code'];
}
$this->countryIsoCodeCache[$cacheKey] = $isoCodes;
}
return $this->countryIsoCodeCache[$cacheKey];
}
public function getActiveCountries(): array
{
$query = $this->getBaseQuery();
$query->select('iso_code');
$query->where('active = ' . true);
$isoCodes = [];
foreach ($this->db->executeS($query) as $country) {
$isoCodes[] = $country['iso_code'];
}
return $isoCodes;
}
public function getShopDefaultCountry(): array
{
return [
'name' => Country::getNameById($this->context->language->id, $this->configurationAdapter->get('PS_COUNTRY_DEFAULT')),
'iso_code' => Country::getIsoById($this->configurationAdapter->get('PS_COUNTRY_DEFAULT')),
];
}
public function getIsoById(int $countryId)
{
return Country::getIsoById($countryId);
}
public function getShopContactCountry(): array
{
if (empty($this->configurationAdapter->get('PS_SHOP_COUNTRY_ID'))) {
return [
'name' => null,
'iso_code' => null,
];
}
return [
'name' => Country::getNameById($this->context->language->id, $this->configurationAdapter->get('PS_SHOP_COUNTRY_ID')),
'iso_code' => Country::getIsoById($this->configurationAdapter->get('PS_SHOP_COUNTRY_ID')),
];
}
public function countryNeedState(int $countryId): bool
{
return Country::containsStates($this->configurationAdapter->get($countryId));
}
/**
* isCompatibleForCSS
*
* @return bool
*/
public function isCompatibleForCSS()
{
$availableCountries = [
'BG',
'BE',
'CZ',
'DK',
'CY',
'LV',
'LT',
'LU',
'ES',
'FR',
'HR',
'IT',
'PL',
'PT',
'RO',
'SI',
'HU',
'MT',
'NL',
'AT',
'IS',
'LI',
'NO',
'SK',
'FI',
'SE',
'DE',
'IE',
'EL',
'CH',
'GB',
];
return in_array($this->country->iso_code, $availableCountries);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Currency;
class CurrencyRepository
{
/**
* @var Currency
*/
private $currency;
/**
* @var Context
*/
private $context;
public function __construct(Currency $currency, Context $context)
{
$this->currency = $currency;
$this->context = $context;
}
/**
* Get details about the currency associated to the shop context.
* Don't return all the details about the currency, as they should be
* available from another source (i.e CLDR json).
*
* @return array
*/
public function getShopCurrency(): array
{
return [
'isoCode' => $this->currency->iso_code,
];
}
public function getActiveCurrencies(): array
{
$isoCodes = [];
foreach (Currency::getCurrenciesByIdShop((int) $this->context->shop->id) as $currency) {
if (!$currency['active'] || $currency['deleted']) {
continue;
}
$isoCodes[] = $currency['iso_code'];
}
return $isoCodes;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Language;
class LanguageRepository
{
/**
* @var int
*/
private $shopId;
public function __construct(int $shopId)
{
$this->shopId = $shopId;
}
public function getIsoById(int $id)
{
return Language::getIsoById($id);
}
public function getLanguages(): array
{
$languages = Language::getLanguages(false, $this->shopId);
return array_map(function ($language) {
return $language['iso_code'];
}, $languages);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Db;
use DbQuery;
class ManufacturerRepository
{
/**
* @var Context
*/
private $context;
public function __construct(Context $context)
{
$this->context = $context;
}
public function getManufacturersList(): array
{
$query = new DbQuery();
$query->select('DISTINCT m.id_manufacturer AS id, m.name AS name')
->from('manufacturer', 'm')
->innerJoin('manufacturer_shop', 'ms', 'ms.id_manufacturer = m.id_manufacturer')
->where('ms.id_shop = ' . (int) $this->context->shop->id)
->where('m.active = 1');
return Db::getInstance()->executeS($query);
}
}

View File

@@ -0,0 +1,121 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Module;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
class ModuleRepository
{
/**
* @var string
*/
private $moduleName;
public function __construct(string $moduleName)
{
$this->moduleName = $moduleName;
}
/**
* @return string|null
*/
public function getModuleVersion()
{
/** @var Module|null $module */
$module = Module::getInstanceByName($this->moduleName);
if (!empty($module)) {
return $module->version;
}
return null;
}
/**
* @return string
*/
public function getUpgradeLink()
{
$router = SymfonyContainer::getInstance()->get('router');
return \Tools::getHttpHost(true) . $router->generate('admin_module_manage_action', [
'action' => 'upgrade',
'module_name' => $this->moduleName,
]);
}
/**
* @return string
*/
public function getEnableLink()
{
$router = SymfonyContainer::getInstance()->get('router');
return \Tools::getHttpHost(true) . $router->generate('admin_module_manage_action', [
'action' => 'enable',
'module_name' => $this->moduleName,
]);
}
/**
* @return array
*/
public function getInformationsAboutModule(): array
{
return [
'version' => $this->getModuleVersion(),
'upgradeLink' => $this->getUpgradeLink(),
'hooks' => $this->getActiveHooks(),
];
}
/**
* @return bool
*/
public function moduleIsEnabled(): bool
{
return Module::isEnabled($this->moduleName);
}
/**
* @return array
*/
public function getActiveHooks(): array
{
$context = Context::getContext();
$hooks = [];
/** @var Module|null $moduleInstance */
$moduleInstance = Module::getInstanceByName($this->moduleName);
if (empty($moduleInstance)) {
return $hooks;
}
foreach (Config::HOOK_LIST as $hook) {
$hooks[$hook] = \Hook::isModuleRegisteredOnHook($moduleInstance, $hook, $context->shop->id);
}
return $hooks;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Db;
use DbQuery;
class ProductRepository
{
public function getProductsTotal($shopId, array $options = [])
{
$sql = new DbQuery();
$sql->select('COUNT(1) as total');
$sql->from('product', 'p');
$sql->innerJoin('product_shop', 'ps', 'ps.id_product = p.id_product');
if (isset($options['splitPerLangAndCombination'])) {
$sql->innerJoin('product_lang', 'pl', 'pl.id_product = ps.id_product AND pl.id_shop = ps.id_shop');
$sql->leftJoin('product_attribute_shop', 'pas', 'pas.id_product = ps.id_product AND pas.id_shop = ps.id_shop');
}
$sql->where('ps.id_shop = ' . (int) $shopId);
if (isset($options['onlyActive'])) {
$sql->where('ps.active = 1');
}
$res = Db::getInstance()->executeS($sql);
return $res[0]['total'];
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Db;
use DbQuery;
class StateRepository
{
/**
* @var Db
*/
private $db;
private $stateIsoCodeCache = [];
public function __construct(Db $db)
{
$this->db = $db;
}
private function getBaseQuery(): DbQuery
{
$query = new DbQuery();
$query->from('state', 's');
return $query;
}
public function getStateIsoCodesByZoneId(int $zoneId, bool $active = true): array
{
$cacheKey = $zoneId . '-' . (int) $active;
if (!isset($this->stateIsoCodeCache[$cacheKey])) {
$query = $this->getBaseQuery();
$query->select('s.iso_code');
$query->innerJoin('country', 'c', 'c.id_country = s.id_country');
$query->where('s.id_zone = ' . (int) $zoneId);
$query->where('s.active = ' . (bool) $active);
$query->where('c.active = ' . (bool) $active);
$isoCodes = [];
foreach ($this->db->executeS($query) as $state) {
$isoCodes[] = $state['iso_code'];
}
$this->stateIsoCodeCache[$cacheKey] = $isoCodes;
}
return $this->stateIsoCodeCache[$cacheKey];
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Db;
use DbQuery;
class TabRepository
{
public function hasChildren(int $tabId): bool
{
$sql = new DbQuery();
$sql->select('id_tab');
$sql->from('tab');
$sql->where('`id_parent` = "' . (int) $tabId . '"');
return (bool) Db::getInstance()->getValue($sql);
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Db;
use DbQuery;
class TaxRepository
{
/**
* @var Db
*/
private $db;
/**
* @var Context
*/
private $context;
private $countryIsoCodeCache = [];
public function __construct(Db $db, Context $context)
{
$this->db = $db;
$this->context = $context;
}
private function getBaseQuery(): DbQuery
{
$query = new DbQuery();
$query->from('tax', 't')
->innerJoin('tax_rule', 'tr', 'tr.id_tax = t.id_tax')
->innerJoin('tax_rules_group', 'trg', 'trg.id_tax_rules_group = tr.id_tax_rules_group')
->innerJoin('tax_rules_group_shop', 'trgs', 'trgs.id_tax_rules_group = tr.id_tax_rules_group')
->innerJoin('tax_lang', 'tl', 'tl.id_tax = t.id_tax')
->where('trgs.id_shop = ' . (int) $this->context->shop->id)
->where('tl.id_lang = ' . (int) $this->context->language->id);
return $query;
}
public function getCarrierTaxesByTaxRulesGroupId(int $taxRulesGroupId, bool $active = true): array
{
$cacheKey = (int) $taxRulesGroupId . '-' . (int) $active;
if (!isset($this->countryIsoCodeCache[$cacheKey])) {
$query = $this->getBaseQuery();
$query->select('rate, c.iso_code as country_iso_code, GROUP_CONCAT(s.iso_code SEPARATOR ",") as state_iso_code');
$query->leftJoin('country', 'c', 'c.id_country = tr.id_country');
$query->leftJoin('state', 's', 's.id_state = tr.id_state');
$query->where('tr.id_tax_rules_group = ' . (int) $taxRulesGroupId);
$query->where('c.active = ' . (bool) $active);
$query->where('s.active = ' . (bool) $active . ' OR s.active IS NULL');
$query->where('t.active = ' . (bool) $active);
$query->where('c.iso_code IS NOT NULL');
$this->countryIsoCodeCache[$cacheKey] = $this->db->executeS($query);
}
return $this->countryIsoCodeCache[$cacheKey];
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Repository;
use Context;
use Db;
use DbQuery;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
class VerificationTagRepository
{
/**
* @var Db
*/
private $db;
/**
* @var Context
*/
private $context;
public function __construct(Db $db, Context $context)
{
$this->db = $db;
$this->context = $context;
}
/**
* @return array|false
*/
public function getConfiguration()
{
$query = new DbQuery();
$query->select('c.value, c.date_upd')
->from('configuration', 'c')
->where('(c.id_shop = ' . (int) $this->context->shop->id . ' or ISNULL(c.id_shop))')
->where('c.name = "' . Config::PSX_MKTG_WITH_GOOGLE_WEBSITE_VERIFICATION_META . '"');
return $this->db->getRow($query);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,192 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Tracker;
use Context;
use PrestaShop\Module\PsxMarketingWithGoogle\Config\Config;
class Segment implements TrackerInterface
{
/**
* @var string
*/
private $message = '';
/**
* @var array
*/
private $options = [];
/**
* @var Context
*/
private $context;
/**
* Segment constructor.
*/
public function __construct(Context $context)
{
$this->context = $context;
$this->init();
}
/**
* Init segment client with the api key
*/
private function init()
{
\Segment::init(Config::PSX_MKTG_WITH_GOOGLE_SEGMENT_API_KEY);
}
/**
* Track event on segment
*
* @return bool
*
* @throws \PrestaShopException
*/
public function track()
{
if (empty($this->message)) {
throw new \PrestaShopException('Message cannot be empty. Need to set it with setMessage() method.');
}
// Dispatch track depending on context shop
$this->dispatchTrack();
return true;
}
private function segmentTrack($userId)
{
$userAgent = array_key_exists('HTTP_USER_AGENT', $_SERVER) === true ? $_SERVER['HTTP_USER_AGENT'] : '';
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) === true ? $_SERVER['REMOTE_ADDR'] : '';
$referer = array_key_exists('HTTP_REFERER', $_SERVER) === true ? $_SERVER['HTTP_REFERER'] : '';
$url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
\Segment::track([
'userId' => $userId,
'event' => $this->message,
'channel' => 'browser',
'context' => [
'ip' => $ip,
'userAgent' => $userAgent,
'locale' => $this->context->language->iso_code,
'page' => [
'referrer' => $referer,
'url' => $url,
],
],
'properties' => array_merge([
'module' => 'psxmarketingwithgoogle',
], $this->options),
]);
\Segment::flush();
}
/**
* Handle tracking differently depending on the shop context
*
* @return mixed
*/
private function dispatchTrack()
{
$dictionary = [
\Shop::CONTEXT_SHOP => function () {
return $this->trackShop();
},
\Shop::CONTEXT_GROUP => function () {
return $this->trackShopGroup();
},
\Shop::CONTEXT_ALL => function () {
return $this->trackAllShops();
},
];
return call_user_func($dictionary[$this->context->shop->getContext()]);
}
/**
* Send track segment only for the current shop
*/
private function trackShop()
{
$userId = $this->context->shop->domain;
$this->segmentTrack($userId);
}
/**
* Send track segment for each shop in the current shop group
*/
private function trackShopGroup()
{
$shops = $this->context->shop->getShops(true, $this->context->shop->getContextShopGroupID());
foreach ($shops as $shop) {
$this->segmentTrack($shop['domain']);
}
}
/**
* Send track segment for all shops
*/
private function trackAllShops()
{
$shops = $this->context->shop->getShops();
foreach ($shops as $shop) {
$this->segmentTrack($shop['domain']);
}
}
/**
* @return string
*/
public function getMessage()
{
return $this->message;
}
/**
* @param string $message
*/
public function setMessage($message)
{
$this->message = $message;
}
/**
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* @param array $options
*/
public function setOptions($options)
{
$this->options = $options;
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Tracker;
interface TrackerInterface
{
/**
* @return void
*/
public function track();
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,74 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Config;
class Config
{
public const PSX_MKTG_WITH_GOOGLE_API_URL = 'https://googleshopping-api.psessentials.net';
public const PSX_MKTG_WITH_GOOGLE_CDN_URL = 'https://storage.googleapis.com/psxmarketing-cdn/v1.x.x/js/';
public const PSX_MKTG_WITH_GOOGLE_BILLING_CDC_URL = 'https://unpkg.com/@prestashopcorp/billing-cdc/dist/bundle.js';
public const PSX_MKTG_WITH_GOOGLE_BILLING_PREPROD_CDC_URL = 'https://unpkg.com/@prestashopcorp/billing-cdc@preprod/dist/bundle.js';
public const PSX_MKTG_WITH_GOOGLE_CLOUDSYNC_CDC_URL = 'https://assets.prestashop3.com/ext/cloudsync-merchant-sync-consent/latest/cloudsync-cdc.js';
public const PSX_MKTG_WITH_GOOGLE_CLOUDSYNC_PREPROD_CDC_URL = 'https://integration-assets.prestashop3.com/ext/cloudsync-merchant-sync-consent/latest/cloudsync-cdc.js';
public const HOOK_LIST = [
'displayBackOfficeHeader',
'displayHeader',
'displayOrderConfirmation',
'displayTop',
'actionCartUpdateQuantityBefore',
];
public const CONFIGURATION_LIST = [];
public const MODULE_ADMIN_CONTROLLERS = [
'AdminAjaxPsgoogleshipping',
'AdminPsgoogleshippingModule',
];
public const PSX_MKTG_WITH_GOOGLE_SENTRY_CREDENTIALS_PHP = 'https://446479f8bca645fa8838c1a5f99dceba@o298402.ingest.sentry.io/5949536';
public const PSX_MKTG_WITH_GOOGLE_SENTRY_CREDENTIALS_VUE = 'https://6504c60594bd490eab93afa78f274e35@o298402.ingest.sentry.io/5984715';
public const USE_LOCAL_VUE_APP = false;
public const USE_LIVE_VUE_APP = false;
public const USE_BILLING_SANDBOX = 0;
public const USE_BILLING_PREPROD = 0;
public const USE_CLOUDSYNC_PREPROD = 0;
public const PSX_MKTG_WITH_GOOGLE_SEGMENT_API_KEY = 'RqYiLJKyoWv13t9aKxBvza6vsCsRpPpC';
public const PSX_MKTG_WITH_GOOGLE_WEBSITE_VERIFICATION_META = 'PSX_MKTG_WITH_GOOGLE_WEBSITE_VERIFICATION_META';
public const PSX_MKTG_WITH_GOOGLE_WEBSITE_REQUIREMENTS_STATUS = 'PSX_MKTG_WITH_GOOGLE_WEBSITE_REQUIREMENTS_STATUS';
public const PSX_MKTG_WITH_GOOGLE_REMARKETING_STATUS = 'PSX_MKTG_WITH_GOOGLE_REMARKETING_STATUS';
public const PSX_MKTG_WITH_GOOGLE_REMARKETING_ENHANCED_STATUS = 'PSX_MKTG_WITH_GOOGLE_REMARKETING_ENHANCED_STATUS';
public const PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG = 'PSX_MKTG_WITH_GOOGLE_REMARKETING_TAG';
public const PSX_MKTG_WITH_GOOGLE_REMARKETING_CONVERSION_LABELS = 'PSX_MKTG_WITH_GOOGLE_REMARKETING_CONVERSION_LABELS';
public const REMARKETING_CONVERSION_LABEL_PURCHASE = 'PURCHASE';
public const REMARKETING_CONVERSION_LABEL_ADD_TO_CART = 'ADD_TO_CART';
public const REMARKETING_CONVERSION_LABEL_PAGE_VIEW = 'PAGE_VIEW';
public const REMARKETING_CONVERSION_LABELS = [
self::REMARKETING_CONVERSION_LABEL_PURCHASE,
self::REMARKETING_CONVERSION_LABEL_ADD_TO_CART,
self::REMARKETING_CONVERSION_LABEL_PAGE_VIEW,
];
public const REMARKETING_CONVERSION_MERCHANT_GMC_ID = 'REMARKETING_CONVERSION_MERCHANT_GMC_ID';
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
namespace PrestaShop\Module\PsxMarketingWithGoogle\Config;
/**
* This class allows to retrieve config data that can be overwritten by a .env file.
* Otherwise it returns by default from the Config class.
*/
class Env
{
/**
* @param string $key
*
* @return string
*/
public function get($key)
{
if (!empty($_ENV[$key])) {
return $_ENV[$key];
}
return constant(Config::class . '::' . $key);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;