diff --git a/.gitignore b/.gitignore index a9a3290..8d80310 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ retailcrm/views/css/less/*.map retailcrm/views/css/*.css retailcrm/views/css/*.map !retailcrm/views/css/*.min.css -retailcrm/config_*.xml +retailcrm/config*.xml +retailcrm/custom coverage.xml \ No newline at end of file diff --git a/README.md b/README.md index a597a6a..886da6b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,31 @@ Module allows integrate CMS Prestashop with [RetailCRM](https://www.retailcrm.pr #### Customization -If you want to change the default behavior of a module classes and be sure that these changes won't be overwritten during the module upgrade process, you should **copy the original classes** that you are going to customize to the `prestashop-root/modules/retailcrm_custom/classes` directory. +##### Filters + +If you want to modify data, sent between CRM and CMS you can use custom filters. +There are list of available filters: + +* *RetailcrmFilterProcessOrder* - order array, which will be sent to CRM +* *RetailcrmFilterProcessCustomer* - customer array, which will be sent to CRM +* *RetailcrmFilterProcessCustomerCorporate* - corporate customer array, which will be sent to CRM +* *RetailcrmFilterProcessAddress* - address array, which will be sent to CRM +* *RetailcrmFilterProcessOffer* - offer array, which will be sent to CRM (saved into Icml file) + +* *RetailcrmFilterCustomersHistory* - array with assembled history for customer, loaded from CRM +* *RetailcrmFilterOrdersHistory* - array with assembled history for order, loaded from CRM + +* *RetailcrmFilterSaveCustomer* - built customer object, which will be saved to CMS +* *RetailcrmFilterSaveCustomerAddress* - built customer address object, which will be saved to CMS +* *RetailcrmFilterSaveCorporateCustomer* - built corporate customer object, which will be saved to CMS +* *RetailcrmFilterSaveCorporateCustomerAddress* - built corporate customer address object, which will be saved to CMS + +To use filters you should define a new class in `/modules/retailcrm/custom/hooks`. Filename and classname must match the filter name. +Filter class should implement interface *RetailcrmFilterInterface*. In filter class you must define *filter()* function, which will take initial `$object` and return customized `$object`. + +##### Classes + +If you want to change the default behavior of a module classes and be sure that these changes won't be overwritten during the module upgrade process, you should **copy the original classes** that you are going to customize to the `/modules/retailcrm/custom/classes` directory. From here you can modify the methods of the classes for your own purposes, and they will not be affected during the module upgrade process. diff --git a/retailcrm/bootstrap.php b/retailcrm/bootstrap.php index 5c80da4..24087e1 100644 --- a/retailcrm/bootstrap.php +++ b/retailcrm/bootstrap.php @@ -87,6 +87,8 @@ class RetailcrmAutoloader && !class_exists($className) ) { include_once $file->getPathname(); + + return; } } } @@ -101,6 +103,8 @@ class RetailcrmAutoloader && !class_exists($className) ) { include_once $file->getPathname(); + + return; } } } @@ -139,6 +143,6 @@ class RetailcrmAutoloader } RetailcrmAutoloader::setPath(realpath(dirname(__FILE__))); -RetailcrmAutoloader::setPathCustom(realpath(_PS_MODULE_DIR_ . '/retailcrm_custom/classes')); +RetailcrmAutoloader::setPathCustom(realpath(_PS_MODULE_DIR_ . '/retailcrm/custom')); RetailcrmAutoloader::setFileExt('.php'); spl_autoload_register('RetailcrmAutoloader::loader'); diff --git a/retailcrm/lib/RetailcrmAddressBuilder.php b/retailcrm/lib/RetailcrmAddressBuilder.php index 5a63f19..f914692 100644 --- a/retailcrm/lib/RetailcrmAddressBuilder.php +++ b/retailcrm/lib/RetailcrmAddressBuilder.php @@ -185,6 +185,14 @@ class RetailcrmAddressBuilder extends RetailcrmAbstractDataBuilder } } + $this->data = RetailcrmTools::filter( + 'RetailcrmFilterProcessAddress', + $this->data, + array( + 'address' => $this->address, + 'mode' => $this->mode + )); + return $this; } diff --git a/retailcrm/lib/RetailcrmCatalog.php b/retailcrm/lib/RetailcrmCatalog.php index 22cc1cd..76f1ba9 100644 --- a/retailcrm/lib/RetailcrmCatalog.php +++ b/retailcrm/lib/RetailcrmCatalog.php @@ -287,7 +287,14 @@ class RetailcrmCatalog } } - yield $item; + yield RetailcrmTools::filter( + 'RetailcrmFilterProcessOffer', + $item, + array( + 'product' => $product, + 'offer' => $offer + ) + ); } } else { @@ -304,7 +311,7 @@ class RetailcrmCatalog $quantity = (int)StockAvailable::getQuantityAvailableByProduct($product['id_product']); } - yield array( + $item = array( 'id' => $product['id_product'], 'productId' => $product['id_product'], 'productActivity' => ($available_for_order) ? 'Y' : 'N', @@ -321,6 +328,14 @@ class RetailcrmCatalog 'weight' => $weight, 'dimensions' => $dimensions ); + + yield RetailcrmTools::filter( + 'RetailcrmFilterProcessOffer', + $item, + array( + 'product' => $product + ) + ); } } diff --git a/retailcrm/lib/RetailcrmCorporateCustomerBuilder.php b/retailcrm/lib/RetailcrmCorporateCustomerBuilder.php index 580c5e9..729fb08 100644 --- a/retailcrm/lib/RetailcrmCorporateCustomerBuilder.php +++ b/retailcrm/lib/RetailcrmCorporateCustomerBuilder.php @@ -201,6 +201,20 @@ class RetailcrmCorporateCustomerBuilder extends RetailcrmAbstractBuilder impleme } } + $this->corporateCustomer = RetailcrmTools::filter( + 'RetailcrmFilterSaveCorporateCustomer', + $this->corporateCustomer, + array( + 'dataCrm' => $this->dataCrm, + )); + + $this->corporateAddress = RetailcrmTools::filter( + 'RetailcrmFilterSaveCorporateCustomerAddress', + $this->corporateAddress, + array( + 'dataCrm' => $this->dataCrm, + )); + return $this; } } diff --git a/retailcrm/lib/RetailcrmCustomerAddressBuilder.php b/retailcrm/lib/RetailcrmCustomerAddressBuilder.php index 4b67091..637f855 100644 --- a/retailcrm/lib/RetailcrmCustomerAddressBuilder.php +++ b/retailcrm/lib/RetailcrmCustomerAddressBuilder.php @@ -190,6 +190,13 @@ class RetailcrmCustomerAddressBuilder extends RetailcrmAbstractBuilder implement $this->customerAddress->postcode = isset($this->dataCrm['index']) ? $this->dataCrm['index'] : ''; $this->customerAddress->phone = !empty($this->phone) ? $this->phone : ''; + $this->customerAddress = RetailcrmTools::filter( + 'RetailcrmFilterSaveCustomerAddress', + $this->customerAddress, + array( + 'dataCrm' => $this->dataCrm + )); + return $this; } } diff --git a/retailcrm/lib/RetailcrmCustomerBuilder.php b/retailcrm/lib/RetailcrmCustomerBuilder.php index 3b16026..43775c6 100644 --- a/retailcrm/lib/RetailcrmCustomerBuilder.php +++ b/retailcrm/lib/RetailcrmCustomerBuilder.php @@ -155,6 +155,13 @@ class RetailcrmCustomerBuilder extends RetailcrmAbstractBuilder implements Retai $this->customer->passwd = Tools::substr(str_shuffle(Tools::strtolower(sha1(rand() . time()))), 0, 5); } + $this->customer = RetailcrmTools::filter( + 'RetailcrmFilterSaveCustomer', + $this->customer, + array( + 'dataCrm' => $this->dataCrm, + )); + return $this; } } diff --git a/retailcrm/lib/RetailcrmFilterInterface.php b/retailcrm/lib/RetailcrmFilterInterface.php new file mode 100644 index 0000000..0ca1a8d --- /dev/null +++ b/retailcrm/lib/RetailcrmFilterInterface.php @@ -0,0 +1,47 @@ + + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ +interface RetailcrmFilterInterface +{ + /** + * @param object|array|string $object + * @param array $parameters + * @return object|array|string + */ + public static function filter($object, array $parameters); +} \ No newline at end of file diff --git a/retailcrm/lib/RetailcrmHistory.php b/retailcrm/lib/RetailcrmHistory.php index 37f184a..86004c0 100644 --- a/retailcrm/lib/RetailcrmHistory.php +++ b/retailcrm/lib/RetailcrmHistory.php @@ -79,6 +79,11 @@ class RetailcrmHistory RetailcrmLogger::writeDebugArray(__METHOD__, array('Assembled history:', $customersHistory)); foreach ($customersHistory as $customerHistory) { + $customerHistory = RetailcrmTools::filter( + 'RetailcrmFilterCustomersHistory', + $customerHistory + ); + if (isset($customerHistory['deleted']) && $customerHistory['deleted']) { continue; } @@ -217,6 +222,11 @@ class RetailcrmHistory RetailcrmLogger::writeDebugArray(__METHOD__, array('Assembled history:', $orders)); foreach ($orders as $order_history) { + $order_history = RetailcrmTools::filter( + 'RetailcrmFilterOrdersHistory', + $order_history + ); + if (isset($order_history['deleted']) && $order_history['deleted'] == true) { continue; } diff --git a/retailcrm/lib/RetailcrmOrderBuilder.php b/retailcrm/lib/RetailcrmOrderBuilder.php index d5bbbee..cf54f7a 100644 --- a/retailcrm/lib/RetailcrmOrderBuilder.php +++ b/retailcrm/lib/RetailcrmOrderBuilder.php @@ -1070,7 +1070,14 @@ class RetailcrmOrderBuilder } } - return RetailcrmTools::clearArray($crmOrder); + return RetailcrmTools::filter( + 'RetailcrmFilterProcessOrder', + RetailcrmTools::clearArray($crmOrder), + array( + 'order' => $order, + 'customer' => $customer, + 'cart' => $cart + )); } /** @@ -1142,7 +1149,7 @@ class RetailcrmOrderBuilder */ public static function buildCrmCustomer(Customer $object, $address = array()) { - return array_filter(array_merge( + $customer = array_filter(array_merge( array( 'externalId' => !empty($object->id) ? $object->id : null, 'firstName' => $object->firstname, @@ -1159,6 +1166,14 @@ class RetailcrmOrderBuilder ), function ($value) { return !($value === '' || $value === null || (is_array($value) ? count($value) == 0 : false)); }); + + return RetailcrmTools::filter( + 'RetailcrmFilterProcessCustomer', + $customer, + array( + 'customer' => $object, + 'address' => $address + )); } public static function buildCrmCustomerCorporate( @@ -1240,7 +1255,12 @@ class RetailcrmOrderBuilder $customer['addresses'] = $customerAddresses; } - return RetailcrmTools::clearArray($customer); + return RetailcrmTools::filter( + 'RetailcrmFilterProcessCustomerCorporate', + RetailcrmTools::clearArray($customer), + array( + 'customer' => $object + )); } /** diff --git a/retailcrm/lib/RetailcrmTools.php b/retailcrm/lib/RetailcrmTools.php index cf75f8a..8505dee 100644 --- a/retailcrm/lib/RetailcrmTools.php +++ b/retailcrm/lib/RetailcrmTools.php @@ -692,4 +692,32 @@ class RetailcrmTools Shop::setContext(Shop::CONTEXT_SHOP, $id_shop); Context::getContext()->shop = new Shop($id_shop); } + + /** + * Call custom filters for the object + * + * @param string $filter + * @param object|array|string $object + * @param array $parameters + * + * @return false|mixed + */ + public static function filter($filter, $object, $parameters = array()) + { + if (class_exists($filter) && method_exists($filter, 'filter')) { + try { + $result = call_user_func_array( + array($filter, 'filter'), + array($object, $parameters) + ); + + return (null === $result || false === $result) ? $object : $result; + } catch (Exception $e) { + RetailcrmLogger::writeCaller(__METHOD__, 'Error in custom filter: ' . $e->getMessage()); + RetailcrmLogger::writeDebug(__METHOD__, $e->getTraceAsString()); + } + } + + return $object; + } } diff --git a/retailcrm/upgrade/upgrade-3.2.7.php b/retailcrm/upgrade/upgrade-3.2.7.php new file mode 100644 index 0000000..6f48c85 --- /dev/null +++ b/retailcrm/upgrade/upgrade-3.2.7.php @@ -0,0 +1,104 @@ + + * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL + * @license https://opensource.org/licenses/MIT The MIT License + * + * Don't forget to prefix your containers with your own identifier + * to avoid any conflicts with others containers. + */ + +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * Upgrade module to version 3.2.7 + * + * @param \RetailCRM $module + * + * @return bool + */ +function upgrade_module_3_2_7($module) +{ + if ('retailcrm' != $module->name) { + return false; + } + + $oldCustomFolder = _PS_MODULE_DIR_ . '/retailcrm_custom/classes'; + $newCustomFolder = _PS_MODULE_DIR_ . '/retailcrm/custom/classes'; + + if (file_exists($oldCustomFolder)) { + if (!file_exists($newCustomFolder)) { + mkdir($newCustomFolder, 0777, true); + } + + retailcrm_upgrade_recursive_copy($oldCustomFolder, $newCustomFolder); + } + + return true; +} + +function retailcrm_upgrade_recursive_copy($src, $dst, $childFolder = '') +{ + $dir = opendir($src); + + if(!file_exists($dst)) { + mkdir($dst); + } + + if ($childFolder != '') { + if(!file_exists($dst . '/' . $childFolder)) + mkdir($dst . '/' . $childFolder); + + while (false !== ($file = readdir($dir))) { + if (($file != '.') && ($file != '..')) { + if (is_dir($src . '/' . $file)) { + retailcrm_upgrade_recursive_copy($src . '/' . $file, $dst . '/' . $childFolder . '/' . $file); + } else { + copy($src . '/' . $file, $dst . '/' . $childFolder . '/' . $file); + } + } + } + } else { + while (false !== ($file = readdir($dir))) { + if (($file != '.') && ($file != '..')) { + if (is_dir($src . '/' . $file)) { + retailcrm_upgrade_recursive_copy($src . '/' . $file, $dst . '/' . $file); + } else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + } + + closedir($dir); +} \ No newline at end of file