diff --git a/README.md b/README.md index bf64bb2..db6a944 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Opecart module -============= +============== Opencart module for interaction with [IntaroCRM](http://www.intarocrm.com) through [REST API](http://docs.intarocrm.ru/rest-api/). @@ -9,47 +9,6 @@ Module allows: * Configure relations between dictionaries of IntaroCRM and Opencart (statuses, payments, delivery types and etc) * Generate [ICML](http://docs.intarocrm.ru/index.php?n=Пользователи.ФорматICML) (IntaroCRM Markup Language) for catalog loading by IntaroCRM -Installation -------------- - -### 1. Manual installation - - -#### Clone module. -``` -git clone git@github.com:/intarocrm/opencart-module.git -``` - -#### Install Rest API Client. - -``` -cd opencart-module/system/library/intarocrm -./composer.phar install -``` - -#### Install module -``` -cp -r opencart-module/* /path/to/opecart/instance -``` - -#### Activate via Admin interface. - -Go to Modules -> Intstall module. - -#### Export - -Catalog export script will be here -``` -/index.php?route=export/intarocrm -``` - -#### Exchange setup - -Look into example folder - -#### TODO -* Edit order hook -* Export old customers & orders -* Generate static xml -* New customers export - +* [Install](doc/Install.md) +* [Changelog](doc/Changelog.md) +* [TODO](doc/TODO.md) diff --git a/admin/controller/module/intarocrm.php b/admin/controller/module/intarocrm.php index c4b6b8f..2c04773 100644 --- a/admin/controller/module/intarocrm.php +++ b/admin/controller/module/intarocrm.php @@ -4,6 +4,7 @@ require_once __DIR__ . '/../../../system/library/intarocrm/vendor/autoload.php'; class ControllerModuleIntarocrm extends Controller { private $error = array(); + protected $dd, $eCategories, $eOffers; public function install() { $this->load->model('setting/setting'); @@ -204,6 +205,10 @@ class ControllerModuleIntarocrm extends Controller { $this->load->model('setting/setting'); $this->load->model('setting/store'); $this->load->model('sale/order'); + $this->load->model('sale/customer'); + + + $settings = $this->model_setting_setting->getSetting('intarocrm'); $settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST); @@ -211,112 +216,172 @@ class ControllerModuleIntarocrm extends Controller { include_once __DIR__ . '/../../../system/library/intarocrm/apihelper.php'; $crm = new ApiHelper($settings); $orders = $crm->orderHistory(); - $forFix = array(); + $ordersIdsFix = array(); + $customersIdsFix = array(); + $subtotalSettings = $this->model_setting_setting->getSetting('sub_total'); + $totalSettings = $this->model_setting_setting->getSetting('total'); + $shippingSettings = $this->model_setting_setting->getSetting('shipping'); foreach ($orders as $order) { - $data = array(); + if (!isset($order['deleted']) || !$order['deleted']) { - $delivery = array_flip($settings['intarocrm_delivery']); - $payment = array_flip($settings['intarocrm_payment']); - $status = array_flip($settings['intarocrm_status']); + $data = array(); - $ocPayment = $this->getOpercartPaymentTypes(); - $ocDelivery = $this->getOpercartDeliveryMethods(); + $customer_id = (isset($order['customer']['externalId'])) + ? $order['customer']['externalId'] + : '' + ; - $data['store_id'] = ($this->config->get('config_store_id') == null) ? 0 : $this->config->get('config_store_id'); - $data['customer'] = $order['customer']['firstName']; - $data['customer_id'] = (isset($order['customer']['externalId'])) ? $order['customer']['externalId']: ''; - $data['customer_group_id'] = '1'; - $data['firstname'] = $order['customer']['firstName']; - $data['lastname'] = (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' '; - $data['email'] = $order['customer']['email']; - $data['telephone'] = (isset($order['customer']['phones'][0]['number'])) ? $order['customer']['phones'][0]['number'] : ' '; - $data['comment'] = $order['customerComment']; + if ($customer_id == '') { + $cData = array( + 'customer_group_id' => '1', + 'firstname' => $order['customer']['firstName'], + 'lastname' => (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' ', + 'email' => $order['customer']['email'], + 'telephone' => (isset($order['customer']['phones'][0]['number'])) ? $order['customer']['phones'][0]['number'] : ' ', + 'newsletter' => 0, + 'password' => 'tmppass', + 'status' => 1, + 'address' => array( + 'firstname' => $order['customer']['firstName'], + 'lastname' => (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' ', + 'address_1' => $order['customer']['address']['text'], + 'city' => $order['customer']['address']['city'], + 'postcode' => $order['customer']['address']['index'] + ), + ); - $data['payment_address'] = '0'; - $data['payment_firstname'] = $order['firstName']; - $data['payment_lastname'] = (isset($order['lastName'])) ? $order['lastName'] : ' '; - $data['payment_address_1'] = $order['customer']['address']['text']; - $data['payment_city'] = $order['customer']['address']['city']; - $data['payment_postcode'] = $order['customer']['address']['index']; + $this->model_sale_customer->addCustomer($cData); - /* - * TODO: add country & zone id detection - */ - //$data['payment_country_id'] = '176'; - //$data['payment_zone_id'] = '2778'; - //$data['shipping_country_id'] = '176'; - //$data['shipping_zone_id'] = '2778'; + if (isset($order['customer']['email']) && $order['customer']['email'] != '') { + $tryToFind = $this->model_sale_customer->getCustomerByEmail($order['customer']['email']); + $customer_id = $tryToFind['customer_id']; + } else { + $last = $this->model_sale_customer->getCustomers($data = array('order' => 'DESC', 'limit' => 1)); + $customer_id = $last[0]['customer_id']; + } - $data['shipping_address'] = '0'; - $data['shipping_firstname'] = $order['customer']['firstName']; - $data['shipping_lastname'] = (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' '; - $data['shipping_address_1'] = $order['delivery']['address']['text']; - $data['shipping_city'] = $order['delivery']['address']['city']; - $data['shipping_postcode'] = $order['delivery']['address']['index']; + $customersIdsFix[] = array('id' => $order['customer']['id'], 'externalId' => (int) $customer_id); + } - $data['shipping'] = $delivery[$order['delivery']['code']]; - $data['shipping_method'] = $ocDelivery[$data['shipping']]; - $data['shipping_code'] = $delivery[$order['delivery']['code']]; - $data['payment'] = $payment[$order['paymentType']]; - $data['payment_method'] = $ocPayment[$data['payment']]; - $data['payment_code'] = $payment[$order['paymentType']]; - $data['order_status_id'] = $status[$order['status']]; - - $data['order_product'] = array(); + $delivery = array_flip($settings['intarocrm_delivery']); + $payment = array_flip($settings['intarocrm_payment']); + $status = array_flip($settings['intarocrm_status']); - $subtotal = 0; - $shipping = isset($order['delivery']['cost']) ? $order['delivery']['cost'] : 0; + $ocPayment = $this->getOpercartPaymentTypes(); + $ocDelivery = $this->getOpercartDeliveryMethods(); - foreach($order['items'] as $item) { - $data['order_product'][] = array( - 'product_id' => $item['offer']['externalId'], - 'name' => $item['offer']['name'], - 'quantity' => $item['quantity'], - 'price' => $item['initialPrice'], - 'total' => $item['initialPrice'] * $item['quantity'], + $data['store_id'] = ($this->config->get('config_store_id') == null) ? 0 : $this->config->get('config_store_id'); + $data['customer'] = $order['customer']['firstName']; + $data['customer_id'] = $customer_id; + $data['firstname'] = $order['customer']['firstName']; + $data['lastname'] = (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' '; + $data['email'] = $order['customer']['email']; + $data['telephone'] = (isset($order['customer']['phones'][0]['number'])) ? $order['customer']['phones'][0]['number'] : ' '; + $data['comment'] = $order['customerComment']; + + $data['payment_address'] = '0'; + $data['payment_firstname'] = $order['firstName']; + $data['payment_lastname'] = (isset($order['lastName'])) ? $order['lastName'] : ' '; + $data['payment_address_1'] = $order['customer']['address']['text']; + $data['payment_city'] = $order['customer']['address']['city']; + $data['payment_postcode'] = $order['customer']['address']['index']; + + /* + * TODO: add country & zone id detection + */ + //$data['payment_country_id'] = '176'; + //$data['payment_zone_id'] = '2778'; + //$data['shipping_country_id'] = '176'; + //$data['shipping_zone_id'] = '2778'; + + $data['shipping_address'] = '0'; + $data['shipping_firstname'] = $order['customer']['firstName']; + $data['shipping_lastname'] = (isset($order['customer']['lastName'])) ? $order['customer']['lastName'] : ' '; + $data['shipping_address_1'] = $order['delivery']['address']['text']; + $data['shipping_city'] = $order['delivery']['address']['city']; + $data['shipping_postcode'] = $order['delivery']['address']['index']; + + $data['shipping'] = $delivery[$order['delivery']['code']]; + $data['shipping_method'] = $ocDelivery[$data['shipping']]; + $data['shipping_code'] = $delivery[$order['delivery']['code']]; + $data['payment'] = $payment[$order['paymentType']]; + $data['payment_method'] = $ocPayment[$data['payment']]; + $data['payment_code'] = $payment[$order['paymentType']]; + $data['order_status_id'] = $status[$order['status']]; + + $data['order_product'] = array(); + + foreach($order['items'] as $item) { + $data['order_product'][] = array( + 'product_id' => $item['offer']['externalId'], + 'name' => $item['offer']['name'], + 'quantity' => $item['quantity'], + 'price' => $item['initialPrice'], + 'total' => $item['initialPrice'] * $item['quantity'], + ); + } + + $deliveryCost = isset($order['delivery']['cost']) ? $order['delivery']['cost'] : 0; + + $data['order_total'] = array( + array( + 'order_total_id' => '', + 'code' => 'sub_total', + 'value' => $order['summ'], + 'sort_order' => $subtotalSettings['sub_total_sort_order'] + ), + array( + 'order_total_id' => '', + 'code' => 'shipping', + 'value' => $deliveryCost, + 'sort_order' => $shippingSettings['shipping_sort_order'] + ), + array( + 'order_total_id' => '', + 'code' => 'total', + 'value' => isset($order['totalSumm']) ? $order['totalSumm'] : $order['summ'] + $deliveryCost, + 'sort_order' => $totalSettings['total_sort_order'] + ) ); - $subtotal += $item['initialPrice'] * $item['quantity']; - } + if (isset($order['externalId'])) { + /* + * opercart developers believe that to remove all + * products from the order during the editing is a good idea... + * + * so we have to get all the goods before orders are breaks + * + */ + $items = $crm->getOrderItems($order['externalId']); + $data['order_product'] = array(); - $subtotalSettings = $this->model_setting_setting->getSetting('sub_total'); - $totalSettings = $this->model_setting_setting->getSetting('total'); - $shippingSettings = $this->model_setting_setting->getSetting('shipping'); + foreach($items as $item) { + $data['order_product'][] = array( + 'product_id' => $item['offer']['externalId'], + 'name' => $item['offer']['name'], + 'quantity' => $item['quantity'], + 'price' => $item['initialPrice'], + 'total' => $item['initialPrice'] * $item['quantity'], + ); + } - $data['order_total'] = array( - array( - 'order_total_id' => '', - 'code' => 'sub_total', - 'value' => $subtotal, - 'sort_order' => $subtotalSettings['sub_total_sort_order'] - ), - array( - 'order_total_id' => '', - 'code' => 'shipping', - 'value' => $shipping, - 'sort_order' => $shippingSettings['shipping_sort_order'] - ), - array( - 'order_total_id' => '', - 'code' => 'total', - 'value' => $subtotal + $shipping, - 'sort_order' => $totalSettings['total_sort_order'] - ) - ); - - if (isset($order['externalId'])) { - $this->model_sale_order->editOrder($order['externalId'], $data); - } else { - $this->model_sale_order->addOrder($data); - $last = $this->model_sale_order->getOrders($data = array('order' => 'DESC', 'limit' => 1)); - $forFix[] = array('id' => $order['id'], 'externalId' => (int) $last[0]['order_id']); + $this->model_sale_order->editOrder($order['externalId'], $data); + } else { + $this->model_sale_order->addOrder($data); + $last = $this->model_sale_order->getOrders($data = array('order' => 'DESC', 'limit' => 1)); + $ordersIdsFix[] = array('id' => $order['id'], 'externalId' => (int) $last[0]['order_id']); + } } } - if (!empty($forFix)) { - $crm->orderFixExternalIds($forFix); + if (!empty($customersIdsFix)) { + $crm->customerFixExternalIds($customersIdsFix); + } + + if (!empty($ordersIdsFix)) { + $crm->orderFixExternalIds($ordersIdsFix); } } else { @@ -324,6 +389,10 @@ class ControllerModuleIntarocrm extends Controller { } } + public function export() { + file_put_contents(__DIR__ . '/../../../download/intarocrm.xml', $this->xml()); + } + private function validate() { if (!$this->user->hasPermission('modify', 'module/intarocrm')) { $this->error['warning'] = $this->language->get('error_permission'); @@ -381,5 +450,115 @@ class ControllerModuleIntarocrm extends Controller { return $paymentTypes; } + + private function xml() + { + $this->dd = new DOMDocument(); + $this->dd->loadXML(' + + + '.$this->config->get('config_name').' + + + + + '); + + $this->eCategories = $this->dd->getElementsByTagName('categories')->item(0); + $this->eOffers = $this->dd->getElementsByTagName('offers')->item(0); + + $this->addCategories(); + $this->addOffers(); + return $this->dd->saveXML(); + } + + private function addCategories() + { + $this->load->model('catalog/category'); + + foreach ($this->model_catalog_category->getCategories(array()) as $category) { + $e = $this->eCategories->appendChild($this->dd->createElement('category', $category['name'])); + $e->setAttribute('id',$category['category_id']); + } + + } + + private function addOffers() + { + $this->load->model('catalog/product'); + $this->load->model('catalog/manufacturer'); + $this->load->model('tool/image'); + + $offerManufacturers = array(); + + $manufacturers = $this->model_catalog_manufacturer->getManufacturers(array()); + + foreach ($manufacturers as $manufacturer) { + $offerManufacturers[$manufacturer['manufacturer_id']] = $manufacturer['name']; + } + + foreach ($this->model_catalog_product->getProducts(array()) as $offer) { + + $e = $this->eOffers->appendChild($this->dd->createElement('offer')); + $e->setAttribute('id', $offer['product_id']); + $e->setAttribute('productId', $offer['product_id']); + $e->setAttribute('quantity', $offer['quantity']); + $e->setAttribute('available', $offer['status'] ? 'true' : 'false'); + + /* + * DIRTY HACK, NEED TO REFACTOR + */ + + $sql = "SELECT * FROM `" . DB_PREFIX . "product_to_category` WHERE `product_id` = " .$offer['product_id']. ";"; + $result = $this->db->query($sql); + foreach ($result->rows as $row) { + $e->appendChild($this->dd->createElement('categoryId', $row['category_id'])); + } + + $e->appendChild($this->dd->createElement('name'))->appendChild($this->dd->createTextNode($offer['name'])); + $e->appendChild($this->dd->createElement('productName'))->appendChild($this->dd->createTextNode($offer['name'])); + if ($offer['manufacturer_id'] != 0) { + $e->appendChild($this->dd->createElement('vendor'))->appendChild($this->dd->createTextNode($offerManufacturers[$offer['manufacturer_id']])); + } + $e->appendChild($this->dd->createElement('price', $offer['price'])); + + if ($offer['image']) { + $e->appendChild( + $this->dd->createElement( + 'picture', + $this->model_tool_image->resize($offer['image'], $this->config->get('config_image_product_width'), $this->config->get('config_image_product_height')) + ) + ); + } + + $e->appendChild($this->dd->createElement('url'))->appendChild( + $this->dd->createTextNode( + $this->url->link('product/product&product_id=' . $offer['product_id']) + ) + ); + + if ($offer['sku'] != '') { + $sku = $this->dd->createElement('param'); + $sku->setAttribute('name', 'article'); + $sku->appendChild($this->dd->createTextNode($offer['sku'])); + $e->appendChild($sku); + } + + if ($offer['weight'] != '') { + $weight = $this->dd->createElement('param'); + $weight->setAttribute('name', 'weight'); + $weightValue = (isset($offer['weight_class'])) ? $offer['weight'] . ' ' . $offer['weight_class'] : $offer['weight']; + $weight->appendChild($this->dd->createTextNode($weightValue)); + $e->appendChild($weight); + } + + if ($offer['length'] != '' && $offer['width'] != '' && $offer['height'] != '') { + $size = $this->dd->createElement('param'); + $size->setAttribute('name', 'size'); + $size->appendChild($this->dd->createTextNode($offer['length'] .'x'. $offer['width'] .'x'. $offer['height'])); + $e->appendChild($size); + } + } + } } ?> \ No newline at end of file diff --git a/catalog/controller/export/intarocrm.php b/catalog/controller/export/intarocrm.php deleted file mode 100644 index 9966965..0000000 --- a/catalog/controller/export/intarocrm.php +++ /dev/null @@ -1,113 +0,0 @@ -xml(); - } - - private function xml() - { - $this->dd = new DOMDocument(); - $this->dd->loadXML(' - - - '.$this->config->get('config_name').' - - - - - '); - - $this->eCategories = $this->dd->getElementsByTagName('categories')->item(0); - $this->eOffers = $this->dd->getElementsByTagName('offers')->item(0); - - $this->addCategories(); - $this->addOffers(); - return $this->dd->saveXML(); - } - - private function addCategories() - { - $this->language->load('product/category'); - $this->load->model('catalog/category'); - - foreach ($this->model_catalog_category->getCategories() as $category) { - $e = $this->eCategories->appendChild($this->dd->createElement('category', $category['name'])); - $e->setAttribute('id',$category['category_id']); - } - - } - - private function addOffers() - { - $this->load->model('catalog/product'); - $this->load->model('tool/image'); - - foreach ($this->model_catalog_product->getProducts(array()) as $offer) { - $e = $this->eOffers->appendChild($this->dd->createElement('offer')); - $e->setAttribute('id', $offer['product_id']); - $e->setAttribute('productId', $offer['product_id']); - $e->setAttribute('quantity', $offer['quantity']); - $e->setAttribute('available', $offer['status'] ? 'true' : 'false'); - - /* - * DIRTY HACK, NEED TO REFACTOR - */ - - $sql = "SELECT * FROM `" . DB_PREFIX . "product_to_category` WHERE `product_id` = " .$offer['product_id']. ";"; - $result = $this->db->query($sql); - foreach ($result->rows as $row) { - $e->appendChild($this->dd->createElement('categoryId', $row['category_id'])); - } - - $e->appendChild($this->dd->createElement('name'))->appendChild($this->dd->createTextNode($offer['name'])); - $e->appendChild($this->dd->createElement('productName'))->appendChild($this->dd->createTextNode($offer['name'])); - $e->appendChild($this->dd->createElement('vendor'))->appendChild($this->dd->createTextNode($offer['manufacturer'])); - $e->appendChild($this->dd->createElement('price', $offer['price'])); - - if ($offer['image']) { - $e->appendChild( - $this->dd->createElement( - 'picture', - $this->model_tool_image->resize($offer['image'], $this->config->get('config_image_product_width'), $this->config->get('config_image_product_height')) - ) - ); - } - - $e->appendChild($this->dd->createElement('url'))->appendChild( - $this->dd->createTextNode( - $this->url->link('product/product&product_id=' . $offer['product_id']) - ) - ); - - if ($offer['sku'] != '') { - $sku = $this->dd->createElement('param'); - $sku->setAttribute('name', 'article'); - $sku->appendChild($this->dd->createTextNode($offer['sku'])); - $e->appendChild($sku); - } - - if ($offer['weight'] != '') { - $weight = $this->dd->createElement('param'); - $weight->setAttribute('name', 'weight'); - $weightValue = (isset($offer['weight_class'])) ? $offer['weight'] . ' ' . $offer['weight_class'] : $offer['weight']; - $weight->appendChild($this->dd->createTextNode($weightValue)); - $e->appendChild($weight); - } - - if ($offer['length'] != '' && $offer['width'] != '' && $offer['height'] != '') { - $size = $this->dd->createElement('param'); - $size->setAttribute('name', 'size'); - $size->appendChild($this->dd->createTextNode($offer['length'] .'x'. $offer['width'] .'x'. $offer['height'])); - $e->appendChild($size); - } - } - } - -} -?> diff --git a/cli/cli_dispatch.php b/cli/cli_dispatch.php new file mode 100644 index 0000000..8baa5e4 --- /dev/null +++ b/cli/cli_dispatch.php @@ -0,0 +1,141 @@ +write("ERROR: cli $cli_action call attempted by non-cli."); + http_response_code(400); + exit; +} + +// Ensure $cli_action is set +if (!isset($cli_action)) { + echo 'ERROR: $cli_action must be set in calling script.'; + $log->write('ERROR: $cli_action must be set in calling script.'); + http_response_code(400); + exit; +} + +// Version +define('VERSION', '1.5.6'); + +// Configuration (note we're using the admin config) +require_once(__DIR__ . '/../admin/config.php'); + +// Configuration check +if (!defined('DIR_APPLICATION')) { + echo "ERROR: cli $cli_action call missing configuration."; + $log->write("ERROR: cli $cli_action call missing configuration."); + http_response_code(400); + exit; +} + +// Startup +require_once(DIR_SYSTEM . 'startup.php'); + +// Application Classes +require_once(DIR_SYSTEM . 'library/currency.php'); +require_once(DIR_SYSTEM . 'library/user.php'); +require_once(DIR_SYSTEM . 'library/weight.php'); +require_once(DIR_SYSTEM . 'library/length.php'); + +// Registry +$registry = new Registry(); + +// Loader +$loader = new Loader($registry); +$registry->set('load', $loader); + +// Config +$config = new Config(); +$registry->set('config', $config); + +// Database +$db = new DB(DB_DRIVER, DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE); +$registry->set('db', $db); + +// Settings +$query = $db->query("SELECT * FROM " . DB_PREFIX . "setting WHERE store_id = '0'"); + +foreach ($query->rows as $setting) { + if (!$setting['serialized']) { + $config->set($setting['key'], $setting['value']); + } else { + $config->set($setting['key'], unserialize($setting['value'])); + } +} + +// Url +$url = new Url(HTTP_SERVER, HTTPS_SERVER); +$registry->set('url', $url); + +// Log +$log = new Log($config->get('config_error_filename')); +$registry->set('log', $log); + +function error_handler($errno, $errstr, $errfile, $errline) { + global $log, $config; + + switch ($errno) { + case E_NOTICE: + case E_USER_NOTICE: + $error = 'Notice'; + break; + case E_WARNING: + case E_USER_WARNING: + $error = 'Warning'; + break; + case E_ERROR: + case E_USER_ERROR: + $error = 'Fatal Error'; + break; + default: + $error = 'Unknown'; + break; + } + + if ($config->get('config_error_display')) { + echo "\n".'PHP ' . $error . ': ' . $errstr . ' in ' . $errfile . ' on line ' . $errline."\n"; + } + + if ($config->get('config_error_log')) { + $log->write('PHP ' . $error . ': ' . $errstr . ' in ' . $errfile . ' on line ' . $errline); + } + + return true; +} +set_error_handler('error_handler'); +$request = new Request(); +$registry->set('request', $request); +$response = new Response(); +$response->addHeader('Content-Type: text/html; charset=utf-8'); +$registry->set('response', $response); +$cache = new Cache(); +$registry->set('cache', $cache); +$session = new Session(); +$registry->set('session', $session); +$languages = array(); + +$query = $db->query("SELECT * FROM " . DB_PREFIX . "language"); +foreach ($query->rows as $result) { + $languages[$result['code']] = $result; +} +$config->set('config_language_id', $languages[$config->get('config_admin_language')]['language_id']); +$language = new Language($languages[$config->get('config_admin_language')]['directory']); +$language->load($languages[$config->get('config_admin_language')]['filename']); +$registry->set('language', $language); + +$document = new Document(); +$registry->set('document', $document); + +$registry->set('currency', new Currency($registry)); +$registry->set('weight', new Weight($registry)); +$registry->set('length', new Length($registry)); +$registry->set('user', new User($registry)); + +$controller = new Front($registry); +$action = new Action($cli_action); +$controller->dispatch($action, new Action('error/not_found')); + +// Output +$response->output(); +?> \ No newline at end of file diff --git a/cli/cli_export.php b/cli/cli_export.php new file mode 100644 index 0000000..095a52c --- /dev/null +++ b/cli/cli_export.php @@ -0,0 +1,3 @@ + Intstall module. Before running exchange you must configure module. + +### Export + +Setup cron job for periodically catalog export + +``` +0 */12 0 0 0 /usr/bin/php /path/to/opencart/instance/cli/cli_export.php >> /path/to/opencart/instance/system/logs/cronjob_export.log 2>&1 +``` + +### Exchange setup + + +#### Export new order from shop to CRM + +Open /catalog/model/checkout/order.php script. Into addOrder method add this line before return statement: + +``` +$this->crmOrderAction($data, $order_id, 'create'); +``` + +In the end of this file add method: + +``` +protected function crmOrderAction($order, $order_id, $action=null) +{ + $this->load->model('setting/setting'); + $settings = $this->model_setting_setting->getSetting('intarocrm'); + $settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST); + + if(isset($settings['intarocrm_url']) && $settings['intarocrm_url'] != '' && isset($settings['intarocrm_apikey']) && $settings['intarocrm_apikey'] != '') { + include_once __DIR__ . '/../../../system/library/intarocrm/apihelper.php'; + + $order['order_id'] = $order_id; + $crm = new ApiHelper($settings); + + if ($action != null) { + $method = 'order' . ucfirst($action); + $crm->$method($order); + } + } + +} +``` + +#### Export new order from CRM to shop + +Setup cron job for exchange between CRM & your shop + +``` +*/5 0 0 0 0 /usr/bin/php /path/to/opencart/instance/cli/cli_export.php >> /path/to/opencart/instance/system/logs/cronjob_history.log 2>&1 +``` \ No newline at end of file diff --git a/doc/TODO.md b/doc/TODO.md new file mode 100644 index 0000000..4b1d6c0 --- /dev/null +++ b/doc/TODO.md @@ -0,0 +1,6 @@ +TODO +==== + +* Edit order hook +* Export old customers & orders +* New customers export \ No newline at end of file diff --git a/example/catalog/model/checkout/order.php b/example/catalog/model/checkout/order.php deleted file mode 100644 index 21eecf4..0000000 --- a/example/catalog/model/checkout/order.php +++ /dev/null @@ -1,82 +0,0 @@ -db->query("INSERT INTO `" . DB_PREFIX . "order` SET invoice_prefix = '" . $this->db->escape($data['invoice_prefix']) . "', store_id = '" . (int)$data['store_id'] . "', store_name = '" . $this->db->escape($data['store_name']) . "', store_url = '" . $this->db->escape($data['store_url']) . "', customer_id = '" . (int)$data['customer_id'] . "', customer_group_id = '" . (int)$data['customer_group_id'] . "', firstname = '" . $this->db->escape($data['firstname']) . "', lastname = '" . $this->db->escape($data['lastname']) . "', email = '" . $this->db->escape($data['email']) . "', telephone = '" . $this->db->escape($data['telephone']) . "', fax = '" . $this->db->escape($data['fax']) . "', payment_firstname = '" . $this->db->escape($data['payment_firstname']) . "', payment_lastname = '" . $this->db->escape($data['payment_lastname']) . "', payment_company = '" . $this->db->escape($data['payment_company']) . "', payment_company_id = '" . $this->db->escape($data['payment_company_id']) . "', payment_tax_id = '" . $this->db->escape($data['payment_tax_id']) . "', payment_address_1 = '" . $this->db->escape($data['payment_address_1']) . "', payment_address_2 = '" . $this->db->escape($data['payment_address_2']) . "', payment_city = '" . $this->db->escape($data['payment_city']) . "', payment_postcode = '" . $this->db->escape($data['payment_postcode']) . "', payment_country = '" . $this->db->escape($data['payment_country']) . "', payment_country_id = '" . (int)$data['payment_country_id'] . "', payment_zone = '" . $this->db->escape($data['payment_zone']) . "', payment_zone_id = '" . (int)$data['payment_zone_id'] . "', payment_address_format = '" . $this->db->escape($data['payment_address_format']) . "', payment_method = '" . $this->db->escape($data['payment_method']) . "', payment_code = '" . $this->db->escape($data['payment_code']) . "', shipping_firstname = '" . $this->db->escape($data['shipping_firstname']) . "', shipping_lastname = '" . $this->db->escape($data['shipping_lastname']) . "', shipping_company = '" . $this->db->escape($data['shipping_company']) . "', shipping_address_1 = '" . $this->db->escape($data['shipping_address_1']) . "', shipping_address_2 = '" . $this->db->escape($data['shipping_address_2']) . "', shipping_city = '" . $this->db->escape($data['shipping_city']) . "', shipping_postcode = '" . $this->db->escape($data['shipping_postcode']) . "', shipping_country = '" . $this->db->escape($data['shipping_country']) . "', shipping_country_id = '" . (int)$data['shipping_country_id'] . "', shipping_zone = '" . $this->db->escape($data['shipping_zone']) . "', shipping_zone_id = '" . (int)$data['shipping_zone_id'] . "', shipping_address_format = '" . $this->db->escape($data['shipping_address_format']) . "', shipping_method = '" . $this->db->escape($data['shipping_method']) . "', shipping_code = '" . $this->db->escape($data['shipping_code']) . "', comment = '" . $this->db->escape($data['comment']) . "', total = '" . (float)$data['total'] . "', affiliate_id = '" . (int)$data['affiliate_id'] . "', commission = '" . (float)$data['commission'] . "', language_id = '" . (int)$data['language_id'] . "', currency_id = '" . (int)$data['currency_id'] . "', currency_code = '" . $this->db->escape($data['currency_code']) . "', currency_value = '" . (float)$data['currency_value'] . "', ip = '" . $this->db->escape($data['ip']) . "', forwarded_ip = '" . $this->db->escape($data['forwarded_ip']) . "', user_agent = '" . $this->db->escape($data['user_agent']) . "', accept_language = '" . $this->db->escape($data['accept_language']) . "', date_added = NOW(), date_modified = NOW()"); - - $order_id = $this->db->getLastId(); - - foreach ($data['products'] as $product) { - $this->db->query("INSERT INTO " . DB_PREFIX . "order_product SET order_id = '" . (int)$order_id . "', product_id = '" . (int)$product['product_id'] . "', name = '" . $this->db->escape($product['name']) . "', model = '" . $this->db->escape($product['model']) . "', quantity = '" . (int)$product['quantity'] . "', price = '" . (float)$product['price'] . "', total = '" . (float)$product['total'] . "', tax = '" . (float)$product['tax'] . "', reward = '" . (int)$product['reward'] . "'"); - - $order_product_id = $this->db->getLastId(); - - foreach ($product['option'] as $option) { - $this->db->query("INSERT INTO " . DB_PREFIX . "order_option SET order_id = '" . (int)$order_id . "', order_product_id = '" . (int)$order_product_id . "', product_option_id = '" . (int)$option['product_option_id'] . "', product_option_value_id = '" . (int)$option['product_option_value_id'] . "', name = '" . $this->db->escape($option['name']) . "', `value` = '" . $this->db->escape($option['value']) . "', `type` = '" . $this->db->escape($option['type']) . "'"); - } - - foreach ($product['download'] as $download) { - $this->db->query("INSERT INTO " . DB_PREFIX . "order_download SET order_id = '" . (int)$order_id . "', order_product_id = '" . (int)$order_product_id . "', name = '" . $this->db->escape($download['name']) . "', filename = '" . $this->db->escape($download['filename']) . "', mask = '" . $this->db->escape($download['mask']) . "', remaining = '" . (int)($download['remaining'] * $product['quantity']) . "'"); - } - } - - foreach ($data['vouchers'] as $voucher) { - $this->db->query("INSERT INTO " . DB_PREFIX . "order_voucher SET order_id = '" . (int)$order_id . "', description = '" . $this->db->escape($voucher['description']) . "', code = '" . $this->db->escape($voucher['code']) . "', from_name = '" . $this->db->escape($voucher['from_name']) . "', from_email = '" . $this->db->escape($voucher['from_email']) . "', to_name = '" . $this->db->escape($voucher['to_name']) . "', to_email = '" . $this->db->escape($voucher['to_email']) . "', voucher_theme_id = '" . (int)$voucher['voucher_theme_id'] . "', message = '" . $this->db->escape($voucher['message']) . "', amount = '" . (float)$voucher['amount'] . "'"); - } - - foreach ($data['totals'] as $total) { - $this->db->query("INSERT INTO " . DB_PREFIX . "order_total SET order_id = '" . (int)$order_id . "', code = '" . $this->db->escape($total['code']) . "', title = '" . $this->db->escape($total['title']) . "', text = '" . $this->db->escape($total['text']) . "', `value` = '" . (float)$total['value'] . "', sort_order = '" . (int)$total['sort_order'] . "'"); - } - - /* - * This is integration code - */ - $this->crmOrderAction($data, $order_id, 'create'); - - /* - * This is original code again - */ - return $order_id; - } - - - - /* - * Crm order action method. Add it into the end of class code. - * - * @param $action string values: edit, create - */ - protected function crmOrderAction($order, $order_id, $action=null) - { - $this->load->model('setting/setting'); - $settings = $this->model_setting_setting->getSetting('intarocrm'); - $settings['domain'] = parse_url(HTTP_SERVER, PHP_URL_HOST); - - if(isset($settings['intarocrm_url']) && $settings['intarocrm_url'] != '' && isset($settings['intarocrm_apikey']) && $settings['intarocrm_apikey'] != '') { - include_once __DIR__ . '/../../../system/library/intarocrm/apihelper.php'; - - $order['order_id'] = $order_id; - $crm = new ApiHelper($settings); - - if ($action == null) { - $crm->dumperData($order); - } else { - $method = 'order' . ucfirst($action); - $crm->$method($order); - } - } - - } - -} -?> \ No newline at end of file diff --git a/system/library/intarocrm/.gitignore b/system/library/intarocrm/.gitignore new file mode 100644 index 0000000..61ead86 --- /dev/null +++ b/system/library/intarocrm/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/system/library/intarocrm/apihelper.php b/system/library/intarocrm/apihelper.php index 453ba57..75938ee 100644 --- a/system/library/intarocrm/apihelper.php +++ b/system/library/intarocrm/apihelper.php @@ -157,6 +157,41 @@ class ApiHelper } } + public function customerFixExternalIds($data) + { + try { + $this->intaroApi->customerFixExternalIds($data); + } catch (ApiException $e) { + $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds:' . $e->getMessage()); + $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds:' . json_encode($data)); + + return false; + } catch (CurlException $e) { + $this->log->addError('['.$this->domain.'] RestApi::customerFixExternalIds::Curl:' . $e->getMessage()); + + return false; + } + } + + public function getOrderItems($order_id) + { + try { + $order = $this->intaroApi->orderGet($order_id); + + return $order['items']; + } catch (ApiException $e) { + $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . $e->getMessage()); + $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds:' . json_encode($data)); + + return false; + } catch (CurlException $e) { + $this->log->addError('['.$this->domain.'] RestApi::orderFixExternalIds::Curl:' . $e->getMessage()); + + return false; + } + + } + private function saveDate($date) { file_put_contents($this->fileDate, $date, LOCK_EX); } diff --git a/system/library/intarocrm/composer.lock b/system/library/intarocrm/composer.lock new file mode 100644 index 0000000..d035da2 --- /dev/null +++ b/system/library/intarocrm/composer.lock @@ -0,0 +1,231 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "de9234b1e9e1ac5b5aaa5c5377eaafce", + "packages": [ + { + "name": "intarocrm/rest-api-client", + "version": "v1.2.5", + "source": { + "type": "git", + "url": "https://github.com/intarocrm/rest-api-client", + "reference": "b54350ff2f09d8202cf2931895bba8dced4dcf21" + }, + "require": { + "ext-curl": "*", + "php": ">=5.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "IntaroCrm\\": "lib/" + } + }, + "authors": [ + { + "name": "Kruglov Kirill", + "email": "kruglov@intaro.ru", + "role": "Developer" + } + ], + "description": "PHP Client for IntaroCRM REST API", + "homepage": "http://www.intarocrm.ru/", + "keywords": [ + "Intaro CRM", + "api", + "rest" + ], + "support": { + "email": "support@intarocrm.ru" + }, + "time": "2014-04-13 09:58:37" + }, + { + "name": "monolog/monolog", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "12545cda2f7a0bd82a110f742ef455fe735e60cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/12545cda2f7a0bd82a110f742ef455fe735e60cf", + "reference": "12545cda2f7a0bd82a110f742ef455fe735e60cf", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~3.7.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2014-07-31 22:12:22" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "symfony/console", + "version": "dev-master", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/Console.git", + "reference": "919345e2757aa3d3aca1d1ce5a8f53f65d1990ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Console/zipball/919345e2757aa3d3aca1d1ce5a8f53f65d1990ef", + "reference": "919345e2757aa3d3aca1d1ce5a8f53f65d1990ef", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2014-08-14 16:37:29" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "symfony/console": 20, + "monolog/monolog": 20 + }, + "prefer-stable": false, + "platform": { + "php": ">=5.3" + }, + "platform-dev": [] +}