<?php
namespace App\EventSubscriber;
use App\Ecommerce\Model\AbstractTaxClass;
use Pimcore\Event\DataObjectEvents;
use Pimcore\Event\Model\DataObjectEvent;
use Pimcore\Model\DataObject\OnlineShopTaxClass;
use Pimcore\Model\DataObject\Service;
use App\Classes\Tools\ForceInheritance;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class TaxClassEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
DataObjectEvents::PRE_ADD => [
['addPrefixToNewEntry', 10]
],
DataObjectEvents::PRE_UPDATE => [
['updateKey', 10],
['updatePath', 8],
['updateAttributes', 6],
['calculateZipCodes', 4],
['validate', 2]
]
];
}
private function isResponsibleFor(DataObjectEvent $event): bool
{
if ($event->getObject() instanceof AbstractTaxClass) {
return true;
}
return false;
}
protected function isCountryObjectOnly(OnlineShopTaxClass $tax)
{
$state = ForceInheritance::run(function () use ($tax) {
return strtoupper($tax->getState());
});
if (!empty($state) && $state != '*') {
return false;
}
if (!empty($tax->getZipCode()) && $this->trimZipCodes($tax->getZipCode()) != '*') {
return false;
}
return true;
}
protected function isStateObjectOnly(OnlineShopTaxClass $tax)
{
$state = ForceInheritance::run(function () use ($tax) {
return strtoupper($tax->getState());
});
if (empty($state)) {
return false;
}
if (!empty($tax->getZipCode()) && $this->trimZipCodes($tax->getZipCode()) != '*') {
return false;
}
return true;
}
protected function isTaxOverideObjectOnly(OnlineShopTaxClass $tax)
{
if (empty($tax->getZipCode()) && $this->trimZipCodes($tax->getZipCode()) != '*') {
return false;
}
return true;
}
public function addPrefixToNewEntry(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
return;
/** @var OnlineShopTaxClass */
$object = $event->getObject();
$object->setKey('__'.$object->getKey());
}
public function updateKey(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
/** @var OnlineShopTaxClass */
$object = $event->getObject();
$inheritedCountryCode = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getCountryCode());
});
$inheritedStateCode = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getState());
});
$key = $object->getKey();
if ($object->isPublished() && $this->isCountryObjectOnly($object)) {
$key = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getCountryCode());
});
} else if ($object->isPublished() && $this->isStateObjectOnly($object)) {
if (empty($inheritedCountryCode)) {
throw new \Exception("You must select country code!");
}
$key = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getState());
});
} else if ($object->isPublished()){
if (empty($inheritedStateCode)) {
throw new \Exception("You must select state/region!");
}
}
$object->setKey($key);
}
public function updatePath(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
/** @var OnlineShopTaxClass */
$object = $event->getObject();
$countryCode = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getCountryCode());
});
$stateCode = ForceInheritance::run(function () use ($object) {
return strtoupper($object->getState());
});
$combinationMode = ForceInheritance::run(function () use ($object) {
return $object->getTaxEntryCombinationType();
});
$applicationType = ForceInheritance::run(function () use ($object) {
return $object->getApplyToAddressType();
});
$parent = Service::createFolderByPath(AbstractTaxClass::FOLDER_PATH);
$options = [
'combination_mode' => $combinationMode,
'application_type' => $applicationType
];
if ($object->isPublished() && $this->isStateObjectOnly($object)) {
$parent = OnlineShopTaxClass::getByPath(AbstractTaxClass::FOLDER_PATH.$countryCode);
if (!$parent) {
$parent = $this->createTax($countryCode, null, $options);
// Leave empty so he would inherit this value from parent
// This should apply only once, during creation tree, so this is reason why we put this here
$object->setTaxEntryCombinationType('');
$object->setApplyToAddressType('');
}
}
if ($object->isPublished() && $this->isTaxOverideObjectOnly($object)) {
$parent = OnlineShopTaxClass::getByPath(AbstractTaxClass::FOLDER_PATH.$countryCode.'/'.$stateCode);
if (!$parent) {
$parent = $this->createTax($countryCode, $stateCode, $options);
// Leave empty so he would inherit this value from parent
// This should apply only once, during creation tree, so this is reason why we put this here
$object->setTaxEntryCombinationType('');
$object->setApplyToAddressType('');
}
}
$object->setParent($parent);
}
public function updateAttributes(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
$object = $event->getObject();
if (!$object->isPublished()) {
return;
}
if (!empty($object->getZipCode())) {
$object->setCountry("");
$object->setState("");
} else if (!empty($object->getState())) {
$object->setCountry("");
} else if (!empty($object->getCountry())) {
}
}
public function calculateZipCodes(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
/** @var OnlineShopTaxClass */
$object = $event->getObject();
$cleanZipcode = $this->trimZipCodes($object->getZipCode() ?? '');
if (!$this->isPatern($cleanZipcode)) {
$object->setZipCodeValues(','.$cleanZipcode.',');
}
}
public function validate(DataObjectEvent $event)
{
if (!$this->isResponsibleFor($event)) {
return;
}
/** @var OnlineShopTaxClass */
$object = $event->getObject();
if (!$object->isPublished()) {
return;
}
// Nothing for now
}
protected function isPatern(string $value)
{
return preg_match_all('/^[A-Za-z0-9,]$/', $value, $matches);
}
protected function trimZipCodes(?string $zipCodes)
{
$zipCodes = str_replace(' ', '', $zipCodes ?? '');
return trim($zipCodes, " ,\t\n\r\0\x0B");
}
protected function createTax(string $countryCode, ?string $stateCode = null, array $options = [])
{
$object = new OnlineShopTaxClass();
// $object->setTaxEntryCombinationType(OnlineShopTaxClass::COMBINATION_MODE_COMBINE);
$object->setTaxEntryCombinationType($options['combination_mode']);
$object->setApplyToAddressType($options['application_type']);
$object->setCountry($countryCode);
$object->setPublished(true);
$object->setKey($countryCode);
$path = OnlineShopTaxClass::FOLDER_PATH;
if ($stateCode) {
$path = OnlineShopTaxClass::FOLDER_PATH.strtoupper($countryCode).'/';
// Leave empty so he would inherit this value from parent
$object->setCountry("");
$object->setState($stateCode);
$object->setKey($stateCode);
}
$parent = null;
if ($stateCode) {
$parent = OnlineShopTaxClass::getByPath($path);
if (!$parent) {
$parent = $this->createTax($countryCode, null, $options);
// Leave empty so he would inherit this value from parent
$object->setTaxEntryCombinationType('');
$object->setApplyToAddressType('');
}
} else {
$parent = Service::createFolderByPath(AbstractTaxClass::FOLDER_PATH);
}
$object->setParent($parent);
// dd($object->getKey(), $object->getPath(), '-----', $parent->getPath(), $parent->getKey());
$object->save();
return $object;
}
}