From 608c4be21b5fff8bff101b6e73ea493bcd4c3183 Mon Sep 17 00:00:00 2001 From: max-baranikov Date: Fri, 29 Jan 2021 14:01:42 +0300 Subject: [PATCH] Added export of customers without orders. Updated orders export --- retailcrm/lib/RetailcrmExport.php | 201 ++++++++++++++++++ retailcrm/lib/events/RetailcrmExportEvent.php | 64 +++++- 2 files changed, 255 insertions(+), 10 deletions(-) create mode 100644 retailcrm/lib/RetailcrmExport.php diff --git a/retailcrm/lib/RetailcrmExport.php b/retailcrm/lib/RetailcrmExport.php new file mode 100644 index 0000000..8d2d3b0 --- /dev/null +++ b/retailcrm/lib/RetailcrmExport.php @@ -0,0 +1,201 @@ + + * @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. + */ +class RetailcrmExport +{ + + /** + * Get total count of orders for context shop + * + * @return int + */ + public static function getOrdersCount() + { + $sql = 'SELECT count(o.id_order) + FROM `' . _DB_PREFIX_ . 'orders` o + WHERE 1 + ' . Shop::addSqlRestriction(false, 'o'); + + return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql); + } + + /** + * Get orders ids from the database + * + * @param int $start Sets the LIMIT start parameter for sql query + * @param int|null $count Sets the count of orders to get from database + * + * @return Generator + * @throws PrestaShopDatabaseException + */ + public static function getOrdersIds($start = 0, $count = null) + { + if (is_null($count)) { + $count = static::getOrdersCount(); + } + + if ($count > 0) { + $loadSize = 5000; + $predefinedSql = 'SELECT o.`id_order` + FROM `' . _DB_PREFIX_ . 'orders` o + WHERE 1 + ' . Shop::addSqlRestriction(false, 'o') . ' + ORDER BY o.`id_order` ASC'; + + while ($start <= $count) { + $offset = ($start + $loadSize > $count) ? $count - $start : $loadSize; + + $sql = $predefinedSql . ' + LIMIT ' . (int)$start . ', ' . (int)$offset; + + $orders = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); + + if (empty($orders)) + break; + + foreach ($orders as $order) { + yield $order; + } + + $start += $offset; + } + } + } + + /** + * Get total count of customers without orders for context shop + * + * @return int + */ + public static function getCustomersCount() + { + $sql = 'SELECT count(c.id_customer) + FROM `' . _DB_PREFIX_ . 'customer` c + WHERE 1 + ' . Shop::addSqlRestriction(false, 'c') . ' + AND c.id_customer not in ( + select o.id_customer + from `' . _DB_PREFIX_ . 'orders` o + WHERE 1 + ' . Shop::addSqlRestriction(false, 'o') . ' + group by o.id_customer + )'; + + return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql); + } + + /** + * Get customers ids from database + * + * @param int $start Sets the LIMIT start parameter for sql query + * @param null $count Sets the count of customers to get from database + * @param bool $withAddressId If set to true, then also return address id in `id_address` + * + * @return Generator + * @throws PrestaShopDatabaseException + */ + public static function getCustomersIds($start = 0, $count = null, $withAddressId = true) + { + if (is_null($count)) { + $count = static::getCustomersCount(); + } + + if ($count > 0) { + $loadSize = 500; + $predefinedSql = 'SELECT c.`id_customer` + ' . ($withAddressId ? ', a.`id_address`' : '') . ' + FROM `' . _DB_PREFIX_ . 'customer` c + ' . ($withAddressId ? ' + LEFT JOIN + ( + SELECT + ad.`id_customer`, + ad.`id_address` + FROM + `' . _DB_PREFIX_ . 'address` ad + INNER JOIN + ( + SELECT + `id_customer`, + MAX(`date_add`) AS `date_add` + FROM + `' . _DB_PREFIX_ . 'address` + GROUP BY + id_customer + ) ad2 + ON + ad2.`id_customer` = ad.`id_customer` AND ad2.`date_add` = ad.`date_add` + ORDER BY + ad.`id_customer` ASC + ) a + ON + a.`id_customer` = c.`id_customer` + ' : '') . ' + WHERE 1 + ' . Shop::addSqlRestriction(false, 'c') . ' + AND c.`id_customer` not in ( + select o.`id_customer` + from `' . _DB_PREFIX_ . 'orders` o + WHERE 1 + ' . Shop::addSqlRestriction(false, 'o') . ' + group by o.`id_customer` + ) + ORDER BY c.`id_customer` ASC'; + + + while ($start <= $count) { + $offset = ($start + $loadSize > $count) ? $count - $start : $loadSize; + + $sql = $predefinedSql . ' + LIMIT ' . (int)$start . ', ' . (int)$offset; + + $customers = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); + + if (empty($customers)) + break; + + foreach ($customers as $customer) { + yield $customer; + } + + $start += $offset; + } + } + } + +} diff --git a/retailcrm/lib/events/RetailcrmExportEvent.php b/retailcrm/lib/events/RetailcrmExportEvent.php index 773bebf..b4e90d1 100644 --- a/retailcrm/lib/events/RetailcrmExportEvent.php +++ b/retailcrm/lib/events/RetailcrmExportEvent.php @@ -28,9 +28,9 @@ * versions in the future. If you wish to customize PrestaShop for your * needs please refer to http://www.prestashop.com for more information. * - * @author DIGITAL RETAIL TECHNOLOGIES SL - * @copyright 2020 DIGITAL RETAIL TECHNOLOGIES SL - * @license https://opensource.org/licenses/MIT The MIT License + * @author DIGITAL RETAIL TECHNOLOGIES SL + * @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. @@ -65,7 +65,7 @@ class RetailcrmExportEvent extends RetailcrmAbstractEvent implements RetailcrmEv } $orders = array(); - $orderRecords = Order::getOrdersWithInformations(); + $orderRecords = RetailcrmExport::getOrdersIds(); $orderBuilder = new RetailcrmOrderBuilder(); $orderBuilder->defaultLangFromConfiguration()->setApi($api); @@ -97,20 +97,64 @@ class RetailcrmExportEvent extends RetailcrmAbstractEvent implements RetailcrmEv try { $orders[] = $orderBuilder->buildOrderWithPreparedCustomer(); } catch (\InvalidArgumentException $exception) { - RetailcrmLogger::writeCaller('export', $exception->getMessage()); + RetailcrmLogger::writeCaller('export', sprintf('Error while building %s: %s', $record['id_order'], $exception->getMessage())); RetailcrmLogger::writeNoCaller($exception->getTraceAsString()); RetailcrmLogger::output($exception->getMessage()); } - time_nanosleep(0, 500000000); + time_nanosleep(0, 250000000); + + if (count($orders) == 50) { + $api->ordersUpload($orders); + $orders = array(); + } } - unset($orderRecords); + if (count($orders)) { + $api->ordersUpload($orders); + } - $orders = array_chunk($orders, 50); + $customers = array(); + $customersRecords = RetailcrmExport::getCustomersIds(); - foreach ($orders as $chunk) { - $api->ordersUpload($chunk); + foreach ($customersRecords as $record) { + $customerId = $record['id_customer']; + $addressId = $record['id_address']; + + $cmsCustomer = new Customer($customerId); + + if (Validate::isLoadedObject($cmsCustomer)) { + if ($addressId) { + $cmsAddress = new Address($addressId); + + $addressBuilder = new RetailcrmAddressBuilder(); + $address = $addressBuilder + ->setAddress($cmsAddress) + ->build() + ->getDataArray(); + } else { + $address = array(); + } + + try { + $customers[] = RetailcrmOrderBuilder::buildCrmCustomer($cmsCustomer, $address); + } catch (\Exception $exception) { + RetailcrmLogger::writeCaller('export', sprintf('Error while building %s: %s', $customerId, $exception->getMessage())); + RetailcrmLogger::writeNoCaller($exception->getTraceAsString()); + RetailcrmLogger::output($exception->getMessage()); + } + + if (count($customers) == 50) { + $api->customersUpload($customers); + $customers = array(); + + time_nanosleep(0, 250000000); + } + } + } + + if (count($customers)) { + $api->customersUpload($customers); } }