From 804cbfac37cc50c655d1b98d1eb13f969d1aa7b7 Mon Sep 17 00:00:00 2001 From: Neur0toxine Date: Fri, 10 Jul 2020 13:14:03 +0300 Subject: [PATCH] Corporate clients support * corporate customers support * skip new payments without type * extract customer data from order for guests * extract customer phone and email from order for guests * set item discount to zero if no discount applies * create order from back-office * sync phone via history * fixed customer squashing * fixed createdAt crash * fixed customer id assigning & possible crash after errors in order creation --- .docker/Dockerfile | 2 +- .env-dist | 6 + CHANGELOG.md | 4 + VERSION | 2 +- composer.json | 4 +- resources/pot/retailcrm-es_ES.pot | 6 + resources/pot/retailcrm-ru_RU.pot | 6 + src/config/objects.xml | 17 + .../class-wc-retailcrm-abstract-builder.php | 86 + .../class-wc-retailcrm-abstracts-address.php | 96 + .../class-wc-retailcrm-abstracts-data.php | 10 +- .../class-wc-retailcrm-abstracts-settings.php | 68 +- .../api/class-wc-retailcrm-client-v5.php | 905 ++++++- src/include/api/class-wc-retailcrm-proxy.php | 121 +- .../api/class-wc-retailcrm-response.php | 38 + src/include/class-wc-retailcrm-base.php | 123 +- src/include/class-wc-retailcrm-customers.php | 441 +++- src/include/class-wc-retailcrm-history.php | 877 ++++--- src/include/class-wc-retailcrm-orders.php | 407 ++- src/include/class-wc-retailcrm-plugin.php | 74 +- .../class-wc-retailcrm-customer-switcher.php | 318 +++ .../class-wc-retailcrm-history-assembler.php | 402 +++ .../components/class-wc-retailcrm-logger.php | 125 + .../class-wc-retailcrm-paginated-request.php | 188 ++ .../class-wc-retailcrm-customer-address.php | 31 +- ...c-retailcrm-customer-corporate-address.php | 158 ++ ...class-wc-retailcrm-wc-customer-builder.php | 237 ++ src/include/functions.php | 12 +- .../class-wc-retailcrm-builder-interface.php | 48 + ...-wc-retailcrm-customer-switcher-result.php | 77 + ...s-wc-retailcrm-customer-switcher-state.php | 178 ++ .../class-wc-retailcrm-order-address.php | 3 +- .../order/class-wc-retailcrm-order-item.php | 8 +- .../class-wc-retailcrm-order-payment.php | 25 + .../order/class-wc-retailcrm-order.php | 9 +- src/languages/retailcrm-es_ES.mo | Bin 6334 -> 6445 bytes src/languages/retailcrm-ru_RU.mo | Bin 7802 -> 7966 bytes src/readme.txt | 4 + src/retailcrm.php | 114 +- src/uninstall.php | 2 +- tests/bin/install.sh | 0 tests/bootstrap.php | 8 + ...t-wc-retailcrm-customer-switcher-state.php | 88 + .../test-wc-retailcrm-wc-customer-builder.php | 137 + .../class-wc-retailcrm-log-handler-stdout.php | 117 + .../class-wc-retailcrm-test-case-helper.php | 44 +- ...-wc-retailcrm-customer-switcher-result.php | 51 + .../order/test-wc-retailcrm-order-address.php | 7 +- .../order/test-wc-retailcrm-order-payment.php | 21 +- tests/test-wc-retailcrm-base.php | 1 - tests/test-wc-retailcrm-customers.php | 6 +- tests/test-wc-retailcrm-history.php | 2212 ++++++++++++++++- tests/test-wc-retailcrm-orders.php | 106 +- tests/test-wc-retailcrm-plugin.php | 97 +- 54 files changed, 7142 insertions(+), 985 deletions(-) create mode 100644 src/include/abstracts/class-wc-retailcrm-abstract-builder.php create mode 100644 src/include/components/class-wc-retailcrm-customer-switcher.php create mode 100644 src/include/components/class-wc-retailcrm-history-assembler.php create mode 100644 src/include/components/class-wc-retailcrm-logger.php create mode 100644 src/include/components/class-wc-retailcrm-paginated-request.php create mode 100644 src/include/customer/class-wc-retailcrm-customer-corporate-address.php create mode 100644 src/include/customer/woocommerce/class-wc-retailcrm-wc-customer-builder.php create mode 100644 src/include/interfaces/class-wc-retailcrm-builder-interface.php create mode 100644 src/include/models/class-wc-retailcrm-customer-switcher-result.php create mode 100644 src/include/models/class-wc-retailcrm-customer-switcher-state.php mode change 100755 => 100644 tests/bin/install.sh create mode 100644 tests/customer/woocommerce/test-wc-retailcrm-customer-switcher-state.php create mode 100644 tests/customer/woocommerce/test-wc-retailcrm-wc-customer-builder.php create mode 100644 tests/helpers/class-wc-retailcrm-log-handler-stdout.php create mode 100644 tests/models/test-wc-retailcrm-customer-switcher-result.php diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 3452dc8..6703c53 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get install -y subversion RUN apt-get install -y wget RUN wget -O /usr/bin/phpunit https://phar.phpunit.de/phpunit-7.phar && chmod +x /usr/bin/phpunit -RUN curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer +RUN curl --insecure https://getcomposer.org/download/1.9.3/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - RUN apt-get install -y nodejs diff --git a/.env-dist b/.env-dist index 17a33c9..f89fd7b 100644 --- a/.env-dist +++ b/.env-dist @@ -1,6 +1,12 @@ +# MySQL host and credentials DB_NAME=wc_retailcrm_test DB_USER=wc_retailcrm DB_PASS=wc_retailcrm DB_HOST=mysql + +# WordPress and WooCommerce versions WP_VERSION=4.4 WC_VERSION=3.0.0 + +# Enable this in order to pipe all module log messages (including debug ones) to STDOUT. +MODULE_LOGS_TO_STDOUT=0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e01c0c..208de8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2020-06-18 4.0.0 +* Поддержка корпоративных клиентов +* Поддержка изменения покупателя в заказе + ## 2020-06-18 3.6.4 * Передача названия региона / штата / провинции вместо кода diff --git a/VERSION b/VERSION index 0f44168..fcdb2e1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.6.4 +4.0.0 diff --git a/composer.json b/composer.json index a298fba..c287da6 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,9 @@ } ], "minimum-stability": "dev", - "require": {}, + "require": { + "ext-simplexml": "*" + }, "require-dev": { "ext-json": "*", "ext-mbstring": "*", diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot index 0d5e56d..536b254 100644 --- a/resources/pot/retailcrm-es_ES.pot +++ b/resources/pot/retailcrm-es_ES.pot @@ -222,3 +222,9 @@ msgstr "Transferencia de un número de pedido" msgid "Transferring the payment amount" msgstr "Transferencia de un monto de pago" + +msgid "Corporate customers support" +msgstr "Soporte a clientes corporativos" + +msgid "Enabled" +msgstr "Habilitado" diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index d8164b7..30cf233 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -231,3 +231,9 @@ msgstr "Передача номера заказа" msgid "Transferring the payment amount" msgstr "Передача суммы оплаты" + +msgid "Corporate customers support" +msgstr "Поддержка корпоративных клиентов" + +msgid "Enabled" +msgstr "Включено" diff --git a/src/config/objects.xml b/src/config/objects.xml index f5ca5cf..11e27b9 100644 --- a/src/config/objects.xml +++ b/src/config/objects.xml @@ -15,6 +15,20 @@ personalDiscount discountCardNumber + id + externalId + nickName + vip + bad + customFields + personalDiscount + discountCardNumber + manager + address + mainCustomerContact + companyInn + company + index country region @@ -45,6 +59,7 @@ orderMethod site status + customer manager firstName lastName @@ -62,6 +77,8 @@ shipmentStore shipmentDate shipped + contact + company payment amount diff --git a/src/include/abstracts/class-wc-retailcrm-abstract-builder.php b/src/include/abstracts/class-wc-retailcrm-abstract-builder.php new file mode 100644 index 0000000..dc2ac80 --- /dev/null +++ b/src/include/abstracts/class-wc-retailcrm-abstract-builder.php @@ -0,0 +1,86 @@ +data = $data; + return $this; + } + + /** + * @return array|mixed + */ + public function getData() + { + return $this->data; + } + + /** + * @return $this|\WC_Retailcrm_Builder_Interface + */ + public function reset() + { + $this->data = array(); + return $this; + } + + /** + * Returns key if it's present in data array (or object which implements ArrayAccess). + * Returns default value if key is not present in data, or data is not accessible as array. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + protected function dataValue($key, $default = '') + { + return self::arrayValue($this->data, $key, $default); + } + + /** + * Returns key from array if it's present in array + * + * @param array|\ArrayObject $data + * @param mixed $key + * @param string $default + * + * @return mixed|string + */ + protected static function arrayValue($data, $key, $default = '') + { + if (!is_array($data) && !($data instanceof ArrayAccess)) { + return $default; + } + + if (array_key_exists($key, $data) && !empty($data[$key])) { + return $data[$key]; + } + + return $default; + } + + /** + * @return \WC_Retailcrm_Builder_Interface + */ + abstract public function build(); + + /** + * Returns builder result. Should return null if WC_Retailcrm_Abstract_Builder::isBuilt() == false. + * + * @return mixed|null + */ + abstract public function getResult(); +} diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-address.php b/src/include/abstracts/class-wc-retailcrm-abstracts-address.php index f951aec..aae346e 100644 --- a/src/include/abstracts/class-wc-retailcrm-abstracts-address.php +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-address.php @@ -11,6 +11,19 @@ abstract class WC_Retailcrm_Abstracts_Address extends WC_Retailcrm_Abstracts_Data { + const ADDRESS_TYPE_BILLING = 'billing'; + const ADDRESS_TYPE_SHIPPING = 'shipping'; + + /** @var string $address_type */ + protected $address_type = 'shipping'; + + /** @var bool $fallback_to_billing */ + protected $fallback_to_billing = false; + + /** @var bool $fallback_to_shipping */ + protected $fallback_to_shipping = false; + + /** @var array $data */ protected $data = array( 'index' => '', 'city' => '', @@ -18,6 +31,9 @@ abstract class WC_Retailcrm_Abstracts_Address extends WC_Retailcrm_Abstracts_Dat 'text' => '', ); + /** + * Resets inner state + */ public function reset_data() { $this->data = array( @@ -26,6 +42,86 @@ abstract class WC_Retailcrm_Abstracts_Address extends WC_Retailcrm_Abstracts_Dat 'region' => '', 'text' => '', ); + + return $this; + } + + /** + * @param bool $fallback_to_billing + * + * @return self + */ + public function setFallbackToBilling($fallback_to_billing) + { + $this->fallback_to_billing = $fallback_to_billing; + return $this; + } + + /** + * @param bool $fallback_to_shipping + * + * @return WC_Retailcrm_Abstracts_Address + */ + public function setFallbackToShipping($fallback_to_shipping) + { + $this->fallback_to_shipping = $fallback_to_shipping; + return $this; + } + + /** + * Sets woocommerce address type to work with + * + * @param string $addressType + * + * @return self + */ + public function setWCAddressType($addressType = WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_SHIPPING) + { + $this->address_type = $addressType; + return $this; + } + + /** + * Returns address from order. Respects fallback_to_billing parameter. + * + * @param \WC_Order $order + * + * @return array + */ + protected function getOrderAddress($order) + { + $orderAddress = $order->get_address($this->address_type); + + if (empty($orderAddress) && $this->address_type === self::ADDRESS_TYPE_BILLING && $this->fallback_to_shipping) { + $orderAddress = $order->get_address(self::ADDRESS_TYPE_SHIPPING); + } + + if (empty($orderAddress) && $this->address_type === self::ADDRESS_TYPE_SHIPPING && $this->fallback_to_billing) { + $orderAddress = $order->get_address(self::ADDRESS_TYPE_BILLING); + } + + return $orderAddress; + } + + /** + * Glue two addresses + * + * @param string $address1 + * @param string $address2 + * + * @return string + */ + protected function joinAddresses($address1 = '', $address2 = '') + { + if (empty($address1) && empty($address2)) { + return ''; + } + + if (empty($address2) && !empty($address1)) { + return $address1; + } + + return $address1 . ', ' . $address2; } /** diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-data.php b/src/include/abstracts/class-wc-retailcrm-abstracts-data.php index 20ad0b3..dcd6f79 100644 --- a/src/include/abstracts/class-wc-retailcrm-abstracts-data.php +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-data.php @@ -58,6 +58,14 @@ abstract class WC_Retailcrm_Abstracts_Data */ public function get_data() { - return apply_filters('retailcrm_before_send_' . $this->filter_name, $this->data); + return apply_filters('retailcrm_before_send_' . $this->filter_name, WC_Retailcrm_Plugin::clearArray($this->data)); + } + + /** + * @return array + */ + protected function get_data_without_filters() + { + return $this->data; } } diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php index fdb66c3..c0794e4 100644 --- a/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php @@ -122,11 +122,6 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration ) ); - $api_version_list = array( - 'v4' => 'v4', - 'v5' => 'v5' - ); - $this->form_fields[] = array( 'title' => __( 'API settings', 'retailcrm' ), 'type' => 'title', @@ -134,23 +129,22 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration 'id' => 'api_options' ); - $this->form_fields['api_version'] = array( - 'title' => __( 'API version', 'retailcrm' ), - 'description' => __( 'Select API version', 'retailcrm' ), - 'css' => 'min-width:50px;', - 'class' => 'select', - 'type' => 'select', - 'options' => $api_version_list, - 'desc_tip' => true, - ); - $this->form_fields['send_payment_amount'] = array( 'title' => __( 'Transferring the payment amount', 'retailcrm' ), 'label' => ' ', 'description' => '', 'class' => 'checkbox', 'type' => 'checkbox', - 'desc_tip' => true, + 'desc_tip' => true + ); + + $this->form_fields['corporate_enabled'] = array( + 'title' => __('Corporate customers support', 'retailcrm'), + 'label' => __('Enabled'), + 'description' => '', + 'class' => 'checkbox', + 'type' => 'checkbox', + 'desc_tip' => true ); $this->form_fields[] = array( @@ -563,40 +557,6 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration return ob_get_clean(); } - /** - * Validate API version - * - * @param string $key - * @param string $value - * - * @return string - */ - public function validate_api_version_field($key, $value) - { - $post = $this->get_post_data(); - - $versionMap = array( - 'v4' => '4.0', - 'v5' => '5.0' - ); - - $api = new WC_Retailcrm_Proxy( - $post[$this->plugin_id . $this->id . '_api_url'], - $post[$this->plugin_id . $this->id . '_api_key'] - ); - - $response = $api->apiVersions(); - - if (!empty($response) && $response->isSuccessful()) { - if (!in_array($versionMap[$value], $response['versions'])) { - WC_Admin_Settings::add_error( esc_html__( 'The selected API version is unavailable', 'retailcrm' ) ); - $value = ''; - } - } - - return $value; - } - /** * Validate API url * @@ -610,7 +570,8 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration $post = $this->get_post_data(); $api = new WC_Retailcrm_Proxy( $value, - $post[$this->plugin_id . $this->id . '_api_key'] + $post[$this->plugin_id . $this->id . '_api_key'], + $this->get_option('corporate_enabled', 'no') === 'yes' ); $response = $api->apiVersions(); @@ -636,7 +597,8 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration $post = $this->get_post_data(); $api = new WC_Retailcrm_Proxy( $post[$this->plugin_id . $this->id . '_api_url'], - $value + $value, + $this->get_option('corporate_enabled', 'no') === 'yes' ); $response = $api->apiVersions(); @@ -645,7 +607,7 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration $value = ''; } - if (!$response->isSuccessful()) { + if (empty($response) || !$response->isSuccessful()) { WC_Admin_Settings::add_error( esc_html__( 'Enter the correct API key', 'retailcrm' ) ); $value = ''; } diff --git a/src/include/api/class-wc-retailcrm-client-v5.php b/src/include/api/class-wc-retailcrm-client-v5.php index f83e972..3ec37cd 100644 --- a/src/include/api/class-wc-retailcrm-client-v5.php +++ b/src/include/api/class-wc-retailcrm-client-v5.php @@ -23,6 +23,7 @@ if ( ! class_exists( 'WC_Retailcrm_Response' ) ) { class WC_Retailcrm_Client_V5 { protected $client; + protected $unversionedClient; /** * Site code @@ -36,7 +37,7 @@ class WC_Retailcrm_Client_V5 * @param string $apiKey api key * @param string $site site code * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * */ public function __construct($url, $apiKey, $version = null, $site = null) @@ -45,9 +46,11 @@ class WC_Retailcrm_Client_V5 $url .= '/'; } + $unversionedUrl = $url . 'api'; $url = $version == null ? $url . 'api' : $url . 'api/' . $version; $this->client = new WC_Retailcrm_Request($url, array('apiKey' => $apiKey)); + $this->unversionedClient = new WC_Retailcrm_Request($unversionedUrl, array('apiKey' => $apiKey)); $this->siteCode = $site; } @@ -58,7 +61,623 @@ class WC_Retailcrm_Client_V5 */ public function apiVersions() { - return $this->client->makeRequest('/api-versions', WC_Retailcrm_Request::METHOD_GET); + return $this->unversionedClient->makeRequest('/api-versions', WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Returns credentials list + * + * @return WC_Retailcrm_Response + */ + public function credentials() + { + return $this->unversionedClient->makeRequest('/credentials', WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Returns filtered corporate customers list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateList(array $filter= array(), $page = null, $limit = null) + { + $parameters= array(); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate', + "GET", + $parameters + ); + } + + /** + * Create a corporate customer + * + * @param array $customerCorporate corporate customer data + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateCreate(array $customerCorporate, $site = null) + { + if (! count($customerCorporate)) { + throw new InvalidArgumentException( + 'Parameter `customerCorporate` must contains a data' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/create', + "POST", + $this->fillSite($site, array('customerCorporate' => json_encode($customerCorporate))) + ); + } + + /** + * Save corporate customer IDs' (id and externalId) association in the CRM + * + * @param array $ids ids mapping + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/fix-external-ids', + "POST", + array('customersCorporate' => json_encode($ids)) + ); + } + + /** + * Get corporate customers history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateHistory(array $filter= array(), $page = null, $limit = null) + { + $parameters= array(); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/history', + "GET", + $parameters + ); + } + + /** + * Returns filtered corporate customers notes list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateNotesList(array $filter= array(), $page = null, $limit = null) + { + $parameters= array(); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/notes', + "GET", + $parameters + ); + } + + /** + * Create corporate customer note + * + * @param array $note (default: array()) + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateNotesCreate($note, $site = null) + { + if (empty($note['customer']['id']) && empty($note['customer']['externalId'])) { + throw new InvalidArgumentException( + 'Customer identifier must be set' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/notes/create', + "POST", + $this->fillSite($site, array('note' => json_encode($note))) + ); + } + + /** + * Delete corporate customer note + * + * @param integer $id + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateNotesDelete($id) + { + if (empty($id)) { + throw new InvalidArgumentException( + 'Note id must be set' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/notes/$id/delete", + "POST" + ); + } + + /** + * Upload array of the corporate customers + * + * @param array $customersCorporate array of corporate customers + * @param string $site (default: null) + * + * @return WC_Retailcrm_Response + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @throws InvalidArgumentException + */ + public function customersCorporateUpload(array $customersCorporate, $site = null) + { + if (!count($customersCorporate)) { + throw new InvalidArgumentException( + 'Parameter `customersCorporate` must contains array of the corporate customers' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + '/customers-corporate/upload', + "POST", + $this->fillSite($site, array('customersCorporate' => json_encode($customersCorporate))) + ); + } + + /** + * Get corporate customer by id or externalId + * + * @param string $id corporate customer identifier + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id", + "GET", + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Get corporate customer addresses by id or externalId + * + * @param string $id corporate customer identifier + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateAddresses( + $id, + array $filter= array(), + $page = null, + $limit = null, + $by = 'externalId', + $site = null + ) { + $this->checkIdParameter($by); + $parameters = array('by' => $by); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/addresses", + "GET", + $this->fillSite($site, $parameters) + ); + } + + /** + * Create corporate customer address + * + * @param string $id corporate customer identifier + * @param array $address (default: array()) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateAddressesCreate($id, array $address= array(), $by = 'externalId', $site = null) + { + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/addresses/create", + "POST", + $this->fillSite($site, array('address' => json_encode($address), 'by' => $by)) + ); + } + + /** + * Edit corporate customer address + * + * @param string $customerId corporate customer identifier + * @param string $addressId corporate customer identifier + * @param array $address (default: array()) + * @param string $customerBy (default: 'externalId') + * @param string $addressBy (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateAddressesEdit( + $customerId, + $addressId, + array $address= array(), + $customerBy = 'externalId', + $addressBy = 'externalId', + $site = null + ) { + $addressFiltered = array_filter($address); + if ((count(array_keys($addressFiltered)) <= 1) + && (!isset($addressFiltered['text']) + || (isset($addressFiltered['text']) && empty($addressFiltered['text'])) + ) + ) { + throw new InvalidArgumentException( + 'Parameter `address` must contain address text or all other address field' + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$customerId/addresses/$addressId/edit", + "POST", + $this->fillSite($site, array( + 'address' => json_encode($address), + 'by' => $customerBy, + 'entityBy' => $addressBy + )) + ); + } + + /** + * Get corporate customer companies by id or externalId + * + * @param string $id corporate customer identifier + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateCompanies( + $id, + array $filter= array(), + $page = null, + $limit = null, + $by = 'externalId', + $site = null + ) { + $this->checkIdParameter($by); + $parameters = array('by' => $by); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/companies", + "GET", + $this->fillSite($site, $parameters) + ); + } + + /** + * Create corporate customer company + * + * @param string $id corporate customer identifier + * @param array $company (default: array()) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateCompaniesCreate($id, array $company= array(), $by = 'externalId', $site = null) + { + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/companies/create", + "POST", + $this->fillSite($site, array('company' => json_encode($company), 'by' => $by)) + ); + } + + /** + * Edit corporate customer company + * + * @param string $customerId corporate customer identifier + * @param string $companyId corporate customer identifier + * @param array $company (default: array()) + * @param string $customerBy (default: 'externalId') + * @param string $companyBy (default: 'externalId') + * @param string $site (default: null) + * + * @return WC_Retailcrm_Response + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + */ + public function customersCorporateCompaniesEdit( + $customerId, + $companyId, + array $company= array(), + $customerBy = 'externalId', + $companyBy = 'externalId', + $site = null + ) { + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$customerId/companies/$companyId/edit", + "POST", + $this->fillSite($site, array( + 'company' => json_encode($company), + 'by' => $customerBy, + 'entityBy' => $companyBy + )) + ); + } + + /** + * Get corporate customer contacts by id or externalId + * + * @param string $id corporate customer identifier + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateContacts( + $id, + array $filter= array(), + $page = null, + $limit = null, + $by = 'externalId', + $site = null + ) { + $this->checkIdParameter($by); + $parameters = array('by' => $by); + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/contacts", + "GET", + $this->fillSite($site, $parameters) + ); + } + + /** + * Create corporate customer contact + * + * @param string $id corporate customer identifier + * @param array $contact (default: array()) + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @return WC_Retailcrm_Response + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @throws InvalidArgumentException + */ + public function customersCorporateContactsCreate($id, array $contact= array(), $by = 'externalId', $site = null) + { + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$id/contacts/create", + "POST", + $this->fillSite($site, array('contact' => json_encode($contact), 'by' => $by)) + ); + } + + /** + * Edit corporate customer contact + * + * @param string $customerId corporate customer identifier + * @param string $contactId corporate customer identifier + * @param array $contact (default: array()) + * @param string $customerBy (default: 'externalId') + * @param string $contactBy (default: 'externalId') + * @param string $site (default: null) + * + * @return WC_Retailcrm_Response + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + */ + public function customersCorporateContactsEdit( + $customerId, + $contactId, + array $contact= array(), + $customerBy = 'externalId', + $contactBy = 'externalId', + $site = null + ) { + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + "/customers-corporate/$customerId/contacts/$contactId/edit", + "POST", + $this->fillSite($site, array( + 'contact' => json_encode($contact), + 'by' => $customerBy, + 'entityBy' => $contactBy + )) + ); + } + + /** + * Edit a corporate customer + * + * @param array $customerCorporate corporate customer data + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersCorporateEdit(array $customerCorporate, $by = 'externalId', $site = null) + { + if (!count($customerCorporate)) { + throw new InvalidArgumentException( + 'Parameter `customerCorporate` must contains a data' + ); + } + $this->checkIdParameter($by); + if (!array_key_exists($by, $customerCorporate)) { + throw new InvalidArgumentException( + sprintf('Corporate customer array must contain the "%s" parameter.', $by) + ); + } + /* @noinspection PhpUndefinedMethodInspection */ + return $this->client->makeRequest( + sprintf('/customers-corporate/%s/edit', $customerCorporate[$by]), + "POST", + $this->fillSite( + $site, + array('customerCorporate' => json_encode($customerCorporate), 'by' => $by) + ) + ); } /** @@ -70,7 +689,7 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ @@ -102,7 +721,7 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ @@ -124,7 +743,7 @@ class WC_Retailcrm_Client_V5 $statuses = array("free", "busy", "dinner", "break"); if (empty($status) || !in_array($status, $statuses)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `status` must be not empty & must be equal one of these values: free|busy|dinner|break' ); } @@ -211,13 +830,13 @@ class WC_Retailcrm_Client_V5 empty($customField['name']) || empty($customField['type']) ) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `customField` must contain a data & fields `code`, `name` & `type` must be set' ); } if (empty($entity) || $entity != 'customer' || $entity != 'order') { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `entity` must contain a data & value must be `order` or `customer`' ); } @@ -240,13 +859,13 @@ class WC_Retailcrm_Client_V5 public function customFieldsEdit($entity, $customField) { if (!count($customField) || empty($customField['code'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `customField` must contain a data & fields `code` must be set' ); } if (empty($entity) || $entity != 'customer' || $entity != 'order') { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `entity` must contain a data & value must be `order` or `customer`' ); } @@ -269,12 +888,12 @@ class WC_Retailcrm_Client_V5 public function customFieldsGet($entity, $code) { if (empty($code)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `code` must be not empty' ); } - - if (empty($entity) || !in_array($entity, ['customer', 'order', 'customer_corporate', 'company'])) { + + if (empty($entity) || !in_array($entity, array('customer', 'order', 'customer_corporate', 'company'))) { throw new \InvalidArgumentException( sprintf( 'Parameter `entity` must contain a data & value must be %s', @@ -332,7 +951,7 @@ class WC_Retailcrm_Client_V5 empty($customDictionary['code']) || empty($customDictionary['elements']) ) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' ); } @@ -357,7 +976,7 @@ class WC_Retailcrm_Client_V5 empty($customDictionary['code']) || empty($customDictionary['elements']) ) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' ); } @@ -379,7 +998,7 @@ class WC_Retailcrm_Client_V5 public function customDictionariesGet($code) { if (empty($code)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `code` must be not empty' ); } @@ -397,7 +1016,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -430,7 +1049,7 @@ class WC_Retailcrm_Client_V5 * @param array $order order data * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -439,7 +1058,7 @@ class WC_Retailcrm_Client_V5 public function ordersCreate(array $order, $site = null) { if (!count($order)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `order` must contains a data' ); } @@ -456,7 +1075,7 @@ class WC_Retailcrm_Client_V5 * * @param array $ids order identificators * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -465,7 +1084,7 @@ class WC_Retailcrm_Client_V5 public function ordersFixExternalIds(array $ids) { if (! count($ids)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Method parameter must contains at least one IDs pair' ); } @@ -484,7 +1103,7 @@ class WC_Retailcrm_Client_V5 * @param array $ids (default: array()) * @param array $externalIds (default: array()) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -514,7 +1133,7 @@ class WC_Retailcrm_Client_V5 * @param array $orders array of orders * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -523,7 +1142,7 @@ class WC_Retailcrm_Client_V5 public function ordersUpload(array $orders, $site = null) { if (!count($orders)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `orders` must contains array of the orders' ); } @@ -542,7 +1161,7 @@ class WC_Retailcrm_Client_V5 * @param string $by (default: 'externalId') * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -566,7 +1185,7 @@ class WC_Retailcrm_Client_V5 * @param string $by (default: 'externalId') * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -575,7 +1194,7 @@ class WC_Retailcrm_Client_V5 public function ordersEdit(array $order, $by = 'externalId', $site = null) { if (!count($order)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `order` must contains a data' ); } @@ -583,7 +1202,7 @@ class WC_Retailcrm_Client_V5 $this->checkIdParameter($by); if (!array_key_exists($by, $order)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( sprintf('Order array must contain the "%s" parameter.', $by) ); } @@ -641,13 +1260,13 @@ class WC_Retailcrm_Client_V5 $techniques = array('ours', 'summ', 'theirs'); if (!count($order) || !count($resultOrder)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameters `order` & `resultOrder` must contains a data' ); } if (!in_array($technique, $techniques)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `technique` must be on of ours|summ|theirs' ); } @@ -668,7 +1287,7 @@ class WC_Retailcrm_Client_V5 * * @param array $payment order data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -677,7 +1296,7 @@ class WC_Retailcrm_Client_V5 public function ordersPaymentCreate(array $payment) { if (!count($payment)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `payment` must contains a data' ); } @@ -701,7 +1320,7 @@ class WC_Retailcrm_Client_V5 public function ordersPaymentEdit(array $payment, $by = 'externalId', $site = null) { if (!count($payment)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `payment` must contains a data' ); } @@ -709,7 +1328,7 @@ class WC_Retailcrm_Client_V5 $this->checkIdParameter($by); if (!array_key_exists($by, $payment)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( sprintf('Order array must contain the "%s" parameter.', $by) ); } @@ -734,7 +1353,7 @@ class WC_Retailcrm_Client_V5 public function ordersPaymentDelete($id) { if (!$id) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `id` must be set' ); } @@ -752,7 +1371,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -785,7 +1404,7 @@ class WC_Retailcrm_Client_V5 * @param array $customer customer data * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -794,7 +1413,7 @@ class WC_Retailcrm_Client_V5 public function customersCreate(array $customer, $site = null) { if (! count($customer)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `customer` must contains a data' ); } @@ -811,7 +1430,7 @@ class WC_Retailcrm_Client_V5 * * @param array $ids ids mapping * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -820,7 +1439,7 @@ class WC_Retailcrm_Client_V5 public function customersFixExternalIds(array $ids) { if (! count($ids)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Method parameter must contains at least one IDs pair' ); } @@ -838,7 +1457,7 @@ class WC_Retailcrm_Client_V5 * @param array $customers array of customers * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -847,7 +1466,7 @@ class WC_Retailcrm_Client_V5 public function customersUpload(array $customers, $site = null) { if (! count($customers)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `customers` must contains array of the customers' ); } @@ -866,7 +1485,7 @@ class WC_Retailcrm_Client_V5 * @param string $by (default: 'externalId') * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -890,7 +1509,7 @@ class WC_Retailcrm_Client_V5 * @param string $by (default: 'externalId') * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -899,7 +1518,7 @@ class WC_Retailcrm_Client_V5 public function customersEdit(array $customer, $by = 'externalId', $site = null) { if (!count($customer)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `customer` must contains a data' ); } @@ -907,7 +1526,7 @@ class WC_Retailcrm_Client_V5 $this->checkIdParameter($by); if (!array_key_exists($by, $customer)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( sprintf('Customer array must contain the "%s" parameter.', $by) ); } @@ -963,7 +1582,7 @@ class WC_Retailcrm_Client_V5 { if (!count($customers) || !count($resultCustomer)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameters `customers` & `resultCustomer` must contains a data' ); } @@ -985,7 +1604,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1016,7 +1635,7 @@ class WC_Retailcrm_Client_V5 * @param array $note (default: array()) * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1025,7 +1644,7 @@ class WC_Retailcrm_Client_V5 public function customersNotesCreate($note, $site = null) { if (empty($note['customer']['id']) && empty($note['customer']['externalId'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Customer identifier must be set' ); } @@ -1041,7 +1660,7 @@ class WC_Retailcrm_Client_V5 * * @param integer $id * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1050,7 +1669,7 @@ class WC_Retailcrm_Client_V5 public function customersNotesDelete($id) { if (empty($id)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Note id must be set' ); } @@ -1067,7 +1686,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1100,7 +1719,7 @@ class WC_Retailcrm_Client_V5 * @param array $pack pack data * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1109,7 +1728,7 @@ class WC_Retailcrm_Client_V5 public function ordersPacksCreate(array $pack, $site = null) { if (!count($pack)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `pack` must contains a data' ); } @@ -1128,7 +1747,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1160,7 +1779,7 @@ class WC_Retailcrm_Client_V5 * * @param string $id pack identificator * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1169,7 +1788,7 @@ class WC_Retailcrm_Client_V5 public function ordersPacksGet($id) { if (empty($id)) { - throw new \InvalidArgumentException('Parameter `id` must be set'); + throw new InvalidArgumentException('Parameter `id` must be set'); } return $this->client->makeRequest( @@ -1183,7 +1802,7 @@ class WC_Retailcrm_Client_V5 * * @param string $id pack identificator * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1192,7 +1811,7 @@ class WC_Retailcrm_Client_V5 public function ordersPacksDelete($id) { if (empty($id)) { - throw new \InvalidArgumentException('Parameter `id` must be set'); + throw new InvalidArgumentException('Parameter `id` must be set'); } return $this->client->makeRequest( @@ -1207,7 +1826,7 @@ class WC_Retailcrm_Client_V5 * @param array $pack pack data * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1216,7 +1835,7 @@ class WC_Retailcrm_Client_V5 public function ordersPacksEdit(array $pack, $site = null) { if (!count($pack) || empty($pack['id'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `pack` must contains a data & pack `id` must be set' ); } @@ -1270,7 +1889,7 @@ class WC_Retailcrm_Client_V5 public function tasksCreate($task, $site = null) { if (!count($task)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `task` must contain a data' ); } @@ -1297,7 +1916,7 @@ class WC_Retailcrm_Client_V5 public function tasksEdit($task, $site = null) { if (!count($task)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `task` must contain a data' ); } @@ -1322,7 +1941,7 @@ class WC_Retailcrm_Client_V5 public function tasksGet($id) { if (empty($id)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `id` must be not empty' ); } @@ -1340,7 +1959,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1374,7 +1993,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1409,14 +2028,14 @@ class WC_Retailcrm_Client_V5 * @return WC_Retailcrm_Response * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function storeSettingsGet($code) { if (empty($code)) { - throw new \InvalidArgumentException('Parameter `code` must be set'); + throw new InvalidArgumentException('Parameter `code` must be set'); } return $this->client->makeRequest( @@ -1432,14 +2051,14 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function storeSettingsEdit(array $configuration) { if (!count($configuration) || empty($configuration['code'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `configuration` must contains a data & configuration `code` must be set' ); } @@ -1457,7 +2076,7 @@ class WC_Retailcrm_Client_V5 * @param array $offers offers data * @param string $site (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1466,7 +2085,7 @@ class WC_Retailcrm_Client_V5 public function storeInventoriesUpload(array $offers, $site = null) { if (!count($offers)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `offers` must contains array of the offers' ); } @@ -1485,7 +2104,7 @@ class WC_Retailcrm_Client_V5 * @param int $page (default: null) * @param int $limit (default: null) * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1517,7 +2136,7 @@ class WC_Retailcrm_Client_V5 * * @param string $code * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1526,7 +2145,7 @@ class WC_Retailcrm_Client_V5 public function deliverySettingsGet($code) { if (empty($code)) { - throw new \InvalidArgumentException('Parameter `code` must be set'); + throw new InvalidArgumentException('Parameter `code` must be set'); } return $this->client->makeRequest( @@ -1542,14 +2161,14 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function deliverySettingsEdit(array $configuration) { if (!count($configuration) || empty($configuration['code'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `configuration` must contains a data & configuration `code` must be set' ); } @@ -1569,18 +2188,18 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function deliveryTracking($code, array $statusUpdate) { if (empty($code)) { - throw new \InvalidArgumentException('Parameter `code` must be set'); + throw new InvalidArgumentException('Parameter `code` must be set'); } if (!count($statusUpdate)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `statusUpdate` must contains a data' ); } @@ -1595,7 +2214,7 @@ class WC_Retailcrm_Client_V5 /** * Returns available county list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1612,7 +2231,7 @@ class WC_Retailcrm_Client_V5 /** * Returns deliveryServices list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1631,7 +2250,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data delivery service data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1640,7 +2259,7 @@ class WC_Retailcrm_Client_V5 public function deliveryServicesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1655,7 +2274,7 @@ class WC_Retailcrm_Client_V5 /** * Returns deliveryTypes list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1674,7 +2293,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data delivery type data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1683,7 +2302,7 @@ class WC_Retailcrm_Client_V5 public function deliveryTypesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1698,7 +2317,7 @@ class WC_Retailcrm_Client_V5 /** * Returns orderMethods list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1717,7 +2336,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data order method data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1726,7 +2345,7 @@ class WC_Retailcrm_Client_V5 public function orderMethodsEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1741,7 +2360,7 @@ class WC_Retailcrm_Client_V5 /** * Returns orderTypes list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1760,7 +2379,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data order type data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1769,7 +2388,7 @@ class WC_Retailcrm_Client_V5 public function orderTypesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1784,7 +2403,7 @@ class WC_Retailcrm_Client_V5 /** * Returns paymentStatuses list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1803,7 +2422,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data payment status data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1812,7 +2431,7 @@ class WC_Retailcrm_Client_V5 public function paymentStatusesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1827,7 +2446,7 @@ class WC_Retailcrm_Client_V5 /** * Returns paymentTypes list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1846,7 +2465,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data payment type data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1855,7 +2474,7 @@ class WC_Retailcrm_Client_V5 public function paymentTypesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1870,7 +2489,7 @@ class WC_Retailcrm_Client_V5 /** * Returns productStatuses list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1889,7 +2508,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data product status data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1898,7 +2517,7 @@ class WC_Retailcrm_Client_V5 public function productStatusesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1913,7 +2532,7 @@ class WC_Retailcrm_Client_V5 /** * Returns sites list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1932,7 +2551,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data site data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1941,7 +2560,7 @@ class WC_Retailcrm_Client_V5 public function sitesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -1956,7 +2575,7 @@ class WC_Retailcrm_Client_V5 /** * Returns statusGroups list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1973,7 +2592,7 @@ class WC_Retailcrm_Client_V5 /** * Returns statuses list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -1992,7 +2611,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data status data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2001,7 +2620,7 @@ class WC_Retailcrm_Client_V5 public function statusesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } @@ -2016,7 +2635,7 @@ class WC_Retailcrm_Client_V5 /** * Returns stores list * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2035,7 +2654,7 @@ class WC_Retailcrm_Client_V5 * * @param array $data site data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2044,13 +2663,13 @@ class WC_Retailcrm_Client_V5 public function storesEdit(array $data) { if (!array_key_exists('code', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "code" parameter.' ); } if (!array_key_exists('name', $data)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Data must contain "name" parameter.' ); } @@ -2069,14 +2688,14 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function telephonySettingsGet($code) { if (empty($code)) { - throw new \InvalidArgumentException('Parameter `code` must be set'); + throw new InvalidArgumentException('Parameter `code` must be set'); } return $this->client->makeRequest( @@ -2122,13 +2741,13 @@ class WC_Retailcrm_Client_V5 ) { if (!isset($code)) { - throw new \InvalidArgumentException('Code must be set'); + throw new InvalidArgumentException('Code must be set'); } $parameters['code'] = $code; if (!isset($clientId)) { - throw new \InvalidArgumentException('client id must be set'); + throw new InvalidArgumentException('client id must be set'); } $parameters['clientId'] = $clientId; @@ -2140,7 +2759,7 @@ class WC_Retailcrm_Client_V5 } if (!isset($name)) { - throw new \InvalidArgumentException('name must be set'); + throw new InvalidArgumentException('name must be set'); } if (isset($name)) { @@ -2215,15 +2834,15 @@ class WC_Retailcrm_Client_V5 ) { if (!isset($phone)) { - throw new \InvalidArgumentException('Phone number must be set'); + throw new InvalidArgumentException('Phone number must be set'); } if (!isset($type)) { - throw new \InvalidArgumentException('Type must be set (in|out|hangup)'); + throw new InvalidArgumentException('Type must be set (in|out|hangup)'); } if (empty($codes)) { - throw new \InvalidArgumentException('Codes array must be set'); + throw new InvalidArgumentException('Codes array must be set'); } $parameters['phone'] = $phone; @@ -2246,7 +2865,7 @@ class WC_Retailcrm_Client_V5 * * @param array $calls calls data * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2255,7 +2874,7 @@ class WC_Retailcrm_Client_V5 public function telephonyCallsUpload(array $calls) { if (!count($calls)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `calls` must contains array of the calls' ); } @@ -2273,7 +2892,7 @@ class WC_Retailcrm_Client_V5 * @param string $phone phone number * @param bool $details detailed information * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2282,7 +2901,7 @@ class WC_Retailcrm_Client_V5 public function telephonyCallManager($phone, $details) { if (!isset($phone)) { - throw new \InvalidArgumentException('Phone number must be set'); + throw new InvalidArgumentException('Phone number must be set'); } $parameters['phone'] = $phone; @@ -2302,14 +2921,14 @@ class WC_Retailcrm_Client_V5 * * @throws WC_Retailcrm_Exception_Json * @throws WC_Retailcrm_Exception_Curl - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return WC_Retailcrm_Response */ public function integrationModulesEdit(array $configuration) { if (!count($configuration) || empty($configuration['code'])) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( 'Parameter `configuration` must contains a data & configuration `code` must be set' ); } @@ -2326,7 +2945,7 @@ class WC_Retailcrm_Client_V5 /** * Update CRM basic statistic * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * @throws WC_Retailcrm_Exception_Curl * @throws WC_Retailcrm_Exception_Json * @@ -2350,6 +2969,32 @@ class WC_Retailcrm_Client_V5 return $this->siteCode; } + /** + * getSingleSiteForKey + * + * @return string|bool + */ + public function getSingleSiteForKey() + { + $site = $this->getSite(); + + if (!empty($site)) { + return $this->getSite(); + } + + $response = $this->credentials(); + + if ($response instanceof WC_Retailcrm_Response + && $response->offsetExists('sitesAvailable') + && is_array($response['sitesAvailable']) + && !empty($response['sitesAvailable']) + ) { + $this->siteCode = $response['sitesAvailable'][0]; + } + + return $this->getSite(); + } + /** * Set site * @@ -2367,7 +3012,7 @@ class WC_Retailcrm_Client_V5 * * @param string $by identify by * - * @throws \InvalidArgumentException + * @throws InvalidArgumentException * * @return bool */ @@ -2379,7 +3024,7 @@ class WC_Retailcrm_Client_V5 ); if (!in_array($by, $allowedForBy, false)) { - throw new \InvalidArgumentException( + throw new InvalidArgumentException( sprintf( 'Value "%s" for "by" param is not valid. Allowed values are %s.', $by, diff --git a/src/include/api/class-wc-retailcrm-proxy.php b/src/include/api/class-wc-retailcrm-proxy.php index 54450b3..c109639 100644 --- a/src/include/api/class-wc-retailcrm-proxy.php +++ b/src/include/api/class-wc-retailcrm-proxy.php @@ -15,64 +15,127 @@ if ( ! class_exists( 'WC_Retailcrm_Proxy' ) ) : class WC_Retailcrm_Proxy { protected $retailcrm; - protected $logger; + protected $corporateEnabled; - public function __construct($api_url, $api_key, $api_vers = null) - { - $this->logger = new WC_Logger(); - - if ( ! class_exists( 'WC_Retailcrm_Client_V4' ) ) { - include_once( __DIR__ . '/class-wc-retailcrm-client-v4.php' ); - } + public function __construct($api_url, $api_key, $corporateEnabled = false) + { + $this->corporateEnabled = $corporateEnabled; if ( ! class_exists( 'WC_Retailcrm_Client_V5' ) ) { include_once( __DIR__ . '/class-wc-retailcrm-client-v5.php' ); } - switch ($api_vers) { - case 'v4': - $this->retailcrm = new WC_Retailcrm_Client_V4($api_url, $api_key, $api_vers); - break; - case 'v5': - $this->retailcrm = new WC_Retailcrm_Client_V5($api_url, $api_key, $api_vers); - break; - case null: - $this->retailcrm = new WC_Retailcrm_Client_V4($api_url, $api_key, $api_vers); - break; + $this->retailcrm = new WC_Retailcrm_Client_V5($api_url, $api_key, 'v5'); + } + + /** + * getCorporateEnabled + * + * @return bool + */ + public function getCorporateEnabled() + { + return $this->corporateEnabled; + } + + private static function reduceErrors($errors) + { + $result = ''; + + foreach ($errors as $key => $error) { + $result .= " [$key] => $error"; } + + return $result; + } + + /** + * Response will be omitted in debug logs for those methods + * + * @return string[] + */ + private function methodsWithoutDebugResponse() + { + $methodsList = array('statusesList', 'paymentTypesList', 'deliveryTypesList', 'orderMethodsList'); + + foreach ($methodsList as $key => $method) { + $method = get_class($this->retailcrm) . '::' . $method; + $methodsList[$key] = $method; + } + + return $methodsList; } public function __call($method, $arguments) { + $result = ''; + $response = null; + $called = sprintf('%s::%s', get_class($this->retailcrm), $method); + try { + WC_Retailcrm_Logger::debug( + $called, + array(empty($arguments) ? '[no params]' : print_r($arguments, true)) + ); + /** @var \WC_Retailcrm_Response $response */ $response = call_user_func_array(array($this->retailcrm, $method), $arguments); - if (!empty($response) && $response->isSuccessful()) { + if (is_string($response)) { + WC_Retailcrm_Logger::debug($called, array($response)); + return $response; + } + + if (empty($response)) { + WC_Retailcrm_Logger::add(sprintf("[%s] null (no response whatsoever)", $called)); + return null; + } + + if ($response->isSuccessful()) { + // Don't print long lists in debug logs (errors while calling this will be easy to detect anyway) + // Also don't call useless array_map at all while debug mode is off. + if (retailcrm_is_debug()) { + if (in_array( + $called, + $this->methodsWithoutDebugResponse() + )) { + WC_Retailcrm_Logger::debug($called, array('[request was successful, but response is omitted]')); + } else { + WC_Retailcrm_Logger::debug($called, array($response->getRawResponse())); + } + } + $result = ' Ok'; } else { $result = sprintf( - $method ." : Error: [HTTP-code %s] %s", + $called ." : Error: [HTTP-code %s] %s", $response->getStatusCode(), - $response->getErrorMsg() + $response->getErrorString() ); if (isset($response['errors'])) { - foreach ($response['errors'] as $error) { - $result .= " $error"; - } + $result .= self::reduceErrors($response['errors']); } + + WC_Retailcrm_Logger::debug($called, array($response->getErrorString())); + WC_Retailcrm_Logger::debug($called, array($response->getRawResponse())); } - $this->logger->add('retailcrm', sprintf("[%s] %s", $method, $result)); + WC_Retailcrm_Logger::add(sprintf("[%s] %s", $called, $result)); } catch (WC_Retailcrm_Exception_Curl $exception) { - $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + WC_Retailcrm_Logger::debug(get_class($this->retailcrm).'::'.$called, array($exception->getMessage())); + WC_Retailcrm_Logger::debug('', array($exception->getTraceAsString())); + WC_Retailcrm_Logger::add(sprintf("[%s] %s - %s", $called, $exception->getMessage(), $result)); } catch (WC_Retailcrm_Exception_Json $exception) { - $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + WC_Retailcrm_Logger::debug(get_class($this->retailcrm).'::'.$called, array($exception->getMessage())); + WC_Retailcrm_Logger::debug('', array($exception->getTraceAsString())); + WC_Retailcrm_Logger::add(sprintf("[%s] %s - %s", $called, $exception->getMessage(), $result)); } catch (InvalidArgumentException $exception) { - $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + WC_Retailcrm_Logger::debug(get_class($this->retailcrm).'::'.$called, array($exception->getMessage())); + WC_Retailcrm_Logger::debug('', array($exception->getTraceAsString())); + WC_Retailcrm_Logger::add(sprintf("[%s] %s - %s", $called, $exception->getMessage(), $result)); } - return $response; + return !empty($response) ? $response : new WC_Retailcrm_Response(900, '{}'); } } endif; \ No newline at end of file diff --git a/src/include/api/class-wc-retailcrm-response.php b/src/include/api/class-wc-retailcrm-response.php index e9e8ed9..b5f4bff 100644 --- a/src/include/api/class-wc-retailcrm-response.php +++ b/src/include/api/class-wc-retailcrm-response.php @@ -24,6 +24,9 @@ class WC_Retailcrm_Response implements \ArrayAccess // response assoc array protected $response; + // response raw data + protected $rawResponse; + /** * ApiResponse constructor. * @@ -35,6 +38,7 @@ class WC_Retailcrm_Response implements \ArrayAccess public function __construct($statusCode, $responseBody = null) { $this->statusCode = (int) $statusCode; + $this->rawResponse = $responseBody; if (!empty($responseBody)) { $response = json_decode($responseBody, true); @@ -166,4 +170,38 @@ class WC_Retailcrm_Response implements \ArrayAccess return $this->response[$offset]; } + + /** + * Returns error string. If there's multiple errors present - they will be squashed into single string. + * + * @return string + */ + public function getErrorString() + { + if ($this->offsetExists('error')) { + return (string) $this->response['error']; + } elseif ($this->offsetExists('errors') && is_array($this->response['errors'])) { + $errorMessage = ''; + + foreach ($this->response['errors'] as $error) { + $errorMessage .= $error . ' >'; + } + + if (strlen($errorMessage) > 2) { + return (string) substr($errorMessage, 0, strlen($errorMessage) - 2); + } + + return $errorMessage; + } + + return ''; + } + + /** + * @return mixed|null + */ + public function getRawResponse() + { + return $this->rawResponse; + } } diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index d5326fd..269c1b1 100644 --- a/src/include/class-wc-retailcrm-base.php +++ b/src/include/class-wc-retailcrm-base.php @@ -17,17 +17,30 @@ if (!class_exists('WC_Retailcrm_Base')) { */ class WC_Retailcrm_Base extends WC_Retailcrm_Abstracts_Settings { + /** @var string */ protected $api_url; + + /** @var string */ protected $api_key; + + /** @var \WC_Retailcrm_Proxy|WC_Retailcrm_Client_V4|WC_Retailcrm_Client_V5|bool */ protected $apiClient; + + /** @var mixed */ protected $order_item; + + /** @var mixed */ protected $order_address; + + /** @var \WC_Retailcrm_Customers */ protected $customers; + + /** @var \WC_Retailcrm_Orders */ protected $orders; /** * Init and hook in the integration. - * @param $retailcrm (default = false) + * @param \WC_Retailcrm_Proxy|WC_Retailcrm_Client_V4|WC_Retailcrm_Client_V5|bool $retailcrm (default = false) */ public function __construct($retailcrm = false) { parent::__construct(); @@ -83,6 +96,8 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('admin_print_footer_scripts', array($this, 'ajax_selected_order'), 99); add_action('woocommerce_created_customer', array($this, 'create_customer'), 10, 1); add_action('woocommerce_update_customer', array($this, 'update_customer'), 10, 1); + add_action('user_register', array($this, 'create_customer'), 10, 2); + add_action('profile_update', array($this, 'update_customer'), 10, 2); add_action('wp_print_scripts', array($this, 'initialize_analytics'), 98); add_action('wp_print_scripts', array($this, 'initialize_daemon_collector'), 99); add_action('wp_print_footer_scripts', array($this, 'send_analytics'), 99); @@ -207,11 +222,33 @@ if (!class_exists('WC_Retailcrm_Base')) { $ids = false; if (isset($_GET['order_ids_retailcrm'])) { + $appendix = array(); $ids = explode(',', $_GET['order_ids_retailcrm']); + + foreach ($ids as $key => $id) { + if (stripos($id, '-') !== false) { + $idSplit = explode('-', $id); + + if (count($idSplit) == 2) { + $expanded = array(); + $first = (int) $idSplit[0]; + $last = (int) $idSplit[1]; + + for ($i = $first; $i <= $last; $i++) { + $expanded[] = $i; + } + + $appendix = array_merge($appendix, $expanded); + unset($ids[$key]); + } + } + } + + $ids = array_unique(array_merge($ids, $appendix)); } if ($ids) { - $this->orders->ordersUpload($ids, true); + $this->orders->ordersUpload($ids); } } @@ -229,34 +266,64 @@ if (!class_exists('WC_Retailcrm_Base')) { update_option(static::$option_key, $options); } - /** - * Create customer in retailCRM - * - * @param int $customer_id - * - * @return void - * @throws \Exception - */ + /** + * Create customer in retailCRM + * + * @param int $customer_id + * + * @return void + * @throws \Exception + */ public function create_customer($customer_id) { if (WC_Retailcrm_Plugin::history_running() === true) { return; } - $client = $this->getApiClient(); + $client = $this->getApiClient(); - if (empty($client)) { - return; + if (empty($client)) { + return; + } + + $wcCustomer = new WC_Customer($customer_id); + $email = $wcCustomer->get_billing_email(); + + if (empty($email)) { + $email = $wcCustomer->get_email(); } - $wcCustomer = new WC_Customer($customer_id); - $response = $client->customersList(array('email' => $wcCustomer->get_billing_email())); - - if ((!empty($response) && $response->isSuccessful()) && isset($response['customers']) && count($response['customers']) > 0) { - return; + if (empty($email)) { + return; + } else { + $wcCustomer->set_billing_email($email); + $wcCustomer->save(); } - $this->customers->createCustomer($customer_id); + $response = $client->customersList(array('email' => $email)); + + if (!empty($response) + && $response->isSuccessful() + && isset($response['customers']) + && count($response['customers']) > 0 + ) { + $customers = $response['customers']; + $customer = reset($customers); + + if (isset($customer['id'])) { + $this->customers->updateCustomerById($customer_id, $customer['id']); + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $builder + ->setWcCustomer($wcCustomer) + ->setPhones(isset($customer['phones']) ? $customer['phones'] : array()) + ->setAddress(isset($customer['address']) ? $customer['address'] : false) + ->build() + ->getResult() + ->save(); + } + } else { + $this->customers->createCustomer($customer_id); + } } /** @@ -269,6 +336,10 @@ if (!class_exists('WC_Retailcrm_Base')) { return; } + if (empty($customer_id)) { + return; + } + $this->customers->updateCustomer($customer_id); } @@ -286,7 +357,10 @@ if (!class_exists('WC_Retailcrm_Base')) { /** * Edit order in retailCRM + * * @param int $order_id + * + * @throws \Exception */ public function update_order($order_id) { @@ -359,7 +433,7 @@ if (!class_exists('WC_Retailcrm_Base')) { return new WC_Retailcrm_Proxy( $this->get_option('api_url'), $this->get_option('api_key'), - $this->get_option('api_version') + $this->get_option('corporate_enabled', 'no') === 'yes' ); } @@ -375,9 +449,8 @@ if (!class_exists('WC_Retailcrm_Base')) { { $api_client = $this->getApiClient(); $clientId = get_option('retailcrm_client_id'); - $api_version = $this->get_option('api_version'); - WC_Retailcrm_Plugin::integration_module($api_client, $clientId, $api_version, false); + WC_Retailcrm_Plugin::integration_module($api_client, $clientId, false); delete_option('retailcrm_active_in_crm'); } @@ -394,14 +467,14 @@ if (!class_exists('WC_Retailcrm_Base')) { $client_id = uniqid(); } - if ($settings['api_url'] && $settings['api_key'] && $settings['api_version']) { + if ($settings['api_url'] && $settings['api_key']) { $api_client = new WC_Retailcrm_Proxy( $settings['api_url'], $settings['api_key'], - $settings['api_version'] + $settings['corporate_enabled'] === 'yes' ); - $result = WC_Retailcrm_Plugin::integration_module($api_client, $client_id, $settings['api_version']); + $result = WC_Retailcrm_Plugin::integration_module($api_client, $client_id); if ($result) { update_option('retailcrm_active_in_crm', true); diff --git a/src/include/class-wc-retailcrm-customers.php b/src/include/class-wc-retailcrm-customers.php index eecc736..981b921 100644 --- a/src/include/class-wc-retailcrm-customers.php +++ b/src/include/class-wc-retailcrm-customers.php @@ -12,11 +12,19 @@ if (!class_exists('WC_Retailcrm_Customers')) : /** * Class WC_Retailcrm_Customers */ - class WC_Retailcrm_Customers { + class WC_Retailcrm_Customers + { + /** + * Administrator role + */ + const ADMIN_ROLE = 'administrator'; + /** + * Every customer has this role + */ const CUSTOMER_ROLE = 'customer'; - /** @var bool | WC_Retailcrm_Proxy | \WC_Retailcrm_Client_V5 */ + /** @var bool | WC_Retailcrm_Proxy | \WC_Retailcrm_Client_V5 */ protected $retailcrm; /** @var array */ @@ -28,11 +36,20 @@ if (!class_exists('WC_Retailcrm_Customers')) : /** @var array */ private $customer = array(); + /** @var array */ + private $customerCorporate = array(); + + /** @var array */ + private $customerCorporateCompany = array(); + + /** @var array */ + private $customerCorporateAddress = array(); + /** * WC_Retailcrm_Customers constructor. * - * @param bool | WC_Retailcrm_Proxy $retailcrm - * @param array $retailcrm_settings + * @param bool | WC_Retailcrm_Proxy $retailcrm + * @param array $retailcrm_settings * @param WC_Retailcrm_Customer_Address $customer_address */ public function __construct($retailcrm = false, $retailcrm_settings, $customer_address) @@ -42,10 +59,41 @@ if (!class_exists('WC_Retailcrm_Customers')) : $this->customer_address = $customer_address; } + /** + * setCustomerAddress + * + * @param $address + * + * @return $this + */ + public function setCustomerAddress($address) + { + if ($address instanceof WC_Retailcrm_Customer_Address) { + $this->customer_address = $address; + } + + return $this; + } + + /** + * Is corporate customers enabled in provided API + * + * @return bool + */ + public function isCorporateEnabled() + { + if (!$this->retailcrm) { + return false; + } + + return $this->retailcrm->getCorporateEnabled(); + } + /** * Upload customers to CRM * * @param array $ids + * * @return array mixed */ public function customersUpload($ids = array()) @@ -58,7 +106,7 @@ if (!class_exists('WC_Retailcrm_Customers')) : $data_customers = array(); foreach ($users as $user) { - if (!\in_array(self::CUSTOMER_ROLE, $user->roles)) { + if (!static::isCustomer($user)) { continue; } @@ -82,9 +130,12 @@ if (!class_exists('WC_Retailcrm_Customers')) : * * @param int | WC_Customer $customer * + * @param \WC_Order|null $order + * * @return mixed + * @throws \Exception */ - public function createCustomer($customer) + public function createCustomer($customer, $order = null) { if (!$this->retailcrm) { return null; @@ -98,8 +149,8 @@ if (!class_exists('WC_Retailcrm_Customers')) : return null; } - if ($customer->get_role() == self::CUSTOMER_ROLE) { - $this->processCustomer($customer); + if (self::isCustomer($customer)) { + $this->processCustomer($customer, $order); $response = $this->retailcrm->customersCreate($this->customer); if ((!empty($response) && $response->isSuccessful()) && isset($response['id'])) { @@ -111,11 +162,12 @@ if (!class_exists('WC_Retailcrm_Customers')) : } /** - * Edit customer in CRM + * Update customer in CRM * - * @param int $customer_id + * @param $customer_id * - * @return WC_Customer $customer + * @return void|\WC_Customer + * @throws \Exception */ public function updateCustomer($customer_id) { @@ -125,7 +177,7 @@ if (!class_exists('WC_Retailcrm_Customers')) : $customer = $this->wcCustomerGet($customer_id); - if ($customer->get_role() == self::CUSTOMER_ROLE){ + if (self::isCustomer($customer)) { $this->processCustomer($customer); $this->retailcrm->customersEdit($this->customer); } @@ -133,36 +185,288 @@ if (!class_exists('WC_Retailcrm_Customers')) : return $customer; } + /** + * Update customer in CRM by ID + * + * @param int $customer_id + * @param int|string $crmCustomerId + * + * @return void|\WC_Customer + * @throws \Exception + */ + public function updateCustomerById($customer_id, $crmCustomerId) + { + if (!$this->retailcrm) { + return; + } + + $customer = $this->wcCustomerGet($customer_id); + + if (self::isCustomer($customer)) { + $this->processCustomer($customer); + $this->customer['id'] = $crmCustomerId; + $this->retailcrm->customersEdit($this->customer, 'id'); + } + + return $customer; + } + + /** + * Create corporate customer in CRM + * + * @param int $crmCustomerId + * @param int | WC_Customer $customer + * @param \WC_Order $order + * + * @return mixed + * @throws \Exception + */ + public function createCorporateCustomerForOrder($crmCustomerId, $customer, $order) + { + if (!$this->retailcrm) { + return null; + } + + if (is_int($customer)) { + $customer = $this->wcCustomerGet($customer); + } + + if (!$customer instanceof WC_Customer) { + return null; + } + + if (self::isCustomer($customer)) { + $this->processCorporateCustomer($crmCustomerId, $customer, $order); + $response = $this->retailcrm->customersCorporateCreate($this->customerCorporate); + + return $this->fillCorporateCustomer($response); + } + + return null; + } + + /** + * Create new address in corporate customer (if needed) + * + * @param int $corporateId + * @param \WC_Customer $customer + * @param \WC_Order|null $order + */ + public function fillCorporateAddress($corporateId, $customer, $order = null) + { + $found = false; + $builder = new WC_Retailcrm_Customer_Corporate_Address(); + $newAddress = $builder + ->setFallbackToShipping(true) + ->setIsMain(false) + ->setExplicitIsMain(false) + ->setWCAddressType(WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_BILLING) + ->build($customer, $order) + ->get_data(); + $addresses = $this->retailcrm->customersCorporateAddresses( + $corporateId, + array(), + null, + 100, + 'id' + ); + + if ($addresses && $addresses->isSuccessful() && $addresses->offsetExists('addresses')) { + foreach ($addresses['addresses'] as $address) { + foreach ($newAddress as $field => $value) { + if (isset($address[$field]) && $address[$field] != $value) { + continue 2; + } + } + + $found = true; + + break; + } + } else { + $found = true; + } + + if (!$found) { + $this->retailcrm->customersCorporateAddressesCreate( + $corporateId, + $newAddress, + 'id', + $this->retailcrm->getSingleSiteForKey() + ); + } + } + + /** + * Fills corporate customer with required data after customer was created or updated. + * Create or update response after sending customer must be passed. + * + * @param \WC_Retailcrm_Response $response + * + * @return string|int|null + */ + protected function fillCorporateCustomer($response) + { + if (!$response->isSuccessful() || $response->isSuccessful() && !$response->offsetExists('id')) { + return null; + } + + $customerId = $response['id']; + $response = $this->retailcrm->customersCorporateAddressesCreate( + $customerId, + $this->customerCorporateAddress, + 'id', + $this->retailcrm->getSingleSiteForKey() + ); + + if ($response->isSuccessful() && $response->offsetExists('id')) { + $this->customerCorporateCompany['address'] = array( + 'id' => $response['id'], + ); + $this->retailcrm->customersCorporateCompaniesCreate( + $customerId, + $this->customerCorporateCompany, + 'id', + $this->retailcrm->getSingleSiteForKey() + ); + } + + return $customerId; + } + /** * Process customer * - * @param WC_Customer $customer + * @param WC_Customer $customer + * @param WC_Order|null $order * * @return void + * @throws \Exception */ - protected function processCustomer($customer) + protected function processCustomer($customer, $order = null) { $createdAt = $customer->get_date_created(); $firstName = $customer->get_first_name(); + $lastName = $customer->get_last_name(); + $billingPhone = $customer->get_billing_phone(); + $email = $customer->get_billing_email(); + + if (empty($firstName) && empty($lastName) && $order instanceof WC_Order) { + $firstName = $order->get_billing_first_name(); + $lastName = $order->get_billing_last_name(); + + if (empty($firstName) && empty($lastName)) { + $firstName = $order->get_shipping_first_name(); + $lastName = $order->get_shipping_last_name(); + } + + if (empty($firstName)) { + $firstName = $customer->get_username(); + } + + if (empty($email)) { + $email = $order->get_billing_email(); + } + + if (empty($billingPhone)) { + $order->get_billing_phone(); + } + } + + if (empty($createdAt)) { + $createdAt = new WC_DateTime(); + } + $data_customer = array( 'createdAt' => $createdAt->date('Y-m-d H:i:s'), 'firstName' => $firstName ? $firstName : $customer->get_username(), - 'lastName' => $customer->get_last_name(), + 'lastName' => $lastName, 'email' => $customer->get_billing_email(), - 'address' => $this->customer_address->build($customer)->get_data() + 'address' => $this->customer_address->build($customer, $order)->get_data() ); if ($customer->get_id() > 0) { $data_customer['externalId'] = $customer->get_id(); } - if ($customer->get_billing_phone()) { + if (!empty($billingPhone)) { $data_customer['phones'][] = array( - 'number' => $customer->get_billing_phone() + 'number' => $customer->get_billing_phone() ); } - $this->customer = apply_filters('retailcrm_process_customer', $data_customer, $customer); + $this->customer = apply_filters( + 'retailcrm_process_customer', + WC_Retailcrm_Plugin::clearArray($data_customer), + $customer + ); + } + + /** + * Process corporate customer + * + * @param int $crmCustomerId + * @param WC_Customer $customer + * @param \WC_Order $order + * + * @return void + */ + protected function processCorporateCustomer($crmCustomerId, $customer, $order) + { + $data_company = array( + 'isMain' => true, + 'name' => $order->get_billing_company() + ); + + $data_customer = array( + 'nickName' => $order->get_billing_company(), + 'customerContacts' => array( + array( + 'isMain' => true, + 'customer' => array( + 'id' => $crmCustomerId + ) + ) + ) + ); + + $orderAddress = new WC_Retailcrm_Order_Address(); + $corpAddress = new WC_Retailcrm_Customer_Corporate_Address(); + + $address = $orderAddress + ->setWCAddressType(WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_BILLING) + ->build($order) + ->get_data(); + + $shippingAddress = $corpAddress + ->setWCAddressType(WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_BILLING) + ->setFallbackToBilling(true) + ->setIsMain(true) + ->build($customer, $order) + ->get_data(); + + if (isset($address['text'])) { + $data_company['contragent']['legalAddress'] = $address['text']; + } + + $this->customerCorporate = apply_filters( + 'retailcrm_process_customer_corporate', + WC_Retailcrm_Plugin::clearArray($data_customer), + $customer + ); + $this->customerCorporateAddress = apply_filters( + 'retailcrm_process_customer_corporate_address', + WC_Retailcrm_Plugin::clearArray(array_merge( + $shippingAddress, + array('isMain' => true) + )), + $customer + ); + $this->customerCorporateCompany = apply_filters( + 'retailcrm_process_customer_corporate_company', + WC_Retailcrm_Plugin::clearArray($data_company), + $customer + ); } /** @@ -170,7 +474,7 @@ if (!class_exists('WC_Retailcrm_Customers')) : * * @return bool|array */ - public function searchCustomer($filter) + private function searchCustomer($filter) { if (isset($filter['externalId'])) { $search = $this->retailcrm->customersGet($filter['externalId']); @@ -183,15 +487,82 @@ if (!class_exists('WC_Retailcrm_Customers')) : } if (!empty($search) && $search->isSuccessful()) { + $customer = false; + if (isset($search['customers'])) { if (empty($search['customers'])) { return false; } - - $arrayCustumers = $search['customers']; - $customer = reset($arrayCustumers); + + if (isset($filter['email']) && count($filter) == 1) { + foreach ($search['customers'] as $finding) { + if (isset($finding['email']) && $finding['email'] == $filter['email']) { + $customer = $finding; + } + } + } else { + $dataCustomers = $search['customers']; + $customer = reset($dataCustomers); + } } else { - $customer = $search['customer']; + $customer = !empty($search['customer']) ? $search['customer'] : false; + } + + return $customer; + } + + return false; + } + + /** + * Returns customer data by externalId or by email, returns false in case of failure + * + * @param $customerExternalId + * @param $customerEmailOrPhone + * + * @return array|bool + */ + public function findCustomerEmailOrId($customerExternalId, $customerEmailOrPhone) + { + $customer = false; + + if (!empty($customerExternalId)) { + $customer = $this->searchCustomer(array('externalId' => $customerExternalId)); + } + + if (!$customer && !empty($customerEmailOrPhone)) { + $customer = $this->searchCustomer(array('email' => $customerEmailOrPhone)); + } + + return $customer; + } + + /** + * Search by provided filter, returns first found customer + * + * @param array $filter + * @param bool $returnGroup Return all customers for group filter instead of first + * + * @return bool|array + */ + public function searchCorporateCustomer($filter, $returnGroup = false) + { + $search = $this->retailcrm->customersCorporateList($filter); + + if (!empty($search) && $search->isSuccessful()) { + if (isset($search['customersCorporate'])) { + if (empty($search['customersCorporate'])) { + return false; + } + + if ($returnGroup) { + return $search['customersCorporate']; + } else { + $dataCorporateCustomers = $search['customersCorporate']; + $customer = reset($dataCorporateCustomers); + } + } else { + $customer = false; } return $customer; @@ -208,7 +579,7 @@ if (!class_exists('WC_Retailcrm_Customers')) : */ public function buildCustomerFromOrderData($order) { - $new_customer = new WC_Customer; + $new_customer = new WC_Customer(); foreach ($order->get_address('billing') as $prop => $value) { $new_customer->{'set_billing_' . $prop}($value); @@ -226,6 +597,7 @@ if (!class_exists('WC_Retailcrm_Customers')) : * @param int $customer_id * * @return WC_Customer + * @throws \Exception */ public function wcCustomerGet($customer_id) { @@ -239,5 +611,24 @@ if (!class_exists('WC_Retailcrm_Customers')) : { return $this->customer; } + + /** + * Returns true if provided WP_User or WC_Customer should be uploaded to CRM + * + * @param \WC_Customer|\WP_User $user + * + * @return bool + */ + public static function isCustomer($user) + { + if ($user instanceof WC_Customer) { + return $user->get_role() == self::CUSTOMER_ROLE || $user->get_role() == self::ADMIN_ROLE; + } elseif ($user instanceof WP_User) { + return in_array(self::CUSTOMER_ROLE, $user->roles) + || in_array(self::ADMIN_ROLE, $user->roles); + } + + return false; + } } endif; diff --git a/src/include/class-wc-retailcrm-history.php b/src/include/class-wc-retailcrm-history.php index 886ac7f..4f2aa03 100644 --- a/src/include/class-wc-retailcrm-history.php +++ b/src/include/class-wc-retailcrm-history.php @@ -14,12 +14,25 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : */ class WC_Retailcrm_History { + /** @var \DateTime */ protected $startDateOrders; + + /** @var \DateTime */ protected $startDateCustomers; + + /** @var \DateTime */ protected $startDate; + + /** @var array|mixed|void */ protected $retailcrm_settings; + + /** @var bool|\WC_Retailcrm_Proxy|\WC_Retailcrm_Client_V4|\WC_Retailcrm_Client_V5 */ protected $retailcrm; + + /** @var array|mixed */ protected $order_methods = array(); + + /** @var string */ protected $bind_field = 'externalId'; /** @var WC_Retailcrm_Order_Item */ @@ -27,7 +40,10 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : /** * WC_Retailcrm_History constructor. - * @param $retailcrm (default = false) + * + * @param \WC_Retailcrm_Proxy|\WC_Retailcrm_Client_V4|\WC_Retailcrm_Client_V5|bool $retailcrm (default = false) + * + * @throws \Exception */ public function __construct($retailcrm = false) { @@ -52,9 +68,10 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : } /** - * Get history method + * Get history method. * * @return void + * @throws \Exception */ public function getHistory() { @@ -69,140 +86,131 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : $this->startDateCustomers = new DateTime($this->retailcrm_settings['history_orders']); } - $this->customersHistory($this->startDateCustomers->format('Y-m-d H:i:s'), $customers_since_id); - $this->ordersHistory($this->startDateOrders->format('Y-m-d H:i:s'), $orders_since_id); + try { + $this->customersHistory($this->startDateCustomers->format('Y-m-d H:i:s'), $customers_since_id); + $this->ordersHistory($this->startDateOrders->format('Y-m-d H:i:s'), $orders_since_id); + } catch (\Exception $exception) { + WC_Retailcrm_Logger::add( + sprintf("[%s] - %s", $exception->getMessage(), + 'Exception in file - ' . $exception->getFile() . ' on line ' . $exception->getLine()) + ); + } } /** * History customers * * @param string $date - * @param int $since_id + * @param int $sinceId * - * @return null + * @return void + * @throws \Exception */ - protected function customersHistory($date, $since_id) + protected function customersHistory($date, $sinceId) { - if ($since_id) { - $response = $this->retailcrm->customersHistory(array('sinceId' => $since_id)); - } else { - $response = $this->retailcrm->customersHistory(array('startDate' => $date)); + $filter = array('startDate' => $date); + + if ($sinceId) { + $filter = array('sinceId' => $sinceId); } - if (!empty($response) && $response->isSuccessful()) { - if (empty($response['history'])) { - return; - } + $request = new WC_Retailcrm_Paginated_Request(); + $history = $request + ->setApi($this->retailcrm) + ->setMethod('customersHistory') + ->setParams(array($filter, '{{page}}')) + ->setDataKey('history') + ->setLimit(100) + ->execute() + ->getData(); - $history = $response['history']; - $end_change = end($history); - $new_since_id = $end_change['id']; + if (!empty($history)) { + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $lastChange = end($history); + $customers = WC_Retailcrm_History_Assembler::assemblyCustomer($history); + WC_Retailcrm_Plugin::$history_run = true; + WC_Retailcrm_Logger::debug(__METHOD__, array('Assembled customers history:', $customers)); - foreach ($history as $record) { - if ($record['source'] == 'api' && $record['apiKey']['current'] == true) { + foreach ($customers as $crmCustomer) { + if (!isset($crmCustomer['externalId'])) { continue; } - if (isset($record['customer']['externalId'])) { - $customer = new WC_Customer($record['customer']['externalId']); + try { + $builder->reset(); - if ($customer->get_id() == 0) { + if (!$builder->loadExternalId($crmCustomer['externalId'])) { + WC_Retailcrm_Logger::addCaller(__METHOD__, sprintf( + 'Customer with id=%s is not found in the DB, skipping...', + $crmCustomer['externalId'] + )); continue; } - } - WC_Retailcrm_Plugin::$history_run = true; + $wcCustomer = $builder + ->setData($crmCustomer) + ->build() + ->getResult(); - if ($record['field'] == 'first_name' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'first_name', $record['newValue']); + if ($wcCustomer instanceof WC_Customer) { + $wcCustomer->save(); } - } - elseif ($record['field'] == 'last_name' && isset($record['customer']['externalId'])) { - if ($record['newValue']) { - update_user_meta($record['customer']['externalId'], 'last_name', $record['newValue']); - } + WC_Retailcrm_Logger::debug(__METHOD__, array('Updated WC_Customer:', $wcCustomer)); + } catch (\Exception $exception) { + WC_Retailcrm_Logger::error(sprintf( + 'Error while trying to process history: %s', + $exception->getMessage() + )); + WC_Retailcrm_Logger::error(sprintf( + '%s:%d', + $exception->getFile(), + $exception->getLine() + )); + WC_Retailcrm_Logger::error($exception->getTraceAsString()); } - - elseif ($record['field'] == 'email' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_email', $record['newValue']); - } - } - - elseif ($record['field'] == 'phones' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_phone', $record['newValue']); - } - } - - elseif ($record['field'] == 'address.region' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_state', $record['newValue']); - } - } - - elseif ($record['field'] == 'address.index' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_postcode', $record['newValue']); - } - } - - elseif ($record['field'] == 'address.country' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_country', $record['newValue']); - } - } - - elseif ($record['field'] == 'address.city' && isset($record['customer']['externalId'])) { - if ($record['newValue']){ - update_user_meta($record['customer']['externalId'], 'billing_city', $record['newValue']); - } - } - - WC_Retailcrm_Plugin::$history_run = false; } - } - if (empty($response)) { - return; + update_option('retailcrm_customers_history_since_id', $lastChange['id']); + WC_Retailcrm_Plugin::$history_run = false; } - - update_option('retailcrm_customers_history_since_id', $new_since_id); } - /** - * History orders - * - * @param string $date - * @param int $since_id - * - * @return boolean - */ + /** + * History orders + * + * @param string $date + * @param int $since_id + * + * @return boolean + */ protected function ordersHistory($date, $since_id) { + $filter = array('startDate' => $date); $options = array_flip(array_filter($this->retailcrm_settings)); if ($since_id) { - $response = $this->retailcrm->ordersHistory(array('sinceId' => $since_id)); - } else { - $response = $this->retailcrm->ordersHistory(array('startDate' => $date)); + $filter = array('sinceId' => $since_id); } - if (!empty($response) && $response->isSuccessful()) { - if (empty($response['history'])) { - return false; - } + $request = new WC_Retailcrm_Paginated_Request(); + $history = $request + ->setApi($this->retailcrm) + ->setMethod('ordersHistory') + ->setParams(array($filter, '{{page}}')) + ->setDataKey('history') + ->setLimit(100) + ->execute() + ->getData(); - $history = $response['history']; + if (!empty($history)) { $last_change = end($history); - $historyAssembly = self::assemblyOrder($response['history']); - + $historyAssembly = WC_Retailcrm_History_Assembler::assemblyOrder($history); + WC_Retailcrm_Logger::debug(__METHOD__, array('Assembled orders history:', $historyAssembly)); WC_Retailcrm_Plugin::$history_run = true; foreach ($historyAssembly as $orderHistory) { - $order = apply_filters('retailcrm_history_before_save', $orderHistory); + $order = WC_Retailcrm_Plugin::clearArray(apply_filters('retailcrm_history_before_save', $orderHistory)); if (isset($order['deleted']) && $order['deleted'] == true) { continue; @@ -221,8 +229,7 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : $this->update_total($wc_order); } } catch (Exception $exception) { - $logger = new WC_Logger(); - $logger->add('retailcrm', + WC_Retailcrm_Logger::add( sprintf("[%s] - %s", $exception->getMessage(), 'Exception in file - ' . $exception->getFile() . ' on line ' . $exception->getLine()) ); @@ -241,11 +248,12 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : /** * Update shipping * - * @param array $order - * @param array $options + * @param array $order + * @param array $options * @param WC_Order $wc_order * * @return boolean + * @throws \WC_Data_Exception */ protected function updateShippingItemId($order, $options, $wc_order) { @@ -317,6 +325,7 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : * @param array $options * * @return bool + * @throws \Exception * @throws \WC_Data_Exception */ protected function orderUpdate($order, $options) @@ -347,22 +356,35 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : $wc_order->set_shipping_last_name($order['lastName']); } - if (isset($order['phone'])) { - $wc_order->set_billing_phone($order['phone']); - } + if (!$this->handleCustomerDataChange($wc_order, $order)) { + if (isset($order['phone'])) { + $wc_order->set_billing_phone($order['phone']); + } - if (isset($order['email'])) { - $wc_order->set_billing_email($order['email']); + if (isset($order['email'])) { + $wc_order->set_billing_email($order['email']); + } + + if (isset($order['company']['address'])) { + $billingAddress = $order['company']['address']; + + $wc_order->set_billing_state(self::arrayValue($billingAddress, 'region', '--')); + $wc_order->set_billing_postcode(self::arrayValue($billingAddress, 'index', '--')); + $wc_order->set_billing_country(self::arrayValue($billingAddress, 'country', '--')); + $wc_order->set_billing_city(self::arrayValue($billingAddress, 'city', '--')); + $wc_order->set_billing_address_1(self::arrayValue($billingAddress, 'text', '--')); + } } if (array_key_exists('items', $order)) { foreach ($order['items'] as $key => $item) { - if (!isset($item['offer'][$this->bind_field])) { continue; } if (isset($item['create']) && $item['create'] == true) { + $arItemsNew = array(); + $arItemsOld = array(); $product = retailcrm_get_wc_product( $item['offer'][$this->bind_field], $this->retailcrm_settings @@ -378,8 +400,9 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : $arItemsNew[$order_item_id] = $order_item_id; } - $diff = array_diff($arItemsNew, $arItemsOld); - $result = end($diff); + $tmpArray = array_diff($arItemsNew, $arItemsOld); + $result = end($tmpArray); + $order['items'][$key]['woocomerceId'] = $result; } else { foreach ($wc_order->get_items() as $order_item_id => $order_item) { @@ -400,11 +423,10 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : } if ($offer_id == $item['offer'][$this->bind_field] - && $itemExternalId[1] == $order_item->get_id() + && (isset($itemExternalId) && $itemExternalId[1] == $order_item->get_id()) ) { $this->deleteOrUpdateOrderItem($item, $order_item, $itemExternalId[1]); } - } } } @@ -478,26 +500,30 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : $wc_order->save(); - $checkNewItem = false; - foreach ($order['items'] as $item) { - if (!empty($item['externalIds'])) { - continue; - } else { - $checkNewItem = true; + if (isset($order['items'])) { + $checkNewItem = false; + foreach ($order['items'] as $item) { + if (!empty($item['externalIds'])) { + continue; + } else { + $checkNewItem = true; + } } - } - if ($checkNewItem == true) { - $this->editOrder($this->retailcrm_settings, $wc_order, $order,'update'); + if ($checkNewItem == true) { + $this->editOrder($this->retailcrm_settings, $wc_order, $order,'update'); + } } return $wc_order->get_id(); } /** - * @param $item - * @param $order_item - * @param $order_item_id + * @param array $item + * @param \WC_Order_Item $order_item + * @param string $order_item_id + * + * @throws \Exception */ private function deleteOrUpdateOrderItem($item, $order_item, $order_item_id) { @@ -527,6 +553,7 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : * @param array $options * * @return bool + * @throws \WC_Data_Exception */ protected function orderCreate($order, $options) { @@ -542,16 +569,99 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : return false; } + $orderResponse = $this->retailcrm->ordersGet($order['id'], 'id'); + + if (null !== $orderResponse && $orderResponse->offsetExists('order')) { + $crmOrder = $orderResponse['order']; + + if (isset($crmOrder['customer'])) { + $order['customer'] = $crmOrder['customer']; + } + + if (isset($crmOrder['contact'])) { + $order['contact'] = $crmOrder['contact']; + } + + if (isset($crmOrder['company'])) { + $order['company'] = $crmOrder['company']; + } + } + + $customerId = isset($order['customer']['externalId']) ? $order['customer']['externalId'] : null; + + if (self::isOrderCorporate($order)) { + $customerId = isset($order['contact']['externalId']) ? $order['contact']['externalId'] : null; + } + $args = array( 'status' => isset($options[$order['status']]) ? $options[$order['status']] : 'processing', - 'customer_id' => isset($order['customer']['externalId']) - ? $order['customer']['externalId'] - : null + 'customer_id' => $customerId ); + /** @var WC_Order|WP_Error $wc_order */ $wc_order = wc_create_order($args); + $customer = $order['customer']; + $contactOrCustomer = array(); + $address = isset($order['customer']['address']) ? $order['customer']['address'] : array(); + $billingAddress = $address; + $companyName = ''; + + if ($this->retailcrm->getCorporateEnabled()) { + $billingAddress = isset($order['company']['address']) ? $order['company']['address'] : $address; + + if (empty($billingAddress)) { + $billingAddress = $address; + } + } + + if ($this->retailcrm->getCorporateEnabled() && self::isOrderCorporate($order)) { + if (isset($order['contact'])) { + $contactOrCustomer = $order['contact']; + + if (self::noRealDataInEntity($contactOrCustomer)) { + $response = $this->retailcrm->customersGet($contactOrCustomer['id'], 'id'); + + if (!empty($response) && $response->offsetExists('customer')) { + $contactOrCustomer = $response['customer']; + } + } + } + } else { + $contactOrCustomer = $customer; + + if (!self::isOrderCorporate($order) && self::noRealDataInEntity($contactOrCustomer)) { + $response = $this->retailcrm->customersGet($contactOrCustomer['id'], 'id'); + + if (!empty($response) && $response->offsetExists('customer')) { + $contactOrCustomer = $response['customer']; + } + } + } + + if ($wc_order instanceof WP_Error) { + WC_Retailcrm_Logger::add(sprintf( + '[%d] error while creating order: %s', + $order['id'], + print_r($wc_order->get_error_messages(), true) + )); + + return false; + } + + if (isset($order['managerComment']) && !empty($order['managerComment'])) { + $wc_order->add_order_note($order['managerComment'], 0, false); + } + + // TODO Check if that works; also don't forget to set this company field while creating order from CMS! + if ($this->retailcrm->getCorporateEnabled() + && self::isOrderCorporate($order) + && !empty($order['company']) + && isset($order['company']['name']) + ) { + $companyName = $order['company']['name']; + } $address_shipping = array( 'first_name' => isset($order['firstName']) ? $order['firstName'] : '', @@ -566,39 +676,28 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : ); $address_billing = array( - 'first_name' => $order['customer']['firstName'], - 'last_name' => isset($order['customer']['lastName']) ? $order['customer']['lastName'] : '', - 'company' => '', - 'email' => isset($order['customer']['email']) ? $order['customer']['email'] : '', - 'phone' => isset($order['customer']['phones'][0]['number']) ? $order['customer']['phones'][0]['number'] : '', - 'address_1' => isset($order['customer']['address']['text']) ? $order['customer']['address']['text'] : '', + 'first_name' => isset($contactOrCustomer['firstName']) ? $contactOrCustomer['firstName'] : '', + 'last_name' => isset($contactOrCustomer['lastName']) ? $contactOrCustomer['lastName'] : '', + 'company' => $companyName, + 'email' => isset($contactOrCustomer['email']) ? $contactOrCustomer['email'] : '', + 'phone' => isset($contactOrCustomer['phones'][0]['number']) ? $contactOrCustomer['phones'][0]['number'] : '', + 'address_1' => isset($billingAddress['text']) ? $billingAddress['text'] : '', 'address_2' => '', - 'city' => isset($order['customer']['address']['city']) ? $order['customer']['address']['city'] : '', - 'state' => isset($order['customer']['address']['region']) ? $order['customer']['address']['region'] : '', - 'postcode' => isset($order['customer']['address']['index']) ? $order['customer']['address']['index'] : '', - 'country' => $order['customer']['address']['countryIso'] + 'city' => isset($billingAddress['city']) ? $billingAddress['city'] : '', + 'state' => isset($billingAddress['region']) ? $billingAddress['region'] : '', + 'postcode' => isset($billingAddress['index']) ? $billingAddress['index'] : '', + 'country' => isset($billingAddress['countryIso']) ? $billingAddress['countryIso'] : '' ); - if ($this->retailcrm_settings['api_version'] == 'v5') { - if (isset($order['payments']) && $order['payments']) { - $payment = WC_Payment_Gateways::instance(); + if (isset($order['payments']) && $order['payments']) { + $payment = WC_Payment_Gateways::instance(); - if (count($order['payments']) == 1) { - $payment_types = $payment->payment_gateways(); - $payments = $order['payments']; - $paymentType = end($payments); - if (isset($options[$paymentType['type']]) && isset($payment_types[$options[$paymentType['type']]])) { - $wc_order->set_payment_method($payment_types[$options[$paymentType['type']]]); - } - } - } - } else { - if (isset($order['paymentType']) && $order['paymentType']) { - $payment = WC_Payment_Gateways::instance(); + if (count($order['payments']) == 1) { $payment_types = $payment->payment_gateways(); - - if (isset($options[$order['paymentType']]) && isset($payment_types[$options[$order['paymentType']]])) { - $wc_order->set_payment_method($payment_types[$options[$order['paymentType']]]); + $payments = $order['payments']; + $paymentType = end($payments); + if (isset($options[$paymentType['type']]) && isset($payment_types[$options[$paymentType['type']]])) { + $wc_order->set_payment_method($payment_types[$options[$paymentType['type']]]); } } } @@ -609,14 +708,17 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : if ($product_data) { foreach ($product_data as $key => $product) { + $arItemsNew = array(); + $arItemsOld = array(); $item = retailcrm_get_wc_product($product['offer'][$this->bind_field], $this->retailcrm_settings); + if (!$item) { $logger = new WC_Logger(); $logger->add('retailcrm', 'Product not found by ' . $this->bind_field); continue; } - if ($product['discountTotal'] > 0) { + if (isset($product['discountTotal']) && $product['discountTotal'] > 0) { $item->set_price($product['initialPrice'] - $product['discountTotal']); } @@ -634,8 +736,8 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : } if (!empty($arItemsOld)) { - $diff = array_diff($arItemsNew, $arItemsOld); - $result = end($diff); + $arItemsTemp = array_diff($arItemsNew, $arItemsOld); + $result = end($arItemsTemp); } else { $result = end($arItemsNew); } @@ -665,9 +767,9 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : } } - if (!wc_tax_enabled()) { + if (isset($order['delivery']['cost']) && !wc_tax_enabled()) { $shipping->set_total($order['delivery']['cost']); - } else { + } elseif (isset($order['delivery']['netCost'])) { $shipping->set_total($order['delivery']['netCost']); } @@ -700,34 +802,89 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : */ protected function editOrder($settings, $wc_order, $order, $event = 'create') { - $order_items = array(); + $data= array(); + $crmOrder= array(); + $order_items= array(); + if ($event == 'update') { $result = $this->retailcrm->ordersGet($order['externalId']); if (!empty($result) && $result->isSuccessful()) { - $orderCrm = $result['order']; + $crmOrder = $result['order']; + $data = $crmOrder; } - - $data = $orderCrm; } if ($event == 'create') { - $data = $order; + $data = $order; } - foreach ($data['items'] as $id => $item) { + $iterableItems = isset($data['items']) ? $data['items'] : array(); + + foreach ($iterableItems as $id => $item) { $order_items[$id]['id'] = $item['id']; $order_items[$id]['offer'] = array('id' => $item['offer']['id']); + + if (!isset($order['items'][$item['id']])) { + if (empty($crmOrder)) { + $result = $this->retailcrm->ordersGet($order['id'], 'id'); + + if (!empty($result) && $result->isSuccessful()) { + $crmOrder = $result['order']; + } + } + + if (!empty($crmOrder) && isset($crmOrder['items'][$item['id']])) { + $woocommerceId = self::getItemWoocommerceId($crmOrder['items'][$item['id']]); + } else { + WC_Retailcrm_Logger::add( + sprintf( + "Order externalId=`%s`: item doesn't have woocomerceId, skipping... (item id=`%s`)", + $order['externalId'], + $item['id'] + ) + ); + continue; + } + } else { + $woocommerceId = self::getItemWoocommerceId($order['items'][$item['id']]); + } + + if (empty($woocommerceId)) { + WC_Retailcrm_Logger::add( + sprintf( + "Order externalId=`%s`: item doesn't have woocomerceId after all assertions, which" . + " is unexpected, skipping... (item id=`%s`)", + $order['externalId'], + $item['id'] + ) + ); + + continue; + } + $externalIds = array( array( 'code' => 'woocomerce', - 'value' => $item['offer']['externalId'] . '_' . $order['items'][$item['id']]['woocomerceId'], + 'value' => $item['offer']['externalId'] . '_' . $woocommerceId, ) ); - if ($item['externalIds']) { - $order_items[$id]['externalIds'] = $item['externalIds']; - $order_items[$id]['externalIds'][] = $externalIds; + if (!empty($item['externalIds'])) { + $found = false; + + foreach ($item['externalIds'] as $key => $extIdArr) { + if (isset($extIdArr['code']) && $extIdArr['code'] == 'woocomerce') { + $item['externalIds'][$key] = $externalIds; + $found = true; + + break; + } + } + + if (!$found) { + $order_items[$id]['externalIds'] = array_merge($item['externalIds'], $externalIds); + } } else { $order_items[$id]['externalIds'] = $externalIds; } @@ -736,7 +893,7 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : if (!empty($order_items)) { $orderEdit = array( 'id' => $order['id'], - 'items' => $order_items, + 'items' => WC_Retailcrm_Plugin::clearArray($order_items), ); $this->retailcrm->ordersEdit($orderEdit, 'id'); @@ -744,151 +901,283 @@ if ( ! class_exists( 'WC_Retailcrm_History' ) ) : } /** - * @param array $orderHistory + * Handle customer data change (from individual to corporate, company change, etc) + * + * @param \WC_Order $wc_order + * @param array $order + * + * @return bool True if customer change happened; false otherwise. + */ + protected function handleCustomerDataChange($wc_order, $order) + { + $handled = false; + $crmOrder = array(); + $newCustomerId = null; + $switcher = new WC_Retailcrm_Customer_Switcher(); + $data = new WC_Retailcrm_Customer_Switcher_State(); + $data->setWcOrder($wc_order); + + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'processing order', + $order + ) + ); + + if (isset($order['customer'])) { + $crmOrder = $this->getCRMOrder($order['id'], 'id'); + + if (empty($crmOrder)) { + WC_Retailcrm_Logger::addCaller(__METHOD__, sprintf( + 'Cannot get order data from retailCRM. Skipping customer change. History data: %s', + print_r($order, true) + )); + + return false; + } + + $newCustomerId = $order['customer']['id']; + $isChangedToRegular = self::isCustomerChangedToRegular($order); + $isChangedToCorporate = self::isCustomerChangedToLegal($order); + + if (!$isChangedToRegular && !$isChangedToCorporate) { + $isChangedToCorporate = self::isOrderCorporate($crmOrder); + $isChangedToRegular = !$isChangedToCorporate; + } + + if ($isChangedToRegular) { + $this->prepareChangeToIndividual( + self::arrayValue($crmOrder, 'customer', array()), + $data + ); + } + } + + if (isset($order['contact'])) { + $newCustomerId = $order['contact']['id']; + + if (empty($crmOrder)) { + $crmOrder = $this->getCRMOrder($order['id'], 'id'); + } + + if (empty($crmOrder)) { + WC_Retailcrm_Logger::addCaller(__METHOD__, sprintf( + 'Cannot get order data from retailCRM. Skipping customer change. History data: %s', + print_r($order, true) + )); + + return false; + } + + if (self::isOrderCorporate($crmOrder)) { + $this->prepareChangeToIndividual( + self::arrayValue($crmOrder, 'contact', array()), + $data, + true + ); + + $data->setNewCustomer(array()); + } + } + + if (isset($order['company'])) { + if (empty($crmOrder)) { + $crmOrder = $this->getCRMOrder($order['id'], 'id'); + } + + $data->setNewCompany($crmOrder['company']); + } + + if ($data->feasible()) { + try { + $result = $switcher->setData($data) + ->build() + ->getResult(); + + $result->save(); + $handled = true; + } catch (\Exception $exception) { + $errorMessage = sprintf( + 'Error switching order externalId=%s to customer id=%s (new company: id=%s %s). Reason: %s', + $order['externalId'], + $newCustomerId, + isset($order['company']) ? $order['company']['id'] : '', + isset($order['company']) ? $order['company']['name'] : '', + $exception->getMessage() + ); + WC_Retailcrm_Logger::addCaller(__METHOD__, $errorMessage); + WC_Retailcrm_Logger::debug(__METHOD__, sprintf( + '%s%s%s', + $errorMessage, + PHP_EOL, + $exception->getTraceAsString() + )); + $handled = false; + } + } + + return $handled; + } + + /** + * Returns retailCRM order by id or by externalId. + * It returns only order data, not ApiResponse or something. + * + * @param string $id Order identifier + * @param string $by Search field (default: 'externalId') * * @return array */ - public static function assemblyOrder($orderHistory) + protected function getCRMOrder($id, $by = 'externalId') { - if (file_exists(__DIR__ . '/../config/objects.xml')) { - $objects = simplexml_load_file(__DIR__ . '/../config/objects.xml'); - foreach($objects->fields->field as $object) { - $fields[(string)$object["group"]][(string)$object["id"]] = (string)$object; - } + $crmOrderResponse = $this->retailcrm->ordersGet($id, $by); + + if (!empty($crmOrderResponse) + && $crmOrderResponse->isSuccessful() + && $crmOrderResponse->offsetExists('order') + ) { + return (array) $crmOrderResponse['order']; } - $orders = array(); - - foreach ($orderHistory as $change) { - if ($change['source'] == 'api' - && isset($change['apiKey']['current']) - && $change['apiKey']['current'] == true - ) { - continue; - } - - $change['order'] = self::removeEmpty($change['order']); - if(isset($change['order']['items']) && $change['order']['items']) { - $items = array(); - foreach($change['order']['items'] as $item) { - if(isset($change['created'])) { - $item['create'] = 1; - } - $items[$item['id']] = $item; - } - $change['order']['items'] = $items; - } - - if(isset($change['order']['contragent']['contragentType']) && $change['order']['contragent']['contragentType']) { - $change['order']['contragentType'] = $change['order']['contragent']['contragentType']; - unset($change['order']['contragent']); - } - - if (!empty($orders) && isset($orders[$change['order']['id']])) { - $orders[$change['order']['id']] = array_merge($orders[$change['order']['id']], $change['order']); - } else { - $orders[$change['order']['id']] = $change['order']; - } - - if (isset($change['item']) && $change['item']) { - if(isset($orders[$change['order']['id']]['items'][$change['item']['id']])) { - $orders[$change['order']['id']]['items'][$change['item']['id']] = array_merge($orders[$change['order']['id']]['items'][$change['item']['id']], $change['item']); - } else { - $orders[$change['order']['id']]['items'][$change['item']['id']] = $change['item']; - } - - if ($change['oldValue'] === null - && $change['field'] == 'order_product' - ) { - $orders[$change['order']['id']]['items'][$change['item']['id']]['create'] = true; - } - - if ($change['newValue'] === null - && $change['field'] == 'order_product' - ) { - $orders[$change['order']['id']]['items'][$change['item']['id']]['delete'] = true; - } - - if (!isset($orders[$change['order']['id']]['items'][$change['item']['id']]['create']) - && isset($fields['item'][$change['field']]) - && $fields['item'][$change['field']] - ) { - $orders[$change['order']['id']]['items'][$change['item']['id']][$fields['item'][$change['field']]] = $change['newValue']; - } - } elseif ($change['field'] == 'payments' && isset($change['payment'])) { - if ($change['newValue'] !== null) { - $orders[$change['order']['id']]['payments'][] = self::newValue($change['payment']); - } - } else { - if (isset($fields['delivery'][$change['field']]) && $fields['delivery'][$change['field']] == 'service') { - $orders[$change['order']['id']]['delivery']['service']['code'] = self::newValue($change['newValue']); - } elseif (isset($fields['delivery'][$change['field']]) && $fields['delivery'][$change['field']]) { - $orders[$change['order']['id']]['delivery'][$fields['delivery'][$change['field']]] = self::newValue($change['newValue']); - } elseif (isset($fields['orderAddress'][$change['field']]) && $fields['orderAddress'][$change['field']]) { - $orders[$change['order']['id']]['delivery']['address'][$fields['orderAddress'][$change['field']]] = $change['newValue']; - } elseif (isset($fields['integrationDelivery'][$change['field']]) && $fields['integrationDelivery'][$change['field']]) { - $orders[$change['order']['id']]['delivery']['service'][$fields['integrationDelivery'][$change['field']]] = self::newValue($change['newValue']); - } elseif (isset($fields['customerContragent'][$change['field']]) && $fields['customerContragent'][$change['field']]) { - $orders[$change['order']['id']][$fields['customerContragent'][$change['field']]] = self::newValue($change['newValue']); - } elseif (strripos($change['field'], 'custom_') !== false) { - $orders[$change['order']['id']]['customFields'][str_replace('custom_', '', $change['field'])] = self::newValue($change['newValue']); - } elseif (isset($fields['order'][$change['field']]) && $fields['order'][$change['field']]) { - $orders[$change['order']['id']][$fields['order'][$change['field']]] = self::newValue($change['newValue']); - } - - if (isset($change['created'])) { - $orders[$change['order']['id']]['create'] = 1; - } - - if (isset($change['deleted'])) { - $orders[$change['order']['id']]['deleted'] = 1; - } - } - } - - return $orders; + return array(); } - public static function assemblyCustomer($customerHistory) + /** + * Sets all needed data for customer switch to switcher state + * + * @param array $crmCustomer + * @param \WC_Retailcrm_Customer_Switcher_State $data + * @param bool $isContact + */ + protected function prepareChangeToIndividual($crmCustomer, $data, $isContact = false) { - $customers = array(); - foreach ($customerHistory as $change) { - $change['order'] = self::removeEmpty($change['customer']); + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Using this individual person data in order to set it into order,', + $data->getWcOrder()->get_id(), + ': ', + $crmCustomer + ) + ); - if (!empty($customers[$change['customer']['id']]) && $customers[$change['customer']['id']]) { - $customers[$change['customer']['id']] = array_merge($customers[$change['customer']['id']], $change['customer']); - } else { - $customers[$change['customer']['id']] = $change['customer']; - } - } - - return $customers; - } - - public static function newValue($value) - { - if (isset($value['code'])) { - return $value['code']; + if ($isContact) { + $data->setNewContact($crmCustomer); } else { - return $value; + $data->setNewCustomer($crmCustomer); } } - public static function removeEmpty($inputArray) + /** + * @param array $itemData + * + * @return int|string|null + */ + protected static function getItemWoocommerceId($itemData) { - $outputArray = array(); - if (!empty($inputArray)) { - foreach ($inputArray as $key => $element) { - if(!empty($element) || $element === 0 || $element === '0'){ - if (is_array($element)) { - $element = self::removeEmpty($element); - } - $outputArray[$key] = $element; + $woocommerceId = null; + + if (isset($itemData['woocomerceId'])) { + $woocommerceId = $itemData['woocomerceId']; + } elseif (isset($itemData['externalIds'])) { + foreach ($itemData['externalIds'] as $extIdArr) { + if (isset($extIdArr['code']) && $extIdArr['code'] == 'woocomerce') { + $woocommerceId = $extIdArr['value']; } } } - return $outputArray; + if (!empty($woocommerceId) && strpos($woocommerceId, '_') !== false) { + $wcIdArr = explode('_', $woocommerceId); + $woocommerceId = $wcIdArr[1]; + } + + return $woocommerceId; + } + + /** + * Returns true if provided crm order is corporate + * + * @param array $order + * + * @return bool + */ + private static function isOrderCorporate($order) + { + return isset($order['customer']['type']) && $order['customer']['type'] == 'customer_corporate'; + } + + /** + * This assertion returns true if customer was changed from legal entity to individual person. + * It doesn't return true if customer was changed from one individual person to another. + * + * @param array $assembledOrder Order data, assembled from history + * + * @return bool True if customer in order was changed from corporate to regular + */ + private static function isCustomerChangedToRegular($assembledOrder) + { + return isset($assembledOrder['contragentType']) && $assembledOrder['contragentType'] == 'individual'; + } + + /** + * This assertion returns true if customer was changed from individual person to a legal entity. + * It doesn't return true if customer was changed from one legal entity to another. + * + * @param array $assembledOrder Order data, assembled from history + * + * @return bool True if customer in order was changed from corporate to regular + */ + private static function isCustomerChangedToLegal($assembledOrder) + { + return isset($assembledOrder['contragentType']) && $assembledOrder['contragentType'] == 'legal-entity'; + } + + /** + * Helper method. Checks if entity only contains identifiers. + * Returns true if entity contains only these keys: 'id', 'externalId', 'site', or if array is empty. + * Returns false otherwise. + * + * @param array $entity + * + * @return bool + */ + private static function noRealDataInEntity($entity) + { + $allowedKeys = array('id', 'externalId', 'site'); + + if (count($entity) <= 3) { + foreach (array_keys($entity) as $key) { + if (!in_array($key, $allowedKeys)) { + return false; + } + } + + return true; + } + + return false; + } + + /** + * @param array|\ArrayObject|\ArrayAccess $arr + * @param string $key + * @param string $def + * + * @return mixed|string + */ + private static function arrayValue($arr, $key, $def = '') + { + if (!is_array($arr) && !($arr instanceof ArrayObject) && !($arr instanceof ArrayAccess)) { + return $def; + } + + if (!array_key_exists($key, $arr) && !empty($arr[$key])) { + return $def; + } + + return isset($arr[$key]) ? $arr[$key] : $def; } } diff --git a/src/include/class-wc-retailcrm-orders.php b/src/include/class-wc-retailcrm-orders.php index 6923015..f96e3e1 100644 --- a/src/include/class-wc-retailcrm-orders.php +++ b/src/include/class-wc-retailcrm-orders.php @@ -14,7 +14,7 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : */ class WC_Retailcrm_Orders { - /** @var bool|WC_Retailcrm_Proxy */ + /** @var bool|WC_Retailcrm_Proxy|\WC_Retailcrm_Client_V5|\WC_Retailcrm_Client_V4 */ protected $retailcrm; /** @var array */ @@ -35,6 +35,9 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : /** @var WC_Retailcrm_Order */ protected $orders; + /** @var array */ + private $ordersGetRequestCache = array(); + /** @var array */ private $order = array(); @@ -62,16 +65,23 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : /** * Upload orders to CRM * - * @param bool $withCustomers * @param array $include + * * @return array $uploadOrders | null + * @throws \Exception */ - public function ordersUpload($include = array(), $withCustomers = false) + public function ordersUpload($include = array()) { if (!$this->retailcrm) { return null; } + $uploader = new WC_Retailcrm_Customers( + $this->retailcrm, + $this->retailcrm_settings, + new WC_Retailcrm_Customer_Address() + ); + $orders = get_posts(array( 'numberposts' => -1, 'post_type' => wc_get_order_types('view-orders'), @@ -79,46 +89,36 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : 'include' => $include )); - $orders_data = array(); + $regularUploadErrors = array(); + $corporateUploadErrors = array(); foreach ($orders as $data_order) { $order = wc_get_order($data_order->ID); - $this->processOrder($order); - $customer = $order->get_user(); - $customers = array(); - if ($customer != false) { - $this->order['customer']['externalId'] = $customer->get('ID'); + $errorMessage = $this->orderCreate($data_order->ID); - if ($withCustomers === true) { - $customers[] = $customer->get('ID'); + if (is_string($errorMessage)) { + if ($this->retailcrm->getCorporateEnabled() && self::isCorporateOrder($order)) { + $corporateUploadErrors[$data_order->ID] = $errorMessage; + } else { + $regularUploadErrors[$data_order->ID] = $errorMessage; } } - - $orders_data[] = $this->order; } - if ($withCustomers === true && !empty($customers)) { - $this->customers->customersUpload($customers); - } + static::logOrdersUploadErrors($regularUploadErrors, 'Error while uploading these regular orders'); + static::logOrdersUploadErrors($corporateUploadErrors, 'Error while uploading these corporate orders'); - $uploadOrders = array_chunk($orders_data, 50); - - foreach ($uploadOrders as $uploadOrder) { - $this->retailcrm->ordersUpload($uploadOrder); - time_nanosleep(0, 250000000); - } - - return $uploadOrders; + return array(); } /** - * Create order + * Create order. Returns wc_get_order data or error string. * - * @param $order_id + * @param $order_id * - * @return mixed - * @throws Exception + * @return bool|WC_Order|WC_Order_Refund|string + * @throws \Exception */ public function orderCreate($order_id) { @@ -126,59 +126,155 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : return null; } + $this->order_payment->reset_data(); + $wcOrder = wc_get_order($order_id); $this->processOrder($wcOrder); + + try { + $response = $this->retailcrm->ordersCreate($this->order); + + if ($response instanceof WC_Retailcrm_Response) { + if ($response->isSuccessful()) { + return $wcOrder; + } + + return $response->getErrorString(); + } + } catch (InvalidArgumentException $exception) { + return $exception->getMessage(); + } + + return $wcOrder; + } + + /** + * Process order customer data + * + * @param \WC_Order $wcOrder + * @param bool $update + * + * @return bool Returns false if order cannot be processed + * @throws \Exception + */ + protected function processOrderCustomerInfo($wcOrder, $update = false) + { + $customerWasChanged = false; $wpUser = $wcOrder->get_user(); - if ($wpUser instanceof WP_User) { - $wpUserId = (int)$wpUser->get('ID'); - $foundCustomer = $this->customers->searchCustomer(array( - 'externalId' => $wpUserId - )); + if ($update) { + $response = $this->getCrmOrder($wcOrder->get_id()); - if (empty($foundCustomer)) { - $foundCustomer = $this->customers->searchCustomer(array( - 'email' => $wcOrder->get_billing_email() - )); - } - - if (empty($foundCustomer)) { - $customerId = $this->customers->createCustomer($wpUserId); - - if (!empty($customerId)) { - $this->order['customer']['id'] = $customerId; - } - } else { - if (!empty($foundCustomer['externalId'])) { - $this->order['customer']['externalId'] = $foundCustomer['externalId']; - } else { - $this->order['customer']['id'] = $foundCustomer['id']; - } - } - } else { - $foundCustomer = $this->customers->searchCustomer(array( - 'email' => $wcOrder->get_billing_email() - )); - - if (empty($foundCustomer)) { - $wcCustomer = $this->customers->buildCustomerFromOrderData($wcOrder); - $customerId = $this->customers->createCustomer($wcCustomer); - - if (!empty($customerId)) { - $this->order['customer']['id'] = $customerId; - } - } else { - if (!empty($foundCustomer['externalId'])) { - $this->order['customer']['externalId'] = $foundCustomer['externalId']; - } else { - $this->order['customer']['id'] = $foundCustomer['id']; - } + if (!empty($response)) { + $customerWasChanged = self::isOrderCustomerWasChanged($wcOrder, $response); } } - $this->retailcrm->ordersCreate($this->order); + if ($wpUser instanceof WP_User) { + if (!WC_Retailcrm_Customers::isCustomer($wpUser)) { + return false; + } - return $wcOrder; + $wpUserId = (int) $wpUser->get('ID'); + + if (!$update || ($update && $customerWasChanged)) { + $this->fillOrderCreate($wpUserId, $wpUser->get('billing_email'), $wcOrder); + } + } else { + $wcCustomer = $this->customers->buildCustomerFromOrderData($wcOrder); + + if (!$update || ($update && $customerWasChanged)) { + $this->fillOrderCreate(0, $wcCustomer->get_billing_email(), $wcOrder); + } + } + + if ($update && $customerWasChanged) { + $this->order['firstName'] = $wcOrder->get_shipping_first_name(); + $this->order['lastName'] = $wcOrder->get_shipping_last_name(); + } + + return true; + } + + /** + * Fill order on create + * + * @param int $wcCustomerId + * @param string $wcCustomerEmail + * @param \WC_Order $wcOrder + * + * @throws \Exception + */ + protected function fillOrderCreate($wcCustomerId, $wcCustomerEmail, $wcOrder) + { + $foundCustomerId = ''; + $foundCustomer = $this->customers->findCustomerEmailOrId($wcCustomerId, $wcCustomerEmail); + + if (empty($foundCustomer)) { + $foundCustomerId = $this->customers->createCustomer($wcCustomerId, $wcOrder); + + if (!empty($foundCustomerId)) { + $this->order['customer']['id'] = $foundCustomerId; + } + } else { + $this->order['customer']['id'] = $foundCustomer['id']; + $foundCustomerId = $foundCustomer['id']; + } + + $this->order['contragent']['contragentType'] = 'individual'; + + if ($this->retailcrm->getCorporateEnabled() && static::isCorporateOrder($wcOrder)) { + unset($this->order['contragent']['contragentType']); + + $crmCorporate = $this->customers->searchCorporateCustomer(array( + 'contactIds' => array($foundCustomerId), + 'companyName' => $wcOrder->get_billing_company() + )); + + if (empty($crmCorporate)) { + $crmCorporate = $this->customers->searchCorporateCustomer(array( + 'companyName' => $wcOrder->get_billing_company() + )); + } + + if (empty($crmCorporate)) { + $corporateId = $this->customers->createCorporateCustomerForOrder( + $foundCustomerId, + $wcCustomerId, + $wcOrder + ); + $this->order['customer']['id'] = $corporateId; + } else { + $this->customers->fillCorporateAddress( + $crmCorporate['id'], + new WC_Customer($wcCustomerId), + $wcOrder + ); + $this->order['customer']['id'] = $crmCorporate['id']; + } + + $companiesResponse = $this->retailcrm->customersCorporateCompanies( + $this->order['customer']['id'], + array(), + null, + null, + 'id' + ); + + if (!empty($companiesResponse) && $companiesResponse->isSuccessful()) { + foreach ($companiesResponse['companies'] as $company) { + if ($company['name'] == $wcOrder->get_billing_company()) { + $this->order['company'] = array( + 'id' => $company['id'], + 'name' => $company['name'] + ); + break; + } + } + } + + $this->order['contact']['id'] = $foundCustomerId; + } } /** @@ -187,6 +283,7 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : * @param int $order_id * * @return WC_Order $order | null + * @throws \Exception */ public function updateOrder($order_id) { @@ -194,20 +291,16 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : return null; } - $order = wc_get_order($order_id); - $this->processOrder($order, true); - - if ($this->retailcrm_settings['api_version'] == 'v4') { - $this->order['paymentType'] = $this->retailcrm_settings[$order->get_payment_method()]; - } + $wcOrder = wc_get_order($order_id); + $this->processOrder($wcOrder, true); $response = $this->retailcrm->ordersEdit($this->order); - if ((!empty($response) && $response->isSuccessful()) && $this->retailcrm_settings['api_version'] == 'v5') { - $this->payment = $this->orderUpdatePaymentType($order); + if (!empty($response) && $response->isSuccessful()) { + $this->payment = $this->orderUpdatePaymentType($wcOrder); } - return $order; + return $wcOrder; } /** @@ -223,11 +316,9 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : return null; } - $response = $this->retailcrm->ordersGet($order->get_id()); - - if (!empty($response) && $response->isSuccessful()) { - $retailcrmOrder = $response['order']; + $retailcrmOrder = $this->getCrmOrder($order->get_id()); + if (!empty($retailcrmOrder)) { foreach ($retailcrmOrder['payments'] as $payment_data) { $payment_external_id = explode('-', $payment_data['externalId']); @@ -260,9 +351,10 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : * process to combine order data * * @param WC_Order $order - * @param boolean $update + * @param boolean $update * * @return void + * @throws \Exception */ protected function processOrder($order, $update = false) { @@ -313,8 +405,12 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : } } - $order_data['delivery']['address'] = $this->order_address->build($order)->get_data(); $order_items = array(); + $order_data['delivery']['address'] = $this->order_address + ->setFallbackToBilling(true) + ->setWCAddressType(WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_SHIPPING) + ->build($order) + ->get_data(); /** @var WC_Order_Item_Product $item */ foreach ($order->get_items() as $item) { @@ -324,12 +420,19 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : $order_data['items'] = $order_items; - if ($this->retailcrm_settings['api_version'] == 'v5' && !$update) { + if (!$update) { $this->order_payment->is_new = true; $order_data['payments'][] = $this->order_payment->build($order)->get_data(); } - $this->order = apply_filters('retailcrm_process_order', $order_data, $order); + $this->order = WC_Retailcrm_Plugin::clearArray($order_data); + $this->processOrderCustomerInfo($order, $update); + + $this->order = apply_filters( + 'retailcrm_process_order', + WC_Retailcrm_Plugin::clearArray($this->order), + $order + ); } /** @@ -355,6 +458,31 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : return $payment; } + /** + * ordersGet wrapper with cache (in order to minimize request count). + * + * @param int|string $orderId + * @param bool $cached + * + * @return array + */ + protected function getCrmOrder($orderId, $cached = true) + { + if ($cached && isset($this->ordersGetRequestCache[$orderId])) { + return (array) $this->ordersGetRequestCache[$orderId]; + } + + $crmOrder = array(); + $response = $this->retailcrm->ordersGet($orderId); + + if (!empty($response) && $response->isSuccessful() && isset($response['order'])) { + $crmOrder = (array) $response['order']; + $this->ordersGetRequestCache[$orderId] = $crmOrder; + } + + return $crmOrder; + } + /** * @return array */ @@ -370,5 +498,106 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) : { return $this->payment; } + + /** + * Returns true if provided order is for corporate customer + * + * @param WC_Order $order + * + * @return bool + */ + public static function isCorporateOrder($order) + { + $billingCompany = $order->get_billing_company(); + + return !empty($billingCompany); + } + + /** + * Returns true if passed crm order is corporate + * + * @param array|\ArrayAccess $order + * + * @return bool + */ + public static function isCorporateCrmOrder($order) + { + return (is_array($order) || $order instanceof ArrayAccess) + && isset($order['customer']) + && isset($order['customer']['type']) + && $order['customer']['type'] == 'customer_corporate'; + } + + /** + * Returns true if customer in order was changed. `true` will be returned if one of these four conditions is met: + * + * 1. If CMS order is corporate and retailCRM order is not corporate or vice versa, then customer obviously + * needs to be updated in retailCRM. + * 2. If billing company from CMS order is not the same as the one in the retailCRM order, + * then company needs to be updated. + * 3. If contact person or individual externalId is different from customer ID in the CMS order, then + * contact person or customer in retailCRM should be updated (even if customer id in the order is not set). + * 4. If contact person or individual email is not the same as the CMS order billing email, then + * contact person or customer in retailCRM should be updated. + * + * @param \WC_Order $wcOrder + * @param array|\ArrayAccess $crmOrder + * + * @return bool + */ + public static function isOrderCustomerWasChanged($wcOrder, $crmOrder) + { + if (!isset($crmOrder['customer'])) { + return false; + } + + $customerWasChanged = self::isCorporateOrder($wcOrder) != self::isCorporateCrmOrder($crmOrder); + $synchronizableUserData = self::isCorporateCrmOrder($crmOrder) + ? $crmOrder['contact'] : $crmOrder['customer']; + + if (!$customerWasChanged) { + if (self::isCorporateCrmOrder($crmOrder)) { + $currentCrmCompany = isset($crmOrder['company']) ? $crmOrder['company']['name'] : ''; + + if (!empty($currentCrmCompany) && $currentCrmCompany != $wcOrder->get_billing_company()) { + $customerWasChanged = true; + } + } + + if (isset($synchronizableUserData['externalId']) + && $synchronizableUserData['externalId'] != $wcOrder->get_customer_id() + ) { + $customerWasChanged = true; + } elseif (isset($synchronizableUserData['email']) + && $synchronizableUserData['email'] != $wcOrder->get_billing_email() + ) { + $customerWasChanged = true; + } + } + + return $customerWasChanged; + } + + /** + * Logs orders upload errors with prefix log message. + * Array keys must be orders ID's in WooCommerce, values must be strings (error messages). + * + * @param array $errors + * @param string $prefix + */ + public static function logOrdersUploadErrors($errors, $prefix = 'Errors while uploading these orders') + { + if (empty($errors)) { + return; + } + + WC_Retailcrm_Logger::add($prefix); + + foreach ($errors as $orderId => $error) { + WC_Retailcrm_Logger::add(sprintf("[%d] => %s", $orderId, $error)); + } + + WC_Retailcrm_Logger::add('=================================='); + } } endif; diff --git a/src/include/class-wc-retailcrm-plugin.php b/src/include/class-wc-retailcrm-plugin.php index f78c62e..cedf936 100644 --- a/src/include/class-wc-retailcrm-plugin.php +++ b/src/include/class-wc-retailcrm-plugin.php @@ -53,6 +53,12 @@ class WC_Retailcrm_Plugin { } public function activate() { + if (!class_exists( 'WC_Integration' ) ) { + add_action('admin_notices', array(new WC_Integration_Retailcrm(), 'woocommerce_missing_notice')); + + return; + } + if (!class_exists('WC_Retailcrm_Icml')) { require_once (dirname(__FILE__) . '/class-wc-retailcrm-icml.php'); } @@ -84,13 +90,13 @@ class WC_Retailcrm_Plugin { /** * Edit configuration in CRM * - * @param WC_Retailcrm_Proxy $api_client + * @param WC_Retailcrm_Proxy|\WC_Retailcrm_Client_V4|\WC_Retailcrm_Client_V5 $api_client * @param string $client_id * @param bool $active * * @return boolean */ - public static function integration_module($api_client, $client_id, $api_version, $active = true) { + public static function integration_module($api_client, $client_id, $active = true) { if (!$api_client) { return false; @@ -103,18 +109,12 @@ class WC_Retailcrm_Plugin { 'active' => $active, ); - if ($api_version == 'v4') { - $configuration['configurationUrl'] = get_site_url(); + $configuration['integrationCode'] = self::INTEGRATION_CODE; + $configuration['baseUrl'] = get_site_url(); + $configuration['clientId'] = $client_id; + $configuration['accountUrl'] = get_site_url(); - $response = $api_client->marketplaceSettingsEdit($configuration); - } else { - $configuration['integrationCode'] = self::INTEGRATION_CODE; - $configuration['baseUrl'] = get_site_url(); - $configuration['clientId'] = $client_id; - $configuration['accountUrl'] = get_site_url(); - - $response = $api_client->integrationModulesEdit($configuration); - } + $response = $api_client->integrationModulesEdit($configuration); if (!$response) { return false; @@ -127,6 +127,53 @@ class WC_Retailcrm_Plugin { return false; } + /** + * Unset empty fields + * + * @param array $arr input array + * + * @return array + */ + public static function clearArray(array $arr) + { + if (!is_array($arr)) { + return $arr; + } + + $result = array(); + + foreach ($arr as $index => $node) { + $result[$index] = (is_array($node)) + ? self::clearArray($node) + : $node; + + if ($result[$index] === '' + || $result[$index] === null + || (is_array($result[$index]) && count($result[$index]) < 1) + ) { + unset($result[$index]); + } + } + + return $result; + } + + /** + * Returns WC_Customer by id. Returns null if there's no such customer. + * + * @param int $id + * + * @return \WC_Customer|null + */ + public static function getWcCustomerById($id) + { + try { + return new WC_Customer($id); + } catch (\Exception $exception) { + return null; + } + } + /** * Check running history * @@ -137,4 +184,3 @@ class WC_Retailcrm_Plugin { return self::$history_run; } } - diff --git a/src/include/components/class-wc-retailcrm-customer-switcher.php b/src/include/components/class-wc-retailcrm-customer-switcher.php new file mode 100644 index 0000000..5cf7652 --- /dev/null +++ b/src/include/components/class-wc-retailcrm-customer-switcher.php @@ -0,0 +1,318 @@ +reset(); + } + + /** + * In fact, this will execute customer change in provided order. + * This will not produce any new entities. + * + * @return $this|\WC_Retailcrm_Builder_Interface + * @throws \WC_Data_Exception + */ + public function build() + { + $this->data->validate(); + + WC_Retailcrm_Logger::debug(__METHOD__, array('state', $this->data)); + + $newCustomer = $this->data->getNewCustomer(); + $newContact = $this->data->getNewContact(); + $newCompany = $this->data->getNewCompanyName(); + $companyAddress = $this->data->getCompanyAddress(); + + if (!empty($newCustomer)) { + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Changing to individual customer for order', + $this->data->getWcOrder()->get_id() + ) + ); + $this->processChangeToRegular($this->data->getWcOrder(), $newCustomer, false); + $this->data->getWcOrder()->set_billing_company(''); + } else { + if (!empty($newContact)) { + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Changing to contact person customer for order', + $this->data->getWcOrder()->get_id() + ) + ); + $this->processChangeToRegular($this->data->getWcOrder(), $newContact, true); + } + + if (!empty($newCompany)) { + WC_Retailcrm_Logger::debug( + __METHOD__, + array(sprintf( + 'Replacing old order id=`%d` company `%s` with new company `%s`', + $this->data->getWcOrder()->get_id(), + $this->data->getWcOrder()->get_billing_company(), + $newCompany + )) + ); + $this->processCompanyChange(); + } + + if (!empty($companyAddress)) { + $this->processCompanyAddress(); + } + } + + return $this; + } + + /** + * Change order customer to regular one + * + * @param \WC_Order $wcOrder + * @param array $newCustomer + * @param bool $isContact + * + * @throws \WC_Data_Exception + */ + public function processChangeToRegular($wcOrder, $newCustomer, $isContact) + { + $wcCustomer = null; + + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Switching in order', + $wcOrder->get_id(), + 'to', + $newCustomer + ) + ); + + if (isset($newCustomer['externalId'])) { + $wcCustomer = WC_Retailcrm_Plugin::getWcCustomerById($newCustomer['externalId']); + + if (!empty($wcCustomer)) { + $wcOrder->set_customer_id($wcCustomer->get_id()); + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Set customer to', + $wcCustomer->get_id(), + 'in order', + $wcOrder->get_id() + ) + ); + } + } else { + $wcOrder->set_customer_id(0); + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Set customer to 0 (guest) in order', + $wcOrder->get_id() + ) + ); + } + + $fields = array( + 'billing_first_name' => self::arrayValue($newCustomer, 'firstName'), + 'billing_last_name' => self::arrayValue($newCustomer, 'lastName'), + 'billing_email' => self::arrayValue($newCustomer, 'email') + ); + + foreach ($fields as $field => $value) { + $wcOrder->{'set_' . $field}($value); + } + + $address = self::arrayValue($newCustomer, 'address', array()); + + if ($isContact) { + self::setShippingAddressToOrder($wcOrder, $address); + } else { + self::setBillingAddressToOrder($wcOrder, $address); + self::setShippingAddressToOrder($wcOrder, $address); + } + + $wcOrder->set_billing_phone(self::singleCustomerPhone($newCustomer)); + + $this->result = new WC_Retailcrm_Customer_Switcher_Result($wcCustomer, $wcOrder); + } + + /** + * Process company address. + * + * @throws \WC_Data_Exception + */ + protected function processCompanyAddress() + { + $wcOrder = $this->data->getWcOrder(); + $companyAddress = $this->data->getCompanyAddress(); + + if (!empty($companyAddress)) { + self::setBillingAddressToOrder($wcOrder, $companyAddress); + } + + if (empty($this->result)) { + $this->result = new WC_Retailcrm_Customer_Switcher_Result(null, $wcOrder); + } + } + + /** + * This will update company field in order and create result if it's not set (happens when only company was changed). + * + * @throws \WC_Data_Exception + */ + public function processCompanyChange() + { + $this->data->getWcOrder()->set_billing_company($this->data->getNewCompanyName()); + + if (empty($this->result)) { + $this->result = new WC_Retailcrm_Customer_Switcher_Result(null, $this->data->getWcOrder()); + } + } + + /** + * @return $this|\WC_Retailcrm_Builder_Interface + */ + public function reset() + { + $this->data = new WC_Retailcrm_Customer_Switcher_State(); + $this->result = null; + return $this; + } + + /** + * Set initial state into component + * + * @param \WC_Retailcrm_Customer_Switcher_State $data + * + * @return $this|\WC_Retailcrm_Builder_Interface + */ + public function setData($data) + { + if (!($data instanceof WC_Retailcrm_Customer_Switcher_State)) { + throw new \InvalidArgumentException('Invalid data type'); + } + + $this->data = $data; + return $this; + } + + /** + * @return \WC_Retailcrm_Customer_Switcher_Result|null + */ + public function getResult() + { + return $this->result; + } + + /** + * @return \WC_Retailcrm_Customer_Switcher_State + */ + public function getData() + { + return $this->data; + } + + /** + * Sets billing address properties in order + * + * @param \WC_Order $wcOrder + * @param array $address + * + * @throws \WC_Data_Exception + */ + private static function setBillingAddressToOrder($wcOrder, $address) + { + $wcOrder->set_billing_state(self::arrayValue($address, 'region', '--')); + $wcOrder->set_billing_postcode(self::arrayValue($address, 'index', '--')); + $wcOrder->set_billing_country(self::arrayValue($address, 'country', '--')); + $wcOrder->set_billing_city(self::arrayValue($address, 'city', '--')); + $wcOrder->set_billing_address_1(self::arrayValue($address, 'text', '--')); + } + + /** + * Sets shipping address properties in order + * + * @param \WC_Order $wcOrder + * @param array $address + * + * @throws \WC_Data_Exception + */ + private static function setShippingAddressToOrder($wcOrder, $address) + { + $wcOrder->set_shipping_state(self::arrayValue($address, 'region', '--')); + $wcOrder->set_shipping_postcode(self::arrayValue($address, 'index', '--')); + $wcOrder->set_shipping_country(self::arrayValue($address, 'country', '--')); + $wcOrder->set_shipping_city(self::arrayValue($address, 'city', '--')); + $wcOrder->set_shipping_address_1(self::arrayValue($address, 'text', '--')); + } + + /** + * @param array|\ArrayObject|\ArrayAccess $arr + * @param string $key + * @param string $def + * + * @return mixed|string + */ + private static function arrayValue($arr, $key, $def = '') + { + if (!is_array($arr) && !($arr instanceof ArrayObject) && !($arr instanceof ArrayAccess)) { + return $def; + } + + if (!array_key_exists($key, $arr) && !empty($arr[$key])) { + return $def; + } + + return isset($arr[$key]) ? $arr[$key] : $def; + } + + /** + * Returns first phone from order data or null + * + * @param array $customerData + * + * @return string|null + */ + private static function singleCustomerPhone($customerData) + { + if (!array_key_exists('phones', $customerData)) { + return ''; + } + + if (empty($customerData['phones']) || !is_array($customerData['phones'])) { + return ''; + } + + $phones = $customerData['phones']; + $phone = reset($phones); + + if (!isset($phone['number'])) { + return ''; + } + + return (string) $phone['number']; + } +} diff --git a/src/include/components/class-wc-retailcrm-history-assembler.php b/src/include/components/class-wc-retailcrm-history-assembler.php new file mode 100644 index 0000000..0b5ace7 --- /dev/null +++ b/src/include/components/class-wc-retailcrm-history-assembler.php @@ -0,0 +1,402 @@ + &$customer) { + if (empty($customer['id']) && !empty($id)) { + $customer['id'] = $id; + $customer['deleted'] = true; + } + } + + return $customersCorporate; + } + + /** + * Returns mapping data for retailCRM entities. Used to assembly entities from history. + * + * @param array $groupFilter + * + * @return array + */ + private static function getMappingValues($groupFilter = array()) + { + $fields = array(); + $mappingFile = realpath(implode( + DIRECTORY_SEPARATOR, + array(__DIR__, '..', '..', 'config', 'objects.xml') + )); + + if (file_exists($mappingFile)) { + $objects = simplexml_load_file($mappingFile); + + foreach($objects->fields->field as $object) { + if (empty($groupFilter) || in_array($object["group"], $groupFilter)) { + $fields[(string)$object["group"]][(string)$object["id"]] = (string)$object; + } + } + } + + return $fields; + } + + /** + * Value accessor + * + * @param array $value + * + * @return mixed + */ + private static function newValue($value) + { + if (isset($value['code'])) { + return $value['code']; + } else { + return $value; + } + } + + /** + * Returns array without values which are considered empty + * + * @param array|\ArrayAccess $inputArray + * + * @return array + */ + private static function removeEmpty($inputArray) + { + $outputArray = array(); + + if (!empty($inputArray)) { + foreach ($inputArray as $key => $element) { + if(!empty($element) || $element === 0 || $element === '0'){ + if (is_array($element)) { + $element = self::removeEmpty($element); + } + + $outputArray[$key] = $element; + } + } + } + + return $outputArray; + } + + /** + * Filters out history by these terms: + * - Changes from current API key will be added only if CMS changes are more actual than history. + * - All other changes will be merged as usual. + * It fixes these problems: + * - Changes from current API key are merged when it's not needed. + * - Changes from CRM can overwrite more actual changes from CMS due to ignoring current API key changes. + * + * @param array $historyEntries Raw history from CRM + * @param string $recordType Entity field name, e.g. `customer` or `order`. + * + * @return array + */ + private static function filterHistory($historyEntries, $recordType) + { + $history = array(); + $organizedHistory = array(); + $notOurChanges = array(); + + foreach ($historyEntries as $entry) { + if (!isset($entry[$recordType]['externalId'])) { + if ($entry['source'] == 'api' + && isset($change['apiKey']['current']) + && $entry['apiKey']['current'] == true + && $entry['field'] != 'externalId' + ) { + continue; + } else { + $history[] = $entry; + } + + continue; + } + + $externalId = $entry[$recordType]['externalId']; + $field = $entry['field']; + + if (!isset($organizedHistory[$externalId])) { + $organizedHistory[$externalId] = array(); + } + + if (!isset($notOurChanges[$externalId])) { + $notOurChanges[$externalId] = array(); + } + + if ($entry['source'] == 'api' + && isset($entry['apiKey']['current']) + && $entry['apiKey']['current'] == true + ) { + if (isset($notOurChanges[$externalId][$field]) || $entry['field'] == 'externalId') { + $organizedHistory[$externalId][] = $entry; + } else { + continue; + } + } else { + $organizedHistory[$externalId][] = $entry; + $notOurChanges[$externalId][$field] = true; + } + } + + unset($notOurChanges); + + foreach ($organizedHistory as $historyChunk) { + $history = array_merge($history, $historyChunk); + } + + return $history; + } +} \ No newline at end of file diff --git a/src/include/components/class-wc-retailcrm-logger.php b/src/include/components/class-wc-retailcrm-logger.php new file mode 100644 index 0000000..cf9e798 --- /dev/null +++ b/src/include/components/class-wc-retailcrm-logger.php @@ -0,0 +1,125 @@ +add(self::HANDLE, $message, $level); + } + + /** + * Regular logging with caller prefix + * + * @param string $caller + * @param string $message + * @param string $level + */ + public static function addCaller($caller, $message, $level = WC_Log_Levels::NOTICE) + { + self::add(sprintf('<%s> => %s', $caller, $message), $level); + } + + /** + * Log error + * + * @param string $message + */ + public static function error($message) + { + self::add($message, WC_Log_Levels::ERROR); + } + + /** + * Debug logging. Contains a lot of debug data like full requests & responses. + * This log will work only if debug mode is enabled (see retailcrm_is_debug() for details). + * Caller should be specified, or message will be ignored at all. + * + * @param string $method + * @param array|string $messages + */ + public static function debug($method, $messages) + { + if (retailcrm_is_debug()) { + if (!empty($method) && !empty($messages)) { + $result = is_array($messages) ? substr( + array_reduce( + $messages, + function ($carry, $item) { + $carry .= ' ' . print_r($item, true); + return $carry; + } + ), + 1 + ) : $messages; + + self::getInstance()->add( + self::HANDLE . '_debug', + sprintf( + '<%s> => %s', + $method, + $result + ), + WC_Log_Levels::DEBUG + ); + } + } + } + } +endif; diff --git a/src/include/components/class-wc-retailcrm-paginated-request.php b/src/include/components/class-wc-retailcrm-paginated-request.php new file mode 100644 index 0000000..e190de9 --- /dev/null +++ b/src/include/components/class-wc-retailcrm-paginated-request.php @@ -0,0 +1,188 @@ +reset(); + } + + /** + * Sets retailCRM api client to request + * + * @param \WC_Retailcrm_Proxy|\WC_Retailcrm_Client_V5 $api + * + * @return self + */ + public function setApi($api) + { + $this->api = $api; + return $this; + } + + /** + * Sets API client method to request + * + * @param string $method + * + * @return self + */ + public function setMethod($method) + { + $this->method = $method; + return $this; + } + + /** + * Sets method params for API client (leave `{{page}}` instead of page and `{{limit}}` instead of limit) + * + * @param array $params + * + * @return self + */ + public function setParams($params) + { + $this->params = $params; + return $this; + } + + /** + * Sets dataKey (key with data in response) + * + * @param string $dataKey + * + * @return self + */ + public function setDataKey($dataKey) + { + $this->dataKey = $dataKey; + return $this; + } + + /** + * Sets record limit per request + * + * @param int $limit + * + * @return self + */ + public function setLimit($limit) + { + $this->limit = $limit; + return $this; + } + + /** + * Executes request + * + * @return $this + */ + public function execute() + { + $this->data = array(); + $response = true; + $page = 1; + + do { + $response = call_user_func_array( + array($this->api, $this->method), + $this->buildParams($this->params, $page) + ); + + if ($response instanceof WC_Retailcrm_Response && $response->offsetExists($this->dataKey)) { + $this->data = array_merge($response[$this->dataKey]); + $page = $response['pagination']['currentPage'] + 1; + } + + time_nanosleep(0, 300000000); + } while ($response && (isset($response['pagination']) + && $response['pagination']['currentPage'] < $response['pagination']['totalPageCount'])); + + return $this; + } + + /** + * Returns data + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * Reset paginated request + * + * @return $this + */ + public function reset() + { + $this->method = ''; + $this->limit = 100; + $this->data = array(); + + return $this; + } + + /** + * buildParams + * + * @param array $placeholderParams + * @param int $currentPage + * + * @return mixed + */ + private function buildParams($placeholderParams, $currentPage) + { + foreach ($placeholderParams as $key => $param) { + if ($param == '{{page}}') { + $placeholderParams[$key] = $currentPage; + } + + if ($param == '{{limit}}') { + $placeholderParams[$key] = $this->limit; + } + } + + return $placeholderParams; + } +} diff --git a/src/include/customer/class-wc-retailcrm-customer-address.php b/src/include/customer/class-wc-retailcrm-customer-address.php index 198f170..88edf00 100644 --- a/src/include/customer/class-wc-retailcrm-customer-address.php +++ b/src/include/customer/class-wc-retailcrm-customer-address.php @@ -17,19 +17,32 @@ class WC_Retailcrm_Customer_Address extends WC_Retailcrm_Abstracts_Address protected $filter_name = 'customer_address'; /** - * @param WC_Customer $customer + * @param WC_Customer $customer + * @param \WC_Order|null $order * * @return self */ - public function build($customer) + public function build($customer, $order = null) { - $data = array( - 'index' => $customer->get_billing_postcode(), - 'countryIso' => $customer->get_billing_country(), - 'region' => $this->get_state_name($customer->get_billing_country(), $customer->get_billing_state()), - 'city' => $customer->get_billing_city(), - 'text' => $customer->get_billing_address_1() . ', ' . $customer->get_billing_address_2() - ); + $customerBillingAddress = $customer->get_billing_address(); + + if ($order instanceof WC_Order && empty($customerBillingAddress)) { + $data = array( + 'index' => $order->get_billing_postcode(), + 'countryIso' => $order->get_billing_country(), + 'region' => $this->get_state_name($order->get_billing_country(), $order->get_billing_state()), + 'city' => $order->get_billing_city(), + 'text' => $order->get_billing_address_1() . ', ' . $order->get_billing_address_2() + ); + } else { + $data = array( + 'index' => $customer->get_billing_postcode(), + 'countryIso' => $customer->get_billing_country(), + 'region' => $this->get_state_name($customer->get_billing_country(), $customer->get_billing_state()), + 'city' => $customer->get_billing_city(), + 'text' => $customer->get_billing_address_1() . ', ' . $customer->get_billing_address_2() + ); + } $this->set_data_fields($data); diff --git a/src/include/customer/class-wc-retailcrm-customer-corporate-address.php b/src/include/customer/class-wc-retailcrm-customer-corporate-address.php new file mode 100644 index 0000000..088c432 --- /dev/null +++ b/src/include/customer/class-wc-retailcrm-customer-corporate-address.php @@ -0,0 +1,158 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Customer_Address + */ +class WC_Retailcrm_Customer_Corporate_Address extends WC_Retailcrm_Abstracts_Address +{ + /** @var string $filter_name */ + protected $filter_name = 'customer_address'; + + /** @var bool $isMain */ + protected $isMain = true; + + /** @var bool $explicitIsMain */ + protected $explicitIsMain; + + /** + * Sets woocommerce address type to work with + * + * @param string $addressType + * + * @return \WC_Retailcrm_Customer_Corporate_Address + */ + public function setWCAddressType($addressType = WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_SHIPPING) + { + $this->address_type = $addressType; + return $this; + } + + /** + * @param bool $fallback_to_shipping + * + * @return WC_Retailcrm_Customer_Corporate_Address + */ + public function setFallbackToShipping($fallback_to_shipping) + { + $this->fallback_to_shipping = $fallback_to_shipping; + return $this; + } + + /** + * @param bool $isMain + * + * @return WC_Retailcrm_Customer_Corporate_Address + */ + public function setIsMain($isMain) + { + $this->isMain = $isMain; + return $this; + } + + /** + * @param bool $explicitIsMain + * + * @return WC_Retailcrm_Customer_Corporate_Address + */ + public function setExplicitIsMain($explicitIsMain) + { + $this->explicitIsMain = $explicitIsMain; + return $this; + } + + /** + * @param WC_Customer $customer + * @param \WC_Order|null $order + * + * @return self + */ + public function build($customer, $order = null) + { + if ($order instanceof WC_Order) { + $address = $this->getOrderAddress($order); + $data = array( + 'index' => $address['postcode'], + 'countryIso' => $address['country'], + 'region' => $address['state'], + 'city' => $address['city'], + 'name' => $address['company'], + 'text' => $this->joinAddresses($address['address_1'], $address['address_2']) + ); + } else if (self::ADDRESS_TYPE_SHIPPING === $this->address_type) { + $data = $this->getCustomerShippingAddress($customer); + + if (empty($address) && $this->fallback_to_billing) { + $data = $this->getCustomerBillingAddress($customer); + } + } elseif (self::ADDRESS_TYPE_BILLING === $this->address_type) { + $data = $this->getCustomerBillingAddress($customer); + + if (empty($address) && $this->fallback_to_shipping) { + $data = $this->getCustomerShippingAddress($customer); + } + } + + if ($this->isMain) { + $data['isMain'] = true; + } elseif ($this->explicitIsMain) { + $data['isMain'] = false; + } + + $this->set_data_fields($data); + + return $this; + } + + /** + * Returns built customer billing address + * + * @param \WC_Customer|\WP_User $customer + * + * @return array + */ + public function getCustomerBillingAddress($customer) + { + return array( + 'index' => $customer->get_billing_postcode(), + 'countryIso' => $customer->get_billing_country(), + 'region' => $customer->get_billing_state(), + 'city' => $customer->get_billing_city(), + 'name' => $customer->get_billing_company(), + 'text' => $this->joinAddresses( + $customer->get_billing_address_1(), + $customer->get_billing_address_2() + ) + ); + } + + /** + * Returns built customer shipping address + * + * @param \WC_Customer|\WP_User $customer + * + * @return array + */ + public function getCustomerShippingAddress($customer) + { + return array( + 'index' => $customer->get_shipping_postcode(), + 'countryIso' => $customer->get_shipping_country(), + 'region' => $customer->get_shipping_state(), + 'city' => $customer->get_shipping_city(), + 'name' => $customer->get_shipping_company(), + 'text' => $this->joinAddresses( + $customer->get_shipping_address_1(), + $customer->get_shipping_address_2() + ) + ); + } +} diff --git a/src/include/customer/woocommerce/class-wc-retailcrm-wc-customer-builder.php b/src/include/customer/woocommerce/class-wc-retailcrm-wc-customer-builder.php new file mode 100644 index 0000000..7eddc4e --- /dev/null +++ b/src/include/customer/woocommerce/class-wc-retailcrm-wc-customer-builder.php @@ -0,0 +1,237 @@ +reset(); + } + + /** + * @param string $firstName + * + * @return $this + */ + public function setFirstName($firstName) + { + $this->data['firstName'] = $firstName; + return $this; + } + + /** + * @param string $lastName + * + * @return $this + */ + public function setLastName($lastName) + { + $this->data['lastName'] = $lastName; + return $this; + } + + /** + * @param string $email + * + * @return $this + */ + public function setEmail($email) + { + $this->data['email'] = $email; + return $this; + } + + /** + * @param string $externalId + * + * @return $this + */ + public function setExternalId($externalId) + { + $this->data['externalId'] = $externalId; + return $this; + } + + /** + * @param array $phones + * + * @return $this + */ + public function setPhones($phones) + { + if (self::isPhonesArrayValid($phones)) { + $this->data['phones'] = $phones; + } + + return $this; + } + + /** + * @param array $address + * + * @return $this + */ + public function setAddress($address) + { + if (is_array($address)) { + $this->data['address'] = $address; + } + + return $this; + } + + /** + * @param \WC_Customer $customer + * + * @return $this + */ + public function setWcCustomer($customer) + { + if ($customer instanceof WC_Customer) { + $this->customer = $customer; + } + + return $this; + } + + /** + * Sets provided externalId and loads associated customer from DB (it it exists there). + * Returns true if everything went find; returns false if customer wasn't found. + * + * @param string $externalId + * + * @return bool + * @throws \Exception + */ + public function loadExternalId($externalId) + { + try { + $wcCustomer = new WC_Customer($externalId); + } catch (\Exception $exception) { + return false; + } + + $this->setExternalId($externalId); + $this->setWcCustomer($wcCustomer); + + return true; + } + + public function reset() + { + parent::reset(); + $this->customer = new WC_Customer(); + + return $this; + } + + /** + * Fill WC_Customer fields with customer data from retailCRM. + * If field is not present in retailCRM customer - it will remain unchanged. + * + * @return $this|\WC_Retailcrm_Builder_Interface + */ + public function build() + { + $this->checkBuilderValidity(); + WC_Retailcrm_Logger::debug(__METHOD__, array('Building WC_Customer from data:', $this->data)); + $this->customer->set_first_name($this->dataValue('firstName', $this->customer->get_first_name())); + $this->customer->set_last_name($this->dataValue('lastName', $this->customer->get_last_name())); + $this->customer->set_billing_email($this->dataValue('email', $this->customer->get_billing_email())); + $phones = $this->dataValue('phones', array()); + + if ((is_array($phones) || $phones instanceof Countable) && count($phones) > 0) { + $phoneData = reset($phones); + + if (is_array($phoneData) && isset($phoneData['number'])) { + $this->customer->set_billing_phone($phoneData['number']); + } + } elseif (is_string($phones) || is_numeric($phones)) { + $this->customer->set_billing_phone($phones); + } + + $address = $this->dataValue('address'); + + if (!empty($address)) { + $this->customer->set_billing_state(self::arrayValue( + $address, + 'region', + $this->customer->get_billing_state()) + ); + $this->customer->set_billing_postcode(self::arrayValue( + $address, + 'index', + $this->customer->get_billing_postcode()) + ); + $this->customer->set_billing_country(self::arrayValue( + $address, + 'country', + $this->customer->get_billing_country()) + ); + $this->customer->set_billing_city(self::arrayValue( + $address, + 'city', + $this->customer->get_billing_city()) + ); + } + + return $this; + } + + /** + * @return mixed|\WC_Customer|null + */ + public function getResult() + { + return $this->customer; + } + + /** + * Throws an exception if internal state is not ready for data building. + * + * @throws \RuntimeException + */ + private function checkBuilderValidity() + { + if (empty($this->data)) { + throw new \RuntimeException('Empty data'); + } + + if (!is_array($this->data)) { + throw new \RuntimeException('Data must be an array'); + } + } + + /** + * Returns true if provided variable contains array with customer phones. + * + * @param mixed $phones + * + * @return bool + */ + private static function isPhonesArrayValid($phones) + { + if (!is_array($phones)) { + return false; + } + + foreach ($phones as $phone) { + if (!is_array($phone) || count($phone) != 1 || !array_key_exists('number', $phone)) { + return false; + } + } + + return true; + } +} diff --git a/src/include/functions.php b/src/include/functions.php index f15eb41..c207d44 100644 --- a/src/include/functions.php +++ b/src/include/functions.php @@ -67,7 +67,7 @@ function get_wc_shipping_methods() { ); } - return apply_filters('retailcrm_shipping_list', $result); + return apply_filters('retailcrm_shipping_list', WC_Retailcrm_Plugin::clearArray($result)); } function retailcrm_get_delivery_service($method_id, $instance_id) { @@ -98,3 +98,13 @@ function retailcrm_get_wc_product($id, $settings) { return wc_get_product($id); } + +/** + * Returns true if either wordpress debug mode or module debugging is enabled + * + * @return bool + */ +function retailcrm_is_debug() { + return (defined('WP_DEBUG') && WP_DEBUG == true) + || (defined('RCRM_DEBUG') && RCRM_DEBUG == true); +} diff --git a/src/include/interfaces/class-wc-retailcrm-builder-interface.php b/src/include/interfaces/class-wc-retailcrm-builder-interface.php new file mode 100644 index 0000000..034b681 --- /dev/null +++ b/src/include/interfaces/class-wc-retailcrm-builder-interface.php @@ -0,0 +1,48 @@ +wcCustomer = $wcCustomer; + $this->wcOrder = $wcOrder; + + if ((!is_null($this->wcCustomer) && !($this->wcCustomer instanceof WC_Customer)) + || !($this->wcOrder instanceof WC_Order) + ) { + throw new \InvalidArgumentException(sprintf('Incorrect data provided to %s', __CLASS__)); + } + } + + /** + * @return \WC_Customer|null + */ + public function getWcCustomer() + { + return $this->wcCustomer; + } + + /** + * @return \WC_Order + */ + public function getWcOrder() + { + return $this->wcOrder; + } + + /** + * Save customer (if exists) and order. + * + * @return $this + */ + public function save() + { + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'Saving customer and order:', + $this->wcCustomer, + $this->wcOrder + ) + ); + + if (!empty($this->wcCustomer) && $this->wcCustomer->get_id()) { + $this->wcCustomer->save(); + } + + if (!empty($this->wcOrder) && $this->wcOrder->get_id()) { + $this->wcOrder->save(); + } + + return $this; + } +} diff --git a/src/include/models/class-wc-retailcrm-customer-switcher-state.php b/src/include/models/class-wc-retailcrm-customer-switcher-state.php new file mode 100644 index 0000000..7364b8e --- /dev/null +++ b/src/include/models/class-wc-retailcrm-customer-switcher-state.php @@ -0,0 +1,178 @@ +wcOrder; + } + + /** + * @param \WC_Order $wcOrder + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setWcOrder($wcOrder) + { + $this->wcOrder = $wcOrder; + return $this; + } + + /** + * @return array + */ + public function getNewCustomer() + { + return $this->newCustomer; + } + + /** + * @param array $newCustomer + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setNewCustomer($newCustomer) + { + $this->newCustomer = $newCustomer; + return $this; + } + + /** + * @return array + */ + public function getNewContact() + { + return $this->newContact; + } + + /** + * @param array $newContact + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setNewContact($newContact) + { + $this->newContact = $newContact; + return $this; + } + + /** + * @return string + */ + public function getNewCompanyName() + { + return $this->newCompanyName; + } + + /** + * @param string $newCompanyName + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setNewCompanyName($newCompanyName) + { + $this->newCompanyName = $newCompanyName; + return $this; + } + + /** + * @return array + */ + public function getCompanyAddress() + { + return $this->companyAddress; + } + + /** + * @param array $companyAddress + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setCompanyAddress($companyAddress) + { + $this->companyAddress = $companyAddress; + return $this; + } + + /** + * @param array $newCompany + * + * @return WC_Retailcrm_Customer_Switcher_State + */ + public function setNewCompany($newCompany) + { + if (isset($newCompany['name'])) { + $this->setNewCompanyName($newCompany['name']); + } + + if (isset($newCompany['address']) && !empty($newCompany['address'])) { + $this->setCompanyAddress($newCompany['address']); + } + + return $this; + } + + /** + * Returns true if current state may be processable (e.g. when customer or related data was changed). + * It doesn't guarantee state validity. + * + * @return bool + */ + public function feasible() + { + return !(empty($this->newCustomer) && empty($this->newContact) && empty($this->newCompanyName)); + } + + /** + * Throws an exception if state is not valid + * + * @throws \InvalidArgumentException + * @return void + */ + public function validate() + { + if (empty($this->wcOrder)) { + throw new \InvalidArgumentException('Empty WC_Order.'); + } + + if (empty($this->newCustomer) && empty($this->newContact) && empty($this->newCompanyName)) { + throw new \InvalidArgumentException('New customer, new contact and new company is empty.'); + } + + if (!empty($this->newCustomer) && !empty($this->newContact)) { + WC_Retailcrm_Logger::debug( + __METHOD__, + array( + 'State data (customer and contact):' . PHP_EOL, + $this->getNewCustomer(), + $this->getNewContact() + ) + ); + throw new \InvalidArgumentException( + 'Too much data in state - cannot determine which customer should be used.' + ); + } + } +} diff --git a/src/include/order/class-wc-retailcrm-order-address.php b/src/include/order/class-wc-retailcrm-order-address.php index 82522d3..934d468 100644 --- a/src/include/order/class-wc-retailcrm-order-address.php +++ b/src/include/order/class-wc-retailcrm-order-address.php @@ -11,6 +11,7 @@ class WC_Retailcrm_Order_Address extends WC_Retailcrm_Abstracts_Address { + /** @var string $filter_name */ protected $filter_name = 'order_address'; /** @@ -20,7 +21,7 @@ class WC_Retailcrm_Order_Address extends WC_Retailcrm_Abstracts_Address */ public function build($order) { - $address = $order->get_address('shipping'); + $address = $this->getOrderAddress($order); if (!empty($address)) { $data = array( diff --git a/src/include/order/class-wc-retailcrm-order-item.php b/src/include/order/class-wc-retailcrm-order-item.php index 0392156..2cbb170 100644 --- a/src/include/order/class-wc-retailcrm-order-item.php +++ b/src/include/order/class-wc-retailcrm-order-item.php @@ -65,12 +65,7 @@ class WC_Retailcrm_Order_Item extends WC_Retailcrm_Abstracts_Data $this->set_data_fields($data); $this->set_offer($item); - - if ($this->settings['api_version'] == 'v5' && round($discount_price, 2)) { - $this->set_data_field('discountManualAmount',round($discount_price, 2)); - } elseif ($this->settings['api_version'] == 'v4' && round($discount_price, 2)) { - $this->set_data_field('discount', round($discount_price, 2)); - } + $this->set_data_field('discountManualAmount', (float) round($discount_price, 2)); return $this; } @@ -114,6 +109,7 @@ class WC_Retailcrm_Order_Item extends WC_Retailcrm_Abstracts_Data * @param $price * * @return float|int + * @todo Rounding issues with prices in pennies / cents should be expected here. */ private function calculate_discount(WC_Order_Item_Product $item, $price) { diff --git a/src/include/order/class-wc-retailcrm-order-payment.php b/src/include/order/class-wc-retailcrm-order-payment.php index a1aa1a9..bc44905 100644 --- a/src/include/order/class-wc-retailcrm-order-payment.php +++ b/src/include/order/class-wc-retailcrm-order-payment.php @@ -50,6 +50,7 @@ class WC_Retailcrm_Order_Payment extends WC_Retailcrm_Abstracts_Data */ public function build($order, $externalId = false) { + $this->reset_data(); $data = array(); if (!empty($this->settings['send_payment_amount']) @@ -79,6 +80,8 @@ class WC_Retailcrm_Order_Payment extends WC_Retailcrm_Abstracts_Data if ($this->is_new) { if (isset($this->settings[$order->get_payment_method()])) { $data['type'] = $this->settings[$order->get_payment_method()]; + } else { + $data = array(); } } @@ -87,6 +90,28 @@ class WC_Retailcrm_Order_Payment extends WC_Retailcrm_Abstracts_Data return $this; } + /** + * Returns false if payment doesn't have method + * + * @return array + */ + public function get_data() + { + $data = parent::get_data(); + + if (empty($data['type'])) { + return array(); + } + + if (!empty($this->settings['send_payment_amount']) + && $this->settings['send_payment_amount'] === WC_Retailcrm_Base::NO + ) { + unset($data['amount']); + } + + return $data; + } + public function reset_data() { $this->data = array( diff --git a/src/include/order/class-wc-retailcrm-order.php b/src/include/order/class-wc-retailcrm-order.php index 760f880..2f82450 100644 --- a/src/include/order/class-wc-retailcrm-order.php +++ b/src/include/order/class-wc-retailcrm-order.php @@ -64,13 +64,14 @@ class WC_Retailcrm_Order extends WC_Retailcrm_Abstracts_Data 'countryIso' => $order->get_shipping_country() ); + if ($data['countryIso'] == '--') { + $countries = new WC_Countries(); + $data['countryIso'] = $countries->get_base_country(); + } + $this->set_data_fields($data); $this->set_number($order); - if ($this->settings['api_version'] != 'v5') { - $this->set_payment_data($order); - } - if (isset($this->settings[$order->get_status()])) { $this->set_data_field('status', $this->settings[$order->get_status()]); } diff --git a/src/languages/retailcrm-es_ES.mo b/src/languages/retailcrm-es_ES.mo index 45b2e9e18d69c48731225656990040cde5c2407c..8cc5fc41c4c74d645d23e9293fbb2342c192ec81 100644 GIT binary patch delta 1667 zcmXxkOGs2v9LMov&8U^yjMMuy*V4=^pOdMTWo2oSP(enxneT0}zMpL0C;pU*vW@7#ON|Np-}EAOvJe986P zFpNfG8PPVwm@wY)@WF7>jmf|~oQ*}8g&~}S^|%=K+WApj$vlQWyovL%50~PgJ^v|n zK4JcGpc`cKlqFb*Ik+A3a39uS4A)^lcH#&YV?$4B;Wn#cMbZ@7nW^ zQP;n+=ig%!&o|#W&`Qh6CyO*KsFbzZ`3dV;)PoXOiq|k72T=?AhK1;37p+*0^>`hZ z<2wxE1X5+=<7T>-32>m51(9l)GF*TgQMGJA2Tx-)_Ml4i2DQ);)b$g%4l_7Ol1vEW zX~xtc&ooKW%q8YI>i5HQ$-h!R%EuxcN0MRES&eG%M?Iht)jUn89k^J4mytj7h!35A zipt1GR0$@r2z`FagSA+Sm$4fk`^kSf2Wz-m4?c{W(M3JzKCZ==s3sc6{a6%8^~^=o z&aR?%bPKh^hju=I%FJu5!p~TX0UARaYf0FH4pi#S<00(B6{xH9Rs@mFm|ANys-|t| z;(26K<}31In4fn37uCdBtU{&ENA*}4YU7C-4tSP1jyv%Zmf&kVh`(?bHggxHya!d9 zC#WVGLG5@H)xF0n&njzE=#!#8~gKDBxyv+2F z*+{I`oKR_s3EgmdaJi`?$gpt;jqNGSR;x0jMe4qlM84jC4W&XusZqmdXKIu!#0FwL zp}J|OTBJsZP)b!MWl+0ThBTBR{S%^}r*=!*OpR^UY1SO$sM^lR+|=03r%IsuD)k!b zZZ+6ULa(TrR1K-#P}$VH6@-USLsk)ug#I7Y6aL;8-azkLuct`4RVOtN%KP-#VGmR+ zjk4ZJ@4Y3_?o-k3aNKp;&&1-<6K;3RiJdvcck$$%^xJ9P@R2UJBN@sZ&j=of>TA~t oJMCQ&_hj6SIqml6k+acQ((!#ro81^b66uP>!yVD&Z~svGf0s_6U;qFB delta 1575 zcmX}sOGs2v9LMqh)HpsyQ%CJRsum=luWw>&=n}#i5Tr_XVRh z(3jGi=9ulnJ~sz7k6A3ZFahH+5!2C&0bGOy&UquQ;JgJ>@Hl4RpmTl1x&9D&E@ZD5 zEarx9I1fF%Er1zVjg^>>-FOg3F%RS8%nGp_wSaci2KuoEFJUvjMJ*&d-Yf|#F&XPI zk@wp!=fZwmzz;pBiHEQN@1Y+2f|_XBIrk8bGS1V{he1roy{P-UQTKE{gh5=1Cr}F;#nm{DyYUy+ViWoC<5^seV@OtQ9J$3_ zq89c6Lqy%aGnkJ*QMpUtt(jPWRoIM5%^+%_7g6_*VLm=Vf?`wH>oWU;Ol4ifnW6Qe zo*zQ~Y?#ABypc@&iGn@mf^z->^@1O`1Y=m{Dh!}j+{i)K+fb3{MTLGCb8rl|;~Ol( zKq~3P9axM{aXtPS+qTOoIvGp5x1R z=yZLv4zvw3L?feUsu;CGlBCHy%iEj$(D&QTInx?AbW{A{ar2APh9VZY~UV0YMake*gdg diff --git a/src/languages/retailcrm-ru_RU.mo b/src/languages/retailcrm-ru_RU.mo index a379a3d141f67808bdfc6b392e66d2bd6817570b..9727ac5aa08e0a6dddb2700e54ec5307c90cbe00 100644 GIT binary patch delta 1764 zcmXZcTWm~09LMp0x7sdsX}5L1ZR=iIR8{Lzm)4~uLP|=IC|0OeX}9Tvu&qQ8A>xuo zB*lYE8lQiZD-OoXn1h{IiZPslseZFsoP*P`1NoD^#UlKG1(?=9@!ew70@vYM ztj7$-x2H4)apN5h!7r#4_ImxlIGnzpcYRzgD$RAMD=Ma}dEvIu*D3SG?WfAj1`edrI)L?5%Bh=r($RpS&qhShin zmtqPpjm4E18BZfbgKf8C$hYhSY9$wtZL{mBExC=u@HHwDUonVD>{AKmBEPnUizZx) zdcGBBU^@~_dx_yBv-g9EKa;X@M$_J{L%pyGHGu{$)36nlG@ZBxU*Q}KWSULD6>8 z)PTvHF-^D#r{h)BcVehW^`R!5$*6ii7tdh@Dl(stwOS;=G!>dj$YQM$*&f^GS%;d? zA=E%GaX0?L60BylQ+O8Ja15E7haIR1y+P&HZ&Xh7p>ijk3}gZkE1;p|Sc;2rKQ6?( zsL=P~W}G?BY&M=medvj29QFPWRB~mrvE-H&QdL-}TS~bqmnJ2;7Q`Vs|Kx~!ES94} z%W-v&p9asT&ZV+gH{n*JibAR~KY_aBM_bX;X;RS^Eu;Dv-pNjTJTjE!Tl0scUt)vnZchx%YV5^igHJ#h??fM5+_HI)Ao{PZrQ8r z;zZj$8br}Ol9N&4R!CKn6SzsZh_-T~%)3Xfxw)V&`RV>sN=I#@$^u=^=cjg$YG^#r z&{z`=1$Q<#g&XQajZML(<^$XdN57|DPD-iSQ5V`3J?wwu&%5IEIQRK^5N~xJI^9lJ xkV_Ap=kB#De$;v7+;g7APo2*hn-#6deBm3^?L3K}i63_!IM1A(XmWPTfd9Qazmxy~ delta 1626 zcmY+^TSyd99LMpaZtiLqFS%=K*>nS@ncbQBpa1!vy;(6?ZjB|o zt{I|^F`scD+L(QK$HfPcA8U*ogBXvcI18(BCWbH#Tb%PVIFIx5xEQZvB0fbgzH_dB zja;`(98cE+(lH&2a1L(8MYsn`u@eJ0j7RVr=3t|Td$0rZFpPTMXViqIumRKJB8eQv z*_^jyg0YOb$bn|mXJ0U85K}pSfSSQ;)PpB57c(h?9#D^(*)He26_rRkCgTvM;E416 z2h{J!o$r5R9q%_D>ZnW`kz~zrRH@pW^Gl9>s2305DjdS4IEG3rhFL7fAnwFwtit=a z0Ds{^OyVJ|vI(Nay{3o*WmbtSiwU8Yq6vL?3RQ`2^y6JD!MCWTa`T~teW>3DFn}A8 zqL~wTI?9-{NDgKqA<|P*s=sb<@pdJU!N&>=U~Rp=bk zR-SIFE~&}A5kyzGp&PIk0lt!9{i47 z*v8ve;v_1eEIL=s)PPLZgiyV52$euLsuynHdVGcD7*9u1am&Q8!aLyJ;$s)v*75V^CXGOR<(wz)*R$B&7`fi)+iRVbn1c>K8VI9s13Gp;D`{ sHZime|DxJC(Ap~Uds||M!-ektsPKEwb5HnF(nxggpf@r6IAwqQUlMMIa{vGU diff --git a/src/readme.txt b/src/readme.txt index 3afba74..4d0bcd5 100644 --- a/src/readme.txt +++ b/src/readme.txt @@ -45,6 +45,10 @@ API-ключ должен быть для отдельного магазина 2. В появившихся списках справочников настройте соответствие способов доставки и оплаты, а так же статусов заказов. Отметьте галочку "Выгружать остатки", если хотите выгружать остатки из Retailcrm в магазин (подробнее смотрите в описании). == Changelog == += 4.0.0 = +* Поддержка корпоративных клиентов +* Поддержка изменения покупателя в заказе + = 3.6.4 = * Передача названия региона / штата / провинции вместо кода diff --git a/src/retailcrm.php b/src/retailcrm.php index fbb44b9..ed10388 100644 --- a/src/retailcrm.php +++ b/src/retailcrm.php @@ -1,6 +1,6 @@ load_plugin_textdomain(); - if (class_exists( 'WC_Integration' ) ) { - require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-settings.php'); - require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-data.php'); - require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-address.php'); - require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order.php'); - require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-payment.php'); - require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-item.php'); - require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-address.php'); - require_once(dirname(__FILE__ ) . '/include/customer/class-wc-retailcrm-customer-address.php'); - require_once(dirname(__FILE__ ) . '/include/class-wc-retailcrm-base.php'); - require_once(dirname(__FILE__ ) . '/include/functions.php'); + if (class_exists( 'WC_Integration' )) { + self::load_module(); add_filter('woocommerce_integrations', array( $this, 'add_integration')); } else { add_action('admin_notices', array($this, 'woocommerce_missing_notice')); @@ -56,7 +49,30 @@ if (!class_exists( 'WC_Integration_Retailcrm')) : } public function woocommerce_missing_notice() { - echo '

Woocommerce is not installed

'; + if (static::isWooCommerceInstalled()) { + if (!is_plugin_active(static::WOOCOMMERCE_PLUGIN_PATH)) { + echo ' +
+

+ Activate WooCommerce in order to enable retailCRM integration! + + Click here to open plugins manager + +

+
+ '; + } + } else { + echo ' +
+

+ Install WooCommerce in order to enable retailCRM integration! +

+
+ '; + } } public function load_plugin_textdomain() { @@ -74,6 +90,78 @@ if (!class_exists( 'WC_Integration_Retailcrm')) : $integrations[] = 'WC_Retailcrm_Base'; return $integrations; } + + /** + * Loads module classes. + */ + public static function load_module() + { + require_once(dirname(__FILE__) . '/include/interfaces/class-wc-retailcrm-builder-interface.php'); + require_once(dirname(__FILE__) . '/include/models/class-wc-retailcrm-customer-switcher-state.php'); + require_once(dirname(__FILE__) . '/include/models/class-wc-retailcrm-customer-switcher-result.php'); + require_once(dirname(__FILE__ ) . '/include/components/class-wc-retailcrm-logger.php'); + require_once(dirname(__FILE__ ) . '/include/components/class-wc-retailcrm-history-assembler.php'); + require_once(dirname(__FILE__ ) . '/include/components/class-wc-retailcrm-paginated-request.php'); + require_once(dirname(__FILE__) . '/include/components/class-wc-retailcrm-customer-switcher.php'); + require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstract-builder.php'); + require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-settings.php'); + require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-data.php'); + require_once(dirname(__FILE__ ) . '/include/abstracts/class-wc-retailcrm-abstracts-address.php'); + require_once(dirname(__FILE__ ) . '/include/customer/woocommerce/class-wc-retailcrm-wc-customer-builder.php'); + require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order.php'); + require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-payment.php'); + require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-item.php'); + require_once(dirname(__FILE__ ) . '/include/order/class-wc-retailcrm-order-address.php'); + require_once(dirname(__FILE__ ) . '/include/customer/class-wc-retailcrm-customer-address.php'); + require_once(dirname(__FILE__ ) . '/include/customer/class-wc-retailcrm-customer-corporate-address.php'); + require_once(dirname(__FILE__ ) . '/include/class-wc-retailcrm-base.php'); + require_once(dirname(__FILE__ ) . '/include/functions.php'); + } + + /** + * Returns true if WooCommerce was found in plugin cache + * + * @return bool + */ + private function isWooCommerceInstalled() + { + $plugins = wp_cache_get( 'plugins', 'plugins' ); + + if (!$plugins) { + $plugins = get_plugins(); + } elseif (isset($plugins[''])) { + $plugins = $plugins['']; + } + + if (!isset($plugins[static::WOOCOMMERCE_PLUGIN_PATH])) { + return false; + } + + return true; + } + + /** + * Generate plugin installation url + * + * @param $pluginSlug + * + * @return string + */ + private function generatePluginInstallationUrl($pluginSlug) + { + $action = 'install-plugin'; + + return wp_nonce_url( + add_query_arg( + array( + 'action' => $action, + 'plugin' => $pluginSlug + ), + admin_url( 'update.php' ) + ), + $action.'_'.$pluginSlug + ); + } } if (!class_exists('WC_Retailcrm_Plugin')) { diff --git a/src/uninstall.php b/src/uninstall.php index 8571558..93c4695 100644 --- a/src/uninstall.php +++ b/src/uninstall.php @@ -15,7 +15,7 @@ * * * @link https://wordpress.org/plugins/woo-retailcrm/ - * @version 3.6.4 + * @version 4.0.0 * * @package RetailCRM */ diff --git a/tests/bin/install.sh b/tests/bin/install.sh old mode 100755 new mode 100644 diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5f32196..093598d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,6 +1,7 @@ + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Customer_Switcher_State_Test extends WC_Retailcrm_Test_Case_Helper +{ + public function test_feasible() + { + $state = new WC_Retailcrm_Customer_Switcher_State(); + $this->assertFalse($state->feasible()); + + $state->setNewCustomer(array()) + ->setNewContact(array()) + ->setNewCompanyName(''); + $this->assertFalse($state->feasible()); + + $state->setNewCustomer(array('id' => 1)); + $this->assertTrue($state->feasible()); + + $state->setNewCustomer(array()) + ->setNewContact(array('id' => 1)); + $this->assertTrue($state->feasible()); + + $state->setNewCustomer(array()) + ->setNewContact(array()) + ->setNewCompanyName('test'); + $this->assertTrue($state->feasible()); + + $state->setNewCustomer(array()) + ->setNewContact(array()) + ->setNewCompany(array('name' => 'test')); + $this->assertTrue($state->feasible()); + + $state->setNewCustomer(array()) + ->setNewContact(array()) + ->setNewCompanyName(''); + $this->assertFalse($state->feasible()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function test_validate_empty() + { + $state = new WC_Retailcrm_Customer_Switcher_State(); + $state->validate(); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function test_validate_order() + { + $state = new WC_Retailcrm_Customer_Switcher_State(); + $state->setWcOrder(new WC_Order()) + ->validate(); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function test_validate_customer_and_contact_set() + { + $state = new WC_Retailcrm_Customer_Switcher_State(); + $state->setWcOrder(new WC_Order()) + ->setNewCustomer(array('id' => 1)) + ->setNewContact(array('id' => 1)) + ->validate(); + } + + /** + * @@doesNotPerformAssertions + */ + public function test_validate_ok() + { + $state = new WC_Retailcrm_Customer_Switcher_State(); + $state->setWcOrder(new WC_Order()) + ->setNewCustomer(array('id' => 1)) + ->validate(); + } +} diff --git a/tests/customer/woocommerce/test-wc-retailcrm-wc-customer-builder.php b/tests/customer/woocommerce/test-wc-retailcrm-wc-customer-builder.php new file mode 100644 index 0000000..55bc258 --- /dev/null +++ b/tests/customer/woocommerce/test-wc-retailcrm-wc-customer-builder.php @@ -0,0 +1,137 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_WC_Customer_Builder_Test extends WC_Retailcrm_Test_Case_Helper +{ + /** + * @expectedException \RuntimeException + */ + public function test_empty() + { + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $builder->build(); + } + + /** + * @expectedException \RuntimeException + */ + public function test_empty_array() + { + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $builder->setData(array())->build(); + } + + /** + * @expectedException \RuntimeException + */ + public function test_not_array() + { + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $builder->setData(new stdClass())->build(); + } + + /** + * @dataProvider customerData + * + * @param array $customerData + */ + public function test_build($customerData) + { + $builder = new WC_Retailcrm_WC_Customer_Builder(); + $wcCustomer = $builder->setData($customerData)->build()->getResult(); + + $this->assertInstanceOf('\WC_Customer', $wcCustomer); + + if (isset($customerData['firstName'])) { + $this->assertEquals($customerData['firstName'], $wcCustomer->get_first_name()); + } + + if (isset($customerData['lastName'])) { + $this->assertEquals($customerData['lastName'], $wcCustomer->get_last_name()); + } + + if (isset($customerData['email'])) { + $this->assertEquals($customerData['email'], $wcCustomer->get_billing_email()); + } + + if (isset($customerData['phones']) && count($customerData['phones']) > 0) { + $this->assertEquals($customerData['phones'][0]['number'], $wcCustomer->get_billing_phone()); + } + + if (isset($customerData['address']) && !empty($customerData['address'])) { + $address = $customerData['address']; + + if (isset($address['region'])) { + $this->assertEquals($address['region'], $wcCustomer->get_billing_state()); + } + + if (isset($address['index'])) { + $this->assertEquals($address['index'], $wcCustomer->get_billing_postcode()); + } + + if (isset($address['country'])) { + $this->assertEquals($address['country'], $wcCustomer->get_billing_country()); + } + + if (isset($address['city'])) { + $this->assertEquals($address['city'], $wcCustomer->get_billing_city()); + } + } + } + + public function customerData() + { + return array( + array( + 'customer' => array( + 'type' => 'customer', + 'id' => 4228, + 'externalId' => '2', + ) + ), + array( + 'customer' => array( + 'type' => 'customer', + 'id' => 4228, + 'externalId' => '2', + 'isContact' => false, + 'createdAt' => '2020-06-01 15:31:46', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'bitrix-test', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 9412, + 'totalSumm' => 9412, + 'averageSumm' => 9412, + 'ordersCount' => 1, + 'costSumm' => 0, + 'customFields' => array(), + 'personalDiscount' => 0, + 'cumulativeDiscount' => 0, + 'address' => array( + 'id' => 3132, + 'text' => 'ул. Пушкина дом Колотушкина', + ), + 'segments' => array(), + 'firstName' => 'tester001', + 'lastName' => 'tester001', + 'email' => 'tester001@example.com', + 'emailMarketingUnsubscribedAt' => '2020-06-01 15:34:23', + 'phones' => array(array('number' => '2354708915097')) + ) + ) + ); + } +} diff --git a/tests/helpers/class-wc-retailcrm-log-handler-stdout.php b/tests/helpers/class-wc-retailcrm-log-handler-stdout.php new file mode 100644 index 0000000..213d463 --- /dev/null +++ b/tests/helpers/class-wc-retailcrm-log-handler-stdout.php @@ -0,0 +1,117 @@ +add($entry, $handle); + } + + /** + * @param int $timestamp + * @param string $level + * @param string $message + * @param array $context + * + * @return string + */ + protected static function format_entry($timestamp, $level, $message, $context) + { + if (isset($context['_legacy'] ) && true === $context['_legacy']) { + if (isset($context['source']) && $context['source']) { + $handle = $context['source']; + } else { + $handle = 'log'; + } + + $message = apply_filters('woocommerce_logger_add_message', $message, $handle); + $time = date_i18n('m-d-Y @ H:i:s'); + $entry = sprintf('%s - %s', $time, $message); + } else { + $entry = parent::format_entry( $timestamp, $level, $message, $context ); + } + + return $entry; + } + + /** + * @param string $entry Log entry text. + * @param string $handle Log entry handle. + * + * @return bool True if write was successful. + */ + protected function add($entry, $handle) + { + $result = false; + + if (is_resource(STDOUT)) { + $result = fwrite(STDOUT, $entry . PHP_EOL); + } else { + $this->cache_log($entry, $handle); + } + + return false !== $result; + } + + /** + * Cache log to write later. + * + * @param string $entry Log entry text. + * @param string $handle Log entry handle. + */ + protected function cache_log($entry, $handle) + { + $this->cached_logs[] = array( + 'entry' => $entry, + 'handle' => $handle, + ); + } + + /** + * Write cached logs. + */ + public function write_cached_logs() + { + foreach ($this->cached_logs as $log) { + $this->add($log['entry'], $log['handle']); + } + } +} diff --git a/tests/helpers/class-wc-retailcrm-test-case-helper.php b/tests/helpers/class-wc-retailcrm-test-case-helper.php index a7865a3..53a51a1 100644 --- a/tests/helpers/class-wc-retailcrm-test-case-helper.php +++ b/tests/helpers/class-wc-retailcrm-test-case-helper.php @@ -6,20 +6,19 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case { /** - * @param string $apiVersion - * * @return array */ - protected function setOptions($apiVersion = 'v5') + protected function setOptions() { $options = array( 'api_url' => 'https://example.retailcrm.ru', 'api_key' => 'dhsHJGYdjkHHJKJSGjhasjhgajsgJGHsg', - 'api_version' => $apiVersion, + 'api_version' => 'v5', 'p_draft' => 'no', 'p_pending' => 'no', 'p_private' => 'no', 'p_publish' => 'no', + 'send_payment_amount' => 'yes', 'order_methods' => '', 'flat_rate_shipping' => 'delivery', 'free_shipping' => 'delivery2', @@ -48,6 +47,43 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case return $options; } + /** + * Removes all data from the DB. + */ + protected function deleteAllData() + { + if (function_exists('_delete_all_data')) { + _delete_all_data(); + } else { + global $wpdb; + + foreach ( array( + $wpdb->posts, + $wpdb->postmeta, + $wpdb->comments, + $wpdb->commentmeta, + $wpdb->term_relationships, + $wpdb->termmeta, + ) as $table ) { + //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $wpdb->query( "DELETE FROM {$table}" ); + } + + foreach ( array( + $wpdb->terms, + $wpdb->term_taxonomy, + ) as $table ) { + //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $wpdb->query( "DELETE FROM {$table} WHERE term_id != 1" ); + } + + $wpdb->query( "UPDATE {$wpdb->term_taxonomy} SET count = 0" ); + + $wpdb->query( "DELETE FROM {$wpdb->users} WHERE ID != 1" ); + $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE user_id != 1" ); + } + } + /** * @return array */ diff --git a/tests/models/test-wc-retailcrm-customer-switcher-result.php b/tests/models/test-wc-retailcrm-customer-switcher-result.php new file mode 100644 index 0000000..5ded62d --- /dev/null +++ b/tests/models/test-wc-retailcrm-customer-switcher-result.php @@ -0,0 +1,51 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Customer_Switcher_Result_Test extends WC_Retailcrm_Test_Case_Helper +{ + /** + * @expectedException \InvalidArgumentException + */ + public function test_invalid_both() + { + new WC_Retailcrm_Customer_Switcher_Result(new stdClass(), new stdClass()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function test_invalid_customer() + { + new WC_Retailcrm_Customer_Switcher_Result(new stdClass(), new WC_Order()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function test_invalid_order() + { + new WC_Retailcrm_Customer_Switcher_Result(new WC_Customer(), new stdClass()); + } + + public function test_valid() + { + $result = new WC_Retailcrm_Customer_Switcher_Result(new WC_Customer(), new WC_Order()); + $this->assertInstanceOf('\WC_Customer', $result->getWcCustomer()); + $this->assertInstanceOf('\WC_Order', $result->getWcOrder()); + } + + public function test_valid_no_customer() + { + $result = new WC_Retailcrm_Customer_Switcher_Result(null, new WC_Order()); + $this->assertEmpty($result->getWcCustomer()) +; $this->assertInstanceOf('\WC_Order', $result->getWcOrder()); + } +} diff --git a/tests/order/test-wc-retailcrm-order-address.php b/tests/order/test-wc-retailcrm-order-address.php index b7c0a52..945b8d9 100644 --- a/tests/order/test-wc-retailcrm-order-address.php +++ b/tests/order/test-wc-retailcrm-order-address.php @@ -26,8 +26,11 @@ class WC_Retailcrm_Order_Address_Test extends WC_Retailcrm_Test_Case_Helper public function test_build() { - $order_address = new WC_Retailcrm_Order_Address; - $data = $order_address->build($this->order)->get_data(); + $order_address = new WC_Retailcrm_Order_Address(); + $data = $order_address + ->setWCAddressType(WC_Retailcrm_Abstracts_Address::ADDRESS_TYPE_BILLING) + ->build($this->order) + ->get_data(); $this->assertArrayHasKey('index', $data); $this->assertArrayHasKey('city', $data); diff --git a/tests/order/test-wc-retailcrm-order-payment.php b/tests/order/test-wc-retailcrm-order-payment.php index 90ddb4f..6f029f8 100644 --- a/tests/order/test-wc-retailcrm-order-payment.php +++ b/tests/order/test-wc-retailcrm-order-payment.php @@ -19,6 +19,7 @@ class WC_Retailcrm_Order_Payment_Test extends WC_Retailcrm_Test_Case_Helper parent::setUp(); $this->order = WC_Helper_Order::create_order(); + $this->setOptions(); } /** @@ -28,11 +29,18 @@ class WC_Retailcrm_Order_Payment_Test extends WC_Retailcrm_Test_Case_Helper */ public function test_build($externalId) { - $order_payment = new WC_Retailcrm_Order_Payment($this->getOptions()); + $settings = $this->getOptions(); + $settings['send_payment_amount'] = 'no'; + $order_payment = new WC_Retailcrm_Order_Payment($settings); $data = $order_payment->build($this->order, $externalId)->get_data(); - $this->assertArrayHasKey('externalId', $data); + $this->assertNotEmpty($data); + + if (!empty($externalId)) { + $this->assertArrayHasKey('externalId', $data); + } + $this->assertArrayHasKey('type', $data); $this->assertArrayNotHasKey('amount', $data); $this->assertArrayHasKey('order', $data); @@ -51,8 +59,13 @@ class WC_Retailcrm_Order_Payment_Test extends WC_Retailcrm_Test_Case_Helper $data = $order_payment->build($this->order, $externalId)->get_data(); - $this->assertArrayHasKey('externalId', $data); - $this->assertArrayHasKey('type', $data); + $this->assertNotEmpty($data); + + if (!empty($externalId)) { + $this->assertArrayHasKey('externalId', $data); + } + + $this->assertArrayHasKey('type', $data); $this->assertArrayHasKey('amount', $data); $this->assertArrayHasKey('order', $data); } diff --git a/tests/test-wc-retailcrm-base.php b/tests/test-wc-retailcrm-base.php index b28840a..a5efca4 100644 --- a/tests/test-wc-retailcrm-base.php +++ b/tests/test-wc-retailcrm-base.php @@ -45,7 +45,6 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper $this->assertInternalType('array', $this->unit->form_fields); $this->assertArrayHasKey('api_url', $this->unit->form_fields); $this->assertArrayHasKey('api_key', $this->unit->form_fields); - $this->assertArrayHasKey('api_version', $this->unit->form_fields); foreach (get_post_statuses() as $key => $status) { $this->assertArrayHasKey('p_' . $key, $this->unit->form_fields); diff --git a/tests/test-wc-retailcrm-customers.php b/tests/test-wc-retailcrm-customers.php index 0b1ab89..3dd49ed 100644 --- a/tests/test-wc-retailcrm-customers.php +++ b/tests/test-wc-retailcrm-customers.php @@ -38,6 +38,8 @@ class WC_Retailcrm_Customers_Test extends WC_Retailcrm_Test_Case_Helper ->willReturn($this->responseMock); $this->customer = new WC_Customer(); + $this->customer->set_first_name('Tester'); + $this->customer->set_last_name('Tester'); $this->customer->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); $this->customer->set_billing_email($this->customer->get_email()); $this->customer->set_password('password'); @@ -124,13 +126,15 @@ class WC_Retailcrm_Customers_Test extends WC_Retailcrm_Test_Case_Helper /** * @param $retailcrm + * * @dataProvider dataProviderApiClient + * @throws \Exception */ public function test_create_customer_empty_response($retailcrm) { $this->responseMock = null; $this->apiMock = null; - + $retailcrm_customer = $this->getRetailcrmCustomer($retailcrm); $id = $retailcrm_customer->createCustomer($this->customer->get_id()); diff --git a/tests/test-wc-retailcrm-history.php b/tests/test-wc-retailcrm-history.php index 45d7e4e..f76e8ba 100644 --- a/tests/test-wc-retailcrm-history.php +++ b/tests/test-wc-retailcrm-history.php @@ -2,8 +2,13 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper { + /** @var \PHPUnit\Framework\MockObject\MockObject|\WC_Retailcrm_Proxy */ protected $apiMock; + + /** @var WC_Retailcrm_Response_Helper */ protected $customersHistoryResponse; + + /** @var WC_Retailcrm_Response_Helper */ protected $ordersHistoryResponse; const STATUS_1 = 'status1'; @@ -11,63 +16,31 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper public function setUp() { - $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') - ->disableOriginalConstructor() - ->setMethods(array( - 'ordersHistory', - 'customersHistory' - )) - ->getMock(); - - $this->customersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') - ->disableOriginalConstructor() - ->setMethods(array( - 'isSuccessful' - )) - ->getMock(); - - $this->ordersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') - ->disableOriginalConstructor() - ->setMethods(array( - 'isSuccessful' - )) - ->getMock(); - + $this->regenerateMocks(); parent::setUp(); } - /** - * @dataProvider dataProvider - * @param $api_version - */ - public function test_history_order_create($api_version) + public function test_history_order_create() { - $this->setOptions($api_version); - - $this->customersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - - $this->customersHistoryResponse->setResponse(array('success' => true, 'history' => array())); - - $this->ordersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - $product = WC_Helper_Product::create_simple_product(); - $this->ordersHistoryResponse->setResponse( + $this->mockHistory( + true, + true, + $this->empty_history(), $this->get_history_data_new_order($product->get_id()) ); - $this->apiMock->expects($this->any())->method('customersHistory')->willReturn($this->customersHistoryResponse); - $this->apiMock->expects($this->any())->method('ordersHistory')->willReturn($this->ordersHistoryResponse); - $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); $retailcrm_history->getHistory(); $orders = wc_get_orders(array('numberposts' => -1)); $order_added = end($orders); + + if (!$order_added) { + $this->fail('$order_added is null - no orders were added after receiving history'); + } + $order_added_items = $order_added->get_items(); $order_added_item = reset($order_added_items); $shipping_address = $order_added->get_address('shipping'); @@ -106,34 +79,18 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper } } - /** - * @dataProvider dataProvider - * @param $api_version - */ - public function test_history_order_add_product($api_version) + public function test_history_order_add_product() { - $this->setOptions($api_version); - - $this->customersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - - $this->customersHistoryResponse->setResponse(array('success' => true, 'history' => array())); - - $this->ordersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - $product = WC_Helper_Product::create_simple_product(); $order = WC_Helper_Order::create_order(0); - $this->ordersHistoryResponse->setResponse( + $this->mockHistory( + true, + true, + $this->empty_history(), $this->get_history_data_product_add($product->get_id(), $order->get_id()) ); - $this->apiMock->expects($this->any())->method('customersHistory')->willReturn($this->customersHistoryResponse); - $this->apiMock->expects($this->any())->method('ordersHistory')->willReturn($this->ordersHistoryResponse); - $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); $retailcrm_history->getHistory(); @@ -146,33 +103,17 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper $this->assertEquals($product->get_id(), $order_updated_item->get_product()->get_id()); } - /** - * @dataProvider dataProvider - * @param $api_version - */ - public function test_history_order_update($api_version) + public function test_history_order_update() { - $this->setOptions($api_version); - - $this->customersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - - $this->customersHistoryResponse->setResponse(array('success' => true, 'history' => array())); - - $this->ordersHistoryResponse->expects($this->any()) - ->method('isSuccessful') - ->willReturn(true); - $order = WC_Helper_Order::create_order(0); - $this->ordersHistoryResponse->setResponse( - $this->get_history_data_update($order->get_id(), $api_version) + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_data_update($order->get_id()) ); - $this->apiMock->expects($this->any())->method('customersHistory')->willReturn($this->customersHistoryResponse); - $this->apiMock->expects($this->any())->method('ordersHistory')->willReturn($this->ordersHistoryResponse); - $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); $retailcrm_history->getHistory(); @@ -183,14 +124,543 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper $this->assertEquals('payment2', $options[$order_updated->get_payment_method()]); } - public function dataProvider() + public function test_history_switch_customer_tests() + { + $this->deleteAllData(); + $this->regenerateMocks(); + $order_id = $this->history_order_create_for_changing_customer(); + $this->assertNotEmpty($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_customer($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_customer_to_corporate($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_customer_to_another_corporate($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_only_company($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_only_contact($order_id); + + $this->regenerateMocks(); + $this->history_order_switch_back_to_individual($order_id); + } + + public function history_order_create_for_changing_customer() + { + $product = WC_Helper_Product::create_simple_product(); + + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_order_for_client_replace($product->get_id()) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + $orders = wc_get_orders(array('numberposts' => -1)); + $order_added = end($orders); + + if (!$order_added) { + $this->fail('$order_added is null - no orders were added after receiving history'); + } + + $this->assertEquals('tester001@example.com', $order_added->get_billing_email()); + $this->assertNotEmpty($order_added->get_id()); + + return $order_added->get_id(); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_customer($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_to_another_individual($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact($this->get_new_individual_for_order()) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('tester002', $order->get_billing_first_name()); + $this->assertEquals('tester002', $order->get_billing_last_name()); + $this->assertEquals('ewtrhibehb126879@example.com', $order->get_billing_email()); + $this->assertEquals('с. Верхненазаровское', $order->get_billing_city()); + $this->assertEquals('34000', $order->get_billing_postcode()); + $this->assertEquals('Адыгея Республика', $order->get_billing_state()); + $this->assertEquals('с. Верхненазаровское', $order->get_shipping_city()); + $this->assertEquals('34000', $order->get_shipping_postcode()); + $this->assertEquals('Адыгея Республика', $order->get_shipping_state()); + $this->assertEquals('34687453268933', $order->get_billing_phone()); + $this->assertEmpty($order->get_billing_company()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_customer_to_corporate($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_to_corporate($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact( + $this->get_new_corporate_for_order(), + $this->get_new_contact_for_order(), + array('name' => 'Компания1'), + 'legal-entity' + ) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('psycho913', $order->get_billing_first_name()); + $this->assertEquals('psycho913', $order->get_billing_last_name()); + $this->assertEquals('psycho913@example.com', $order->get_billing_email()); + $this->assertEquals('Валдгейм', $order->get_shipping_city()); + $this->assertEquals('344091', $order->get_shipping_postcode()); + $this->assertEquals('Еврейская Автономная область', $order->get_shipping_state()); + $this->assertEquals('Компания1', $order->get_billing_company()); + $this->assertEquals('9135487458709', $order->get_billing_phone()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_customer_to_another_corporate($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_to_another_corporate($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact( + $this->get_another_corporate_for_order(), + $this->get_another_contact_for_order(), + array('name' => 'TestCompany3428769'), + 'legal-entity' + ) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('Tester4867', $order->get_billing_first_name()); + $this->assertEquals('Tester4867', $order->get_billing_last_name()); + $this->assertEquals('tester4867@example.com', $order->get_billing_email()); + $this->assertEquals('TestCompany3428769', $order->get_billing_company()); + $this->assertEquals('--', $order->get_shipping_city()); + $this->assertEquals('--', $order->get_shipping_postcode()); + $this->assertEquals('--', $order->get_shipping_state()); + $this->assertEquals('--', $order->get_shipping_country()); + $this->assertEquals('', $order->get_billing_phone()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_only_company($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_only_company($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact( + $this->get_another_corporate_for_order(), + $this->get_another_contact_for_order(), + array('name' => 'TestCompany017089465'), + 'legal-entity' + ) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('Tester4867', $order->get_billing_first_name()); + $this->assertEquals('Tester4867', $order->get_billing_last_name()); + $this->assertEquals('tester4867@example.com', $order->get_billing_email()); + $this->assertEquals('TestCompany017089465', $order->get_billing_company()); + $this->assertEquals('--', $order->get_shipping_city()); + $this->assertEquals('--', $order->get_shipping_postcode()); + $this->assertEquals('--', $order->get_shipping_state()); + $this->assertEquals('--', $order->get_shipping_country()); + $this->assertEquals('', $order->get_billing_phone()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_only_contact($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_only_contact($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact( + $this->get_another_corporate_for_order(), + $this->get_contact_when_only_contact_changed(), + array('name' => 'TestCompany017089465'), + 'legal-entity' + ) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('Tester2890', $order->get_billing_first_name()); + $this->assertEquals('Tester2890', $order->get_billing_last_name()); + $this->assertEquals('tester2890@example.com', $order->get_billing_email()); + $this->assertEquals('TestCompany017089465', $order->get_billing_company()); + $this->assertEquals('--', $order->get_shipping_city()); + $this->assertEquals('--', $order->get_shipping_postcode()); + $this->assertEquals('--', $order->get_shipping_state()); + $this->assertEquals('--', $order->get_shipping_country()); + $this->assertEquals('32418790888', $order->get_billing_phone()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * @param int $order_id + * + * @throws \Exception + */ + public function history_order_switch_back_to_individual($order_id) + { + $this->mockHistory( + true, + true, + $this->empty_history(), + $this->get_history_change_from_corporate_to_individual($order_id) + ); + + $this->ordersGetMock( + true, + $this->get_order_with_customer_and_contact($this->get_initial_regular_customer()) + ); + + $retailcrm_history = new \WC_Retailcrm_History($this->apiMock); + $retailcrm_history->getHistory(); + + try { + $order = new WC_Order($order_id); + } catch (\Exception $exception) { + $post = get_post($order_id); + + if (!$post instanceof WP_Post) { + $this->fail(sprintf('Cannot find order with id=%d', $order_id)); + } + + if (!in_array($post->post_type, wc_get_order_types())) { + $this->fail(sprintf( + 'Invalid order post type `%s`. Should be one of these: %s', + $post->post_type, + implode(', ', wc_get_order_types()) + )); + } else { + $this->fail(sprintf( + 'Cannot determine what\'s wrong with order id=%d. Message from WooCommerce: %s', + $order_id, + $exception->getMessage() + )); + } + + return; + } + + $this->assertEquals('tester001', $order->get_billing_first_name()); + $this->assertEquals('tester001', $order->get_billing_last_name()); + $this->assertEquals('tester001@example.com', $order->get_billing_email()); + $this->assertEquals('--', $order->get_billing_city()); + $this->assertEquals('--', $order->get_billing_postcode()); + $this->assertEquals('--', $order->get_billing_state()); + $this->assertEquals('--', $order->get_billing_country()); + $this->assertEquals('--', $order->get_shipping_city()); + $this->assertEquals('--', $order->get_shipping_postcode()); + $this->assertEquals('--', $order->get_shipping_state()); + $this->assertEquals('--', $order->get_shipping_country()); + $this->assertEquals('2354708915097', $order->get_billing_phone()); + $this->assertEquals('ул. Пушкина дом Колотушкина', $order->get_billing_address_1()); + $this->assertEmpty($order->get_billing_company()); + $this->assertEmpty($order->get_customer_id()); + } + + /** + * Mock ordersGet response. + * + * @param bool $isSuccessful + * @param array $response + */ + private function ordersGetMock($isSuccessful, $response) + { + $mock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $mock->expects($this->any()) + ->method('isSuccessful') + ->willReturn($isSuccessful); + + $mock->setResponse($response); + $this->apiMock->expects($this->any())->method('ordersGet')->willReturn($mock); + } + + /** + * Mocks customers and orders history responses with provided data + * + * @param bool $isSuccessfulCustomers + * @param bool $isSuccessfulOrders + * @param array $customersHistoryResponse + * @param array $orderHistoryResponse + */ + private function mockHistory( + $isSuccessfulCustomers, + $isSuccessfulOrders, + $customersHistoryResponse, + $orderHistoryResponse + ) { + $this->setOptions(); + + if (!add_option('retailcrm_orders_history_since_id', 0)) { + update_option('retailcrm_orders_history_since_id', 0); + } + + if (!add_option('retailcrm_customers_history_since_id', 0)) { + update_option('retailcrm_customers_history_since_id', 0); + } + + $this->customersHistoryResponse->expects($this->any()) + ->method('isSuccessful') + ->willReturn($isSuccessfulCustomers); + + $this->ordersHistoryResponse->expects($this->any()) + ->method('isSuccessful') + ->willReturn($isSuccessfulOrders); + + $this->customersHistoryResponse->setResponse($customersHistoryResponse); + $this->ordersHistoryResponse->setResponse($orderHistoryResponse); + + $this->apiMock->expects($this->any())->method('customersHistory')->willReturn($this->customersHistoryResponse); + $this->apiMock->expects($this->any())->method('ordersHistory')->willReturn($this->ordersHistoryResponse); + } + + private function regenerateMocks() + { + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'ordersHistory', + 'customersHistory', + 'ordersGet' + )) + ->getMock(); + + $this->customersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->ordersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + } + + private function empty_history() { return array( - array( - 'api_version' => 'v4' - ), - array( - 'api_version' => 'v5' + 'success' => true, + 'history' => array(), + "pagination" => array( + "limit" => 100, + "totalCount" => 0, + "currentPage" => 1, + "totalPageCount" => 0 ) ); } @@ -233,6 +703,7 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper 'call' => false, 'expired' => false, 'customer' => array( + 'type' => 'customer', 'segments' => array(), 'id' => 1, 'firstName' => 'Test', @@ -328,6 +799,12 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper 'uploadedToExternalStoreSystem' => false ) ) + ), + "pagination" => array( + "limit" => 100, + "totalCount" => 1, + "currentPage" => 1, + "totalPageCount" => 1 ) ); } @@ -382,11 +859,17 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper 'purchasePrice' => 500 ) ) + ), + "pagination" => array( + "limit" => 100, + "totalCount" => 1, + "currentPage" => 1, + "totalPageCount" => 1 ) ); } - private function get_history_data_update($order_id, $api_version) + private function get_history_data_update($order_id) { $history = array( 'success' => true, @@ -413,6 +896,12 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper 'status' => self::STATUS_2 ) ) + ), + "pagination" => array( + "limit" => 100, + "totalCount" => 1, + "currentPage" => 1, + "totalPageCount" => 1 ) ); @@ -440,37 +929,1518 @@ class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper 'type' => 'payment2', "amount" => 100 ) - ); - - $payment_v4 = array( - 'id' => 4, - 'createdAt' => '2018-01-01 00:03:00', - 'source' => 'user', - 'user' => array( - 'id' => 1 - ), - 'field' => 'payment_type', - 'oldValue' => null, - 'newValue' => array( - 'code' => 'payment2' - ), - 'order' => array( - 'id' => 2, - 'externalId' => $order_id, - 'managerId' => 6, - 'site' => 'test-com', - 'status' => self::STATUS_2 - ), ); - if ($api_version == 'v4') { - array_push($history['history'], $payment_v4); - } - - if ($api_version == 'v5') { - array_push($history['history'], $payment_v5); - } + array_push($history['history'], $payment_v5); return $history; } + + private function get_history_order_for_client_replace($productId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-04 15:05:39', + 'history' => array(array( + 'id' => 25011, + 'createdAt' => '2020-06-04 15:05:10', + 'created' => true, + 'source' => 'user', + 'field' => 'status', + 'oldValue' => NULL, + 'newValue' => array ('code' => 'new'), + 'order' => array ( + 'slug' => 5868, + 'id' => 5868, + 'number' => '5868C', + 'orderType' => 'test', + 'orderMethod' => 'phone', + 'countryIso' => 'RU', + 'createdAt' => '2020-06-04 15:05:10', + 'statusUpdatedAt' => '2020-06-04 15:05:10', + 'summ' => 16, + 'totalSumm' => 16, + 'prepaySum' => 0, + 'purchaseSumm' => 0, + 'markDatetime' => '2020-06-04 15:05:10', + 'lastName' => 'tester001', + 'firstName' => 'tester001', + 'phone' => '2354708915097', + 'email' => 'tester001@example.com', + 'call' => false, + 'expired' => false, + 'managerId' => 27, + 'customer' => array( + 'type' => 'customer', + 'id' => 4228, + 'externalId' => '2', + 'isContact' => false, + 'createdAt' => '2020-06-01 15:31:46', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'bitrix-test', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 9412, + 'totalSumm' => 9412, + 'averageSumm' => 9412, + 'ordersCount' => 1, + 'costSumm' => 0, + 'customFields' => array(), + 'personalDiscount' => 0, + 'cumulativeDiscount' => 0, + 'address' => array( + 'id' => 3132, + 'text' => 'ул. Пушкина дом Колотушкина', + ), + 'segments' => array(), + 'firstName' => 'tester001', + 'lastName' => 'tester001', + 'email' => 'tester001@example.com', + 'emailMarketingUnsubscribedAt' => '2020-06-01 15:34:23', + 'phones' => array(array('number' => '2354708915097')) + ), + 'contact' => array( + 'type' => 'customer', + 'id' => 4228, + 'externalId' => '2', + 'isContact' => false, + 'createdAt' => '2020-06-01 15:31:46', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'bitrix-test', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 9412, + 'totalSumm' => 9412, + 'averageSumm' => 9412, + 'ordersCount' => 1, + 'costSumm' => 0, + 'customFields' => array(), + 'personalDiscount' => 0, + 'cumulativeDiscount' => 0, + 'address' => array( + 'id' => 3132, + 'text' => 'ул. Пушкина дом Колотушкина', + ), + 'segments' => array(), + 'firstName' => 'tester001', + 'lastName' => 'tester001', + 'email' => 'tester001@example.com', + 'emailMarketingUnsubscribedAt' => '2020-06-01 15:34:23', + 'phones' => array(array('number' => '2354708915097')) + ), + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'delivery' => array( + 'cost' => 0, + 'netCost' => 0, + 'address' => array( + 'id' => 5864, + 'countryIso' => 'RU', + 'text' => 'ул. Пушкина дом Колотушкина', + ), + ), + 'site' => 'woocommerce', + 'status' => 'new', + 'items' => array( + array( + 'id' => 160, + 'initialPrice' => 100, + 'createdAt' => '2018-01-01 00:00:00', + 'quantity' => 1, + 'status' => 'new', + 'externalIds' =>array( + array( + 'code' =>'woocomerce', + 'value' =>"160_".$productId + ) + ), + 'offer' => array( + 'id' => 1, + 'externalId' => $productId, + 'xmlId' => '1', + 'name' => 'Test name', + 'vatRate' => 'none' + ), + 'properties' => array(), + 'purchasePrice' => 50 + ) + ), + 'fromApi' => false, + 'length' => 0, + 'width' => 0, + 'height' => 0, + 'shipmentStore' => 'main', + 'shipped' => false, + 'customFields' => array() + ) + )), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 1, + 'currentPage' => 1, + 'totalPageCount' => 1, + ) + ); + } + + private function get_history_change_to_another_individual($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 12:29:14', + 'history' => array( + array( + 'id' => 25398, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contact', + 'oldValue' => array( + 'id' => 4228, + 'externalId' => '2', + 'site' => 'bitrix-test', + ), + 'newValue' => array( + 'id' => 4231, + 'site' => 'bitrix-test', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25399, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'customer', + 'oldValue' => array( + 'id' => 4228, + 'externalId' => '2', + 'site' => 'bitrix-test', + ), + 'newValue' => array( + 'id' => 4231, + 'site' => 'bitrix-test', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25400, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'email', + 'oldValue' => 'tester001@example.com', + 'newValue' => 'ewtrhibehb126879@example.com', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25401, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'first_name', + 'oldValue' => 'tester001', + 'newValue' => 'tester002', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25402, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'last_name', + 'oldValue' => 'tester001', + 'newValue' => 'tester002', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25403, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'patronymic', + 'oldValue' => null, + 'newValue' => 'tester002', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25404, + 'createdAt' => '2020-06-05 12:29:08', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'phone', + 'oldValue' => '2354708915097', + 'newValue' => '34687453268933', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 7, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_history_change_to_corporate($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 15:24:19', + 'history' => array( + array( + 'id' => 25744, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'delivery_address.city', + 'oldValue' => 'с. Верхненазаровское', + 'newValue' => 'Валдгейм', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25745, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'delivery_address.index', + 'oldValue' => '34000', + 'newValue' => '344091', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25746, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'delivery_address.region', + 'oldValue' => 'Адыгея Республика', + 'newValue' => 'Еврейская Автономная область', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25747, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contragent.contragent_type', + 'oldValue' => 'individual', + 'newValue' => 'legal-entity', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25748, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contragent.legal_address', + 'oldValue' => null, + 'newValue' => '344090 * Москва упцупуцйпуц йцавафыафыафыафы', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25749, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'company', + 'oldValue' => null, + 'newValue' => array( + 'id' => 591, + 'name' => 'Компания1', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25750, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contact', + 'oldValue' => array( + 'id' => 4231, + 'site' => 'bitrix-test', + ), + 'newValue' => array( + 'id' => 4219, + 'externalId' => '4', + 'site' => 'woocommerce', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25751, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'customer', + 'oldValue' => array( + 'id' => 4231, + 'site' => 'bitrix-test', + ), + 'newValue' => array( + 'id' => 4220, + 'site' => 'woocommerce', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25752, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'email', + 'oldValue' => 'ewtrhibehb126879@example.com', + 'newValue' => 'psycho913@example.com', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25753, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'first_name', + 'oldValue' => 'tester002', + 'newValue' => 'psycho913', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25754, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'last_name', + 'oldValue' => 'tester002', + 'newValue' => 'psycho913', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25755, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'patronymic', + 'oldValue' => 'tester002', + 'newValue' => null, + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25756, + 'createdAt' => '2020-06-05 15:24:12', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'phone', + 'oldValue' => '34687453268933', + 'newValue' => '9135487458709', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 13, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_history_change_to_another_corporate($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 16:37:53', + 'history' => array( + array( + 'id' => 25979, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contragent.legal_address', + 'oldValue' => '344090 * Москва упцупуцйпуц йцавафыафыафыафы', + 'newValue' => null, + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25980, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'company', + 'oldValue' => array( + 'id' => 591, + 'name' => 'Компания1', + ), + 'newValue' => array( + 'id' => 621, + 'name' => 'TestCompany3428769', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25981, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contact', + 'oldValue' => array( + 'id' => 4219, + 'externalId' => '4', + 'site' => 'woocommerce', + ), + 'newValue' => array( + 'id' => 4304, + 'site' => 'woocommerce', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25982, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'customer', + 'oldValue' => array( + 'id' => 4220, + 'site' => 'woocommerce', + ), + 'newValue' => array( + 'id' => 4303, + 'site' => 'woocommerce', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25983, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'email', + 'oldValue' => 'psycho913@example.com', + 'newValue' => 'tester4867@example.com', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25984, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'first_name', + 'oldValue' => 'psycho913', + 'newValue' => 'Tester4867', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25985, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'last_name', + 'oldValue' => 'psycho913', + 'newValue' => 'Tester4867', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25986, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'patronymic', + 'oldValue' => null, + 'newValue' => 'Tester4867', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25987, + 'createdAt' => '2020-06-05 16:37:46', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'phone', + 'oldValue' => '9135487458709', + 'newValue' => null, + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 9, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_history_change_only_company($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 17:13:23', + 'history' => array( + array( + 'id' => 25988, + 'createdAt' => '2020-06-05 17:13:17', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'company', + 'oldValue' => array( + 'id' => 621, + 'name' => 'TestCompany3428769', + ), + 'newValue' => array( + 'id' => 622, + 'name' => 'TestCompany017089465', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 1, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_history_change_only_contact($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 17:36:28', + 'history' => array( + array( + 'id' => 25989, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contact', + 'oldValue' => array( + 'id' => 4304, + 'site' => 'woocommerce', + ), + 'newValue' => array( + 'id' => 4305, + 'site' => 'woocommerce', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25990, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'email', + 'oldValue' => 'tester4867@example.com', + 'newValue' => 'tester2890@example.com', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25991, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'first_name', + 'oldValue' => 'Tester4867', + 'newValue' => 'Tester2890', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25992, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'last_name', + 'oldValue' => 'Tester4867', + 'newValue' => 'Tester2890', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25993, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'patronymic', + 'oldValue' => 'Tester4867', + 'newValue' => 'Tester2890', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25994, + 'createdAt' => '2020-06-05 17:36:20', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'phone', + 'oldValue' => null, + 'newValue' => '32418790888', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 6, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_history_change_from_corporate_to_individual($orderExternalId) + { + return array( + 'success' => true, + 'generatedAt' => '2020-06-05 17:47:05', + 'history' => array( + array( + 'id' => 25995, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contragent.contragent_type', + 'oldValue' => 'legal-entity', + 'newValue' => 'individual', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25996, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'contact', + 'oldValue' => array( + 'id' => 4305, + 'site' => 'woocommerce', + ), + 'newValue' => array( + 'id' => 4228, + 'externalId' => '2', + 'site' => 'bitrix-test', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25997, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'customer', + 'oldValue' => array( + 'id' => 4303, + 'site' => 'woocommerce', + ), + 'newValue' => array( + 'id' => 4228, + 'externalId' => '2', + 'site' => 'bitrix-test', + ), + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25998, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'email', + 'oldValue' => 'tester2890@example.com', + 'newValue' => 'tester001@example.com', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 25999, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'first_name', + 'oldValue' => 'Tester2890', + 'newValue' => 'tester001', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 26000, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'last_name', + 'oldValue' => 'Tester2890', + 'newValue' => 'tester001', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 26001, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'patronymic', + 'oldValue' => 'Tester2890', + 'newValue' => null, + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + array( + 'id' => 26002, + 'createdAt' => '2020-06-05 17:46:58', + 'source' => 'user', + 'user' => array( + 'id' => 27, + ), + 'field' => 'phone', + 'oldValue' => '32418790888', + 'newValue' => '2354708915097', + 'order' => array( + 'id' => 5868, + 'externalId' => $orderExternalId, + 'managerId' => 27, + 'site' => 'woocommerce', + 'status' => 'new', + ), + ), + ), + 'pagination' => array( + 'limit' => 100, + 'totalCount' => 8, + 'currentPage' => 1, + 'totalPageCount' => 1, + ), + ); + } + + private function get_initial_regular_customer() + { + return array( + 'type' => 'customer', + 'id' => 4228, + 'externalId' => '2', + 'isContact' => false, + 'createdAt' => '2020-06-01 15:31:46', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'bitrix-test', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 9428, + 'totalSumm' => 9428, + 'averageSumm' => 4714, + 'ordersCount' => 2, + 'costSumm' => 0, + 'personalDiscount' => 0, + 'address' => array( + 'id' => 3132, + 'text' => 'ул. Пушкина дом Колотушкина', + ), + 'firstName' => 'tester001', + 'lastName' => 'tester001', + 'email' => 'tester001@example.com', + 'emailMarketingUnsubscribedAt' => '2020-06-01 15:34:23', + 'phones' => array( + array( + 'number' => '2354708915097', + ), + ), + ); + } + + private function get_contact_when_only_contact_changed() + { + return array( + 'type' => 'customer', + 'id' => 4305, + 'isContact' => true, + 'createdAt' => '2020-06-05 17:11:53', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'woocommerce', + 'tags' => array(), + 'marginSumm' => 0, + 'totalSumm' => 0, + 'averageSumm' => 0, + 'ordersCount' => 0, + 'costSumm' => 0, + 'customFields' => array( + 'galkatrue' => true, + ), + 'personalDiscount' => 0, + 'segments' => array(), + 'firstName' => 'Tester2890', + 'lastName' => 'Tester2890', + 'patronymic' => 'Tester2890', + 'email' => 'tester2890@example.com', + 'phones' => array( + array( + 'number' => '32418790888', + ), + ), + ); + } + + private function get_order_with_customer_and_contact( + $customer, + $contact = array(), + $company = array(), + $contragentType = 'individual' + ) { + $order = array( + 'success' => true, + 'order' => array( + 'slug' => 5868, + 'id' => 5868, + 'number' => '5868C', + 'externalId' => '85', + 'customer' => $customer, + 'contact' => empty($contact) ? $customer : $contact, + 'orderType' => 'test', + 'orderMethod' => 'phone', + 'countryIso' => 'RU', + 'createdAt' => '2020-06-04 15:05:10', + 'statusUpdatedAt' => '2020-06-04 15:05:10', + 'summ' => 16, + 'totalSumm' => 16, + 'prepaySum' => 0, + 'purchaseSumm' => 0, + 'markDatetime' => '2020-06-04 15:05:10', + 'lastName' => 'tester002', + 'firstName' => 'tester002', + 'patronymic' => 'tester002', + 'phone' => '34687453268933', + 'email' => 'ewtrhibehb126879@example.com', + 'call' => false, + 'expired' => false, + 'managerId' => 27, + 'contragent' => array( + 'contragentType' => $contragentType, + ), + 'delivery' => array( + 'cost' => 0, + 'netCost' => 0, + 'address' => array( + 'index' => '34000', + 'countryIso' => 'RU', + 'region' => 'Адыгея Республика', + 'regionId' => 26, + 'city' => 'с. Верхненазаровское', + 'cityId' => 240863, + 'street' => 'ул. Зеленая', + 'streetId' => 962815, + 'building' => '22', + 'text' => 'ул. Зеленая, д. 22', + ), + ), + 'site' => 'woocommerce', + 'status' => 'new', + 'items' => array( + array( + 'markingCodes' => array(), + 'id' => 8955, + 'externalIds' => array( + array( + 'code' => 'woocomerce', + 'value' => '23_31', + ), + ), + 'priceType' => array( + 'code' => 'base', + ), + 'initialPrice' => 16, + 'discountTotal' => 0, + 'vatRate' => 'none', + 'createdAt' => '2020-06-04 14:54:54', + 'quantity' => 1, + 'status' => 'new', + 'offer' => array( + 'displayName' => 'Cap', + 'id' => 67424, + 'externalId' => '23', + 'name' => 'Cap', + 'vatRate' => 'none', + 'unit' => array( + 'code' => 'pc', + 'name' => 'Штука', + 'sym' => 'шт.', + ), + ), + 'properties' => array(), + 'purchasePrice' => 0, + ), + ), + 'payments' => array(), + 'fromApi' => false, + 'length' => 0, + 'width' => 0, + 'height' => 0, + 'shipmentStore' => 'main', + 'shipped' => false, + 'customFields' => array( + 'galka' => false, + 'test_number' => 0, + 'otpravit_dozakaz' => false, + ), + ), + ); + + if (!empty($company)) { + $order['order']['company'] = $company; + } + + return $order; + } + + private function get_new_individual_for_order() + { + return array( + 'type' => 'customer', + 'id' => 4231, + 'isContact' => false, + 'createdAt' => '2020-06-01 15:50:33', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'bitrix-test', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 2144, + 'totalSumm' => 2144, + 'averageSumm' => 1072, + 'ordersCount' => 2, + 'costSumm' => 0, + 'customFields' => array( + 'galkatrue' => true, + ), + 'personalDiscount' => 0, + 'address' => array( + 'id' => 3135, + 'index' => '34000', + 'countryIso' => 'RU', + 'region' => 'Адыгея Республика', + 'regionId' => 26, + 'city' => 'с. Верхненазаровское', + 'cityId' => 240863, + 'street' => 'ул. Зеленая', + 'streetId' => 962815, + 'building' => '22', + 'text' => 'ул. Зеленая, д. 22', + ), + 'firstName' => 'tester002', + 'lastName' => 'tester002', + 'patronymic' => 'tester002', + 'email' => 'ewtrhibehb126879@example.com', + 'phones' => array( + array( + 'number' => '34687453268933', + ), + ), + ); + } + + private function get_new_corporate_for_order() + { + return array( + 'type' => 'customer_corporate', + 'id' => 4220, + 'nickName' => 'Компания1', + 'mainAddress' => array( + 'id' => 3131, + 'name' => 'Компания2', + ), + 'createdAt' => '2020-05-27 15:20:33', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'woocommerce', + 'tags' => array(), + 'marginSumm' => 604, + 'totalSumm' => 604, + 'averageSumm' => 604, + 'ordersCount' => 1, + 'costSumm' => 0, + 'customFields' => array( + 'galkatrue' => true, + ), + 'personalDiscount' => 0, + 'mainCustomerContact' => array( + 'id' => 711, + 'customer' => array( + 'id' => 4219, + 'externalId' => '4', + ), + 'companies' => array(), + ), + 'mainCompany' => array( + 'id' => 591, + 'name' => 'Компания1', + ), + ); + } + + private function get_new_contact_for_order() + { + return array( + 'type' => 'customer', + 'id' => 4219, + 'externalId' => '4', + 'isContact' => false, + 'createdAt' => '2020-05-27 12:09:00', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'woocommerce', + 'contragent' => array( + 'contragentType' => 'individual', + ), + 'tags' => array(), + 'marginSumm' => 0, + 'totalSumm' => 0, + 'averageSumm' => 0, + 'ordersCount' => 0, + 'costSumm' => 0, + 'customFields' => array( + 'galkatrue' => true, + ), + 'personalDiscount' => 0, + 'address' => array( + 'id' => 3130, + 'index' => '344091', + 'countryIso' => 'RU', + 'region' => 'Еврейская Автономная область', + 'regionId' => 47, + 'city' => 'Валдгейм', + 'text' => 'упцупуцйпуц, йцавафыафыафыафы', + ), + 'firstName' => 'psycho913', + 'lastName' => 'psycho913', + 'email' => 'psycho913@example.com', + 'phones' => array( + array( + 'number' => '9135487458709', + ), + ), + ); + } + + private function get_another_corporate_for_order() + { + return array( + 'type' => 'customer_corporate', + 'id' => 4303, + 'nickName' => 'Another Test Legal Entity', + 'mainAddress' => array( + 'id' => 3177, + 'name' => 'Test Address', + ), + 'createdAt' => '2020-06-05 16:34:05', + 'managerId' => 27, + 'vip' => false, + 'bad' => false, + 'site' => 'woocommerce', + 'tags' => array(), + 'marginSumm' => 0, + 'totalSumm' => 0, + 'averageSumm' => 0, + 'ordersCount' => 0, + 'customFields' => array( + 'galkatrue' => true, + ), + 'personalDiscount' => 0, + 'mainCustomerContact' => array( + 'id' => 748, + 'customer' => array( + 'id' => 4304, + ), + 'companies' => array( + array( + 'id' => 110, + 'company' => array( + 'id' => 621, + 'name' => 'TestCompany3428769', + ), + ), + ), + ), + 'mainCompany' => array( + 'id' => 621, + 'name' => 'TestCompany3428769', + ), + ); + } + + private function get_another_contact_for_order() + { + return array( + 'type' => 'customer', + 'id' => 4304, + 'isContact' => true, + 'createdAt' => '2020-06-05 16:34:27', + 'vip' => false, + 'bad' => false, + 'site' => 'woocommerce', + 'tags' => array(), + 'marginSumm' => 0, + 'totalSumm' => 0, + 'averageSumm' => 0, + 'ordersCount' => 0, + 'personalDiscount' => 0, + 'segments' => array(), + 'firstName' => 'Tester4867', + 'lastName' => 'Tester4867', + 'patronymic' => 'Tester4867', + 'sex' => 'male', + 'email' => 'tester4867@example.com', + 'phones' => array(), + ); + } } diff --git a/tests/test-wc-retailcrm-orders.php b/tests/test-wc-retailcrm-orders.php index 1679e45..28e4f53 100644 --- a/tests/test-wc-retailcrm-orders.php +++ b/tests/test-wc-retailcrm-orders.php @@ -28,12 +28,11 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper /** * @param $retailcrm - * @param $apiVersion * @dataProvider dataProviderRetailcrm */ - public function test_order_upload($retailcrm, $apiVersion) + public function test_order_upload($retailcrm) { - $this->options = $this->setOptions($apiVersion); + $this->options = $this->setOptions(); $retailcrm_orders = $this->getRetailcrmOrders($retailcrm); $upload_orders = $retailcrm_orders->ordersUpload(); @@ -46,10 +45,9 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper /** * @param $retailcrm - * @param $apiVersion * @dataProvider dataProviderRetailcrm */ - public function test_order_create($retailcrm, $apiVersion) + public function test_order_create($retailcrm) { if ($retailcrm) { $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') @@ -82,7 +80,7 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper } $this->createTestOrder(); - $this->options = $this->setOptions($apiVersion); + $this->options = $this->setOptions(); $retailcrm_orders = $this->getRetailcrmOrders($retailcrm); $order = $retailcrm_orders->orderCreate($this->order->get_id()); $order_send = $retailcrm_orders->getOrder(); @@ -114,16 +112,11 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper $this->assertEquals('WooCity', $order_send['delivery']['address']['city']); $this->assertEquals('delivery', $order_send['delivery']['code']); - if ($apiVersion == 'v4') { - $this->assertArrayHasKey('paymentType', $order_send); - $this->assertEquals('payment1', $order_send['paymentType']); - } elseif ($apiVersion == 'v5') { - $this->assertArrayHasKey('payments', $order_send); - $this->assertInternalType('array', $order_send['payments']); - $this->assertArrayHasKey('type', $order_send['payments'][0]); - $this->assertArrayHasKey('externalId', $order_send['payments'][0]); - $this->assertEquals('payment1', $order_send['payments'][0]['type']); - } + $this->assertArrayHasKey('payments', $order_send); + $this->assertInternalType('array', $order_send['payments']); + $this->assertArrayHasKey('type', $order_send['payments'][0]); + $this->assertArrayHasKey('externalId', $order_send['payments'][0]); + $this->assertEquals('payment1', $order_send['payments'][0]['type']); } else { $this->assertEquals(null, $order); } @@ -132,15 +125,15 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper /** * @param $isSuccessful * @param $retailcrm - * @param $apiVersion + * @dataProvider dataProviderUpdateOrder */ - public function test_update_order($isSuccessful, $retailcrm, $apiVersion) + public function test_update_order($isSuccessful, $retailcrm) { $this->createTestOrder(); - $this->options = $this->setOptions($apiVersion); + $this->options = $this->setOptions(); - if ($retailcrm && $apiVersion == 'v5') { + if ($retailcrm) { $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') ->disableOriginalConstructor() ->setMethods(array( @@ -200,24 +193,19 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper $this->assertEquals('WooCity', $order_send['delivery']['address']['city']); $this->assertEquals('delivery', $order_send['delivery']['code']); - if ($apiVersion == 'v4') { - $this->assertArrayHasKey('paymentType', $order_send); - $this->assertEquals('payment1', $order_send['paymentType']); - } elseif ($apiVersion == 'v5') { - $payment = $retailcrm_orders->getPayment(); - $this->assertInternalType('array', $payment); + $payment = $retailcrm_orders->getPayment(); + $this->assertInternalType('array', $payment); - if (!empty($payment)) { - $this->assertArrayHasKey('type', $payment); - $this->assertArrayHasKey('order', $payment); - $this->assertArrayHasKey('externalId', $payment); - $this->assertEquals('payment1', $payment['type']); + if (!empty($payment)) { + $this->assertArrayHasKey('type', $payment); + $this->assertArrayHasKey('order', $payment); + $this->assertArrayHasKey('externalId', $payment); + $this->assertEquals('payment1', $payment['type']); - if (!empty($this->options['send_payment_amount']) && $this->options['send_payment_amount'] == 'yes') { - $this->assertArrayHasKey('amount', $payment); - } else { - $this->assertArrayNotHasKey('amount', $payment); - } + if (!empty($this->options['send_payment_amount']) && $this->options['send_payment_amount'] == 'yes') { + $this->assertArrayHasKey('amount', $payment); + } else { + $this->assertArrayNotHasKey('amount', $payment); } } } else { @@ -232,43 +220,19 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper return array( array( 'is_successful' => true, - 'retailcrm' => $this->apiMock, - 'api_version' => 'v5' + 'retailcrm' => $this->apiMock ), array( 'is_successful' => true, - 'retailcrm' => false, - 'api_version' => 'v5' + 'retailcrm' => false ), array( 'is_successful' => false, - 'retailcrm' => false, - 'api_version' => 'v5' + 'retailcrm' => false ), array( 'is_successful' => false, - 'retailcrm' => $this->apiMock, - 'api_version' => 'v5' - ), - array( - 'is_successful' => false, - 'retailcrm' => $this->apiMock, - 'api_version' => 'v4' - ), - array( - 'is_successful' => true, - 'retailcrm' => $this->apiMock, - 'api_version' => 'v4' - ), - array( - 'is_successful' => false, - 'retailcrm' => false, - 'api_version' => 'v4' - ), - array( - 'is_successful' => true, - 'retailcrm' => false, - 'api_version' => 'v4' + 'retailcrm' => $this->apiMock ) ); } @@ -279,20 +243,10 @@ class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper return array( array( - 'retailcrm' => $this->apiMock, - 'api_version' => 'v4' + 'retailcrm' => $this->apiMock ), array( - 'retailcrm' => false, - 'api_version' => 'v4' - ), - array( - 'retailcrm' => $this->apiMock, - 'api_version' => 'v5' - ), - array( - 'retailcrm' => false, - 'api_version' => 'v5' + 'retailcrm' => false ) ); } diff --git a/tests/test-wc-retailcrm-plugin.php b/tests/test-wc-retailcrm-plugin.php index f858c87..07ddf1e 100644 --- a/tests/test-wc-retailcrm-plugin.php +++ b/tests/test-wc-retailcrm-plugin.php @@ -26,14 +26,13 @@ class WC_Retailcrm_Plugin_Test extends WC_Retailcrm_Test_Case_Helper /** * @param $retailcrm * @param $response - * @param $apiVersion * * @dataProvider dataProviderIntegrationModule */ - public function test_integration_module($retailcrm,$response, $apiVersion) + public function test_integration_module($retailcrm, $response) { $client_id = uniqid(); - $result = WC_Retailcrm_Plugin::integration_module($retailcrm, $client_id, $apiVersion); + $result = WC_Retailcrm_Plugin::integration_module($retailcrm, $client_id); if (!$retailcrm || $response['success'] == false) { $this->assertEquals(false, $result); @@ -58,22 +57,12 @@ class WC_Retailcrm_Plugin_Test extends WC_Retailcrm_Test_Case_Helper private function getResponseData() { return array( - 'v4' => array( - "true" => array( - "success" => true - ), - "false" => array( - "success" => false - ) + "true" => array( + "success" => true ), - 'v5' => array( - "true" => array( - "success" => true - ), - "false" => array( - "success" => false, - "errorMsg" => "Forbidden" - ) + "false" => array( + "success" => false, + "errorMsg" => "Forbidden" ) ); } @@ -81,64 +70,29 @@ class WC_Retailcrm_Plugin_Test extends WC_Retailcrm_Test_Case_Helper public function dataProviderIntegrationModule() { $this->setUp(); + $responseData = $this->getResponseData(); return array( array( - 'retailcrm' => $this->getApiMock( - 'v4', - $this->getResponseData['v4']['true'] - ), - 'response' => $this->getResponseData['v4']['true'], - 'apiVersion' => 'v4' + 'retailcrm' => $this->getApiMock($responseData['true']), + 'response' => $responseData['true'] ), array( 'retailcrm' => false, - 'response' => $this->getResponseData['v4']['true'], - 'apiVersion' => 'v4' + 'response' => $responseData['true'] ), array( - 'retailcrm' => $this->getApiMock( - 'v4', - $this->getResponseData['v4']['false'] - ), - 'response' => $this->getResponseData['v4']['false'], - 'apiVersion' => 'v4' + 'retailcrm' => $this->getApiMock($responseData['false']), + 'response' => $responseData['false'] ), array( 'retailcrm' => false, - 'response' => $this->getResponseData['v4']['false'], - 'apiVersion' => 'v4' - ), - array( - 'retailcrm' => $this->getApiMock( - 'v5', - $this->getResponseData['v5']['true'] - ), - 'response' => $this->getResponseData['v5']['true'], - 'apiVersion' => 'v5' - ), - array( - 'retailcrm' => false, - 'response' => $this->getResponseData['v5']['true'], - 'apiVersion' => 'v5' - ), - array( - 'retailcrm' => $this->getApiMock( - 'v5', - $this->getResponseData['v5']['false'] - ), - 'response' => $this->getResponseData['v5']['false'], - 'apiVersion' => 'v5' - ), - array( - 'retailcrm' => false, - 'response' => $this->getResponseData['v5']['false'], - 'apiVersion' => 'v5' + 'response' => $responseData['false'] ) ); } - private function getApiMock($apiVersion, $response) + private function getApiMock($response) { $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') ->disableOriginalConstructor() @@ -159,29 +113,16 @@ class WC_Retailcrm_Plugin_Test extends WC_Retailcrm_Test_Case_Helper $responseMock->setResponse($response); - if ($apiVersion == 'v4') { - $apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') - ->disableOriginalConstructor() - ->setMethods(array( - 'marketplaceSettingsEdit' - )) - ->getMock(); - - $apiMock->expects($this->any()) - ->method('marketplaceSettingsEdit') - ->willReturn($responseMock); - } else { - $apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + $apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') ->disableOriginalConstructor() ->setMethods(array( 'integrationModulesEdit' )) ->getMock(); - $apiMock->expects($this->any()) - ->method('integrationModulesEdit') - ->willReturn($responseMock); - } + $apiMock->expects($this->any()) + ->method('integrationModulesEdit') + ->willReturn($responseMock); return $apiMock; }