diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a4befe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/nbproject/ +/vendor/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5567970 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,36 @@ +language: php + +sudo: false + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + +env: + - WP_VERSION=latest WP_MULTISITE=0 + +matrix: + fast_finish: true + include: + - php: 5.3 + dist: precise + - php: 7.2 + env: WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1 + +before_script: + - bash tests/bin/install.sh wc_retailcrm_test root '' localhost $WP_VERSION + +script: + - bash tests/bin/script.sh + +deploy: + skip_cleanup: true + provider: script + script: make + on: + php: 7.2 + branch: master + condition: "$DEPLOY = true" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1564cee --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,100 @@ +## 2019-03-06 3.4.5 +* Исправлен баг с добавлением скидки при уменьшении количества товара +* Перенесена инициализация формы настроек после инициализации всех плагинов + +## 2019-02-25 3.4.4 +* Добавлена генерация уникального id к externalId отправляемой оплаты + +## 2019-02-15 3.4.3 +* Исправлено сохранение типа оплаты при создании заказа при обработке истории изменений на стороне WC +* Исправлено сохранение типа оплаты при изменении заказа при обработке истории изменений на стороне WC +* Исправлено подключение файлов методом checkCustomFile + +## 2019-02-07 3.4.2 +* Исправлено изменение типа оплаты на стороне WC +* Добавлен вывод неактивных типов оплаты в настройках +* Удалена генерация внешнего кода клиента + +## 2019-01-22 v3.4.1 +* Исправлена архивная выгрузка клиентов + +## 2019-01-17 v3.4.0 +* Добавлена настройка Daemon Collector +* Изменена логика передачи данных по заказам и клиентам. Данные доставки передаются в заказ, данные оплаты в карточку клиента. + +## 2018-12-14 v3.3.8 +* Добавлена выгрузка картинок для категорий товаров в ICML + +## 2018-12-11 v3.3.7 +* Исправление бага в активации + +## 2018-12-06 v3.3.6 +* Исправлена активация модуля в маркетплейсе retailCRM при использовании api v4 +* Расширена отправляемая конфигурация + +## 2018-10-25 v3.3.5 +* Добавлена активация модуля в маркетплейсе retailCRM + +## 2018-08-30 v3.3.4 +* Исправлен баг с занулением количества товара в заказе WC + +## 2018-08-30 v3.3.3 +* Добавлены кнопки для перехода в настройки плагина и для генерации каталога в админ-панели wordpress +* Добавлена передача статуса оплаты на v5 + +## 2018-08-22 v3.3.2 +* Убрана проверка существования задач в wp-cron при каждой загрузке страницы +* Задачи в wp-cron теперь активируются в настройках плагина + +## 2018-08-09 v3.3.1 +* Исправлена ошибка с дублированием товаров с WC + +## 2018-08-06 v3.3.0 +* Переработана механика обработки истории изменений (добавлена склейка всех изменений) +* Добавлен фильтр "retailcrm_history_before_save" для модификации данных истории + +## 2018-07-19 v3.2.0 +* Улучшен метод выборки данных о доставках и оплатах в настройках плагина. (Выбираются все типы оплат, а не только разрешенные. Доставки, которые созданы для отдельных зон, передаются как сервисы) +* Исправлены ошибки при обработке истории изменений +* Добавлены тесты для обработки истории изменений + +## 2018-06-19 v3.1.1 +* Исправлен код отправки данных в UA +* Добавлены новые фильтры, добавлена передача новых параметров в существущие + +## 2018-05-28 v3.1.0 +* В интерфейс настроек плагина добавлена возможность ручной выгрузки заказов +* Исправлена инициализация кода UA для отправки заказов на всех страницах + +## 2018-04-26 v3.0.0 +* Добавлены тесты +* Произведен рефакторинг кода +* Добавлены хуки + +## 2018-03-22 v2.1.4 +* Исправлена ошибка при активированном модуле без настроек +* Добавлен фильтр при формировании массива заказа +* Исправлена генерация icml с неполной картинкой товара + +## 2018-03-22 v2.1.3 +* Исправлена ошибка на php5.3 + +## 2018-03-21 v2.1.2 +* Добавлена локализация плагина +* Добавлена интеграция с UA + +## 2018-03-12 v2.1.1 +* Исправлена ошибка редактирования информации о клиенте + +## 2018-02-26 v2.1.0 +* Переработана механика генерации icml каталога товаров +* В icml каталог добавлена выгрузка налоговой ставки +* Исправлен пересчет итогов после изменения количества товара в RetailCRM + +## 2018-02-19 v2.0.6 +* Исправлено возникновение Warning на PHP 7.2 при генерации каталога товаров +* Добавлена настройка выгрузки заказов из RetailCRM с определенными способами оформления +* Выгрузка изменений из RetailCRM осуществляется по sinceId + +## 2018-02-02 v2.0.5 +* Исправлен неверный подсчет скидки на товары diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7d0bf51 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 RetailDriver LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..59a6dd0 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +FILE = $(TRAVIS_BUILD_DIR)/VERSION +VERSION = `cat $(FILE)` + +all: svn_clone svn_push remove_dir + +svn_clone: + mkdir /tmp/svn_plugin_dir + svn co $(SVNREPOURL) /tmp/svn_plugin_dir --username $(USERNAME) --password $(PASSWORD) --no-auth-cache + +svn_push: /tmp/svn_plugin_dir + if [ ! -d "/tmp/svn_plugin_dir/tags/$(VERSION)" ]; then \ + svn delete /tmp/svn_plugin_dir/trunk/*; \ + rm -rf /tmp/svn_plugin_dir/trunk/*; \ + cp -R $(TRAVIS_BUILD_DIR)/src/* /tmp/svn_plugin_dir/trunk; \ + svn copy /tmp/svn_plugin_dir/trunk /tmp/svn_plugin_dir/tags/$(VERSION) --username $(USERNAME) --password $(PASSWORD) --no-auth-cache; \ + svn add /tmp/svn_plugin_dir/trunk/* --force; \ + svn add /tmp/svn_plugin_dir/tags/$(VERSION)/* --force; \ + svn ci /tmp/svn_plugin_dir -m $(VERSION) --username $(USERNAME) --password $(PASSWORD) --no-auth-cache; \ + fi + +remove_dir: + rm -rf /tmp/svn_plugin_dir diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c4b834 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +[![Build Status](https://img.shields.io/travis/retailcrm/woocommerce-module/master.svg?style=flat-square)](https://travis-ci.org/retailcrm/woocommerce-module) +[![WordPress plugin](https://img.shields.io/wordpress/plugin/v/woo-retailcrm.svg?style=flat-square)](https://wordpress.org/plugins/woo-retailcrm/) +[![PHP version](https://img.shields.io/badge/PHP->=5.3-blue.svg?style=flat-square)](https://php.net/) + +Woocommerce-module +================== + +Модуль интеграции с [retailCRM](http://retailcrm.ru) + +Информация о [кастомизации](https://github.com/retailcrm/woocommerce-module/wiki/%D0%9A%D0%B0%D1%81%D1%82%D0%BE%D0%BC%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%B8%D0%BD%D1%82%D0%B5%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BB%D0%B0%D0%B3%D0%B8%D0%BD%D0%B0) diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..4f5e697 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +3.4.5 diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..12e462c --- /dev/null +++ b/composer.json @@ -0,0 +1,16 @@ +{ + "name": "retailcrm/woocommerce-retailcrm", + "description": "Integration plugin for WooCommerce & RetailCRM", + "type": "wordpress-plugin", + "authors": [ + { + "name": "RetailDriver LLC", + "email": "integration@retailcrm.ru" + } + ], + "minimum-stability": "dev", + "require": {}, + "require-dev": { + "phpunit/phpunit": "6.*" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..e5541ba --- /dev/null +++ b/composer.lock @@ -0,0 +1,1481 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "07140d4f252afbd8967311bfadf35ede", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "870a62d7b0d63d4e0ffa8f2ce3ab7c8a53d1846d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/870a62d7b0d63d4e0ffa8f2ce3ab7c8a53d1846d", + "reference": "870a62d7b0d63d4e0ffa8f2ce3ab7c8a53d1846d", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "^4.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-shim": "^0.9.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2018-03-05T09:41:42+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "9f807201f6e6a8b7ab3582d815511d1807c9c202" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/9f807201f6e6a8b7ab3582d815511d1807c9c202", + "reference": "9f807201f6e6a8b7ab3582d815511d1807c9c202", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-12-18T00:20:24+00:00" + }, + { + "name": "phar-io/manifest", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "014feadb268809af7c8e2f7ccd396b8494901f58" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/014feadb268809af7c8e2f7ccd396b8494901f58", + "reference": "014feadb268809af7c8e2f7ccd396b8494901f58", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-04-07T07:07:10+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-30T07:14:17+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "5d4764d0b9beb04d5b36801c868cfc79a12c70a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/5d4764d0b9beb04d5b36801c868cfc79a12c70a3", + "reference": "5d4764d0b9beb04d5b36801c868cfc79a12c70a3", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-04-19T14:17:18+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "5.3.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "83f09c29758c52e71bdb81ad2cc9124b85b5a4ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/83f09c29758c52e71bdb81ad2cc9124b85b5a4ef", + "reference": "83f09c29758c52e71bdb81ad2cc9124b85b5a4ef", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^2.0.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-xdebug": "^2.5.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-04-07T12:06:18+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "9513098641797ce5f459dbc1de5a54c29b0ec1fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/9513098641797ce5f459dbc1de5a54c29b0ec1fb", + "reference": "9513098641797ce5f459dbc1de5a54c29b0ec1fb", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2018-01-06T05:27:16+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "2.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "13eb9aba9626b1a3811c6a492acc9669d24bb85a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/13eb9aba9626b1a3811c6a492acc9669d24bb85a", + "reference": "13eb9aba9626b1a3811c6a492acc9669d24bb85a", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-11-27T08:47:38+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "6.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "1617f456e1522f9b32723549ddc5a370f8322e91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1617f456e1522f9b32723549ddc5a370f8322e91", + "reference": "1617f456e1522f9b32723549ddc5a370f8322e91", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.3", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^5.0.5", + "sebastian/comparator": "^2.1", + "sebastian/diff": "^2.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-04-16T03:59:19+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "5.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "e244c19aec6a1f0a2ff9e498b9b4bed22537730a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e244c19aec6a1f0a2ff9e498b9b4bed22537730a", + "reference": "e244c19aec6a1f0a2ff9e498b9b4bed22537730a", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" + }, + "conflict": { + "phpunit/phpunit": "<6.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2018-01-07T17:10:51+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "3488be0a7b346cd6e5361510ed07e88f9bea2e88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/3488be0a7b346cd6e5361510ed07e88f9bea2e88", + "reference": "3488be0a7b346cd6e5361510ed07e88f9bea2e88", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T10:23:55+00:00" + }, + { + "name": "sebastian/comparator", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^2.0 || ^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-02-01T13:46:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "2.0.x-dev", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "abcc70409ddfb310a8cb41ef0c2e857425438cf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/abcc70409ddfb310a8cb41ef0c2e857425438cf4", + "reference": "abcc70409ddfb310a8cb41ef0c2e857425438cf4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-12-14T11:32:19+00:00" + }, + { + "name": "sebastian/environment", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd35e43a53ec1c10424a5dec250c30e952e09ced" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd35e43a53ec1c10424a5dec250c30e952e09ced", + "reference": "cd35e43a53ec1c10424a5dec250c30e952e09ced", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2018-03-21T07:21:42+00:00" + }, + { + "name": "sebastian/exporter", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "573f8b71a29cc8afa5f8285d1aee4b4d52717637" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/573f8b71a29cc8afa5f8285d1aee4b4d52717637", + "reference": "573f8b71a29cc8afa5f8285d1aee4b4d52717637", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-11-16T09:48:09+00:00" + }, + { + "name": "sebastian/global-state", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "a27e666314b2df0ab686c2abdee43ffbda48ac10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a27e666314b2df0ab686c2abdee43ffbda48ac10", + "reference": "a27e666314b2df0ab686c2abdee43ffbda48ac10", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-11-16T09:49:42+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "a496797f3bd6821bfe2acb594e0901dfb00572dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/a496797f3bd6821bfe2acb594e0901dfb00572dd", + "reference": "a496797f3bd6821bfe2acb594e0901dfb00572dd", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-11-16T09:50:04+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "ff755086ff55902772e3fae5dd5f29bcbae68285" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/ff755086ff55902772e3fae5dd5f29bcbae68285", + "reference": "ff755086ff55902772e3fae5dd5f29bcbae68285", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2018-01-07T16:00:13+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "0f7f5eb7697036c570aff6812a8efe60c417725e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0f7f5eb7697036c570aff6812a8efe60c417725e", + "reference": "0f7f5eb7697036c570aff6812a8efe60c417725e", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-11-16T10:04:08+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "fadc83f7c41fb2924e542635fea47ae546816ece" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/fadc83f7c41fb2924e542635fea47ae546816ece", + "reference": "fadc83f7c41fb2924e542635fea47ae546816ece", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2016-10-03T07:43:09+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "23bf61bc8a7cc229d7ce8689b1bf818a9e192cac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/23bf61bc8a7cc229d7ce8689b1bf818a9e192cac", + "reference": "23bf61bc8a7cc229d7ce8689b1bf818a9e192cac", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-04-19T15:46:26+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..8057fd7 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + tests/phpunit + + + + + src/include + + src/include/api + src/retailcrm.php + src/uninstall.php + + + + \ No newline at end of file diff --git a/resources/bin/pot_compile.sh b/resources/bin/pot_compile.sh new file mode 100755 index 0000000..db6e82f --- /dev/null +++ b/resources/bin/pot_compile.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +DIRECTORY=$(cd `dirname $0` && pwd) + +msgfmt $DIRECTORY/../pot/retailcrm-ru_RU.pot -o $DIRECTORY/../../src/languages/retailcrm-ru_RU.mo +msgfmt $DIRECTORY/../pot/retailcrm-es_ES.pot -o $DIRECTORY/../../src/languages/retailcrm-es_ES.mo \ No newline at end of file diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot new file mode 100644 index 0000000..c99cb16 --- /dev/null +++ b/resources/pot/retailcrm-es_ES.pot @@ -0,0 +1,203 @@ +# Translation of Plugins - Woocommerce RetailCRM - Development (trunk) in Spanish +# This file is distributed under the same license as the Plugins - Woocommerce RetailCRM - Development (trunk) package. +msgid "" +msgstr "" +"PO-Revision-Date: 2018-06-06 08:53:26+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: GlotPress/2.4.0-alpha\n" +"Language: es\n" +"Project-Id-Version: Plugins - Woocommerce RetailCRM - Development (trunk)\n" + +#. Author URI of the plugin/theme +msgid "https://retailcrm.pro/" +msgstr "https://retailcrm.pro/" + +#. Author of the plugin/theme +msgid "RetailDriver LLC" +msgstr "RetailDriver LLC" + +#. Description of the plugin/theme +msgid "Integration plugin for WooCommerce & retailCRM" +msgstr "El plugin de integración para WooCommerce & retailCRM" + +#. Plugin URI of the plugin/theme +msgid "https://wordpress.org/plugins/woo-retailcrm/" +msgstr "https://wordpress.org/plugins/woo-retailcrm/" + +#. Plugin Name of the plugin/theme +msgid "WooCommerce retailCRM" +msgstr "WooCommerce retailCRM" + +msgid "This functionality allows to upload orders to CRM differentially." +msgstr "Esta función permite la subida selectiva de los pedidos al retailCRM." + +msgid "Uploading orders by identifiers." +msgstr "Subida de los pedidos por identificadores." + +msgid "Enter orders identifiers separated by a comma." +msgstr "Introduce los identificadores de pedidos separados por coma." + +msgid "Orders identifiers" +msgstr "Los identificadores de pedidos" + +msgid "Order identifier" +msgstr "Los identif de pedido" + +msgid "Upload the order by ID" +msgstr "Subir el pedido por ID" + +msgid "Orders were uploaded" +msgstr "Los pedidos están subidos" + +msgid "The field cannot be empty, enter the order ID" +msgstr "El campo no puede estar vacío, introduce el identificador de pedido" + +msgid "Catalog was generated" +msgstr "El catálogo está generado" + +msgid "Customers and orders were uploaded" +msgstr "Los clientes y pedidos están subidos" + +msgid "Enter the correct API key" +msgstr "Introduce la llave API correcta" + +msgid "Enter the correct URL of CRM" +msgstr "Introduce el enlace del retailCRM correcto" + +msgid "The selected API version is unavailable" +msgstr "La versión de API elegida no está disponible" + +msgid "This functionality allows to generate ICML products catalog for uploading to retailCRM." +msgstr "Esta función permite generar los catálogos de pedidos ICML para subida al retailCRM." + +msgid "Generating ICML" +msgstr "Generando ICML" + +msgid "Generate now" +msgstr "Generar ahora" + +msgid "Generating ICML catalog" +msgstr "Generar catálogo ICML" + +msgid "Settings" +msgstr "Ajustes" + +msgid "Uploading the existing customers and orders to retailCRM" +msgstr "Subida de los clientes existentes y pedidos al retailCRM." + +msgid "Uploading all customers and orders" +msgstr "Subir todos los clientes y pedidos" + +msgid "Upload" +msgstr "Subir" + +msgid "Settings of uploading" +msgstr "Ajustes de subida" + +msgid "User parameter" +msgstr "El parámetro personalizado" + +msgid "UA tracking code" +msgstr "El código de seguimiento UA" + +msgid "Enable this setting for uploading data to UA" +msgstr "Activa esta opción para subir los datos al UA." + +msgid "UA" +msgstr "UA" + +msgid "Activate UA" +msgstr "Activar UA" + +msgid "UA settings" +msgstr "Ajustes de UA" + +msgid "Enable this setting if you would like to get information on leftover stocks from retailCRM to the website." +msgstr "Active esta opción si quiere recibir la información del stock de los productos desde retailCRM a la página web." + +msgid "Stock balance" +msgstr "El stock" + +msgid "Synchronization of the stock balance" +msgstr "Sincronizar el stock" + +msgid "Setting of the stock balance" +msgstr "Ajustes del stock" + +msgid "Statuses" +msgstr "Los estados" + +msgid "Payment types" +msgstr "Métodos de pago" + +msgid "Delivery types" +msgstr "Métodos de envío" + +msgid "Select order methods which will be uploaded from retailCRM to the website" +msgstr "Elige el método de formalización de los pedidos que se van a subir desde retailCRM a la página web" + +msgid "Order methods available for uploading from retailCRM" +msgstr "Los métodos de la formalización de los pedidos disponibles para subida desde retailCRM" + +msgid "Order methods" +msgstr "Los métodos de la formalización del pedido" + +msgid "Catalog settings" +msgstr "Ajustes del catálogo" + +msgid "Select API version" +msgstr "Selecciona la versión de API" + +msgid "API version" +msgstr "Versión de API" + +msgid "API settings" +msgstr "Ajustes de API" + +msgid "Enter your API key. You can find it in the administration section of retailCRM" +msgstr "Introduce la llave API. Puede encontrarla en apartado administrativo del retailCRM" + +msgid "Enter with your API URL (https://yourdomain.retailcrm.pro)." +msgstr "Introduce enlace de API (https://yourdomain.retailcrm.pro)." + +msgid "Integration with retailCRM management system." +msgstr "La integración con el sistema de gestión del retailCRM ." + +msgid "Every 15 minutes" +msgstr "Cada 15 minutos" + +msgid "Every 3 hours" +msgstr "Cada 3 horas" + +msgid "Every 5 minutes" +msgstr "Cada 5 minutos" + +msgid "API Key" +msgstr "La llave API" + +msgid "API of URL" +msgstr "El enlace API" + +msgid "Main settings" +msgstr "Los ajustes generales" + +msgid "retailCRM" +msgstr "retailCRM" + +msgid "Daemon Collector settings" +msgstr "Ajustes de Daemon Collector" + +msgid "Activate Daemon Collector" +msgstr "Activar Daemon Collector" + +msgid "Daemon Collector" +msgstr "Daemon Collector" + +msgid "Enable this setting for activate Daemon Collector on site" +msgstr "Active esta configuración para activar Daemon Collector en la página web" + +msgid "Site key" +msgstr "Clave de la página web" \ No newline at end of file diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot new file mode 100644 index 0000000..3690109 --- /dev/null +++ b/resources/pot/retailcrm-ru_RU.pot @@ -0,0 +1,212 @@ +# Translation of Plugins - Woocommerce RetailCRM - Development (trunk) in Russian +# This file is distributed under the same license as the Plugins - Woocommerce RetailCRM - Development (trunk) package. +msgid "" +msgstr "" +"PO-Revision-Date: 2018-06-06 08:53:26+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: GlotPress/2.4.0-alpha\n" +"Language: ru\n" +"Project-Id-Version: Plugins - Woocommerce RetailCRM - Development (trunk)\n" + +#. Author URI of the plugin/theme +msgid "https://retailcrm.pro/" +msgstr "https://retailcrm.ru/" + +#. Author of the plugin/theme +msgid "RetailDriver LLC" +msgstr "RetailDriver LLC" + +#. Description of the plugin/theme +msgid "Integration plugin for WooCommerce & retailCRM" +msgstr "Интеграционный плагин для WooCommerce & retailCRM" + +#. Plugin URI of the plugin/theme +msgid "https://wordpress.org/plugins/woo-retailcrm/" +msgstr "https://wordpress.org/plugins/woo-retailcrm/" + +#. Plugin Name of the plugin/theme +msgid "WooCommerce retailCRM" +msgstr "WooCommerce retailCRM" + +msgid "Activate history uploads" +msgstr "Активировать загрузку истории изменений" + +msgid "Upload data from retailCRM" +msgstr "Загрузка данных из retailCRM" + +msgid "Generating ICML catalog by wp-cron" +msgstr "Генерация ICML каталога товаров с помощью wp-cron" + +msgid "This functionality allows to upload orders to CRM differentially." +msgstr "Эта функция позволяет производить выборочную выгрузку заказов в retailCRM" + +msgid "Uploading orders by identifiers." +msgstr "Выгрузка заказов по идентификаторам" + +msgid "Enter orders identifiers separated by a comma." +msgstr "Введите идентификаторы заказов через запятую" + +msgid "Orders identifiers" +msgstr "Идентификаторы заказов" + +msgid "Order identifier" +msgstr "Идентификатор заказа" + +msgid "Upload the order by ID" +msgstr "Выгрузить заказ по идентификатору" + +msgid "Orders were uploaded" +msgstr "Заказы были выгружены" + +msgid "The field cannot be empty, enter the order ID" +msgstr "Поле не может быть пустым, введите идентификатор заказа" + +msgid "Catalog was generated" +msgstr "Каталог был сгенерирован" + +msgid "Customers and orders were uploaded" +msgstr "Клиенты и заказы были выгружены" + +msgid "Enter the correct API key" +msgstr "Введите корректный API ключ" + +msgid "Enter the correct URL of CRM" +msgstr "Введите корректный адрес retailCRM" + +msgid "The selected API version is unavailable" +msgstr "Выбранная версия API недоступна" + +msgid "This functionality allows to generate ICML products catalog for uploading to retailCRM." +msgstr "Эта функция позволяет сгенерировать ICML каталог товаров для выгрузки в retailCRM" + +msgid "Generating ICML" +msgstr "Генерация ICML" + +msgid "Generate now" +msgstr "Сгенерировать сейчас" + +msgid "Generating ICML catalog" +msgstr "Генерация ICML каталога" + +msgid "Settings" +msgstr "Настройки" + +msgid "Uploading the existing customers and orders to retailCRM" +msgstr "Выгрузка существующих клиентов и заказов в retailCRM" + +msgid "Uploading all customers and orders" +msgstr "Выгрузка всех клиентов и заказов" + +msgid "Upload" +msgstr "Выгрузить" + +msgid "Settings of uploading" +msgstr "Настройки выгрузки" + +msgid "User parameter" +msgstr "Пользовательский параметр" + +msgid "UA tracking code" +msgstr "Код отслеживания UA" + +msgid "Enable this setting for uploading data to UA" +msgstr "Активируйте эту настройку для выгрузки данных в UA" + +msgid "UA" +msgstr "UA" + +msgid "Activate UA" +msgstr "Активировать UA" + +msgid "UA settings" +msgstr "Настройки UA" + +msgid "Enable this setting if you would like to get information on leftover stocks from retailCRM to the website." +msgstr "Активируйте данную настройку, если хотите получать остатки по товарам из retailCRM на сайт." + +msgid "Stock balance" +msgstr "Остатки" + +msgid "Synchronization of the stock balance" +msgstr "Синхронизация остатков" + +msgid "Setting of the stock balance" +msgstr "Настройка управления остатками" + +msgid "Statuses" +msgstr "Статусы" + +msgid "Payment types" +msgstr "Способы оплаты" + +msgid "Delivery types" +msgstr "Способы доставки" + +msgid "Select order methods which will be uploaded from retailCRM to the website" +msgstr "Выберите способы оформления заказов, которые будут выгружаться из retailCRM на сайт" + +msgid "Order methods available for uploading from retailCRM" +msgstr "Способы оформления заказа, доступные для выгрузки из retailCRM" + +msgid "Order methods" +msgstr "Способы оформления заказа" + +msgid "Catalog settings" +msgstr "Настройки каталога" + +msgid "Select API version" +msgstr "Выберите версию API" + +msgid "API version" +msgstr "Версия API" + +msgid "API settings" +msgstr "Настройки API" + +msgid "Enter your API key. You can find it in the administration section of retailCRM" +msgstr "Введите API ключ. Вы можете найти его в административном разделе retailCRM." + +msgid "Enter API of URL (https://yourdomain.retailcrm.pro)." +msgstr "Введите API URL (https://yourdomain.retailcrm.ru)." + +msgid "Integration with retailCRM management system." +msgstr "Интеграция с системой управления retailCRM" + +msgid "Every 15 minutes" +msgstr "Каждые 15 минут" + +msgid "Every 3 hours" +msgstr "Каждые 3 часа" + +msgid "Every 5 minutes" +msgstr "Каждые 5 минут" + +msgid "API key" +msgstr "API ключ" + +msgid "API of URL" +msgstr "API URL" + +msgid "Main settings" +msgstr "Главные настройки" + +msgid "retailCRM" +msgstr "retailCRM" + +msgid "Daemon Collector settings" +msgstr "Настройка Daemon Collector" + +msgid "Activate Daemon Collector" +msgstr "Активировать Daemon Collector" + +msgid "Daemon Collector" +msgstr "Daemon Collector" + +msgid "Enable this setting for activate Daemon Collector on site" +msgstr "Активируйте эту настройку для активации Daemon Collector на сайте" + +msgid "Site key" +msgstr "Ключ сайта" \ No newline at end of file diff --git a/src/config/objects.xml b/src/config/objects.xml new file mode 100644 index 0000000..f5ca5cf --- /dev/null +++ b/src/config/objects.xml @@ -0,0 +1,106 @@ + + + + id + firstName + lastName + patronymic + email + birthday + phones + manager + commentary + externalId + cumulativeDiscount + personalDiscount + discountCardNumber + + index + country + region + city + street + building + house + block + flat + floor + intercomCode + metro + notes + + contragentType + legalName + legalAddress + certificateNumber + certificateDate + bank + bankAddress + corrAccount + bankAccount + + id + createdAt + orderType + orderMethod + site + status + manager + firstName + lastName + patronymic + phone + additionalPhone + email + paymentType + paymentStatus + discount + discountPercent + prepaySum + customerComment + managerComment + shipmentStore + shipmentDate + shipped + + payment + amount + paidAt + comment + type + status + + id + initialPrice + discount + discountPercent + quantity + status + summ + + code + service + date + time + cost + netCost + + country + index + region + city + street + building + house + block + flat + floor + intercomCode + metro + notes + + status + trackNumber + courier + + \ No newline at end of file diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-address.php b/src/include/abstracts/class-wc-retailcrm-abstracts-address.php new file mode 100644 index 0000000..b27cdc8 --- /dev/null +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-address.php @@ -0,0 +1,30 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +abstract class WC_Retailcrm_Abstracts_Address extends WC_Retailcrm_Abstracts_Data +{ + protected $data = array( + 'index' => '', + 'city' => '', + 'region' => '', + 'text' => '', + ); + + public function reset_data() + { + $this->data = array( + 'index' => '', + 'city' => '', + 'region' => '', + 'text' => '', + ); + } +} diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-data.php b/src/include/abstracts/class-wc-retailcrm-abstracts-data.php new file mode 100644 index 0000000..20ad0b3 --- /dev/null +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-data.php @@ -0,0 +1,63 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Abstracts_Data + */ +abstract class WC_Retailcrm_Abstracts_Data +{ + /** @var string */ + protected $filter_name; + + /** @var array */ + protected $data = array(); + + /** + * @return void + */ + abstract public function reset_data(); + + /** + * @param $data + * + * @return self + */ + abstract public function build($data); + + protected function set_data_field($field, $value) + { + if (isset($this->data[$field]) && \gettype($value) !== \gettype($this->data[$field])) { + return false; + } + + $this->data[$field] = $value; + + return true; + } + + /** + * @param $fields + */ + protected function set_data_fields($fields) + { + foreach ($fields as $field => $value) { + $this->set_data_field($field, $value); + } + } + + /** + * @return array + */ + public function get_data() + { + return apply_filters('retailcrm_before_send_' . $this->filter_name, $this->data); + } +} diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php new file mode 100644 index 0000000..3436f53 --- /dev/null +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php @@ -0,0 +1,705 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration +{ + /** @var string */ + const YES = 'yes'; + + /** @var string */ + const NO = 'no'; + + /** @var string */ + public static $option_key; + + /** + * WC_Retailcrm_Abstracts_Settings constructor. + */ + public function __construct() { + $this->id = 'integration-retailcrm'; + $this->method_title = __('retailCRM', 'retailcrm'); + $this->method_description = __('Integration with retailCRM management system.', 'retailcrm'); + + static::$option_key = $this->get_option_key(); + + if (isset($_GET['page']) && $_GET['page'] == 'wc-settings' + && isset($_GET['tab']) && $_GET['tab'] == 'integration' + ) { + add_action('init', array($this, 'init_settings_fields'), 99); + } + } + + public function ajax_upload() + { + $ajax_url = admin_url('admin-ajax.php'); + ?> + + + + plugin_id . $this->id . '_single_order'; + ?> + + form_fields = array( + array( 'title' => __( 'Main settings', 'retailcrm' ), 'type' => 'title', 'desc' => '', 'id' => 'general_options' ), + + 'api_url' => array( + 'title' => __( 'API of URL', 'retailcrm' ), + 'type' => 'text', + 'description' => __( 'Enter API of URL (https://yourdomain.retailcrm.pro).', 'retailcrm' ), + 'desc_tip' => true, + 'default' => '' + ), + 'api_key' => array( + 'title' => __( 'API key', 'retailcrm' ), + 'type' => 'text', + 'description' => __( 'Enter your API key. You can find it in the administration section of retailCRM', 'retailcrm' ), + 'desc_tip' => true, + 'default' => '' + ) + ); + + $api_version_list = array( + 'v4' => 'v4', + 'v5' => 'v5' + ); + + $this->form_fields[] = array( + 'title' => __( 'API settings', 'retailcrm' ), + 'type' => 'title', + 'description' => '', + '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[] = array( + 'title' => __( 'Catalog settings', 'retailcrm' ), + 'type' => 'title', + 'description' => '', + 'id' => 'catalog_options' + ); + + foreach (get_post_statuses() as $status_key => $status_value) { + $this->form_fields['p_' . $status_key] = array( + 'title' => $status_value, + 'label' => ' ', + 'description' => '', + 'class' => 'checkbox', + 'type' => 'checkbox', + 'desc_tip' => true, + ); + } + + if ($this->apiClient) { + if (isset($_GET['page']) && $_GET['page'] == 'wc-settings' + && isset($_GET['tab']) && $_GET['tab'] == 'integration' + ) { + add_action('admin_print_footer_scripts', array($this, 'show_blocks'), 99); + + /** + * Order methods options + */ + $order_methods_option = array(); + $order_methods_list = $this->apiClient->orderMethodsList(); + + if ($order_methods_list->isSuccessful()) { + foreach ($order_methods_list['orderMethods'] as $order_method) { + if ($order_method['active'] == false) { + continue; + } + + $order_methods_option[$order_method['code']] = $order_method['name']; + } + + $this->form_fields[] = array( + 'title' => __('Order methods', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'order_methods_options' + ); + + $this->form_fields['order_methods'] = array( + 'label' => ' ', + 'title' => __('Order methods available for uploading from retailCRM', 'retailcrm'), + 'class' => '', + 'type' => 'multiselect', + 'description' => __('Select order methods which will be uploaded from retailCRM to the website', 'retailcrm'), + 'options' => $order_methods_option, + 'css' => 'min-height:100px;', + 'select_buttons' => true + ); + } + + /** + * Shipping options + */ + $shipping_option_list = array(); + $retailcrm_shipping_list = $this->apiClient->deliveryTypesList(); + + if ($retailcrm_shipping_list->isSuccessful()) { + foreach ($retailcrm_shipping_list['deliveryTypes'] as $retailcrm_shipping_type) { + $shipping_option_list[$retailcrm_shipping_type['code']] = $retailcrm_shipping_type['name']; + } + + $wc_shipping_list = get_wc_shipping_methods(); + + $this->form_fields[] = array( + 'title' => __('Delivery types', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'shipping_options' + ); + + foreach ($wc_shipping_list as $shipping_code => $shipping) { + if (isset($shipping['enabled']) && $shipping['enabled'] == static::YES) { + $this->form_fields[$shipping_code] = array( + 'title' => __($shipping['title'], 'woocommerce'), + 'description' => __($shipping['description'], 'woocommerce'), + 'css' => 'min-width:350px;', + 'class' => 'select', + 'type' => 'select', + 'options' => $shipping_option_list, + 'desc_tip' => true, + ); + } + } + } + + /** + * Payment options + */ + $payment_option_list = array(); + $retailcrm_payment_list = $this->apiClient->paymentTypesList(); + + if ($retailcrm_payment_list->isSuccessful()) { + foreach ($retailcrm_payment_list['paymentTypes'] as $retailcrm_payment_type) { + $payment_option_list[$retailcrm_payment_type['code']] = $retailcrm_payment_type['name']; + } + + $wc_payment = WC_Payment_Gateways::instance(); + + $this->form_fields[] = array( + 'title' => __('Payment types', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'payment_options' + ); + + foreach ($wc_payment->payment_gateways() as $payment) { + $this->form_fields[$payment->id] = array( + 'title' => __($payment->method_title, 'woocommerce'), + 'description' => __($payment->method_description, 'woocommerce'), + 'css' => 'min-width:350px;', + 'class' => 'select', + 'type' => 'select', + 'options' => $payment_option_list, + 'desc_tip' => true, + ); + } + } + + /** + * Statuses options + */ + $statuses_option_list = array(); + $retailcrm_statuses_list = $this->apiClient->statusesList(); + + if ($retailcrm_statuses_list->isSuccessful()) { + foreach ($retailcrm_statuses_list['statuses'] as $retailcrm_status) { + $statuses_option_list[$retailcrm_status['code']] = $retailcrm_status['name']; + } + + $wc_statuses = wc_get_order_statuses(); + + $this->form_fields[] = array( + 'title' => __('Statuses', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'statuses_options' + ); + + foreach ($wc_statuses as $idx => $name) { + $uid = str_replace('wc-', '', $idx); + $this->form_fields[$uid] = array( + 'title' => __($name, 'woocommerce'), + 'css' => 'min-width:350px;', + 'class' => 'select', + 'type' => 'select', + 'options' => $statuses_option_list, + 'desc_tip' => true, + ); + } + } + + /** + * Inventories options + */ + $this->form_fields[] = array( + 'title' => __('Setting of the stock balance', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'invent_options' + ); + + $this->form_fields['sync'] = array( + 'label' => __('Synchronization of the stock balance', 'retailcrm'), + 'title' => __('Stock balance', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox', + 'description' => __('Enable this setting if you would like to get information on leftover stocks from retailCRM to the website.', 'retailcrm') + ); + + /** + * UA options + */ + $this->form_fields[] = array( + 'title' => __('UA settings', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'ua_options' + ); + + $this->form_fields['ua'] = array( + 'label' => __('Activate UA', 'retailcrm'), + 'title' => __('UA', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox', + 'description' => __('Enable this setting for uploading data to UA', 'retailcrm') + ); + + $this->form_fields['ua_code'] = array( + 'title' => __('UA tracking code', 'retailcrm'), + 'class' => 'input', + 'type' => 'input' + ); + + $this->form_fields['ua_custom'] = array( + 'title' => __('User parameter', 'retailcrm'), + 'class' => 'input', + 'type' => 'input' + ); + + /** + * Daemon collector settings + */ + $this->form_fields[] = array( + 'title' => __('Daemon Collector settings', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'invent_options' + ); + + $this->form_fields['daemon_collector'] = array( + 'label' => __('Activate Daemon Collector', 'retailcrm'), + 'title' => __('Daemon Collector', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox', + 'description' => __('Enable this setting for activate Daemon Collector on site', 'retailcrm') + ); + + $this->form_fields['daemon_collector_key'] = array( + 'title' => __('Site key', 'retailcrm'), + 'class' => 'input', + 'type' => 'input' + ); + + /** + * Uploads options + */ + $options = array_filter(get_option(static::$option_key)); + + if (!isset($options['uploads'])) { + $this->form_fields[] = array( + 'title' => __('Settings of uploading', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'upload_options' + ); + + $this->form_fields['upload-button'] = array( + 'label' => __('Upload', 'retailcrm'), + 'title' => __('Uploading all customers and orders', 'retailcrm' ), + 'type' => 'button', + 'description' => __('Uploading the existing customers and orders to retailCRM', 'retailcrm' ), + 'desc_tip' => true, + 'id' => 'uploads-retailcrm' + ); + } + + /* + * Generate icml file + */ + $this->form_fields[] = array( + 'title' => __('Generating ICML catalog', 'retailcrm'), + 'type' => 'title', + 'description' => '', + 'id' => 'icml_options' + ); + + $this->form_fields[] = array( + 'label' => __('Generate now', 'retailcrm'), + 'title' => __('Generating ICML', 'retailcrm'), + 'type' => 'button', + 'description' => __('This functionality allows to generate ICML products catalog for uploading to retailCRM.', 'retailcrm'), + 'desc_tip' => true, + 'id' => 'icml-retailcrm' + ); + + $this->form_fields['icml'] = array( + 'label' => __('Generating ICML', 'retailcrm'), + 'title' => __('Generating ICML catalog by wp-cron', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox' + ); + + /* + * Upload single order + */ + $this->form_field[] = array( + 'title' => __('Upload the order by ID', 'retailcrm'), + 'type' => 'title', + 'description' => '', + 'id' => 'order_options' + ); + + $this->form_fields['single_order'] = array( + 'label' => __('Order identifier', 'retailcrm'), + 'title' => __('Orders identifiers', 'retailcrm'), + 'type' => 'input', + 'description' => __('Enter orders identifiers separated by a comma.', 'retailcrm'), + 'desc_tip' => true + ); + + $this->form_fields[] = array( + 'label' => __('Upload', 'retailcrm'), + 'title' => __('Uploading orders by identifiers.', 'retailcrm'), + 'type' => 'button', + 'description' => __('This functionality allows to upload orders to CRM differentially.', 'retailcrm'), + 'desc_tip' => true, + 'id' => 'single_order_btn' + ); + + $this->form_fields['history'] = array( + 'label' => __('Activate history uploads', 'retailcrm'), + 'title' => __('Upload data from retailCRM', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox' + ); + + $this->form_fields['deactivate_update_order'] = array( + 'label' => __('Активировать редактирование данных в retailCRM', 'retailcrm'), + 'title' => __('Обновление данных в retailCRM', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox' + ); + + $this->form_fields['bind_by_sku'] = array( + 'label' => __('Активировать связь по sku(xmlId)', 'retailcrm'), + 'title' => __('Синхронизация остатков и связь товаров', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox' + ); + + $this->form_fields['update_number'] = array( + 'label' => __('Активировать передачу номера в retailCRM', 'retailcrm'), + 'title' => __('Передача номера заказа', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox' + ); + } + } + } + + /** + * Generate html button + * + * @param string $key + * @param array $data + * + * @return string + */ + public function generate_button_html($key, $data) + { + $field = $this->plugin_id . $this->id . '_' . $key; + $defaults = array( + 'class' => 'button-secondary', + 'css' => '', + 'custom_attributes' => array(), + 'desc_tip' => false, + 'description' => '', + 'title' => '', + ); + + $data = wp_parse_args( $data, $defaults ); + + ob_start(); + ?> + + + + get_tooltip_html( $data ); ?> + + +
+ + + get_description_html( $data ); ?> +
+ + + get_field_key( $key ); + $defaults = array( + 'title' => '', + 'class' => '', + ); + + $data = wp_parse_args( $data, $defaults ); + + ob_start(); + ?> + +

+ +

+ + + 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 ($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 + * + * @param string $key + * @param string $value + * + * @return string + */ + public function validate_api_url_field($key, $value) + { + $post = $this->get_post_data(); + $api = new WC_Retailcrm_Proxy( + $value, + $post[$this->plugin_id . $this->id . '_api_key'] + ); + + $response = $api->apiVersions(); + + if ($response == null) { + WC_Admin_Settings::add_error(esc_html__( 'Enter the correct URL of CRM', 'retailcrm')); + $value = ''; + } + + return $value; + } + + /** + * Validate API key + * + * @param string $key + * @param string $value + * + * @return string + */ + public function validate_api_key_field($key, $value) + { + $post = $this->get_post_data(); + $api = new WC_Retailcrm_Proxy( + $post[$this->plugin_id . $this->id . '_api_url'], + $value + ); + + $response = $api->apiVersions(); + + if (!is_object($response)) { + $value = ''; + } + + if (!$response->isSuccessful()) { + WC_Admin_Settings::add_error( esc_html__( 'Enter the correct API key', 'retailcrm' ) ); + $value = ''; + } + + return $value; + } + + /** + * Scritp show|hide block settings + */ + function show_blocks() + { + ?> + + add_menu( + array( + 'id' => 'retailcrm_top_menu', + 'title' => __('retailCRM', 'retailcrm') + ) + ); + $wp_admin_bar->add_menu( + array( + 'id' => 'retailcrm_ajax_generate_icml', + 'title' => __('Generating ICML catalog', 'retailcrm'), + 'href' => '#', + 'parent' => 'retailcrm_top_menu', + 'class' => 'retailcrm_ajax_generate_icml' + ) + ); + $wp_admin_bar->add_menu( + array( + 'id' => 'retailcrm_ajax_generate_setings', + 'title' => __('Settings', 'retailcrm'), + 'href'=> get_site_url().'/wp-admin/admin.php?page=wc-settings&tab=integration§ion=integration-retailcrm', + 'parent' => 'retailcrm_top_menu', + 'class' => 'retailcrm_ajax_settings' + ) + ); + } +} diff --git a/src/include/api/class-wc-retailcrm-client-v4.php b/src/include/api/class-wc-retailcrm-client-v4.php new file mode 100644 index 0000000..1cce88f --- /dev/null +++ b/src/include/api/class-wc-retailcrm-client-v4.php @@ -0,0 +1,1868 @@ + + * @license https://opensource.org/licenses/MIT MIT License + * @link http://retailcrm.ru/docs/Developers/ApiVersion4 + */ + +if ( ! class_exists( 'WC_Retailcrm_Request' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-request.php' ); +} + +if ( ! class_exists( 'WC_Retailcrm_Response' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-response.php' ); +} + +class WC_Retailcrm_Client_V4 +{ + protected $client; + + /** + * Site code + */ + protected $siteCode; + + /** + * Client creating + * + * @param string $url api url + * @param string $apiKey api key + * @param string $site site code + * + * @throws \InvalidArgumentException + */ + public function __construct($url, $apiKey, $version = null, $site = null) + { + if ('/' !== $url[strlen($url) - 1]) { + $url .= '/'; + } + + $url = $version == null ? $url . 'api' : $url . 'api/' . $version; + + $this->client = new WC_Retailcrm_Request($url, array('apiKey' => $apiKey)); + $this->siteCode = $site; + } + + /** + * Returns api versions list + * + * @return WC_Retailcrm_Response + */ + public function apiVersions() + { + return $this->client->makeRequest('/api-versions', WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Returns users list + * + * @param array $filter + * @param null $page + * @param null $limit + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function usersList(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; + } + + return $this->client->makeRequest( + '/users', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get user groups + * + * @param null $page + * @param null $limit + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * + * @return WC_Retailcrm_Response + */ + public function usersGroups($page = null, $limit = null) + { + $parameters = array(); + + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/user-groups', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Returns user data + * + * @param integer $id user ID + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function usersGet($id) + { + return $this->client->makeRequest("/users/$id", WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Returns filtered orders 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 ordersList(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; + } + + return $this->client->makeRequest( + '/orders', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create a order + * + * @param array $order order data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersCreate(array $order, $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('order' => json_encode($order))) + ); + } + + /** + * Save order IDs' (id and externalId) association in the CRM + * + * @param array $ids order identificators + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/orders/fix-external-ids', + WC_Retailcrm_Request::METHOD_POST, + array('orders' => json_encode($ids) + ) + ); + } + + /** + * Returns statuses of the orders + * + * @param array $ids (default: array()) + * @param array $externalIds (default: array()) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersStatuses(array $ids = array(), array $externalIds = array()) + { + $parameters = array(); + + if (count($ids)) { + $parameters['ids'] = $ids; + } + if (count($externalIds)) { + $parameters['externalIds'] = $externalIds; + } + + return $this->client->makeRequest( + '/orders/statuses', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Upload array of the orders + * + * @param array $orders array of orders + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersUpload(array $orders, $site = null) + { + if (!count($orders)) { + throw new \InvalidArgumentException( + 'Parameter `orders` must contains array of the orders' + ); + } + + return $this->client->makeRequest( + '/orders/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('orders' => json_encode($orders))) + ); + } + + /** + * Get order by id or externalId + * + * @param string $id order identificator + * @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 ordersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/orders/$id", + WC_Retailcrm_Request::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a order + * + * @param array $order order 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 ordersEdit(array $order, $by = 'externalId', $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $order)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/%s/edit', $order[$by]), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('order' => json_encode($order), 'by' => $by) + ) + ); + } + + /** + * Get orders history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return WC_Retailcrm_Response + */ + public function ordersHistory(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; + } + + return $this->client->makeRequest( + '/orders/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Returns filtered 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 customersList(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; + } + + return $this->client->makeRequest( + '/customers', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create a customer + * + * @param array $customer 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 customersCreate(array $customer, $site = null) + { + if (! count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + return $this->client->makeRequest( + '/customers/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('customer' => json_encode($customer))) + ); + } + + /** + * Save 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 customersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/customers/fix-external-ids', + WC_Retailcrm_Request::METHOD_POST, + array('customers' => json_encode($ids)) + ); + } + + /** + * Upload array of the customers + * + * @param array $customers array of customers + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersUpload(array $customers, $site = null) + { + if (! count($customers)) { + throw new \InvalidArgumentException( + 'Parameter `customers` must contains array of the customers' + ); + } + + return $this->client->makeRequest( + '/customers/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('customers' => json_encode($customers))) + ); + } + + /** + * Get customer by id or externalId + * + * @param string $id customer identificator + * @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 customersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/customers/$id", + WC_Retailcrm_Request::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a customer + * + * @param array $customer 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 customersEdit(array $customer, $by = 'externalId', $site = null) + { + if (!count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $customer)) { + throw new \InvalidArgumentException( + sprintf('Customer array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/customers/%s/edit', $customer[$by]), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('customer' => json_encode($customer), 'by' => $by) + ) + ); + } + + /** + * Get customers history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return WC_Retailcrm_Response + */ + public function customersHistory(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; + } + + return $this->client->makeRequest( + '/customers/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get orders assembly 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 ordersPacksList(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; + } + + return $this->client->makeRequest( + '/orders/packs', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksCreate(array $pack, $site = null) + { + if (!count($pack)) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/packs/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get orders assembly history + * + * @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 ordersPacksHistory(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; + } + + return $this->client->makeRequest( + '/orders/packs/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + "/orders/packs/$id", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Delete orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/delete', $id), + WC_Retailcrm_Request::METHOD_POST + ); + } + + /** + * Edit orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksEdit(array $pack, $site = null) + { + if (!count($pack) || empty($pack['id'])) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data & pack `id` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/edit', $pack['id']), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get purchace prices & stock balance + * + * @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 storeInventories(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; + } + + return $this->client->makeRequest( + '/store/inventories', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get store settings + * + * @param string $code get settings code + * + * @return WC_Retailcrm_Response + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function storeSettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/store/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit store configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function storeSettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/store/setting/%s/edit', $configuration['code']), + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + + /** + * Upload store inventories + * + * @param array $offers offers data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storeInventoriesUpload(array $offers, $site = null) + { + if (!count($offers)) { + throw new \InvalidArgumentException( + 'Parameter `offers` must contains array of the offers' + ); + } + + return $this->client->makeRequest( + '/store/inventories/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('offers' => json_encode($offers))) + ); + } + + /** + * Upload store prices + * + * @param array $prices prices data + * @param string $site default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storePricesUpload(array $prices, $site = null) + { + if (!count($prices)) { + throw new \InvalidArgumentException( + 'Parameter `prices` must contains array of the prices' + ); + } + + return $this->client->makeRequest( + '/store/prices/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('prices' => json_encode($prices))) + ); + } + + /** + * Get products + * + * @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 storeProducts(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; + } + + return $this->client->makeRequest( + '/store/products', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get delivery settings + * + * @param string $code + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliverySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/delivery/generic/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit delivery configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function deliverySettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/setting/%s/edit', $configuration['code']), + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + + /** + * Delivery tracking update + * + * @param string $code + * @param array $statusUpdate + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function deliveryTracking($code, array $statusUpdate) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + if (!count($statusUpdate)) { + throw new \InvalidArgumentException( + 'Parameter `statusUpdate` must contains a data' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/%s/tracking', $code), + WC_Retailcrm_Request::METHOD_POST, + array('statusUpdate' => json_encode($statusUpdate)) + ); + } + + /** + * Returns available county list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function countriesList() + { + return $this->client->makeRequest( + '/reference/countries', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Returns deliveryServices list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryServicesList() + { + return $this->client->makeRequest( + '/reference/delivery-services', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit deliveryService + * + * @param array $data delivery service data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryServicesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-services/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('deliveryService' => json_encode($data)) + ); + } + + /** + * Returns deliveryTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryTypesList() + { + return $this->client->makeRequest( + '/reference/delivery-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit deliveryType + * + * @param array $data delivery type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('deliveryType' => json_encode($data)) + ); + } + + /** + * Returns orderMethods list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderMethodsList() + { + return $this->client->makeRequest( + '/reference/order-methods', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit orderMethod + * + * @param array $data order method data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderMethodsEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-methods/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('orderMethod' => json_encode($data)) + ); + } + + /** + * Returns orderTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderTypesList() + { + return $this->client->makeRequest( + '/reference/order-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit orderType + * + * @param array $data order type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('orderType' => json_encode($data)) + ); + } + + /** + * Returns paymentStatuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentStatusesList() + { + return $this->client->makeRequest( + '/reference/payment-statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit paymentStatus + * + * @param array $data payment status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('paymentStatus' => json_encode($data)) + ); + } + + /** + * Returns paymentTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentTypesList() + { + return $this->client->makeRequest( + '/reference/payment-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit paymentType + * + * @param array $data payment type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('paymentType' => json_encode($data)) + ); + } + + /** + * Returns productStatuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function productStatusesList() + { + return $this->client->makeRequest( + '/reference/product-statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit productStatus + * + * @param array $data product status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function productStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/product-statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('productStatus' => json_encode($data)) + ); + } + + /** + * Returns sites list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function sitesList() + { + return $this->client->makeRequest( + '/reference/sites', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit site + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function sitesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/sites/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('site' => json_encode($data)) + ); + } + + /** + * Returns statusGroups list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusGroupsList() + { + return $this->client->makeRequest( + '/reference/status-groups', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Returns statuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusesList() + { + return $this->client->makeRequest( + '/reference/statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit order status + * + * @param array $data status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('status' => json_encode($data)) + ); + } + + /** + * Returns stores list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storesList() + { + return $this->client->makeRequest( + '/reference/stores', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit store + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/stores/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('store' => json_encode($data)) + ); + } + + /** + * Get prices types + * + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function pricesTypes() + { + return $this->client->makeRequest( + '/reference/price-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit price type + * + * @param array $data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function pricesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/price-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('priceType' => json_encode($data)) + ); + } + + /** + * Get telephony settings + * + * @param string $code + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function telephonySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/telephony/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit telephony settings + * + * @param string $code symbolic code + * @param string $clientId client id + * @param boolean $active telephony activity + * @param mixed $name service name + * @param mixed $makeCallUrl service init url + * @param mixed $image service logo url(svg file) + * + * @param array $additionalCodes + * @param array $externalPhones + * @param bool $allowEdit + * @param bool $inputEventSupported + * @param bool $outputEventSupported + * @param bool $hangupEventSupported + * @param bool $changeUserStatusUrl + * + * @return WC_Retailcrm_Response + */ + public function telephonySettingsEdit( + $code, + $clientId, + $active = false, + $name = false, + $makeCallUrl = false, + $image = false, + $additionalCodes = array(), + $externalPhones = array(), + $allowEdit = false, + $inputEventSupported = false, + $outputEventSupported = false, + $hangupEventSupported = false, + $changeUserStatusUrl = false + ) + { + if (!isset($code)) { + throw new \InvalidArgumentException('Code must be set'); + } + + $parameters['code'] = $code; + + if (!isset($clientId)) { + throw new \InvalidArgumentException('client id must be set'); + } + + $parameters['clientId'] = $clientId; + + if (!isset($active)) { + $parameters['active'] = false; + } else { + $parameters['active'] = $active; + } + + if (!isset($name)) { + throw new \InvalidArgumentException('name must be set'); + } + + if (isset($name)) { + $parameters['name'] = $name; + } + + if (isset($makeCallUrl)) { + $parameters['makeCallUrl'] = $makeCallUrl; + } + + if (isset($image)) { + $parameters['image'] = $image; + } + + if (isset($additionalCodes)) { + $parameters['additionalCodes'] = $additionalCodes; + } + + if (isset($externalPhones)) { + $parameters['externalPhones'] = $externalPhones; + } + + if (isset($allowEdit)) { + $parameters['allowEdit'] = $allowEdit; + } + + if (isset($inputEventSupported)) { + $parameters['inputEventSupported'] = $inputEventSupported; + } + + if (isset($outputEventSupported)) { + $parameters['outputEventSupported'] = $outputEventSupported; + } + + if (isset($hangupEventSupported)) { + $parameters['hangupEventSupported'] = $hangupEventSupported; + } + + if (isset($changeUserStatusUrl)) { + $parameters['changeUserStatusUrl'] = $changeUserStatusUrl; + } + + return $this->client->makeRequest( + "/telephony/setting/$code/edit", + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($parameters)) + ); + } + + /** + * Call event + * + * @param string $phone phone number + * @param string $type call type + * @param array $codes + * @param string $hangupStatus + * @param string $externalPhone + * @param array $webAnalyticsData + * + * @return WC_Retailcrm_Response + * @internal param string $code additional phone code + * @internal param string $status call status + * + */ + public function telephonyCallEvent( + $phone, + $type, + $codes, + $hangupStatus, + $externalPhone = null, + $webAnalyticsData = array() + ) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + if (!isset($type)) { + throw new \InvalidArgumentException('Type must be set (in|out|hangup)'); + } + + if (empty($codes)) { + throw new \InvalidArgumentException('Codes array must be set'); + } + + $parameters['phone'] = $phone; + $parameters['type'] = $type; + $parameters['codes'] = $codes; + $parameters['hangupStatus'] = $hangupStatus; + $parameters['callExternalId'] = $externalPhone; + $parameters['webAnalyticsData'] = $webAnalyticsData; + + + return $this->client->makeRequest( + '/telephony/call/event', + WC_Retailcrm_Request::METHOD_POST, + array('event' => json_encode($parameters)) + ); + } + + /** + * Upload calls + * + * @param array $calls calls data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function telephonyCallsUpload(array $calls) + { + if (!count($calls)) { + throw new \InvalidArgumentException( + 'Parameter `calls` must contains array of the calls' + ); + } + + return $this->client->makeRequest( + '/telephony/calls/upload', + WC_Retailcrm_Request::METHOD_POST, + array('calls' => json_encode($calls)) + ); + } + + /** + * Get call manager + * + * @param string $phone phone number + * @param bool $details detailed information + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function telephonyCallManager($phone, $details) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + $parameters['phone'] = $phone; + $parameters['details'] = isset($details) ? $details : 0; + + return $this->client->makeRequest( + '/telephony/manager', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Edit marketplace configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function marketplaceSettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/marketplace/external/setting/%s/edit', $configuration['code']), + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + + /** + * Update CRM basic statistic + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statisticUpdate() + { + return $this->client->makeRequest( + '/statistic/update', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Return current site + * + * @return string + */ + public function getSite() + { + return $this->siteCode; + } + + /** + * Set site + * + * @param string $site site code + * + * @return void + */ + public function setSite($site) + { + $this->siteCode = $site; + } + + /** + * Check ID parameter + * + * @param string $by identify by + * + * @throws \InvalidArgumentException + * + * @return bool + */ + protected function checkIdParameter($by) + { + $allowedForBy = array( + 'externalId', + 'id' + ); + + if (!in_array($by, $allowedForBy, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Value "%s" for "by" param is not valid. Allowed values are %s.', + $by, + implode(', ', $allowedForBy) + ) + ); + } + + return true; + } + + /** + * Fill params by site value + * + * @param string $site site code + * @param array $params input parameters + * + * @return array + */ + protected function fillSite($site, array $params) + { + if ($site) { + $params['site'] = $site; + } elseif ($this->siteCode) { + $params['site'] = $this->siteCode; + } + + return $params; + } +} diff --git a/src/include/api/class-wc-retailcrm-client-v5.php b/src/include/api/class-wc-retailcrm-client-v5.php new file mode 100644 index 0000000..222f784 --- /dev/null +++ b/src/include/api/class-wc-retailcrm-client-v5.php @@ -0,0 +1,2409 @@ + + * @license https://opensource.org/licenses/MIT MIT License + * @link http://retailcrm.ru/docs/Developers/ApiVersion5 + */ + +if ( ! class_exists( 'WC_Retailcrm_Request' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-request.php' ); +} + +if ( ! class_exists( 'WC_Retailcrm_Response' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-response.php' ); +} + +class WC_Retailcrm_Client_V5 +{ + protected $client; + + /** + * Site code + */ + protected $siteCode; + + /** + * Client creating + * + * @param string $url api url + * @param string $apiKey api key + * @param string $site site code + * + * @throws \InvalidArgumentException + * + */ + public function __construct($url, $apiKey, $version = null, $site = null) + { + if ('/' !== $url[strlen($url) - 1]) { + $url .= '/'; + } + + $url = $version == null ? $url . 'api' : $url . 'api/' . $version; + + $this->client = new WC_Retailcrm_Request($url, array('apiKey' => $apiKey)); + $this->siteCode = $site; + } + + /** + * Returns api versions list + * + * @return WC_Retailcrm_Response + */ + public function apiVersions() + { + return $this->client->makeRequest('/api-versions', WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Returns users list + * + * @param array $filter + * @param null $page + * @param null $limit + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function usersList(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; + } + + return $this->client->makeRequest( + '/users', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Returns user data + * + * @param integer $id user ID + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function usersGet($id) + { + return $this->client->makeRequest("/users/$id", WC_Retailcrm_Request::METHOD_GET); + } + + /** + * Change user status + * + * @param integer $id user ID + * @param string $status user status + * + * @return WC_Retailcrm_Response + */ + public function usersStatus($id, $status) + { + $statuses = array("free", "busy", "dinner", "break"); + + if (empty($status) || !in_array($status, $statuses)) { + throw new \InvalidArgumentException( + 'Parameter `status` must be not empty & must be equal one of these values: free|busy|dinner|break' + ); + } + + return $this->client->makeRequest( + "/users/$id/status", + WC_Retailcrm_Request::METHOD_POST, + array('status' => $status) + ); + } + + /** + * Get segments list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return WC_Retailcrm_Response + */ + public function segmentsList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/segments', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get custom fields list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return WC_Retailcrm_Response + */ + public function customFieldsList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/custom-fields', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create custom field + * + * @param $entity + * @param $customField + * + * @return WC_Retailcrm_Response + */ + public function customFieldsCreate($entity, $customField) + { + if (!count($customField) || + empty($customField['code']) || + empty($customField['name']) || + empty($customField['type']) + ) { + 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( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/create", + WC_Retailcrm_Request::METHOD_POST, + array('customField' => json_encode($customField)) + ); + } + + /** + * Edit custom field + * + * @param $entity + * @param $customField + * + * @return WC_Retailcrm_Response + */ + public function customFieldsEdit($entity, $customField) + { + if (!count($customField) || empty($customField['code'])) { + throw new \InvalidArgumentException( + 'Parameter `customField` must contain a data & fields `code` must be set' + ); + } + + if (empty($entity) || $entity != 'customer' || $entity != 'order') { + throw new \InvalidArgumentException( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/edit/{$customField['code']}", + WC_Retailcrm_Request::METHOD_POST, + array('customField' => json_encode($customField)) + ); + } + + /** + * Get custom field + * + * @param $entity + * @param $code + * + * @return WC_Retailcrm_Response + */ + public function customFieldsGet($entity, $code) + { + if (empty($code)) { + throw new \InvalidArgumentException( + 'Parameter `code` must be not empty' + ); + } + + if (empty($entity) || $entity != 'customer' || $entity != 'order') { + throw new \InvalidArgumentException( + 'Parameter `entity` must contain a data & value must be `order` or `customer`' + ); + } + + return $this->client->makeRequest( + "/custom-fields/$entity/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Get custom dictionaries list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return WC_Retailcrm_Response + */ + public function customDictionariesList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/custom-fields/dictionaries', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create custom dictionary + * + * @param $customDictionary + * + * @return WC_Retailcrm_Response + */ + public function customDictionariesCreate($customDictionary) + { + if (!count($customDictionary) || + empty($customDictionary['code']) || + empty($customDictionary['elements']) + ) { + throw new \InvalidArgumentException( + 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/{$customDictionary['code']}/create", + WC_Retailcrm_Request::METHOD_POST, + array('customDictionary' => json_encode($customDictionary)) + ); + } + + /** + * Edit custom dictionary + * + * @param $customDictionary + * + * @return WC_Retailcrm_Response + */ + public function customDictionariesEdit($customDictionary) + { + if (!count($customDictionary) || + empty($customDictionary['code']) || + empty($customDictionary['elements']) + ) { + throw new \InvalidArgumentException( + 'Parameter `dictionary` must contain a data & fields `code` & `elemets` must be set' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/{$customDictionary['code']}/edit", + WC_Retailcrm_Request::METHOD_POST, + array('customDictionary' => json_encode($customDictionary)) + ); + } + + /** + * Get custom dictionary + * + * @param $code + * + * @return WC_Retailcrm_Response + */ + public function customDictionariesGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException( + 'Parameter `code` must be not empty' + ); + } + + return $this->client->makeRequest( + "/custom-fields/dictionaries/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Returns filtered orders 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 ordersList(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; + } + + return $this->client->makeRequest( + '/orders', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create a order + * + * @param array $order order data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersCreate(array $order, $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('order' => json_encode($order))) + ); + } + + /** + * Save order IDs' (id and externalId) association in the CRM + * + * @param array $ids order identificators + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/orders/fix-external-ids', + WC_Retailcrm_Request::METHOD_POST, + array('orders' => json_encode($ids) + ) + ); + } + + /** + * Returns statuses of the orders + * + * @param array $ids (default: array()) + * @param array $externalIds (default: array()) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersStatuses(array $ids = array(), array $externalIds = array()) + { + $parameters = array(); + + if (count($ids)) { + $parameters['ids'] = $ids; + } + if (count($externalIds)) { + $parameters['externalIds'] = $externalIds; + } + + return $this->client->makeRequest( + '/orders/statuses', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Upload array of the orders + * + * @param array $orders array of orders + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersUpload(array $orders, $site = null) + { + if (!count($orders)) { + throw new \InvalidArgumentException( + 'Parameter `orders` must contains array of the orders' + ); + } + + return $this->client->makeRequest( + '/orders/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('orders' => json_encode($orders))) + ); + } + + /** + * Get order by id or externalId + * + * @param string $id order identificator + * @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 ordersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/orders/$id", + WC_Retailcrm_Request::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a order + * + * @param array $order order 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 ordersEdit(array $order, $by = 'externalId', $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $order)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/%s/edit', $order[$by]), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('order' => json_encode($order), 'by' => $by) + ) + ); + } + + /** + * Get orders history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return WC_Retailcrm_Response + */ + public function ordersHistory(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; + } + + return $this->client->makeRequest( + '/orders/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Combine orders + * + * @param string $technique + * @param array $order + * @param array $resultOrder + * + * @return WC_Retailcrm_Response + */ + public function ordersCombine($order, $resultOrder, $technique = 'ours') + { + $techniques = array('ours', 'summ', 'theirs'); + + if (!count($order) || !count($resultOrder)) { + throw new \InvalidArgumentException( + 'Parameters `order` & `resultOrder` must contains a data' + ); + } + + if (!in_array($technique, $techniques)) { + throw new \InvalidArgumentException( + 'Parameter `technique` must be on of ours|summ|theirs' + ); + } + + return $this->client->makeRequest( + '/orders/combine', + WC_Retailcrm_Request::METHOD_POST, + array( + 'technique' => $technique, + 'order' => json_encode($order), + 'resultOrder' => json_encode($resultOrder) + ) + ); + } + + /** + * Create an order payment + * + * @param array $payment order data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPaymentCreate(array $payment) + { + if (!count($payment)) { + throw new \InvalidArgumentException( + 'Parameter `payment` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/payments/create', + WC_Retailcrm_Request::METHOD_POST, + array('payment' => json_encode($payment)) + ); + } + + /** + * Edit an order payment + * + * @param array $payment order data + * @param string $by by key + * @param null $site site code + * + * @return WC_Retailcrm_Response + */ + public function ordersPaymentEdit(array $payment, $by = 'externalId', $site = null) + { + if (!count($payment)) { + throw new \InvalidArgumentException( + 'Parameter `payment` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $payment)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/payments/%s/edit', $payment[$by]), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('payment' => json_encode($payment), 'by' => $by) + ) + ); + } + + /** + * Edit an order payment + * + * @param string $id payment id + * + * @return WC_Retailcrm_Response + */ + public function ordersPaymentDelete($id) + { + if (!$id) { + throw new \InvalidArgumentException( + 'Parameter `id` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/orders/payments/%s/delete', $id), + WC_Retailcrm_Request::METHOD_POST + ); + } + + /** + * Returns filtered 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 customersList(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; + } + + return $this->client->makeRequest( + '/customers', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create a customer + * + * @param array $customer 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 customersCreate(array $customer, $site = null) + { + if (! count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + return $this->client->makeRequest( + '/customers/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('customer' => json_encode($customer))) + ); + } + + /** + * Save 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 customersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/customers/fix-external-ids', + WC_Retailcrm_Request::METHOD_POST, + array('customers' => json_encode($ids)) + ); + } + + /** + * Upload array of the customers + * + * @param array $customers array of customers + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersUpload(array $customers, $site = null) + { + if (! count($customers)) { + throw new \InvalidArgumentException( + 'Parameter `customers` must contains array of the customers' + ); + } + + return $this->client->makeRequest( + '/customers/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('customers' => json_encode($customers))) + ); + } + + /** + * Get customer by id or externalId + * + * @param string $id customer identificator + * @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 customersGet($id, $by = 'externalId', $site = null) + { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/customers/$id", + WC_Retailcrm_Request::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a customer + * + * @param array $customer 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 customersEdit(array $customer, $by = 'externalId', $site = null) + { + if (!count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $customer)) { + throw new \InvalidArgumentException( + sprintf('Customer array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/customers/%s/edit', $customer[$by]), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('customer' => json_encode($customer), 'by' => $by) + ) + ); + } + + /** + * Get customers history + * @param array $filter + * @param null $page + * @param null $limit + * + * @return WC_Retailcrm_Response + */ + public function customersHistory(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; + } + + return $this->client->makeRequest( + '/customers/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Combine customers + * + * @param array $customers + * @param array $resultCustomer + * + * @return WC_Retailcrm_Response + */ + public function customersCombine(array $customers, $resultCustomer) + { + + if (!count($customers) || !count($resultCustomer)) { + throw new \InvalidArgumentException( + 'Parameters `customers` & `resultCustomer` must contains a data' + ); + } + + return $this->client->makeRequest( + '/customers/combine', + WC_Retailcrm_Request::METHOD_POST, + array( + 'customers' => json_encode($customers), + 'resultCustomer' => json_encode($resultCustomer) + ) + ); + } + + /** + * Returns filtered 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 customersNotesList(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; + } + return $this->client->makeRequest( + '/customers/notes', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create 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 customersNotesCreate($note, $site = null) + { + if (empty($note['customer']['id']) && empty($note['customer']['externalId'])) { + throw new \InvalidArgumentException( + 'Customer identifier must be set' + ); + } + return $this->client->makeRequest( + '/customers/notes/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('note' => json_encode($note))) + ); + } + + /** + * Delete customer note + * + * @param integer $id + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function customersNotesDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException( + 'Note id must be set' + ); + } + return $this->client->makeRequest( + "/customers/notes/$id/delete", + WC_Retailcrm_Request::METHOD_POST + ); + } + + /** + * Get orders assembly 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 ordersPacksList(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; + } + + return $this->client->makeRequest( + '/orders/packs', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksCreate(array $pack, $site = null) + { + if (!count($pack)) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data' + ); + } + + return $this->client->makeRequest( + '/orders/packs/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get orders assembly history + * + * @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 ordersPacksHistory(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; + } + + return $this->client->makeRequest( + '/orders/packs/history', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + "/orders/packs/$id", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Delete orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/delete', $id), + WC_Retailcrm_Request::METHOD_POST + ); + } + + /** + * Edit orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function ordersPacksEdit(array $pack, $site = null) + { + if (!count($pack) || empty($pack['id'])) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data & pack `id` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/edit', $pack['id']), + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get tasks list + * + * @param array $filter + * @param null $limit + * @param null $page + * + * @return WC_Retailcrm_Response + */ + public function tasksList(array $filter = array(), $limit = null, $page = null) + { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/tasks', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Create task + * + * @param array $task + * @param null $site + * + * @return WC_Retailcrm_Response + * + */ + public function tasksCreate($task, $site = null) + { + if (!count($task)) { + throw new \InvalidArgumentException( + 'Parameter `task` must contain a data' + ); + } + + return $this->client->makeRequest( + "/tasks/create", + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('task' => json_encode($task)) + ) + ); + } + + /** + * Edit task + * + * @param array $task + * @param null $site + * + * @return WC_Retailcrm_Response + * + */ + public function tasksEdit($task, $site = null) + { + if (!count($task)) { + throw new \InvalidArgumentException( + 'Parameter `task` must contain a data' + ); + } + + return $this->client->makeRequest( + "/tasks/{$task['id']}/edit", + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite( + $site, + array('task' => json_encode($task)) + ) + ); + } + + /** + * Get custom dictionary + * + * @param $id + * + * @return WC_Retailcrm_Response + */ + public function tasksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException( + 'Parameter `id` must be not empty' + ); + } + + return $this->client->makeRequest( + "/tasks/$id", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Get products groups + * + * @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 storeProductsGroups(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; + } + + return $this->client->makeRequest( + '/store/product-groups', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get purchace prices & stock balance + * + * @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 storeInventories(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; + } + + return $this->client->makeRequest( + '/store/inventories', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get store settings + * + * @param string $code get settings code + * + * @return WC_Retailcrm_Response + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function storeSettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/store/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit store configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function storeSettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/store/setting/%s/edit', $configuration['code']), + WC_Retailcrm_Request::METHOD_POST, + $configuration + ); + } + + /** + * Upload store inventories + * + * @param array $offers offers data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storeInventoriesUpload(array $offers, $site = null) + { + if (!count($offers)) { + throw new \InvalidArgumentException( + 'Parameter `offers` must contains array of the offers' + ); + } + + return $this->client->makeRequest( + '/store/inventories/upload', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, array('offers' => json_encode($offers))) + ); + } + + /** + * Get products + * + * @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 storeProducts(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; + } + + return $this->client->makeRequest( + '/store/products', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Get delivery settings + * + * @param string $code + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliverySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/delivery/generic/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit delivery configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function deliverySettingsEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/setting/%s/edit', $configuration['code']), + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($configuration)) + ); + } + + /** + * Delivery tracking update + * + * @param string $code + * @param array $statusUpdate + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function deliveryTracking($code, array $statusUpdate) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + if (!count($statusUpdate)) { + throw new \InvalidArgumentException( + 'Parameter `statusUpdate` must contains a data' + ); + } + + return $this->client->makeRequest( + sprintf('/delivery/generic/%s/tracking', $code), + WC_Retailcrm_Request::METHOD_POST, + $statusUpdate + ); + } + + /** + * Returns available county list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function countriesList() + { + return $this->client->makeRequest( + '/reference/countries', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Returns deliveryServices list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryServicesList() + { + return $this->client->makeRequest( + '/reference/delivery-services', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit deliveryService + * + * @param array $data delivery service data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryServicesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-services/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('deliveryService' => json_encode($data)) + ); + } + + /** + * Returns deliveryTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryTypesList() + { + return $this->client->makeRequest( + '/reference/delivery-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit deliveryType + * + * @param array $data delivery type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function deliveryTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/delivery-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('deliveryType' => json_encode($data)) + ); + } + + /** + * Returns orderMethods list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderMethodsList() + { + return $this->client->makeRequest( + '/reference/order-methods', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit orderMethod + * + * @param array $data order method data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderMethodsEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-methods/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('orderMethod' => json_encode($data)) + ); + } + + /** + * Returns orderTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderTypesList() + { + return $this->client->makeRequest( + '/reference/order-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit orderType + * + * @param array $data order type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function orderTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/order-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('orderType' => json_encode($data)) + ); + } + + /** + * Returns paymentStatuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentStatusesList() + { + return $this->client->makeRequest( + '/reference/payment-statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit paymentStatus + * + * @param array $data payment status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('paymentStatus' => json_encode($data)) + ); + } + + /** + * Returns paymentTypes list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentTypesList() + { + return $this->client->makeRequest( + '/reference/payment-types', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit paymentType + * + * @param array $data payment type data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function paymentTypesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/payment-types/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('paymentType' => json_encode($data)) + ); + } + + /** + * Returns productStatuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function productStatusesList() + { + return $this->client->makeRequest( + '/reference/product-statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit productStatus + * + * @param array $data product status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function productStatusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/product-statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('productStatus' => json_encode($data)) + ); + } + + /** + * Returns sites list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function sitesList() + { + return $this->client->makeRequest( + '/reference/sites', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit site + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function sitesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/sites/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('site' => json_encode($data)) + ); + } + + /** + * Returns statusGroups list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusGroupsList() + { + return $this->client->makeRequest( + '/reference/status-groups', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Returns statuses list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusesList() + { + return $this->client->makeRequest( + '/reference/statuses', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit order status + * + * @param array $data status data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/statuses/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('status' => json_encode($data)) + ); + } + + /** + * Returns stores list + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storesList() + { + return $this->client->makeRequest( + '/reference/stores', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit store + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function storesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/stores/%s/edit', $data['code']), + WC_Retailcrm_Request::METHOD_POST, + array('store' => json_encode($data)) + ); + } + + /** + * Get telephony settings + * + * @param string $code + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function telephonySettingsGet($code) + { + if (empty($code)) { + throw new \InvalidArgumentException('Parameter `code` must be set'); + } + + return $this->client->makeRequest( + "/telephony/setting/$code", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Edit telephony settings + * + * @param string $code symbolic code + * @param string $clientId client id + * @param boolean $active telephony activity + * @param mixed $name service name + * @param mixed $makeCallUrl service init url + * @param mixed $image service logo url(svg file) + * + * @param array $additionalCodes + * @param array $externalPhones + * @param bool $allowEdit + * @param bool $inputEventSupported + * @param bool $outputEventSupported + * @param bool $hangupEventSupported + * @param bool $changeUserStatusUrl + * + * @return WC_Retailcrm_Response + */ + public function telephonySettingsEdit( + $code, + $clientId, + $active = false, + $name = false, + $makeCallUrl = false, + $image = false, + $additionalCodes = array(), + $externalPhones = array(), + $allowEdit = false, + $inputEventSupported = false, + $outputEventSupported = false, + $hangupEventSupported = false, + $changeUserStatusUrl = false + ) + { + if (!isset($code)) { + throw new \InvalidArgumentException('Code must be set'); + } + + $parameters['code'] = $code; + + if (!isset($clientId)) { + throw new \InvalidArgumentException('client id must be set'); + } + + $parameters['clientId'] = $clientId; + + if (!isset($active)) { + $parameters['active'] = false; + } else { + $parameters['active'] = $active; + } + + if (!isset($name)) { + throw new \InvalidArgumentException('name must be set'); + } + + if (isset($name)) { + $parameters['name'] = $name; + } + + if (isset($makeCallUrl)) { + $parameters['makeCallUrl'] = $makeCallUrl; + } + + if (isset($image)) { + $parameters['image'] = $image; + } + + if (isset($additionalCodes)) { + $parameters['additionalCodes'] = $additionalCodes; + } + + if (isset($externalPhones)) { + $parameters['externalPhones'] = $externalPhones; + } + + if (isset($allowEdit)) { + $parameters['allowEdit'] = $allowEdit; + } + + if (isset($inputEventSupported)) { + $parameters['inputEventSupported'] = $inputEventSupported; + } + + if (isset($outputEventSupported)) { + $parameters['outputEventSupported'] = $outputEventSupported; + } + + if (isset($hangupEventSupported)) { + $parameters['hangupEventSupported'] = $hangupEventSupported; + } + + if (isset($changeUserStatusUrl)) { + $parameters['changeUserStatusUrl'] = $changeUserStatusUrl; + } + + return $this->client->makeRequest( + "/telephony/setting/$code/edit", + WC_Retailcrm_Request::METHOD_POST, + array('configuration' => json_encode($parameters)) + ); + } + + /** + * Call event + * + * @param string $phone phone number + * @param string $type call type + * @param array $codes + * @param string $hangupStatus + * @param string $externalPhone + * @param array $webAnalyticsData + * + * @return WC_Retailcrm_Response + * @internal param string $code additional phone code + * @internal param string $status call status + * + */ + public function telephonyCallEvent( + $phone, + $type, + $codes, + $hangupStatus, + $externalPhone = null, + $webAnalyticsData = array() + ) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + if (!isset($type)) { + throw new \InvalidArgumentException('Type must be set (in|out|hangup)'); + } + + if (empty($codes)) { + throw new \InvalidArgumentException('Codes array must be set'); + } + + $parameters['phone'] = $phone; + $parameters['type'] = $type; + $parameters['codes'] = $codes; + $parameters['hangupStatus'] = $hangupStatus; + $parameters['callExternalId'] = $externalPhone; + $parameters['webAnalyticsData'] = $webAnalyticsData; + + + return $this->client->makeRequest( + '/telephony/call/event', + WC_Retailcrm_Request::METHOD_POST, + array('event' => json_encode($parameters)) + ); + } + + /** + * Upload calls + * + * @param array $calls calls data + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function telephonyCallsUpload(array $calls) + { + if (!count($calls)) { + throw new \InvalidArgumentException( + 'Parameter `calls` must contains array of the calls' + ); + } + + return $this->client->makeRequest( + '/telephony/calls/upload', + WC_Retailcrm_Request::METHOD_POST, + array('calls' => json_encode($calls)) + ); + } + + /** + * Get call manager + * + * @param string $phone phone number + * @param bool $details detailed information + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function telephonyCallManager($phone, $details) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + $parameters['phone'] = $phone; + $parameters['details'] = isset($details) ? $details : 0; + + return $this->client->makeRequest( + '/telephony/manager', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** + * Edit module configuration + * + * @param array $configuration + * + * @throws WC_Retailcrm_Exception_Json + * @throws WC_Retailcrm_Exception_Curl + * @throws \InvalidArgumentException + * + * @return WC_Retailcrm_Response + */ + public function integrationModulesEdit(array $configuration) + { + if (!count($configuration) || empty($configuration['code'])) { + throw new \InvalidArgumentException( + 'Parameter `configuration` must contains a data & configuration `code` must be set' + ); + } + + $code = $configuration['code']; + + return $this->client->makeRequest( + "/integration-modules/$code/edit", + WC_Retailcrm_Request::METHOD_POST, + array('integrationModule' => json_encode($configuration)) + ); + } + + /** + * Update CRM basic statistic + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * @throws WC_Retailcrm_Exception_Json + * + * @return WC_Retailcrm_Response + */ + public function statisticUpdate() + { + return $this->client->makeRequest( + '/statistic/update', + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** + * Return current site + * + * @return string + */ + public function getSite() + { + return $this->siteCode; + } + + /** + * Set site + * + * @param string $site site code + * + * @return void + */ + public function setSite($site) + { + $this->siteCode = $site; + } + + /** + * Check ID parameter + * + * @param string $by identify by + * + * @throws \InvalidArgumentException + * + * @return bool + */ + protected function checkIdParameter($by) + { + $allowedForBy = array( + 'externalId', + 'id' + ); + + if (!in_array($by, $allowedForBy, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Value "%s" for "by" param is not valid. Allowed values are %s.', + $by, + implode(', ', $allowedForBy) + ) + ); + } + + return true; + } + + /** + * Fill params by site value + * + * @param string $site site code + * @param array $params input parameters + * + * @return array + */ + protected function fillSite($site, array $params) + { + if ($site) { + $params['site'] = $site; + } elseif ($this->siteCode) { + $params['site'] = $this->siteCode; + } + + return $params; + } +} diff --git a/src/include/api/class-wc-retailcrm-exception-curl.php b/src/include/api/class-wc-retailcrm-exception-curl.php new file mode 100644 index 0000000..177cd3b --- /dev/null +++ b/src/include/api/class-wc-retailcrm-exception-curl.php @@ -0,0 +1,16 @@ + + * @license https://opensource.org/licenses/MIT MIT License + * @link http://retailcrm.ru/docs/Developers/ApiVersion4 + */ +class WC_Retailcrm_Exception_Curl extends \RuntimeException +{ +} diff --git a/src/include/api/class-wc-retailcrm-exception-json.php b/src/include/api/class-wc-retailcrm-exception-json.php new file mode 100644 index 0000000..403adf2 --- /dev/null +++ b/src/include/api/class-wc-retailcrm-exception-json.php @@ -0,0 +1,16 @@ + + * @license https://opensource.org/licenses/MIT MIT License + */ + +class WC_Retailcrm_Exception_Json extends \DomainException +{ +} diff --git a/src/include/api/class-wc-retailcrm-proxy.php b/src/include/api/class-wc-retailcrm-proxy.php new file mode 100644 index 0000000..6be9439 --- /dev/null +++ b/src/include/api/class-wc-retailcrm-proxy.php @@ -0,0 +1,78 @@ +logger = new WC_Logger(); + + if ( ! class_exists( 'WC_Retailcrm_Client_V4' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-client-v4.php' ); + } + + 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; + } + } + + public function __call($method, $arguments) + { + try { + $response = call_user_func_array(array($this->retailcrm, $method), $arguments); + + if ($response->isSuccessful()) { + $result = ' Ok'; + } else { + $result = sprintf( + $method ." : Error: [HTTP-code %s] %s", + $response->getStatusCode(), + $response->getErrorMsg() + ); + + if (isset($response['errors'])) { + foreach ($response['errors'] as $error) { + $result .= " $error"; + } + } + } + + $this->logger->add('retailcrm', sprintf("[%s] %s", $method, $result)); + } catch (WC_Retailcrm_Exception_Curl $exception) { + $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + } catch (WC_Retailcrm_Exception_Json $exception) { + $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + } catch (InvalidArgumentException $exception) { + $this->logger->add('retailcrm', sprintf("[%s] %s - %s", $method, $exception->getMessage(), $result)); + } + + return $response; + } + } +endif; \ No newline at end of file diff --git a/src/include/api/class-wc-retailcrm-request.php b/src/include/api/class-wc-retailcrm-request.php new file mode 100644 index 0000000..a70420c --- /dev/null +++ b/src/include/api/class-wc-retailcrm-request.php @@ -0,0 +1,116 @@ + + * @license https://opensource.org/licenses/MIT MIT License + */ + +if ( ! class_exists( 'WC_Retailcrm_Exception_Curl' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-exception-curl.php' ); +} + +if ( ! class_exists( 'WC_Retailcrm_Response' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-response.php' ); +} + +class WC_Retailcrm_Request +{ + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; + + protected $url; + protected $defaultParameters; + + /** + * Client constructor. + * + * @param string $url api url + * @param array $defaultParameters array of parameters + * + * @throws \InvalidArgumentException + */ + public function __construct($url, array $defaultParameters = array()) + { + if (false === stripos($url, 'https://')) { + throw new \InvalidArgumentException( + 'API schema requires HTTPS protocol' + ); + } + + $this->url = $url; + $this->defaultParameters = $defaultParameters; + } + + /** + * Make HTTP request + * + * @param string $path request url + * @param string $method (default: 'GET') + * @param array $parameters (default: array()) + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * + * @throws \InvalidArgumentException + * @throws WC_Retailcrm_Exception_Curl + * + * @return WC_Retailcrm_Response + */ + public function makeRequest( + $path, + $method, + array $parameters = array() + ) { + $allowedMethods = array(self::METHOD_GET, self::METHOD_POST); + + if (!in_array($method, $allowedMethods, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Method "%s" is not valid. Allowed methods are %s', + $method, + implode(', ', $allowedMethods) + ) + ); + } + + $parameters = array_merge($this->defaultParameters, $parameters); + + $url = $this->url . $path; + + if (self::METHOD_GET === $method && count($parameters)) { + $url .= '?' . http_build_query($parameters, '', '&'); + } + + $curlHandler = curl_init(); + curl_setopt($curlHandler, CURLOPT_URL, $url); + curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curlHandler, CURLOPT_FAILONERROR, false); + curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($curlHandler, CURLOPT_TIMEOUT, 30); + curl_setopt($curlHandler, CURLOPT_CONNECTTIMEOUT, 30); + + if (self::METHOD_POST === $method) { + curl_setopt($curlHandler, CURLOPT_POST, true); + curl_setopt($curlHandler, CURLOPT_POSTFIELDS, $parameters); + } + + $responseBody = curl_exec($curlHandler); + $statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE); + $errno = curl_errno($curlHandler); + $error = curl_error($curlHandler); + + curl_close($curlHandler); + + if ($errno) { + throw new WC_Retailcrm_Exception_Curl($error, $errno); + } + + return new WC_Retailcrm_Response($statusCode, $responseBody); + } +} diff --git a/src/include/api/class-wc-retailcrm-response.php b/src/include/api/class-wc-retailcrm-response.php new file mode 100644 index 0000000..e9e8ed9 --- /dev/null +++ b/src/include/api/class-wc-retailcrm-response.php @@ -0,0 +1,169 @@ + + * @license https://opensource.org/licenses/MIT MIT License + */ + +if ( ! class_exists( 'WC_Retailcrm_Exception_Json' ) ) { + include_once( __DIR__ . '/class-wc-retailcrm-exception-json.php' ); +} + + +class WC_Retailcrm_Response implements \ArrayAccess +{ + // HTTP response status code + protected $statusCode; + + // response assoc array + protected $response; + + /** + * ApiResponse constructor. + * + * @param int $statusCode HTTP status code + * @param mixed $responseBody HTTP body + * + * @throws WC_Retailcrm_Exception_Json + */ + public function __construct($statusCode, $responseBody = null) + { + $this->statusCode = (int) $statusCode; + + if (!empty($responseBody)) { + $response = json_decode($responseBody, true); + + if (!$response && JSON_ERROR_NONE !== ($error = json_last_error())) { + throw new WC_Retailcrm_Exception_Json( + "Invalid JSON in the API response body. Error code #$error", + $error + ); + } + + $this->response = $response; + } + } + + /** + * Return HTTP response status code + * + * @return int + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * HTTP request was successful + * + * @return bool + */ + public function isSuccessful() + { + return $this->statusCode < 400; + } + + /** + * Allow to access for the property throw class method + * + * @param string $name method name + * @param mixed $arguments method parameters + * + * @throws \InvalidArgumentException + * + * @return mixed + */ + public function __call($name, $arguments) + { + // convert getSomeProperty to someProperty + $propertyName = strtolower(substr($name, 3, 1)) . substr($name, 4); + + if (!isset($this->response[$propertyName])) { + throw new \InvalidArgumentException("Method \"$name\" not found"); + } + + return $this->response[$propertyName]; + } + + /** + * Allow to access for the property throw object property + * + * @param string $name property name + * + * @throws \InvalidArgumentException + * + * @return mixed + */ + public function __get($name) + { + if (!isset($this->response[$name])) { + throw new \InvalidArgumentException("Property \"$name\" not found"); + } + + return $this->response[$name]; + } + + /** + * Offset set + * + * @param mixed $offset offset + * @param mixed $value value + * + * @throws \BadMethodCallException + * @return void + */ + public function offsetSet($offset, $value) + { + throw new \BadMethodCallException('This activity not allowed'); + } + + /** + * Offset unset + * + * @param mixed $offset offset + * + * @throws \BadMethodCallException + * @return void + */ + public function offsetUnset($offset) + { + throw new \BadMethodCallException('This call not allowed'); + } + + /** + * Check offset + * + * @param mixed $offset offset + * + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->response[$offset]); + } + + /** + * Get offset + * + * @param mixed $offset offset + * + * @throws \InvalidArgumentException + * + * @return mixed + */ + public function offsetGet($offset) + { + if (!isset($this->response[$offset])) { + throw new \InvalidArgumentException("Property \"$offset\" not found"); + } + + return $this->response[$offset]; + } +} diff --git a/src/include/api/index.php b/src/include/api/index.php new file mode 100644 index 0000000..e71af0e --- /dev/null +++ b/src/include/api/index.php @@ -0,0 +1 @@ +apiClient = $this->getApiClient(); + } else { + $this->apiClient = $retailcrm; + $this->init_settings_fields(); + } + + if (!class_exists('WC_Retailcrm_Orders')) { + include_once(static::checkCustomFile('orders')); + } + + if (!class_exists('WC_Retailcrm_Customers')) { + include_once(static::checkCustomFile('customers')); + } + + $this->customers = new WC_Retailcrm_Customers( + $this->apiClient, + $this->settings, + new WC_Retailcrm_Customer_Address + ); + + $this->orders = new WC_Retailcrm_Orders( + $this->apiClient, + $this->settings, + new WC_Retailcrm_Order_Item($this->settings), + new WC_Retailcrm_Order_Address, + $this->customers, + new WC_Retailcrm_Order($this->settings), + new WC_Retailcrm_Order_Payment($this->settings) + ); + + // Actions. + add_action('woocommerce_update_options_integration_' . $this->id, array($this, 'process_admin_options')); + add_filter('woocommerce_settings_api_sanitized_fields_' . $this->id, array($this, 'api_sanitized')); + add_action('admin_bar_menu', array($this, 'add_retailcrm_button'), 100 ); + add_action('woocommerce_checkout_order_processed', array($this, 'retailcrm_process_order'), 10, 1); + add_action('retailcrm_history', array($this, 'retailcrm_history_get')); + add_action('retailcrm_icml', array($this, 'generate_icml')); + add_action('retailcrm_inventories', array($this, 'load_stocks')); + add_action('wp_ajax_do_upload', array($this, 'upload_to_crm')); + add_action('wp_ajax_generate_icml', array($this, 'generate_icml')); + add_action('wp_ajax_order_upload', array($this, 'order_upload')); + add_action('admin_print_footer_scripts', array($this, 'ajax_upload'), 99); + add_action('admin_print_footer_scripts', array($this, 'ajax_generate_icml'), 99); + 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('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); + + if (!$this->get_option('deactivate_update_order') + || $this->get_option('deactivate_update_order') == static::NO + ) { + add_action('woocommerce_update_order', array($this, 'update_order'), 11, 1); + } + + // Deactivate hook + add_action('retailcrm_deactivate', array($this, 'deactivate')); + } + + /** + * Init settings fields + */ + public function init_settings_fields() + { + $this->init_form_fields(); + $this->init_settings(); + } + + /** + * @param $settings + * + * @return array + */ + public function api_sanitized($settings) + { + if (isset($settings['sync']) && $settings['sync'] == static::YES) { + if (!wp_next_scheduled('retailcrm_inventories')) { + wp_schedule_event(time(), 'fiveteen_minutes', 'retailcrm_inventories'); + } + } elseif (isset($settings['sync']) && $settings['sync'] == static::NO) { + wp_clear_scheduled_hook('retailcrm_inventories'); + } + + if (isset($settings['history']) && $settings['history'] == static::YES) { + if (!wp_next_scheduled('retailcrm_history')) { + wp_schedule_event(time(), 'five_minutes', 'retailcrm_history'); + } + } elseif (isset($settings['history']) && $settings['history'] == static::NO) { + wp_clear_scheduled_hook('retailcrm_history'); + } + + if (isset($settings['icml']) && $settings['icml'] == static::YES) { + if (!wp_next_scheduled('retailcrm_icml')) { + wp_schedule_event(time(), 'three_hours', 'retailcrm_icml'); + } + } elseif (isset($settings['icml']) && $settings['icml'] == static::NO) { + wp_clear_scheduled_hook('retailcrm_icml'); + } + + if (!$this->get_errors() && !get_option('retailcrm_active_in_crm')) { + $this->activate_integration($settings); + } + + return $settings; + } + + /** + * Check custom file + * + * @param string $file + * + * @return string + */ + public static function checkCustomFile($file) { + if (file_exists( WP_CONTENT_DIR . '/retailcrm-custom/class-wc-retailcrm-' . $file . '.php' )) { + return WP_CONTENT_DIR . '/retailcrm-custom/class-wc-retailcrm-' . $file . '.php'; + } + + return WP_PLUGIN_DIR . '/woo-retailcrm/include/class-wc-retailcrm-' . $file . '.php'; + } + + public function generate_icml() { + if (!class_exists('WC_Retailcrm_Icml')) { + require_once (static::checkCustomFile('icml')); + } + + $retailcrm_icml = new WC_Retailcrm_Icml(); + $retailcrm_icml->generate(); + } + + /** + * Get history + */ + public function retailcrm_history_get() { + if (!class_exists('WC_Retailcrm_History')) { + include_once(static::checkCustomFile('history')); + } + + $retailcrm_history = new WC_Retailcrm_History($this->apiClient); + $retailcrm_history->getHistory(); + } + + /** + * @param int $order_id + */ + public function retailcrm_process_order($order_id) { + $this->orders->orderCreate($order_id); + } + + /** + * Load stock from retailCRM + */ + public function load_stocks() { + if (!class_exists('WC_Retailcrm_Inventories')) { + include_once(static::checkCustomFile('inventories')); + } + + $inventories = new WC_Retailcrm_Inventories($this->apiClient); + $inventories->updateQuantity(); + } + + /** + * Upload selected orders + */ + public function order_upload() { + $ids = false; + + if (isset($_GET['order_ids_retailcrm'])) { + $ids = explode(',', $_GET['order_ids_retailcrm']); + } + + if ($ids) { + $this->orders->ordersUpload($ids, true); + } + } + + /** + * Upload archive customers and order to retailCRM + */ + public function upload_to_crm() + { + $options = array_filter(get_option(static::$option_key)); + + $this->customers->customersUpload(); + $this->orders->ordersUpload(); + + $options['uploads'] = static::YES; + update_option(static::$option_key, $options); + } + + /** + * Create customer in retailCRM + * @param int $customer_id + */ + public function create_customer($customer_id) + { + if (WC_Retailcrm_Plugin::history_running() === true) { + return; + } + + $this->customers->createCustomer($customer_id); + } + + /** + * Edit customer in retailCRM + * @param int $customer_id + */ + public function update_customer($customer_id) + { + if (WC_Retailcrm_Plugin::history_running() === true) { + return; + } + + $this->customers->updateCustomer($customer_id); + } + + /** + * Edit order in retailCRM + * @param int $order_id + */ + public function update_order($order_id) + { + if (WC_Retailcrm_Plugin::history_running() === true) { + return; + } + + $this->orders->updateOrder($order_id); + } + + /** + * Init google analytics code + */ + public function initialize_analytics() + { + if (!class_exists('WC_Retailcrm_Google_Analytics')) { + include_once(static::checkCustomFile('ga')); + } + + if ($this->get_option('ua') && $this->get_option('ua_code')) { + $retailcrm_analytics = WC_Retailcrm_Google_Analytics::getInstance($this->settings); + echo $retailcrm_analytics->initialize_analytics(); + } else { + echo ''; + } + } + + /** + * Google analytics send code + */ + public function send_analytics() + { + if (!class_exists('WC_Retailcrm_Google_Analytics')) { + include_once(static::checkCustomFile('ga')); + } + + if ($this->get_option('ua') == static::YES && $this->get_option('ua_code') && is_checkout()) { + $retailcrm_analytics = WC_Retailcrm_Google_Analytics::getInstance($this->settings); + echo $retailcrm_analytics->send_analytics(); + } else { + echo ''; + } + } + + /** + * Daemon collector + */ + public function initialize_daemon_collector() + { + if (!class_exists('WC_Retailcrm_Daemon_Collector')) { + include_once(static::checkCustomFile('daemon-collector')); + } + + if ($this->get_option('daemon_collector') == static::YES && $this->get_option('daemon_collector_key')) { + $retailcrm_daemon_collector = WC_Retailcrm_Daemon_Collector::getInstance($this->settings); + echo $retailcrm_daemon_collector->initialize_daemon_collector(); + } else { + echo ''; + } + } + + /** + * Get retailcrm api client + * + * @return bool|WC_Retailcrm_Proxy + */ + public function getApiClient() + { + if ($this->get_option('api_url') && $this->get_option('api_key')) { + return new WC_Retailcrm_Proxy( + $this->get_option('api_url'), + $this->get_option('api_key'), + $this->get_option('api_version') + ); + } + + return false; + } + + /** + * Deactivate module in marketplace retailCRM + * + * @return void + */ + public function deactivate() + { + $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); + delete_option('retailcrm_active_in_crm'); + } + + /** + * @param $settings + * + * @return void + */ + private function activate_integration($settings) + { + $client_id = get_option('retailcrm_client_id'); + + if (!$client_id) { + $client_id = uniqid(); + } + + if ($settings['api_url'] && $settings['api_key'] && $settings['api_version']) { + $api_client = new WC_Retailcrm_Proxy( + $settings['api_url'], + $settings['api_key'], + $settings['api_version'] + ); + + $result = WC_Retailcrm_Plugin::integration_module($api_client, $client_id, $settings['api_version']); + + if ($result) { + update_option('retailcrm_active_in_crm', true); + update_option('retailcrm_client_id', $client_id); + } + } + } + } +} diff --git a/src/include/class-wc-retailcrm-customers.php b/src/include/class-wc-retailcrm-customers.php new file mode 100644 index 0000000..f1adb1c --- /dev/null +++ b/src/include/class-wc-retailcrm-customers.php @@ -0,0 +1,238 @@ +retailcrm = $retailcrm; + $this->retailcrm_settings = $retailcrm_settings; + $this->customer_address = $customer_address; + } + + /** + * Upload customers to CRM + * + * @param array $ids + * @return array mixed + */ + public function customersUpload($ids = array()) + { + if (!$this->retailcrm) { + return null; + } + + $users = get_users(array('include' => $ids)); + $data_customers = array(); + + foreach ($users as $user) { + if (!\in_array(self::CUSTOMER_ROLE, $user->roles)) { + continue; + } + + $customer = $this->wcCustomerGet($user->ID); + $this->processCustomer($customer); + $data_customers[] = $this->customer; + } + + $data = \array_chunk($data_customers, 50); + + foreach ($data as $array_customers) { + $this->retailcrm->customersUpload($array_customers); + time_nanosleep(0, 250000000); + } + + return $data; + } + + /** + * Create customer in CRM + * + * @param int | WC_Customer $customer + * + * @return mixed + */ + public function createCustomer($customer) + { + if (!$this->retailcrm) { + return null; + } + + if (is_int($customer)) { + $customer = $this->wcCustomerGet($customer); + } + + if (!$customer instanceof WC_Customer) { + return null; + } + + if ($customer->get_role() == self::CUSTOMER_ROLE) { + $this->processCustomer($customer); + $response = $this->retailcrm->customersCreate($this->customer); + + if ($response->isSuccessful() && isset($response['id'])) { + return $response['id']; + } + } + + return null; + } + + /** + * Edit customer in CRM + * + * @param int $customer_id + * + * @return WC_Customer $customer + */ + public function updateCustomer($customer_id) + { + if (!$this->retailcrm) { + return; + } + + $customer = $this->wcCustomerGet($customer_id); + + if ($customer->get_role() == self::CUSTOMER_ROLE){ + $this->processCustomer($customer); + $this->retailcrm->customersEdit($this->customer); + } + + return $customer; + } + + /** + * Process customer + * + * @param WC_Customer $customer + * + * @return void + */ + protected function processCustomer($customer) + { + $createdAt = $customer->get_date_created(); + $firstName = $customer->get_first_name(); + $data_customer = array( + 'createdAt' => $createdAt->date('Y-m-d H:i:s'), + 'firstName' => $firstName ? $firstName : $customer->get_username(), + 'lastName' => $customer->get_last_name(), + 'email' => $customer->get_email(), + 'address' => $this->customer_address->build($customer)->get_data() + ); + + if ($customer->get_id() > 0) { + $data_customer['externalId'] = $customer->get_id(); + } + + if ($customer->get_billing_phone()) { + $data_customer['phones'][] = array( + 'number' => $customer->get_billing_phone() + ); + } + + $this->customer = apply_filters('retailcrm_process_customer', $data_customer, $customer); + } + + /** + * @param array $filter + * + * @return bool|array + */ + public function searchCustomer($filter) + { + if (isset($filter['id'])) { + $search = $this->retailcrm->customersGet($filter['id']); + } elseif (isset($filter['email'])) { + $search = $this->retailcrm->customersList(array('email' => $filter['email'])); + } + + if ($search->isSuccessful()) { + if (isset($search['customers'])) { + if (empty($search['customers'])) { + return false; + } + + $customer = reset($search['customers']); + } else { + $customer = $search['customer']; + } + + return $customer; + } + + return false; + } + + /** + * @param WC_Order $order + * + * @return WC_Customer + * @throws Exception + */ + public function buildCustomerFromOrderData($order) + { + $new_customer = new WC_Customer; + + foreach ($order->get_address('billing') as $prop => $value) { + $new_customer->{'set_billing_' . $prop}($value); + } + + $new_customer->set_first_name($order->get_billing_first_name()); + $new_customer->set_last_name($order->get_billing_last_name()); + $new_customer->set_email($order->get_billing_email()); + $new_customer->set_date_created($order->get_date_created()); + + return $new_customer; + } + + /** + * @param int $customer_id + * + * @return WC_Customer + */ + public function wcCustomerGet($customer_id) + { + return new WC_Customer($customer_id); + } + + /** + * @return array + */ + public function getCustomer() + { + return $this->customer; + } + } +endif; diff --git a/src/include/class-wc-retailcrm-daemon-collector.php b/src/include/class-wc-retailcrm-daemon-collector.php new file mode 100644 index 0000000..f21db44 --- /dev/null +++ b/src/include/class-wc-retailcrm-daemon-collector.php @@ -0,0 +1,106 @@ +options = $options; + } + + /** + * @return string + */ + public function initialize_daemon_collector() { + if (!$this->code) { + $this->buildHeader() + ->buildParams() + ->buildFooter(); + } + + return $this->code; + } + + /** + * @return $this + */ + private function buildHeader() { + $header = << + (function(_,r,e,t,a,i,l){_['retailCRMObject']=a;_[a]=_[a]||function(){(_[a].q=_[a].q||[]).push(arguments)};_[a].l=1*new Date();l=r.getElementsByTagName(e)[0];i=r.createElement(e);i.async=!0;i.src=t;l.parentNode.insertBefore(i,l)})(window,document,'script','https://collector.retailcrm.pro/w.js','_rc'); + +EOF; + + $this->code .= $header; + + return $this; + } + + /** + * @return $this + */ + private function buildParams() { + $params = array(); + + if ( + function_exists('WC') + && WC()->customer !== null + && WC()->customer->get_id() > 0 + ) { + $params['customerId'] = WC()->customer->get_id(); + } + + $this->code .= apply_filters('retailcrm_daemon_collector', '') . sprintf( + "\t_rc('create', '%s', %s);\n", + $this->options['daemon_collector_key'], + json_encode((object) $params) + ); + + return $this; + } + + /** + * @return $this + */ + private function buildFooter() { + $footer = << + +EOF; + + $this->code .= $footer; + + return $this; + } +} diff --git a/src/include/class-wc-retailcrm-ga.php b/src/include/class-wc-retailcrm-ga.php new file mode 100644 index 0000000..fe2be39 --- /dev/null +++ b/src/include/class-wc-retailcrm-ga.php @@ -0,0 +1,125 @@ +options = $options; + } + + /** + * @return string + */ + public function initialize_analytics() { + return apply_filters('retailcrm_initialize_analytics' ," + + "); + } + + /** + * @return string + */ + public function send_analytics() { + $js = ''; + + if (!isset($_GET['key'])) { + return $js; + } + + $order_id = wc_get_order_id_by_order_key($_GET['key']); + $order = wc_get_order($order_id); + + if (!$order) { + return $js; + } + + foreach ($order->get_items() as $item) { + $uid = ($item['variation_id'] > 0) ? $item['variation_id'] : $item['product_id']; + $_product = wc_get_product($uid); + + if ($_product) { + $order_item = array( + 'id' => $uid, + 'name' => $item['name'], + 'price' => (float)$_product->get_price(), + 'quantity' => $item['qty'], + ); + + $order_items[] = $order_item; + } + } + + $url = parse_url(get_site_url()); + $domain = $url['host']; + + $js .= " + "; + + return apply_filters('retailcrm_send_analytics', $js); + } + } +} diff --git a/src/include/class-wc-retailcrm-history.php b/src/include/class-wc-retailcrm-history.php new file mode 100644 index 0000000..6699d82 --- /dev/null +++ b/src/include/class-wc-retailcrm-history.php @@ -0,0 +1,740 @@ +retailcrm_settings = get_option(WC_Retailcrm_Base::$option_key); + + if (isset($this->retailcrm_settings['bind_by_sku']) + && $this->retailcrm_settings['bind_by_sku'] == WC_Retailcrm_Base::YES + ) { + $this->bind_field = 'xmlId'; + } + + if (isset($this->retailcrm_settings['order_methods'])) { + $this->order_methods = $this->retailcrm_settings['order_methods']; + unset($this->retailcrm_settings['order_methods']); + } + + $this->retailcrm = $retailcrm; + + $this->startDate = new DateTime(date('Y-m-d H:i:s', strtotime('-1 days', strtotime(date('Y-m-d H:i:s'))))); + $this->startDateOrders = $this->startDate; + $this->startDateCustomers = $this->startDate; + } + + /** + * Get history method + * + * @return void + */ + public function getHistory() + { + $orders_since_id = get_option('retailcrm_orders_history_since_id'); + $customers_since_id = get_option('retailcrm_customers_history_since_id'); + + if (!$orders_since_id && isset($this->retailcrm_settings['history_orders'])) { + $this->startDateOrders = new DateTime($this->retailcrm_settings['history_orders']); + } + + if (!$customers_since_id && isset($this->retailcrm_settings['history_customers'])) { + $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); + } + + /** + * History customers + * + * @param string $date + * @param int $since_id + * + * @return null + */ + protected function customersHistory($date, $since_id) + { + if ($since_id) { + $response = $this->retailcrm->customersHistory(array('sinceId' => $since_id)); + } else { + $response = $this->retailcrm->customersHistory(array('startDate' => $date)); + } + + if ($response->isSuccessful()) { + if (empty($response['history'])) { + return; + } + + $history = $response['history']; + $end_change = end($history); + $new_since_id = $end_change['id']; + + foreach ($history as $record) { + if ($record['source'] == 'api' && $record['apiKey']['current'] == true) { + continue; + } + + if (isset($record['customer']['externalId'])) { + $customer = new WC_Customer($record['customer']['externalId']); + + if ($customer->get_id() == 0) { + continue; + } + } + + WC_Retailcrm_Plugin::$history_run = true; + + if ($record['field'] == 'first_name' && isset($record['customer']['externalId'])) { + if ($record['newValue']){ + update_user_meta($record['customer']['externalId'], 'first_name', $record['newValue']); + } + } + + elseif ($record['field'] == 'last_name' && isset($record['customer']['externalId'])) { + if ($record['newValue']) { + update_user_meta($record['customer']['externalId'], 'last_name', $record['newValue']); + } + } + + 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', $new_since_id); + } + + /** + * History orders + * + * @param string $date + * @param int $since_id + * + * @return boolean + */ + protected function ordersHistory($date, $since_id) + { + $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)); + } + + if ($response->isSuccessful()) { + if (empty($response['history'])) { + return false; + } + + $history = $response['history']; + $last_change = end($history); + $historyAssembly = self::assemblyOrder($response['history']); + + WC_Retailcrm_Plugin::$history_run = true; + + foreach ($historyAssembly as $orderHistory) { + $order = apply_filters('retailcrm_history_before_save', $orderHistory); + + if (isset($order['deleted']) && $order['deleted'] == true) { + continue; + } + + try { + if (isset($order['externalId'])) { + $wc_order_id = $this->orderUpdate($order, $options); + } else { + $wc_order_id = $this->orderCreate($order, $options); + } + + $wc_order = wc_get_order($wc_order_id); + + if ($wc_order instanceof WC_Order) { + $this->update_total($wc_order); + } + } catch (Exception $exception) { + $logger = new WC_Logger(); + $logger->add('retailcrm', + sprintf("[%s] - %s", $exception->getMessage(), + 'Exception in file - ' . $exception->getFile() . ' on line ' . $exception->getLine()) + ); + + continue; + } + } + + update_option('retailcrm_orders_history_since_id', $last_change['id']); + WC_Retailcrm_Plugin::$history_run = false; + } + + return true; + } + + /** + * Update shipping + * + * @param array $order + * @param array $options + * @param WC_Order $wc_order + * + * @return boolean + */ + protected function updateShippingItemId($order, $options, $wc_order) + { + $create = false; + + $shippings = $wc_order->get_items('shipping'); + + if (!$shippings) { + $shipping = new WC_Order_Item_Shipping(); + $create = true; + } else { + $shipping = reset($shippings); + } + + $data_store = $shipping->get_data_store(); + + if (isset($order['delivery']['code'])) { + if (!isset($options[$order['delivery']['code']])) { + return false; + } + + $shipping_methods = get_wc_shipping_methods(); + $shipping->set_method_title($shipping_methods[$options[$order['delivery']['code']]]['name']); + $shipping->set_method_id($options[$order['delivery']['code']]); + } + + if (isset($order['delivery']['cost']) && !wc_tax_enabled()) { + $shipping->set_total($order['delivery']['cost']); + } + + if (isset($order['delivery']['netCost']) && wc_tax_enabled()) { + $shipping->set_total($order['delivery']['netCost']); + } + + if (isset($order['delivery']['service']['code'])) { + $service = retailcrm_get_delivery_service($shipping->get_method_id(), $order['delivery']['service']['code']); + + if ($service) { + $shipping->set_instance_id($order['delivery']['service']['code']); + } + } + + if ($create === true) { + $data_store->create($shipping); + $shipping->set_order_id($wc_order->get_id()); + } + + $data_store->update($shipping); + + return true; + } + + /** + * Calculate totals in order + * + * @param WC_Order $order + * + * @return void + */ + protected function update_total($order) + { + $order->calculate_totals(); + } + + /** + * Update order in WC + * + * @param array $order + * @param array $options + * + * @return bool + */ + protected function orderUpdate($order, $options) + { + $wc_order = wc_get_order($order['externalId']); + + if (!$wc_order instanceof WC_Order) { + return false; + } + + if (isset($options[$order['status']])) { + $wc_order->update_status($options[$order['status']]); + } + + if (array_key_exists('items', $order)) { + foreach ($order['items'] as $item) { + if (!isset($item['offer'][$this->bind_field])) { + continue; + } + + if (isset($item['create']) && $item['create'] == true) { + $product = retailcrm_get_wc_product( + $item['offer'][$this->bind_field], + $this->retailcrm_settings + ); + + $wc_order->add_product($product, $item['quantity']); + } else { + foreach ($wc_order->get_items() as $order_item_id => $order_item) { + if ($order_item['variation_id'] != 0 ) { + $offer_id = $order_item['variation_id']; + } else { + $offer_id = $order_item['product_id']; + } + + if ($offer_id == $item['offer'][$this->bind_field]) { + $this->deleteOrUpdateOrderItem($item, $order_item, $order_item_id); + } + } + } + } + } + + if (array_key_exists('delivery', $order)) { + $this->updateShippingItemId($order, $options, $wc_order); + + if (isset($order['delivery']['address'])) { + $shipping_address = $order['delivery']['address']; + + if (isset($shipping_address['region'])) { + $wc_order->set_shipping_state($shipping_address['region']); + } + + if (isset($shipping_address['city'])) { + $wc_order->set_shipping_city($shipping_address['city']); + } + + if (isset($shipping_address['street'])) { + $wc_order->set_shipping_address_1($shipping_address['street']); + } + + if (isset($shipping_address['building'])) { + $wc_order->set_shipping_address_2($shipping_address['building']); + } + } + } + + if (isset($order['paymentType'])) { + if (!empty($options[$order['paymentType']])) { + $payment = WC_Payment_Gateways::instance(); + $payment_types = $payment->payment_gateways(); + + if (isset($payment_types[$options[$order['paymentType']]])) { + $wc_order->set_payment_method($payment_types[$options[$order['paymentType']]]); + } + } + } + + if (isset($order['payments']) && !empty($order['payments'])) { + $payment = WC_Payment_Gateways::instance(); + $payment_types = $payment->payment_gateways(); + + if (count($order['payments']) == 1) { + $paymentType = reset($order['payments']); + + if (isset($paymentType['type']) + && isset($options[$paymentType['type']]) + && isset($payment_types[$options[$paymentType['type']]]) + ) { + $payment_type = $payment_types[$options[$paymentType['type']]]; + $wc_order->set_payment_method($payment_type); + } + } else { + foreach ($order['payments'] as $payment_data) { + if (isset($payment_data['externalId'])) { + $paymentType = $payment_data; + } + } + + if (!isset($paymentType)) { + $paymentType = $order['payments'][0]; + } + + if (isset($payment_types[$options[$paymentType['type']]])) { + $wc_order->set_payment_method($payment_types[$options[$paymentType['type']]]); + } + } + } + + $wc_order->save(); + + return $wc_order->get_id(); + } + + /** + * @param $item + * @param $order_item + * @param $order_item_id + */ + private function deleteOrUpdateOrderItem($item, $order_item, $order_item_id) + { + if (isset($item['delete']) && $item['delete'] == true) { + wc_delete_order_item($order_item_id); + } else { + if (isset($item['quantity']) && $item['quantity']) { + $order_item->set_quantity($item['quantity']); + $product = retailcrm_get_wc_product($item['offer'][$this->bind_field], $this->retailcrm_settings); + $order_item->set_total($product->get_price() * $item['quantity']); + $order_item->set_subtotal($product->get_price()); + $data_store = $order_item->get_data_store(); + $data_store->update($order_item); + } + } + } + + /** + * Create order in WC + * + * @param array $order + * @param array $options + * + * @return bool + */ + protected function orderCreate($order, $options) + { + if (!isset($order['create'])) { + return false; + } + + if (is_array($this->order_methods) + && $this->order_methods + && isset($order['orderMethod']) + && !in_array($order['orderMethod'], $this->order_methods) + ) { + return false; + } + + $args = array( + 'status' => isset($options[$order['status']]) + ? isset($options[$order['status']]) + : 'processing', + 'customer_id' => isset($order['customer']['externalId']) + ? $order['customer']['externalId'] + : null + ); + + $wc_order = wc_create_order($args); + + $address_shipping = array( + 'first_name' => isset($order['firstName']) ? $order['firstName'] : '', + 'last_name' => isset($order['lastName']) ? $order['lastName'] : '', + 'company' => '', + 'address_1' => isset($order['delivery']['address']['text']) ? $order['delivery']['address']['text'] : '', + 'address_2' => '', + 'city' => isset($order['delivery']['address']['city']) ? $order['delivery']['address']['city'] : '', + 'state' => isset($order['delivery']['address']['region']) ? $order['delivery']['address']['region'] : '', + 'postcode' => isset($order['delivery']['address']['index']) ? $order['delivery']['address']['index'] : '', + 'country' => isset($order['delivery']['address']['countryIso']) ? $order['delivery']['address']['countryIso'] : '' + ); + + $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'] : '', + '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'] + ); + + if ($this->retailcrm_settings['api_version'] == 'v5') { + 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(); + $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']]]); + } + } + } + + $wc_order->set_address($address_billing, 'billing'); + $wc_order->set_address($address_shipping, 'shipping'); + $product_data = isset($order['items']) ? $order['items'] : array(); + + if ($product_data) { + foreach ($product_data as $product) { + $wc_order->add_product( + retailcrm_get_wc_product($product['offer'][$this->bind_field], $this->retailcrm_settings), + $product['quantity'] + ); + } + } + + if (array_key_exists('delivery', $order)) { + $deliveryCode = isset($order['delivery']['code']) ? $order['delivery']['code'] : false; + + if ($deliveryCode && isset($options[$deliveryCode])) { + $shipping = new WC_Order_Item_Shipping(); + $shipping_methods = get_wc_shipping_methods(); + $shipping->set_method_title($shipping_methods[$options[$deliveryCode]]['name']); + $shipping->set_method_id($options[$deliveryCode]); + + if (isset($order['delivery']['service']['code'])) { + $service = retailcrm_get_delivery_service( + $shipping->get_method_id(), + $order['delivery']['service']['code'] + ); + + if ($service) { + $shipping->set_instance_id($order['delivery']['service']['code']); + } + } + + if (!wc_tax_enabled()) { + $shipping->set_total($order['delivery']['cost']); + } else { + $shipping->set_total($order['delivery']['netCost']); + } + + $shipping->set_order_id($wc_order->get_id()); + + $shipping->save(); + $wc_order->add_item($shipping); + } + } + + $ids[] = array( + 'id' => (int) $order['id'], + 'externalId' => (int) $wc_order->get_id() + ); + + $wc_order->save(); + + $this->retailcrm->ordersFixExternalIds($ids); + + return $wc_order->get_id(); + } + + /** + * @param array $orderHistory + * + * @return array + */ + public static function assemblyOrder($orderHistory) + { + 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; + } + } + + $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; + } + + public static function assemblyCustomer($customerHistory) + { + $customers = array(); + foreach ($customerHistory as $change) { + $change['order'] = self::removeEmpty($change['customer']); + + 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']; + } else { + return $value; + } + } + + public 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; + } + } +endif; diff --git a/src/include/class-wc-retailcrm-icml.php b/src/include/class-wc-retailcrm-icml.php new file mode 100644 index 0000000..f06e6b0 --- /dev/null +++ b/src/include/class-wc-retailcrm-icml.php @@ -0,0 +1,545 @@ +settings = get_option(WC_Retailcrm_Base::$option_key); + $this->shop = get_bloginfo( 'name' ); + $this->file = ABSPATH . 'retailcrm.xml'; + $this->tmpFile = sprintf('%s.tmp', $this->file); + } + + /** + * Generate file + */ + public function generate() + { + $categories = $this->get_wc_categories_taxonomies(); + + if (file_exists($this->tmpFile)) { + if (filectime($this->tmpFile) + $this->fileLifeTime < time()) { + unlink($this->tmpFile); + $this->writeHead(); + } + } else { + $this->writeHead(); + } + + try { + if (!empty($categories)) { + $this->writeCategories($categories); + unset($categories); + } + + $status_args = $this->checkPostStatuses(); + $this->get_wc_products_taxonomies($status_args); + $dom = dom_import_simplexml(simplexml_load_file($this->tmpFile))->ownerDocument; + $dom->formatOutput = true; + $formatted = $dom->saveXML(); + + unset($dom, $this->xml); + + file_put_contents($this->tmpFile, $formatted); + rename($this->tmpFile, $this->file); + } catch (Exception $e) { + unlink($this->tmpFile); + } + } + + /** + * Load tmp data + * + * @return \SimpleXMLElement + */ + private function loadXml() + { + return new SimpleXMLElement( + $this->tmpFile, + LIBXML_NOENT | LIBXML_NOCDATA | LIBXML_COMPACT | LIBXML_PARSEHUGE, + true + ); + } + + /** + * Generate xml header + */ + private function writeHead() + { + $string = sprintf( + '%s', + current_time('Y-m-d H:i:s'), + $this->shop + ); + + file_put_contents($this->tmpFile, $string, LOCK_EX); + } + + /** + * Write categories in file + * + * @param $categories + */ + private function writeCategories($categories) + { + $chunkCategories = array_chunk($categories, $this->chunk); + foreach ($chunkCategories as $categories) { + $this->xml = $this->loadXml(); + + $this->categories = $this->xml->shop->categories; + $this->addCategories($categories); + + $this->xml->asXML($this->tmpFile); + } + + unset($this->categories); + } + + /** + * Write products in file + * + * @param $offers + */ + private function writeOffers($offers) + { + $chunkOffers = array_chunk($offers, $this->chunk); + foreach ($chunkOffers as $offers) { + $this->xml = $this->loadXml(); + + $this->offers = $this->xml->shop->offers; + $this->addOffers($offers); + + $this->xml->asXML($this->tmpFile); + } + + unset($this->offers); + } + + /** + * Add categories + * + * @param $categories + */ + private function addCategories($categories) + { + $categories = self::filterRecursive($categories); + + foreach($categories as $category) { + if (!array_key_exists('name', $category) || !array_key_exists('id', $category)) { + continue; + } + + /** @var SimpleXMLElement $e */ + /** @var SimpleXMLElement $cat */ + + $cat = $this->categories; + $e = $cat->addChild('category'); + + $e->addAttribute('id', $category['id']); + + if (array_key_exists('parentId', $category) && $category['parentId'] > 0) { + $e->addAttribute('parentId', $category['parentId']); + } + + $e->addChild('name', $category['name']); + + if (array_key_exists('picture', $category)) { + $e->addChild('picture', $category['picture']); + } + } + } + + /** + * Add offers + * + * @param $offers + */ + private function addOffers($offers) + { + $offers = self::filterRecursive($offers); + + foreach ($offers as $key => $offer) { + + if (!array_key_exists('id', $offer)) { + continue; + } + + $e = $this->offers->addChild('offer'); + + $e->addAttribute('id', $offer['id']); + + if (!array_key_exists('productId', $offer) || empty($offer['productId'])) { + $offer['productId'] = $offer['id']; + } + $e->addAttribute('productId', $offer['productId']); + + if (!empty($offer['quantity'])) { + $e->addAttribute('quantity', (int) $offer['quantity']); + } else { + $e->addAttribute('quantity', 0); + } + + if (isset($offer['categoryId']) && $offer['categoryId']) { + if (is_array($offer['categoryId'])) { + foreach ($offer['categoryId'] as $categoryId) { + $e->addChild('categoryId', $categoryId); + } + } else { + $e->addChild('categoryId', $offer['categoryId']); + } + } + + if (!array_key_exists('name', $offer) || empty($offer['name'])) { + $offer['name'] = 'Без названия'; + } + + if (!array_key_exists('productName', $offer) || empty($offer['productName'])) { + $offer['productName'] = $offer['name']; + } + + unset($offer['id'], $offer['productId'], $offer['categoryId'], $offer['quantity']); + array_walk($offer, array($this, 'setOffersProperties'), $e); + + if (array_key_exists('params', $offer) && !empty($offer['params'])) { + array_walk($offer['params'], array($this, 'setOffersParams'), $e); + } + + if (array_key_exists('dimension', $offer)) { + $e->addChild('dimension', $offer['dimension']); + } + + if (array_key_exists('weight', $offer)) { + $e->addChild('weight', $offer['weight']); + } + + if (array_key_exists('tax', $offer)) { + $e->addChild('vatRate', $offer['tax']); + } + + unset($offers[$key]); + } + } + + /** + * Set offer properties + * + * @param $value + * @param $key + * @param $e + */ + private function setOffersProperties($value, $key, &$e) { + if (in_array($key, $this->properties) && $key != 'params') { + /** @var SimpleXMLElement $e */ + $e->addChild($key, htmlspecialchars($value)); + } + } + + /** + * Set offer params + * + * @param $value + * @param $key + * @param $e + */ + private function setOffersParams($value, $key, &$e) { + if ( + array_key_exists('code', $value) && + array_key_exists('name', $value) && + array_key_exists('value', $value) && + !empty($value['code']) && + !empty($value['name']) && + !empty($value['value']) + ) { + /** @var SimpleXMLElement $e */ + $param = $e->addChild('param', htmlspecialchars($value['value'])); + $param->addAttribute('code', $value['code']); + $param->addAttribute('name', substr(htmlspecialchars($value['name']), 0, 200)); + unset($key); + } + } + + /** + * Filter result array + * + * @param $haystack + * + * @return mixed + */ + public static function filterRecursive($haystack) + { + foreach ($haystack as $key => $value) { + if (is_array($value)) { + $haystack[$key] = self::filterRecursive($haystack[$key]); + } + + if (is_null($haystack[$key]) + || $haystack[$key] === '' + || (is_array($haystack[$key]) && count($haystack[$key]) == 0) + ) { + unset($haystack[$key]); + } elseif (!is_array($value)) { + $haystack[$key] = trim($value); + } + } + + return $haystack; + } + + /** + * Get WC products + * + * @return void + */ + private function get_wc_products_taxonomies($status_args) { + if (!$status_args) { + $status_args = array('publish'); + } + + $attribute_taxonomies = wc_get_attribute_taxonomies(); + $product_attributes = array(); + + foreach ($attribute_taxonomies as $product_attribute) { + $attribute_id = wc_attribute_taxonomy_name_by_id($product_attribute->attribute_id); + $product_attributes[$attribute_id] = $product_attribute->attribute_label; + } + + $full_product_list = array(); + + $products = wc_get_products( + array( + 'limit' => -1, + 'status' => $status_args + ) + ); + + foreach ($products as $offer) { + if ($offer->get_type() == 'simple') { + $this->setOffer($full_product_list, $product_attributes, $offer); + } elseif ($offer->get_type() == 'variable') { + foreach ($offer->get_children() as $child_id) { + $child_product = wc_get_product($child_id); + $this->setOffer($full_product_list, $product_attributes, $child_product, $offer); + } + } + } + + if (isset($full_product_list) && $full_product_list) { + $this->writeOffers($full_product_list); + unset($full_product_list); + } + } + + /** + * Get WC categories + * + * @return array + */ + private function get_wc_categories_taxonomies() { + $categories = array(); + $taxonomy = 'product_cat'; + $orderby = 'parent'; + $show_count = 0; // 1 for yes, 0 for no + $pad_counts = 0; // 1 for yes, 0 for no + $hierarchical = 1; // 1 for yes, 0 for no + $title = ''; + $empty = 0; + + $args = array( + 'taxonomy' => $taxonomy, + 'orderby' => $orderby, + 'show_count' => $show_count, + 'pad_counts' => $pad_counts, + 'hierarchical' => $hierarchical, + 'title_li' => $title, + 'hide_empty' => $empty + ); + + $wcatTerms = get_categories($args); + + foreach ($wcatTerms as $term) { + $category = array( + 'id' => $term->term_id, + 'parentId' => $term->parent, + 'name' => $term->name + ); + + $thumbnail_id = get_woocommerce_term_meta($term->term_id, 'thumbnail_id', true); + $picture = wp_get_attachment_url($thumbnail_id); + + if ($picture) { + $category['picture'] = $picture; + } + + $categories[] = $category; + } + + return $categories; + } + + /** + * Set offer for icml catalog + * + * @param array $full_product_list + * @param array $product_attributes + * @param WC_Product $product + * @param bool | WC_Product_Variable $parent + * + * @return void + */ + private function setOffer(&$full_product_list, $product_attributes, $product, $parent = false) { + if ($parent) { + $image = wp_get_attachment_image_src($product->get_image_id(), 'full'); + + if (!$image) { + $image = wp_get_attachment_image_src($parent->get_image_id(), 'full'); + } + + $term_list = $parent->get_category_ids(); + $attributes = get_post_meta($parent->get_id(), '_product_attributes'); + } else { + $image = wp_get_attachment_image_src($product->get_image_id(), 'full'); + $term_list = $product->get_category_ids(); + $attributes = get_post_meta($product->get_id(), '_product_attributes'); + } + + $attributes = (isset($attributes[0])) ? $attributes[0] : $attributes; + + $params = array(); + + if (!empty($attributes)) { + foreach ($attributes as $attribute_name => $attribute) { + $attributeValue = $product->get_attribute($attribute_name); + if ($attribute['is_visible'] == 1 && !empty($attributeValue)) { + $params[] = array( + 'code' => $attribute_name, + 'name' => $product_attributes[$attribute_name], + 'value' => $attributeValue + ); + } + } + } + + $dimension = ''; + + if ($product->get_length() != '') { + $dimension = wc_get_dimension($product->get_length(), 'cm'); + } + + if ($product->get_width() != '') { + $dimension .= '/' . wc_get_dimension($product->get_width(), 'cm'); + } + + if ($product->get_height() != '') { + $dimension .= '/' . wc_get_dimension($product->get_height(), 'cm'); + } + + $weight = ''; + + if ($product->get_weight() != '') { + $weight = wc_get_weight($product->get_weight(), 'kg'); + } + + if ($product->is_taxable()) { + $tax_rates = WC_Tax::get_rates($product->get_tax_class()); + $tax = reset($tax_rates); + } + + $product_data = array( + 'id' => $product->get_id(), + 'productId' => ($product->get_parent_id() > 0) ? $parent->get_id() : $product->get_id(), + 'name' => $product->get_name(), + 'productName' => ($product->get_parent_id() > 0) ? $parent->get_title() : $product->get_title(), + 'price' => wc_get_price_including_tax($product), + 'picture' => $image[0], + 'url' => ($product->get_parent_id() > 0) ? $parent->get_permalink() : $product->get_permalink(), + 'quantity' => is_null($product->get_stock_quantity()) ? 0 : $product->get_stock_quantity(), + 'categoryId' => $term_list, + 'dimension' => $dimension, + 'weight' => $weight, + 'tax' => isset($tax) ? $tax['rate'] : 'none' + ); + + if ($product->get_sku() != '') { + $params[] = array('code' => 'article', 'name' => 'Артикул', 'value' => $product->get_sku()); + + if (isset($this->settings['bind_by_sku']) && $this->settings['bind_by_sku'] == WC_Retailcrm_Base::YES) { + $product_data['xmlId'] = $product->get_sku(); + } + } + + if (!empty($params)) { + $product_data['params'] = $params; + } + + if (isset($product_data)) { + $full_product_list[] = $product_data; + } + + unset($product_data); + } + + /** + * Get product statuses + * + * @return array + */ + private function checkPostStatuses() { + $status_args = array(); + + foreach (get_post_statuses() as $key => $value) { + if (isset($this->settings['p_' . $key]) && $this->settings['p_' . $key] == WC_Retailcrm_Base::YES) { + $status_args[] = $key; + } + } + + return $status_args; + } + } + +endif; diff --git a/src/include/class-wc-retailcrm-inventories.php b/src/include/class-wc-retailcrm-inventories.php new file mode 100644 index 0000000..a2e5406 --- /dev/null +++ b/src/include/class-wc-retailcrm-inventories.php @@ -0,0 +1,102 @@ +retailcrm_settings = get_option(WC_Retailcrm_Base::$option_key); + $this->retailcrm = $retailcrm; + + if (isset($this->retailcrm_settings['bind_by_sky']) + && $this->retailcrm_settings['bind_by_sky'] == WC_Retailcrm_Base::YES + ) { + $this->bind_field = 'xmlId'; + } + } + + /** + * Load stock from retailCRM + * + * @return mixed + */ + public function load_stocks() + { + $success = array(); + + if (!$this->retailcrm) { + return null; + } + + $page = 1; + + do { + /** @var WC_Retailcrm_Response $result */ + $result = $this->retailcrm->storeInventories(array(), $page, 250); + + if (!$result->isSuccessful()) { + return null; + } + + $totalPageCount = $result['pagination']['totalPageCount']; + $page++; + + foreach ($result['offers'] as $offer) { + if (isset($offer[$this->bind_field])) { + $product = retailcrm_get_wc_product($offer[$this->bind_field], $this->retailcrm_settings); + + if ($product instanceof WC_Product) { + if ($product->get_type() == 'variable') { + continue; + } + + $product->set_manage_stock(true); + $product->set_stock_quantity($offer['quantity']); + $success[] = $product->save(); + } + } + } + } while ($page <= $totalPageCount); + + return $success; + } + + /** + * Update stock quantity in WooCommerce + * + * @return mixed + */ + public function updateQuantity() + { + if ($this->retailcrm_settings['sync'] == WC_Retailcrm_Base::YES) { + return $this->load_stocks(); + } + + return false; + } + } +endif; diff --git a/src/include/class-wc-retailcrm-orders.php b/src/include/class-wc-retailcrm-orders.php new file mode 100644 index 0000000..44f5daf --- /dev/null +++ b/src/include/class-wc-retailcrm-orders.php @@ -0,0 +1,352 @@ +retailcrm = $retailcrm; + $this->retailcrm_settings = $retailcrm_settings; + $this->order_item = $order_item; + $this->order_address = $order_address; + $this->customers = $customers; + $this->orders = $orders; + $this->order_payment = $order_payment; + } + + /** + * Upload orders to CRM + * + * @param bool $withCustomers + * @param array $include + * @return array $uploadOrders | null + */ + public function ordersUpload($include = array(), $withCustomers = false) + { + if (!$this->retailcrm) { + return null; + } + + $orders = get_posts(array( + 'numberposts' => -1, + 'post_type' => wc_get_order_types('view-orders'), + 'post_status' => array_keys(wc_get_order_statuses()), + 'include' => $include + )); + + $orders_data = 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'); + + if ($withCustomers === true) { + $customers[] = $customer->get('ID'); + } + } + + $orders_data[] = $this->order; + } + + if ($withCustomers === true && !empty($customers)) { + $this->customers->customersUpload($customers); + } + + $uploadOrders = array_chunk($orders_data, 50); + + foreach ($uploadOrders as $uploadOrder) { + $this->retailcrm->ordersUpload($uploadOrder); + time_nanosleep(0, 250000000); + } + + return $uploadOrders; + } + + /** + * Create order + * + * @param $order_id + * + * @return mixed + */ + public function orderCreate($order_id) + { + if (!$this->retailcrm) { + return null; + } + + $order = wc_get_order($order_id); + $this->processOrder($order); + $customer = $order->get_user(); + + if ($customer != false) { + $search = $this->customers->searchCustomer(array('id' => $customer->get('ID'))); + + if (!$search) { + $this->customers->createCustomer($customer); + } else { + $this->order['customer']['externalId'] = $search['externalId']; + } + } else { + $search = $this->customers->searchCustomer(array('email' => $order->get_billing_email())); + + if (!$search) { + $new_customer = $this->customers->buildCustomerFromOrderData($order); + $id = $this->customers->createCustomer($new_customer); + + if ($id !== null) { + $this->order['customer']['id'] = $id; + } + } else { + $this->order['customer']['externalId'] = $search['externalId']; + } + + unset($new_customer); + } + + $this->retailcrm->ordersCreate($this->order); + + return $order; + } + + /** + * Edit order in CRM + * + * @param int $order_id + * + * @return WC_Order $order | null + */ + public function updateOrder($order_id) + { + if (!$this->retailcrm) { + 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()]; + } + + $response = $this->retailcrm->ordersEdit($this->order); + + if ($response->isSuccessful() && $this->retailcrm_settings['api_version'] == 'v5') { + $this->payment = $this->orderUpdatePaymentType($order); + } + + return $order; + } + + /** + * Update order payment type + * + * @param WC_Order $order + * + * @return null | array $payment + */ + protected function orderUpdatePaymentType($order) + { + if (!isset($this->retailcrm_settings[$order->get_payment_method()])) { + return null; + } + + $response = $this->retailcrm->ordersGet($order->get_id()); + + if ($response->isSuccessful()) { + $retailcrmOrder = $response['order']; + + foreach ($retailcrmOrder['payments'] as $payment_data) { + $payment_external_id = explode('-', $payment_data['externalId']); + + if ($payment_external_id[0] == $order->get_id()) { + $payment = $payment_data; + } + } + } + + if (isset($payment) && $payment['type'] == $this->retailcrm_settings[$order->get_payment_method()] && $order->is_paid()) { + $payment = $this->sendPayment($order, true, $payment['externalId']); + + return $payment; + } + + if (isset($payment) && $payment['type'] != $this->retailcrm_settings[$order->get_payment_method()]) { + $response = $this->retailcrm->ordersPaymentDelete($payment['id']); + + if ($response->isSuccessful()) { + $payment = $this->sendPayment($order); + + return $payment; + } + } + + return null; + } + + /** + * process to combine order data + * + * @param WC_Order $order + * @param boolean $update + * + * @return void + */ + protected function processOrder($order, $update = false) + { + if (!$order instanceof WC_Order) { + return; + } + + if ($update === true) { + $this->orders->is_new = false; + } + + $order_data = $this->orders->build($order)->get_data(); + + if ($order->get_items('shipping')) { + $shippings = $order->get_items( 'shipping' ); + $shipping = reset($shippings); + $shipping_code = explode(':', $shipping['method_id']); + + if (isset($this->retailcrm_settings[$shipping['method_id']])) { + $shipping_method = $shipping['method_id']; + } elseif (isset($this->retailcrm_settings[$shipping_code[0]])) { + $shipping_method = $shipping_code[0]; + } else { + $shipping_method = $shipping['method_id'] . ':' . $shipping['instance_id']; + } + + $shipping_cost = $shipping['total'] + $shipping['total_tax']; + + if (!empty($shipping_method) && !empty($this->retailcrm_settings[$shipping_method])) { + $order_data['delivery']['code'] = $this->retailcrm_settings[$shipping_method]; + $service = retailcrm_get_delivery_service($shipping['method_id'], $shipping['instance_id']); + + if ($service) { + $order_data['delivery']['service'] = array( + 'name' => $service['title'], + 'code' => $service['instance_id'], + 'active' => true + ); + } + } + + if (!empty($shipping_cost)) { + $order_data['delivery']['cost'] = $shipping_cost; + } + + if ($shipping['total']) { + $order_data['delivery']['netCost'] = $shipping['total']; + } + } + + $order_data['delivery']['address'] = $this->order_address->build($order)->get_data(); + $order_items = array(); + + /** @var WC_Order_Item_Product $item */ + foreach ($order->get_items() as $item) { + $order_items[] = $this->order_item->build($item)->get_data(); + $this->order_item->reset_data(); + } + + $order_data['items'] = $order_items; + + if ($this->retailcrm_settings['api_version'] == 'v5' && !$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); + } + + /** + * Send payment in CRM + * + * @param WC_Order $order + * @param boolean $update + * @param mixed $externalId + * + * @return array $payment + */ + protected function sendPayment($order, $update = false, $externalId = false) + { + $this->order_payment->is_new = !$update; + $payment = $this->order_payment->build($order, $externalId)->get_data(); + + if ($update === false) { + $this->retailcrm->ordersPaymentCreate($payment); + } else { + $this->retailcrm->ordersPaymentEdit($payment); + } + + return $payment; + } + + /** + * @return array + */ + public function getOrder() + { + return $this->order; + } + + /** + * @return array + */ + public function getPayment() + { + return $this->payment; + } + } +endif; diff --git a/src/include/class-wc-retailcrm-plugin.php b/src/include/class-wc-retailcrm-plugin.php new file mode 100644 index 0000000..089effe --- /dev/null +++ b/src/include/class-wc-retailcrm-plugin.php @@ -0,0 +1,139 @@ +file = $file; + + add_filter('cron_schedules', array($this, 'filter_cron_schedules'), 10, 1); + } + + public function filter_cron_schedules($schedules) { + return array_merge( + $schedules, + array( + 'five_minutes' => array( + 'interval' => 300, // seconds + 'display' => __('Every 5 minutes') + ), + 'three_hours' => array( + 'interval' => 10800, // seconds + 'display' => __('Every 3 hours') + ), + 'fiveteen_minutes' => array( + 'interval' => 900, // seconds + 'display' => __('Every 15 minutes') + ) + ) + ); + } + + public function register_activation_hook() { + register_activation_hook($this->file, array($this, 'activate')); + } + + public function register_deactivation_hook() { + register_deactivation_hook($this->file, array($this, 'deactivate')); + } + + public function activate() { + if (!class_exists('WC_Retailcrm_Icml')) { + require_once (dirname(__FILE__) . '/class-wc-retailcrm-icml.php'); + } + + if (!class_exists('WC_Retailcrm_Base')) { + require_once (dirname(__FILE__) . '/class-wc-retailcrm-base.php'); + } + + $retailcrm_icml = new WC_Retailcrm_Icml(); + $retailcrm_icml->generate(); + } + + public function deactivate() { + do_action('retailcrm_deactivate'); + + if (wp_next_scheduled('retailcrm_icml')) { + wp_clear_scheduled_hook('retailcrm_icml'); + } + + if (wp_next_scheduled('retailcrm_history')) { + wp_clear_scheduled_hook('retailcrm_history'); + } + + if (wp_next_scheduled('retailcrm_inventories')) { + wp_clear_scheduled_hook('retailcrm_inventories'); + } + } + + /** + * Edit configuration in CRM + * + * @param WC_Retailcrm_Proxy $api_client + * @param string $client_id + * @param bool $active + * + * @return boolean + */ + public static function integration_module($api_client, $client_id, $api_version, $active = true) { + + if (!$api_client) { + return false; + } + + $configuration = array( + 'name' => 'WooCommerce', + 'logo' => self::MARKETPLACE_LOGO, + 'code' => self::INTEGRATION_CODE . '-' . $client_id, + 'active' => $active, + ); + + if ($api_version == 'v4') { + $configuration['configurationUrl'] = 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); + } + + if (!$response) { + return false; + } + + if ($response->isSuccessful()) { + return true; + } + + return false; + } + + /** + * Check running history + * + * @return boolean + */ + public static function history_running() + { + return self::$history_run; + } +} diff --git a/src/include/customer/class-wc-retailcrm-customer-address.php b/src/include/customer/class-wc-retailcrm-customer-address.php new file mode 100644 index 0000000..621fc72 --- /dev/null +++ b/src/include/customer/class-wc-retailcrm-customer-address.php @@ -0,0 +1,38 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Customer_Address + */ +class WC_Retailcrm_Customer_Address extends WC_Retailcrm_Abstracts_Address +{ + protected $filter_name = 'customer_address'; + + /** + * @param WC_Customer $customer + * + * @return self + */ + public function build($customer) + { + $data = array( + 'index' => $customer->get_billing_postcode(), + 'countryIso' => $customer->get_billing_country(), + 'region' => $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); + + return $this; + } +} diff --git a/src/include/functions.php b/src/include/functions.php new file mode 100644 index 0000000..570b093 --- /dev/null +++ b/src/include/functions.php @@ -0,0 +1,100 @@ +get_id()] = array( + $defaultZone->get_data(), + 'zone_id' => $defaultZone->get_id(), + 'formatted_zone_location' => $defaultZone->get_formatted_location(), + 'shipping_methods' => $defaultZone->get_shipping_methods(false) + ); + + if ($shippingZones) { + foreach ($shippingZones as $code => $shippingZone) { + foreach ($shippingZone['shipping_methods'] as $key => $shipping_method) { + $shipping_methods = array( + 'id' => $shipping_method->id, + 'instance_id' => $shipping_method->instance_id, + 'title' => $shipping_method->title + ); + + if ($enhanced) { + $shipping_code = $shipping_method->id; + } else { + $shipping_code = $shipping_method->id . ':' . $shipping_method->instance_id; + } + + if (!isset($result[$shipping_code])) { + $result[$shipping_code] = array( + 'name' => $shipping_method->method_title, + 'enabled' => $shipping_method->enabled, + 'description' => $shipping_method->method_description, + 'title' => $shipping_method->title + ); + } + + if ($enhanced) { + $result[$shipping_method->id]['shipping_methods'][$shipping_method->id . ':' . $shipping_method->instance_id] = $shipping_methods; + unset($shipping_methods); + } + } + } + } + + return $result; +} + +function get_wc_shipping_methods() { + $wc_shipping = WC_Shipping::instance(); + $shipping_methods = $wc_shipping->get_shipping_methods(); + + $result = array(); + + foreach ($shipping_methods as $code => $shipping) { + $result[$code] = array( + 'name' => $shipping->method_title, + 'enabled' => $shipping->enabled, + 'description' => $shipping->method_description, + 'title' => $shipping->title ? $shipping->title : $shipping->method_title + ); + } + + return apply_filters('retailcrm_shipping_list', $result); +} + +function retailcrm_get_delivery_service($method_id, $instance_id) { + $shippings_by_zone = get_wc_shipping_methods_by_zones(true); + $method = explode(':', $method_id); + $method_id = $method[0]; + $shipping = isset($shippings_by_zone[$method_id]) ? $shippings_by_zone[$method_id] : array(); + + if ($shipping && isset($shipping['shipping_methods'][$method_id . ':' . $instance_id])) { + return $shipping['shipping_methods'][$method_id . ':' . $instance_id]; + } + + return false; +} + +/** + * @param $id + * @param $settings + * + * @return false|WC_Product|null + */ +function retailcrm_get_wc_product($id, $settings) { + if (isset($settings['bind_by_sky']) + && $settings['bind_by_sky'] == WC_Retailcrm_Base::YES + ) { + $id = wc_get_product_id_by_sku($id); + } + + return wc_get_product($id); +} diff --git a/src/include/index.php b/src/include/index.php new file mode 100644 index 0000000..e71af0e --- /dev/null +++ b/src/include/index.php @@ -0,0 +1 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Order_Address extends WC_Retailcrm_Abstracts_Address +{ + protected $filter_name = 'order_address'; + + /** + * @param WC_Order $order + * + * @return self + */ + public function build($order) + { + $address = $order->get_address('shipping'); + + if (!empty($address)) { + $data = array( + 'index' => $address['postcode'], + 'city' => $address['city'], + 'region' => $address['state'] + ); + + $this->set_data_fields($data); + } + + $this->set_data_field('text', sprintf( + "%s %s %s %s %s", + $address['postcode'], + $address['state'], + $address['city'], + $address['address_1'], + $address['address_2'] + )); + + return $this; + } +} diff --git a/src/include/order/class-wc-retailcrm-order-item.php b/src/include/order/class-wc-retailcrm-order-item.php new file mode 100644 index 0000000..42e71aa --- /dev/null +++ b/src/include/order/class-wc-retailcrm-order-item.php @@ -0,0 +1,127 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Order_Item + */ +class WC_Retailcrm_Order_Item extends WC_Retailcrm_Abstracts_Data +{ + protected $filter_name = 'order_item'; + + /** + * @var array order item + */ + protected $data = array( + 'offer' => array(), + 'productName' => '', + 'initialPrice' => 0.00, + 'quantity' => 0 + ); + + /** + * @var array + */ + protected $settings = array(); + + /** + * WC_Retailcrm_Order_Item constructor. + * + * @param array $settings + */ + public function __construct($settings) + { + $this->settings = $settings; + } + + /** + * @param WC_Order_Item_Product $item + * + * @return self + */ + public function build($item) + { + $price = $this->calculate_price($item); + $discount_price = $this->calculate_discount($item, $price); + + $data['productName'] = $item['name']; + $data['initialPrice'] = (float)$price; + $data['quantity'] = $item['qty']; + + $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)); + } + + return $this; + } + + /** + * @param WC_Order_Item_Product $item + * + * @return void + */ + private function set_offer(WC_Order_Item_Product $item) + { + $uid = ($item['variation_id'] > 0) ? $item['variation_id'] : $item['product_id'] ; + $offer = array('externalId' => $uid); + + if (isset($this->settings['bind_by_sku']) && $this->settings['bind_by_sku'] == WC_Retailcrm_Base::YES) { + $offer['xmlId'] = $item->get_product()->get_sku(); + } + + $this->set_data_field('offer', $offer); + } + + /** + * @param WC_Order_Item_Product $item + * + * @return float + */ + private function calculate_price(WC_Order_Item_Product $item) + { + $price = ($item['line_subtotal'] / $item->get_quantity()) + ($item['line_subtotal_tax'] / $item->get_quantity()); + + return round($price, 2); + } + + /** + * @param WC_Order_Item_Product $item + * @param $price + * + * @return float|int + */ + private function calculate_discount(WC_Order_Item_Product $item, $price) + { + $product_price = $item->get_total() ? $item->get_total() / $item->get_quantity() : 0; + $product_tax = $item->get_total_tax() ? $item->get_total_tax() / $item->get_quantity() : 0; + $price_item = $product_price + $product_tax; + $discount_price = $price - $price_item; + + return $discount_price; + } + + /** + * Reset data for object + */ + public function reset_data() + { + $this->data = array( + 'offer' => array(), + 'productName' => '', + 'initialPrice' => 0.00, + 'quantity' => 0 + ); + } +} diff --git a/src/include/order/class-wc-retailcrm-order-payment.php b/src/include/order/class-wc-retailcrm-order-payment.php new file mode 100644 index 0000000..da836ee --- /dev/null +++ b/src/include/order/class-wc-retailcrm-order-payment.php @@ -0,0 +1,98 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Order_Payment + */ +class WC_Retailcrm_Order_Payment extends WC_Retailcrm_Abstracts_Data +{ + /** @var string */ + protected $filter_name = 'order_payment'; + + /** @var array */ + protected $data = array( + 'externalId' => '', + 'amount' => 0.00, + 'type' => '', + 'order' => array() + ); + + /** @var bool */ + public $is_new = true; + + /** + * @var array + */ + protected $settings = array(); + + /** + * WC_Retailcrm_Order_Item constructor. + * + * @param array $settings + */ + public function __construct($settings) + { + $this->settings = $settings; + } + + /** + * @param WC_Order $order + * @param mixed $externalId + * + * @return self + */ + public function build($order, $externalId = false) + { + $data = array( + 'amount' => $order->get_total() + ); + + if (!$this->is_new) { + $data['externalId'] = $externalId; + } else { + $data['externalId'] = uniqid($order->get_id()); + } + + $data['order'] = array( + 'externalId' => $order->get_id() + ); + + if ($order->is_paid()) { + $data['status'] = 'paid'; + } + + if ($order->get_date_paid()) { + $data['paidAt'] = $order->get_date_paid()->date('Y-m-d H:i:s'); + } + + if ($this->is_new) { + if (isset($this->settings[$order->get_payment_method()])) { + $data['type'] = $this->settings[$order->get_payment_method()]; + } + } + + $this->set_data_fields($data); + + return $this; + } + + public function reset_data() + { + $this->data = array( + 'externalId' => '', + 'amount' => 0.00, + 'type' => '', + 'status' => '', + 'paidAt' => '', + 'order' => array() + ); + } +} diff --git a/src/include/order/class-wc-retailcrm-order.php b/src/include/order/class-wc-retailcrm-order.php new file mode 100644 index 0000000..69d529c --- /dev/null +++ b/src/include/order/class-wc-retailcrm-order.php @@ -0,0 +1,125 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Order extends WC_Retailcrm_Abstracts_Data +{ + /** @var bool */ + public $is_new = true; + + protected $filter_name = 'order'; + + protected $data = array( + 'externalId' => 0, + 'status' => '', + 'number' => '', + 'createdAt' => '', + 'firstName' => '', + 'lastName' => '', + 'email' => '', + 'paymentType' => '', + 'customerComment' => '', + 'paymentStatus' => '', + 'phone' => '', + 'countryIso' => '' + ); + + /** + * @var array + */ + protected $settings = array(); + + /** + * WC_Retailcrm_Order constructor. + * + * @param array $settings + */ + public function __construct($settings) + { + $this->settings = $settings; + } + + /** + * @param WC_Order $order + * + * @return self + */ + public function build($order) + { + $data = array( + 'externalId' => $order->get_id(), + 'createdAt' => $order->get_date_created()->date('Y-m-d H:i:s'), + 'firstName' => $order->get_shipping_first_name(), + 'lastName' => $order->get_shipping_last_name(), + 'email' => $order->get_billing_email(), + 'customerComment' => $order->get_customer_note(), + 'phone' => $order->get_billing_phone(), + 'countryIso' => $order->get_shipping_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()]); + } + + return $this; + } + + /** + * @param WC_Order $order + */ + protected function set_payment_data($order) + { + if ($order->get_payment_method() && isset($this->settings[$order->get_payment_method()])) { + $this->set_data_field('paymentType', $this->settings[$order->get_payment_method()]); + } + + if ($order->is_paid()) { + $this->set_data_field('paymentStatus', 'paid'); + } + } + + /** + * @param WC_Order $order + */ + protected function set_number($order) + { + if (isset($this->settings['update_number']) + && $this->settings['update_number'] == WC_Retailcrm_Base::YES + && !$this->is_new + ) { + $this->set_data_field('number', $order->get_order_number()); + } + } + + public function reset_data() + { + $this->data = array( + 'externalId' => '', + 'status' => '', + 'number' => '', + 'createdAt' => '', + 'firstName' => '', + 'lastName' => '', + 'email' => '', + 'paymentType' => '', + 'customerComment' => '', + 'paymentStatus' => '', + 'phone' => '', + 'countryIso' => '' + ); + } +} diff --git a/src/index.php b/src/index.php new file mode 100644 index 0000000..e71af0e --- /dev/null +++ b/src/index.php @@ -0,0 +1 @@ +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'); + add_filter('woocommerce_integrations', array( $this, 'add_integration')); + } else { + add_action('admin_notices', array($this, 'woocommerce_missing_notice')); + } + } + + public function woocommerce_missing_notice() { + echo '

Woocommerce is not installed

'; + } + + public function load_plugin_textdomain() { + load_plugin_textdomain('retailcrm', false, dirname(plugin_basename(__FILE__)) . '/languages/'); + } + + /** + * Add a new integration to WooCommerce. + * + * @param $integrations + * + * @return array + */ + public function add_integration( $integrations ) { + $integrations[] = 'WC_Retailcrm_Base'; + return $integrations; + } + } + + if (!class_exists('WC_Retailcrm_Plugin')) { + require_once (dirname(__FILE__) . '/include/class-wc-retailcrm-plugin.php'); + } + + $plugin = WC_Retailcrm_Plugin::getInstance(__FILE__); + $plugin->register_activation_hook(); + $plugin->register_deactivation_hook(); + + add_action('plugins_loaded', array('WC_Integration_Retailcrm', 'get_instance'), 0); +endif; diff --git a/src/uninstall.php b/src/uninstall.php new file mode 100644 index 0000000..aad2219 --- /dev/null +++ b/src/uninstall.php @@ -0,0 +1,46 @@ +query("DELETE FROM $wpdb->options WHERE option_name = 'woocommerce_integration-retailcrm_settings';"); +$wpdb->query("DELETE FROM $wpdb->options WHERE option_name = 'retailcrm_customers_history_since_id';"); +$wpdb->query("DELETE FROM $wpdb->options WHERE option_name = 'retailcrm_orders_history_since_id';"); +$wpdb->query("DELETE FROM $wpdb->options WHERE option_name = 'retailcrm_active_in_crm';"); +$wpdb->query("DELETE FROM $wpdb->options WHERE option_name = 'retailcrm_client_id';"); + +// Clear any cached data that has been removed +wp_cache_flush(); diff --git a/tests/bin/install.sh b/tests/bin/install.sh new file mode 100755 index 0000000..8e9f602 --- /dev/null +++ b/tests/bin/install.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash +# See https://raw.githubusercontent.com/wp-cli/scaffold-command/master/templates/install-wp-tests.sh + +if [ $# -lt 3 ]; then + echo "usage: $0 [db-host] [wp-version] [skip-database-creation]" + exit 1 +fi + +DB_NAME=$1 +DB_USER=$2 +DB_PASS=$3 +DB_HOST=${4-localhost} +WP_VERSION=${5-latest} +SKIP_DB_CREATE=${6-false} + +WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} +WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} + +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + +if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then + WP_TESTS_TAG="tags/$WP_VERSION" +elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + WP_TESTS_TAG="trunk" +else + # http serves a single offer, whereas https serves multiple. we only want one + download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json + grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json + LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') + if [[ -z "$LATEST_VERSION" ]]; then + echo "Latest WordPress version could not be found" + exit 1 + fi + WP_TESTS_TAG="tags/$LATEST_VERSION" +fi + +set -ex + +install_wp() { + + if [ -d $WP_CORE_DIR ]; then + return; + fi + + mkdir -p $WP_CORE_DIR + + if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + mkdir -p /tmp/wordpress-nightly + download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip + unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/ + mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR + else + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz + tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR + fi + + download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php +} + +install_woocommerce() { + cd /tmp + git clone https://github.com/woocommerce/woocommerce.git + cd woocommerce + git checkout master + cd - +} + +install_test_suite() { + # portable in-place argument for both GNU sed and Mac OSX sed + if [[ $(uname -s) == 'Darwin' ]]; then + local ioption='-i .bak' + else + local ioption='-i' + fi + + # set up testing suite if it doesn't yet exist + if [ ! -d $WP_TESTS_DIR ]; then + # set up testing suite + mkdir -p $WP_TESTS_DIR + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data + fi + + if [ ! -f wp-tests-config.php ]; then + download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + # remove all forward slashes in the end + WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php + fi + +} + +install_db() { + + if [ ${SKIP_DB_CREATE} = "true" ]; then + return 0 + fi + + # parse DB_HOST for port or socket references + local PARTS=(${DB_HOST//\:/ }) + local DB_HOSTNAME=${PARTS[0]}; + local DB_SOCK_OR_PORT=${PARTS[1]}; + local EXTRA="" + + if ! [ -z $DB_HOSTNAME ] ; then + if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi + fi + + # create database + mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +} + +install_wp +install_test_suite +install_woocommerce +install_db diff --git a/tests/bin/script.sh b/tests/bin/script.sh new file mode 100644 index 0000000..f92901b --- /dev/null +++ b/tests/bin/script.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +if [[ ${RUN_PHPCS} == 1 ]]; then + composer install + vendor/phpunit/phpunit/phpunit -c phpunit.xml.dist +else + phpunit -c phpunit.xml.dist +fi diff --git a/tests/helpers/class-wc-retailcrm-response-helper.php b/tests/helpers/class-wc-retailcrm-response-helper.php new file mode 100644 index 0000000..32bbc7d --- /dev/null +++ b/tests/helpers/class-wc-retailcrm-response-helper.php @@ -0,0 +1,13 @@ +response = $response; + } +} diff --git a/tests/helpers/class-wc-retailcrm-test-case-helper.php b/tests/helpers/class-wc-retailcrm-test-case-helper.php new file mode 100644 index 0000000..a7865a3 --- /dev/null +++ b/tests/helpers/class-wc-retailcrm-test-case-helper.php @@ -0,0 +1,58 @@ + 'https://example.retailcrm.ru', + 'api_key' => 'dhsHJGYdjkHHJKJSGjhasjhgajsgJGHsg', + 'api_version' => $apiVersion, + 'p_draft' => 'no', + 'p_pending' => 'no', + 'p_private' => 'no', + 'p_publish' => 'no', + 'order_methods' => '', + 'flat_rate_shipping' => 'delivery', + 'free_shipping' => 'delivery2', + 'local_pickup' => 'delivery3', + 'bacs' => 'payment1', + 'cheque' => 'payment2', + 'cod' => 'payment3', + 'paypal' => 'payment4', + 'ppec_paypal' => 'payment5', + 'pending' => 'status1', + 'processing' => 'status2', + 'on-hold' => 'status3', + 'completed' => 'status4', + 'cancelled' => 'status5', + 'refunded' => 'status6', + 'failed' => 'status7', + 'sync' => 'no', + 'ua' => 'yes', + 'ua_code' => 'UA-XXXXXXX-XX', + 'ua_custom' => '1', + 'upload-button' => '' + ); + + update_option(WC_Retailcrm_Base::$option_key, $options); + + return $options; + } + + /** + * @return array + */ + protected function getOptions() + { + return get_option(WC_Retailcrm_Base::$option_key); + } +} diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php new file mode 100644 index 0000000..f531b62 --- /dev/null +++ b/tests/phpunit/bootstrap.php @@ -0,0 +1,30 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Customer_Address_Test extends WC_Retailcrm_Test_Case_Helper +{ + protected $customer; + + public function setUp() + { + parent::setUp(); + + $this->customer = WC_Helper_Customer::create_customer(); + } + + public function test_build() + { + $customer_address = new WC_Retailcrm_Customer_Address; + $data = $customer_address->build($this->customer)->get_data(); + + $this->assertArrayHasKey('index', $data); + $this->assertArrayHasKey('city', $data); + $this->assertArrayHasKey('region', $data); + $this->assertArrayHasKey('text', $data); + $this->assertArrayHasKey('countryIso', $data); + $this->assertNotEmpty($data['index']); + $this->assertNotEmpty($data['city']); + $this->assertNotEmpty($data['region']); + $this->assertNotEmpty($data['text']); + $this->assertNotEmpty($data['countryIso']); + } +} diff --git a/tests/phpunit/order/test-wc-retailcrm-order-address.php b/tests/phpunit/order/test-wc-retailcrm-order-address.php new file mode 100644 index 0000000..b7c0a52 --- /dev/null +++ b/tests/phpunit/order/test-wc-retailcrm-order-address.php @@ -0,0 +1,37 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +/** + * Class WC_Retailcrm_Order_Address_Test + */ +class WC_Retailcrm_Order_Address_Test extends WC_Retailcrm_Test_Case_Helper +{ + /** @var WC_Order */ + protected $order; + + public function setUp() + { + parent::setUp(); + + $this->order = WC_Helper_Order::create_order(); + } + + public function test_build() + { + $order_address = new WC_Retailcrm_Order_Address; + $data = $order_address->build($this->order)->get_data(); + + $this->assertArrayHasKey('index', $data); + $this->assertArrayHasKey('city', $data); + $this->assertArrayHasKey('region', $data); + $this->assertArrayHasKey('text', $data); + } +} diff --git a/tests/phpunit/order/test-wc-retailcrm-order-item.php b/tests/phpunit/order/test-wc-retailcrm-order-item.php new file mode 100644 index 0000000..5c6a523 --- /dev/null +++ b/tests/phpunit/order/test-wc-retailcrm-order-item.php @@ -0,0 +1,38 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Order_Item_Test extends WC_Retailcrm_Test_Case_Helper +{ + /** @var WC_Order */ + protected $order; + + public function setUp() + { + parent::setUp(); + + $this->order = WC_Helper_Order::create_order(); + } + + public function test_build() + { + $order_item = new WC_Retailcrm_Order_Item($this->getOptions()); + + /** @var WC_Order_Item_Product $item */ + foreach ($this->order->get_items() as $item) { + $data = $order_item->build($item)->get_data(); + + $this->assertArrayHasKey('productName', $data); + $this->assertArrayHasKey('initialPrice', $data); + $this->assertArrayHasKey('quantity', $data); + $this->assertArrayHasKey('offer', $data); + } + } +} diff --git a/tests/phpunit/order/test-wc-retailcrm-order-payment.php b/tests/phpunit/order/test-wc-retailcrm-order-payment.php new file mode 100644 index 0000000..31bffde --- /dev/null +++ b/tests/phpunit/order/test-wc-retailcrm-order-payment.php @@ -0,0 +1,55 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Order_Payment_Test extends WC_Retailcrm_Test_Case_Helper +{ + /** @var WC_Order */ + protected $order; + + public function setUp() + { + parent::setUp(); + + $this->order = WC_Helper_Order::create_order(); + } + + /** + * @param mixed $externalId + * + * @dataProvider dataProvider + */ + public function test_build($externalId) + { + $order_payment = new WC_Retailcrm_Order_Payment($this->getOptions()); + + $data = $order_payment->build($this->order, $externalId)->get_data(); + + $this->assertArrayHasKey('externalId', $data); + $this->assertArrayHasKey('type', $data); + $this->assertArrayHasKey('amount', $data); + $this->assertArrayHasKey('order', $data); + } + + /** + * @return array + */ + public function dataProvider() + { + return array( + array( + 'externalId' => false + ), + array( + 'externalId' => uniqid() + ) + ); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-base.php b/tests/phpunit/test-wc-retailcrm-base.php new file mode 100644 index 0000000..b28840a --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-base.php @@ -0,0 +1,221 @@ +apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'orderMethodsList', + 'deliveryTypesList', + 'paymentTypesList', + 'statusesList' + )) + ->getMock(); + + $this->setMockOrderMethods(); + $this->setMockDeliveryTypes(); + $this->setMockPaymentTypes(); + $this->setMockStatuses(); + + $_GET['page'] = 'wc-settings'; + $_GET['tab'] = 'integration'; + + $this->setOptions('v5'); + $this->unit = new \WC_Retailcrm_Base($this->apiMock); + } + + public function test_retailcrm_check_custom_file() + { + $file = \WC_Retailcrm_Base::checkCustomFile('ga'); + $this->assertInternalType('string', $file); + } + + public function test_retailcrm_form_fields() + { + $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); + } + + $this->assertArrayHasKey('order_methods', $this->unit->form_fields); + + foreach (get_wc_shipping_methods() as $code => $value) { + if (isset($value['enabled']) && $value['enabled'] == 'yes') { + $this->assertArrayHasKey($code, $this->unit->form_fields); + } + } + + $wc_payment = WC_Payment_Gateways::instance(); + + foreach ($wc_payment->get_available_payment_gateways() as $payment) { + if (isset($payment->enabled) && $payment->enabled == 'yes') { + $this->assertArrayHasKey($payment->id, $this->unit->form_fields); + } + } + + foreach (wc_get_order_statuses() as $idx => $name ) { + $uid = str_replace('wc-', '', $idx); + $this->assertArrayHasKey($uid, $this->unit->form_fields); + } + } + + private function getResponseOrderMethods() + { + return array( + 'success' => true, + 'orderMethods' => array( + array( + 'name' => 'orderMethod1', + 'code' => 'orderMethod1', + 'active' => true + ), + array( + 'name' => 'orderMethod2', + 'code' => 'orderMethod2', + 'active' => true + ) + ) + ); + } + + private function getResponseDeliveryTypes() + { + return array( + 'success' => true, + 'deliveryTypes' => array( + array( + 'name' => 'delivery1', + 'code' => 'delivery1' + ), + array( + 'name' => 'delivery2', + 'code' => 'delivery2' + ) + ) + ); + } + + private function getResponsePaymentTypes() + { + return array( + 'success' => true, + 'paymentTypes' => array( + array( + 'name' => 'payment1', + 'code' => 'payment1' + ), + array( + 'name' => 'payment2', + 'code' => 'payment2' + ) + ) + ); + } + + private function getResponseStatuses() + { + return array( + 'success' => true, + 'statuses' => array( + array( + 'name' => 'status1', + 'code' => 'status1' + ), + array( + 'name' => 'status2', + 'code' => 'status2' + ) + ) + ); + } + + private function setMockOrderMethods() + { + $this->responseMockOrderMethods = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->responseMockOrderMethods->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + + $this->responseMockOrderMethods->setResponse($this->getResponseOrderMethods()); + $this->apiMock->expects($this->any()) + ->method('orderMethodsList') + ->willReturn($this->responseMockOrderMethods); + } + + private function setMockDeliveryTypes() + { + $this->responseMockDeliveryTypes = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->responseMockDeliveryTypes->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + + $this->responseMockDeliveryTypes->setResponse($this->getResponseDeliveryTypes()); + $this->apiMock->expects($this->any()) + ->method('deliveryTypesList') + ->willReturn($this->responseMockDeliveryTypes); + } + + private function setMockPaymentTypes() + { + $this->responseMockPaymentTypes = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->responseMockPaymentTypes->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + + $this->responseMockPaymentTypes->setResponse($this->getResponsePaymentTypes()); + $this->apiMock->expects($this->any()) + ->method('paymentTypesList') + ->willReturn($this->responseMockPaymentTypes); + } + + private function setMockStatuses() + { + $this->responseMockStatuses = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->responseMockStatuses->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + + $this->responseMockStatuses->setResponse($this->getResponseStatuses()); + $this->apiMock->expects($this->any()) + ->method('statusesList') + ->willReturn($this->responseMockStatuses); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-customers.php b/tests/phpunit/test-wc-retailcrm-customers.php new file mode 100644 index 0000000..35c82c3 --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-customers.php @@ -0,0 +1,151 @@ +responseMock = $this->getMockBuilder('\WC_Retailcrm_Response') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'ordersGet', + 'ordersUpload', + 'ordersCreate', + 'ordersEdit', + 'customersGet', + 'customersUpload', + 'customersCreate', + 'customersEdit' + )) + ->getMock(); + + $this->responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + + $this->apiMock->expects($this->any()) + ->method('customersCreate') + ->willReturn($this->responseMock); + + $this->customer = new WC_Customer(); + $this->customer->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); + $this->customer->set_password('password'); + $this->customer->set_billing_phone('89000000000'); + $this->customer->save(); + } + + /** + * @param retailcrm + * @dataProvider dataProviderApiClient + */ + public function test_wc_customer_get($retailcrm) + { + $wc_customer = new WC_Customer($this->customer->get_id()); + $retailcrm_customer = $this->getRetailcrmCustomer($retailcrm); + $this->assertEquals($wc_customer, $retailcrm_customer->wcCustomerGet($this->customer->get_id())); + } + + /** + * @param retailcrm + * @dataProvider dataProviderApiClient + */ + public function test_customers_upload($retailcrm) + { + $retailcrm_customer = $this->getRetailcrmCustomer($retailcrm); + $data = $retailcrm_customer->customersUpload(); + + if ($retailcrm) { + $this->assertInternalType('array', $data); + $this->assertInternalType('array', $data[0]); + $this->assertArrayHasKey('externalId', $data[0][0]); + } else { + $this->assertEquals(null, $data); + } + } + + /** + * @param $retailcrm + * @dataProvider dataProviderApiClient + */ + public function test_create_customer($retailcrm) + { + $retailcrm_customer = $this->getRetailcrmCustomer($retailcrm); + $id = $retailcrm_customer->createCustomer($this->customer->get_id()); + $customer_send = $retailcrm_customer->getCustomer(); + + if ($retailcrm) { + $this->assertArrayHasKey('firstName', $customer_send); + $this->assertArrayHasKey('createdAt', $customer_send); + $this->assertArrayHasKey('email', $customer_send); + $this->assertNotEmpty($customer_send['externalId']); + $this->assertNotEmpty($customer_send['firstName']); + $this->assertNotEmpty($customer_send['email']); + } else { + $this->assertEquals(null, $id); + $this->assertEquals(array(), $customer_send); + } + } + + /** + * @param $retailcrm + * @dataProvider dataProviderApiClient + */ + public function test_update_customer($retailcrm) + { + $retailcrm_customer = $this->getRetailcrmCustomer($retailcrm); + $customer = $retailcrm_customer->updateCustomer($this->customer->get_id()); + $customer_send = $retailcrm_customer->getCustomer(); + + if ($retailcrm) { + $this->assertArrayHasKey('externalId', $customer_send); + $this->assertArrayHasKey('firstName', $customer_send); + $this->assertArrayHasKey('createdAt', $customer_send); + $this->assertArrayHasKey('email', $customer_send); + $this->assertNotEmpty($customer_send['externalId']); + $this->assertNotEmpty($customer_send['firstName']); + $this->assertNotEmpty($customer_send['email']); + $this->assertInstanceOf('WC_Customer', $customer); + } else { + $this->assertEquals(null, $customer); + $this->assertEquals(array(), $customer_send); + } + } + + public function dataProviderApiClient() + { + $this->setUp(); + + return array( + array( + 'retailcrm' => $this->apiMock + ), + array( + 'retailcrm' => false + ) + ); + } + + /** + * @param $retailcrm + * + * @return WC_Retailcrm_Customers + */ + private function getRetailcrmCustomer($retailcrm) + { + return new WC_Retailcrm_Customers( + $retailcrm, + $this->getOptions(), + new WC_Retailcrm_Customer_Address() + ); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-daemon-collector.php b/tests/phpunit/test-wc-retailcrm-daemon-collector.php new file mode 100644 index 0000000..ce33567 --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-daemon-collector.php @@ -0,0 +1,30 @@ +options = array( + 'daemon_collector_key' => 'RC-XXXXXXXXXX-X' + ); + + $this->daemonCollector = WC_Retailcrm_Daemon_Collector::getInstance($this->options); + } + + public function test_initialize_daemon_collector() + { + $customerObject = WC_Helper_Customer::create_customer(); + WC()->customer = $customerObject; + + $js = $this->daemonCollector->initialize_daemon_collector(); + + $this->assertContains('customerId', $js); + $this->assertContains($this->options['daemon_collector_key'], $js); + $this->assertContains('assertContains('', $js); + $this->assertContains('_rc(\'create\',', $js); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-ga.php b/tests/phpunit/test-wc-retailcrm-ga.php new file mode 100644 index 0000000..af1c424 --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-ga.php @@ -0,0 +1,61 @@ +order = WC_Helper_Order::create_order(0); + $this->orderKey = $this->order->get_order_key(); + $this->setOptions(); + + $this->options = get_option(WC_Retailcrm_Base::$option_key); + $this->ga = WC_Retailcrm_Google_Analytics::getInstance($this->options); + } + + public function test_initialize_analytics() + { + $js = $this->ga->initialize_analytics(); + + $this->assertContains($this->options['ua_code'], $js); + $this->assertContains($this->options['ua_custom'], $js); + } + + /** + * @param $checkout + * @dataProvider dataProvider + */ + public function test_send_analytics($checkout) + { + if ($checkout) { + $_GET['key'] = $this->orderKey; + } + + $js = $this->ga->send_analytics(); + + if ($checkout) { + $this->assertContains((string)$this->order->get_id(), $js); + $this->assertContains((string)$this->order->get_total(), $js); + $this->assertContains((string)$this->order->get_total_tax(), $js); + $this->assertContains((string)$this->order->get_shipping_total(), $js); + } else { + $this->assertEmpty($js); + } + } + + public function dataProvider() + { + return array( + array( + 'checkout' => false + ), + array( + 'checkout' => true + ) + ); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-history.php b/tests/phpunit/test-wc-retailcrm-history.php new file mode 100644 index 0000000..53c6fde --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-history.php @@ -0,0 +1,452 @@ +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(); + + parent::setUp(); + } + + /** + * @dataProvider dataProvider + * @param $api_version + */ + public function test_history_order_create($api_version) + { + $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->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); + $order_added_items = $order_added->get_items(); + $order_added_item = reset($order_added_items); + $shipping_address = $order_added->get_address('shipping'); + $billing_address = $order_added->get_address('billing'); + + $options = get_option(\WC_Retailcrm_Base::$option_key); + + $this->assertEquals(self::STATUS_1, $options[$order_added->get_status()]); + $this->assertEquals($product->get_id(), $order_added_item->get_product()->get_id()); + $this->assertNotEmpty($shipping_address['first_name']); + $this->assertNotEmpty($shipping_address['last_name']); + $this->assertNotEmpty($shipping_address['postcode']); + $this->assertNotEmpty($shipping_address['city']); + $this->assertNotEmpty($shipping_address['country']); + $this->assertNotEmpty($shipping_address['state']); + $this->assertNotEmpty($billing_address['phone']); + $this->assertNotEmpty($billing_address['email']); + $this->assertNotEmpty($billing_address['first_name']); + $this->assertNotEmpty($billing_address['last_name']); + $this->assertNotEmpty($billing_address['postcode']); + $this->assertNotEmpty($billing_address['city']); + $this->assertNotEmpty($billing_address['country']); + $this->assertNotEmpty($billing_address['state']); + $this->assertEquals('payment4', $options[$order_added->get_payment_method()]); + } + + /** + * @dataProvider dataProvider + * @param $api_version + */ + public function test_history_order_add_product($api_version) + { + $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->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(); + + $order_updated = wc_get_order($order->get_id()); + $order_updated_items = $order_updated->get_items(); + $order_updated_item = end($order_updated_items); + + $this->assertEquals(2, count($order_updated_items)); + $this->assertEquals(2, $order_updated_item->get_quantity()); + $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) + { + $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->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(); + + $order_updated = wc_get_order($order->get_id()); + $options = get_option(\WC_Retailcrm_Base::$option_key); + + $this->assertEquals(self::STATUS_2, $options[$order_updated->get_status()]); + $this->assertEquals('payment2', $options[$order_updated->get_payment_method()]); + } + + public function dataProvider() + { + return array( + array( + 'api_version' => 'v4' + ), + array( + 'api_version' => 'v5' + ) + ); + } + + private function get_history_data_new_order($product_create_id) + { + return array( + 'success' => true, + 'history' => array( + array( + 'id' => 1, + 'createdAt' => '2018-01-01 00:00:00', + 'created' => true, + 'source' => 'user', + 'user' => array( + 'id' => 1 + ), + 'field' => 'status', + 'oldValue' => null, + 'newValue' => array( + 'code' => self::STATUS_1 + ), + 'order' => array( + 'slug' => 1, + 'id' => 1, + 'number' => '1C', + 'orderType' => 'eshop-individual', + 'orderMethod' => 'phone', + 'countryIso' => 'RU', + 'createdAt' => '2018-01-01 00:00:00', + 'statusUpdatedAt' => '2018-01-01 00:00:00', + 'summ' => 100, + 'totalSumm' => 100, + 'prepaySum' => 0, + 'purchaseSumm' => 50, + 'markDatetime' => '2018-01-01 00:00:00', + 'firstName' => 'Test', + 'lastName' => 'Test', + 'phone' => '80000000000', + 'call' => false, + 'expired' => false, + 'customer' => array( + 'segments' => array(), + 'id' => 1, + 'firstName' => 'Test', + 'lastName' => 'Test', + 'email' => 'email@test.ru', + 'phones' => array( + array( + 'number' => '111111111111111' + ), + array( + 'number' => '+7111111111' + ) + ), + 'address' => array( + 'index' => '111111', + 'countryIso' => 'RU', + 'region' => 'Test region', + 'city' => 'Test', + 'text' => 'Test text address' + ), + 'createdAt' => '2018-01-01 00:00:00', + 'managerId' => 1, + 'vip' => false, + 'bad' => false, + 'site' => 'test-com', + 'contragent' => array( + 'contragentType' => 'individual' + ), + 'personalDiscount' => 0, + 'cumulativeDiscount' => 0, + 'marginSumm' => 58654, + 'totalSumm' => 61549, + 'averageSumm' => 15387.25, + 'ordersCount' => 4, + 'costSumm' => 101, + 'customFields' => array( + 'custom' => 'test' + ) + ), + 'contragent' => array(), + 'delivery' => array( + 'cost' => 0, + 'netCost' => 0, + 'address' => array( + 'index' => '111111', + 'countryIso' => 'RU', + 'region' => 'Test region', + 'city' => 'Test', + 'text' => 'Test text address' + ) + ), + 'site' => 'test-com', + 'status' => self::STATUS_1, + 'items' => array( + array( + 'id' => 160, + 'initialPrice' => 100, + 'createdAt' => '2018-01-01 00:00:00', + 'quantity' => 1, + 'status' => 'new', + 'offer' => array( + 'id' => 1, + 'externalId' => $product_create_id, + 'xmlId' => '1', + 'name' => 'Test name', + 'vatRate' => 'none' + ), + 'properties' => array(), + 'purchasePrice' => 50 + ) + ), + 'paymentType' => 'payment4', + 'payments' => array( + array( + 'id'=> 1, + 'type'=> 'payment4', + 'amount'=> 100, + ) + ), + 'fromApi' => false, + 'length' => 0, + 'width' => 0, + 'height' => 0, + 'shipmentStore' => 'main', + 'shipped' => false, + 'customFields' => array(), + 'uploadedToExternalStoreSystem' => false + ) + ) + ) + ); + } + + private function get_history_data_product_add($product_add_id, $order_id) + { + return array( + 'success' => true, + 'history' => array( + array( + 'id' => 2, + 'createdAt' => '2018-01-01 00:00:01', + 'source'=> 'user', + 'user' => array( + 'id'=> 1 + ), + 'field' => 'order_product', + 'oldValue' => null, + 'newValue' => array( + 'id' => 2, + 'offer' => array( + 'id'=> 2, + 'externalId' => $product_add_id, + 'xmlId' => 'xmlId' + ) + ), + 'order' => array( + 'id' => 2, + 'externalId' => $order_id, + 'site' => 'test-com', + 'status' => self::STATUS_1 + ), + 'item' => array( + 'id' => 2, + 'initialPrice' => 999, + 'createdAt' => '2018-01-01 00:02:00', + 'quantity' => 2, + 'status' => self::STATUS_1, + 'offer' => array( + 'id' => 2, + 'externalId' => $product_add_id, + 'xmlId' => 'xmlId', + 'name' => 'Test name 2' + ), + 'properties' => array(), + 'purchasePrice' => 500 + ) + ) + ) + ); + } + + private function get_history_data_update($order_id, $api_version) + { + $history = array( + 'success' => true, + 'history' => array( + array( + 'id' => 3, + 'createdAt' => '2018-01-01 00:03:00', + 'source' => 'user', + 'user' => array( + 'id' => 1 + ), + 'field' => 'status', + 'oldValue' => array( + 'code' => 'new' + ), + 'newValue' => array( + 'code' => self::STATUS_2 + ), + 'order' => array( + 'id' => 2, + 'externalId' => $order_id, + 'managerId' => 6, + 'site' => 'test-com', + 'status' => self::STATUS_2 + ) + ) + ) + ); + + $payment_v5 = array( + 'id' => 4, + 'createdAt' => '2018-01-01 00:03:00', + 'source' => 'user', + 'user' => array( + 'id' => 1 + ), + 'field' => 'payments', + 'oldValue' => null, + 'newValue' => array( + 'code' => 'payment2' + ), + 'order' => array( + 'id' => 2, + 'externalId' => $order_id, + 'managerId' => 6, + 'site' => 'test-com', + 'status' => self::STATUS_2 + ), + 'payment' => array( + 'id' => 1, + '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); + } + + return $history; + } +} diff --git a/tests/phpunit/test-wc-retailcrm-inventories.php b/tests/phpunit/test-wc-retailcrm-inventories.php new file mode 100644 index 0000000..908d799 --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-inventories.php @@ -0,0 +1,123 @@ +responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'storeInventories' + )) + ->getMock(); + + parent::setUp(); + } + + /** + * @param $retailcrm + * @param $response + * + * @dataProvider dataProviderLoadStocks + */ + public function test_load_stocks($retailcrm, $response) + { + $offer = WC_Helper_Product::create_simple_product(); + $offer->save(); + + if ($response['success'] == true) { + $response['offers'][0]['externalId'] = $offer->get_id(); + $this->responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + } elseif ($response['success'] == false) { + $this->responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn(false); + } + + $this->responseMock->setResponse($response); + + if ($retailcrm) { + $retailcrm->expects($this->any()) + ->method('storeInventories') + ->willReturn($this->responseMock); + } + + $retailcrm_inventories = new WC_Retailcrm_Inventories($retailcrm); + $result = $retailcrm_inventories->load_stocks(); + + if ($retailcrm && $response['success'] == true) { + $product = new WC_Product_Simple($result[0]); + $this->assertInstanceOf('WC_Product', $product); + $this->assertEquals(10, $product->get_stock_quantity()); + $this->assertContains($product->get_id(), $result); + $this->assertInternalType('array', $result); + } else { + $this->assertEquals(null, $result); + } + } + + private function getResponseData() + { + return array( + 'true' => array( + 'success' => true, + 'pagination' => array( + 'limit' => 250, + 'totalCount' => 1, + 'currentPage' => 1, + 'totalPageCount' => 1 + ), + 'offers' => array( + array( + 'id' => 1, + 'xmlId' => 'xmlId', + 'quantity' => 10 + ) + ) + ), + 'false' => array( + 'success' => false, + 'errorMsg' => 'Forbidden' + ) + ); + } + + public function dataProviderLoadStocks() + { + $this->setUp(); + + $response = $this->getResponseData(); + + return array( + array( + 'retailcrm' => $this->apiMock, + 'response' => $response['true'] + ), + array( + 'retailcrm' => false, + 'response' => $response['true'] + ), + array( + 'retailcrm' => $this->apiMock, + 'response' => $response['false'] + ), + array( + 'retailcrm' => false, + 'response' => $response['false'] + ) + ); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-orders.php b/tests/phpunit/test-wc-retailcrm-orders.php new file mode 100644 index 0000000..b7df534 --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-orders.php @@ -0,0 +1,335 @@ +apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'ordersGet', + 'ordersUpload', + 'ordersCreate', + 'ordersEdit', + 'customersGet', + 'customersCreate', + 'ordersPaymentCreate', + 'ordersPaymentDelete', + 'customersList' + )) + ->getMock(); + + parent::setUp(); + } + + /** + * @param $retailcrm + * @param $apiVersion + * @dataProvider dataProviderRetailcrm + */ + public function test_order_upload($retailcrm, $apiVersion) + { + $this->options = $this->setOptions($apiVersion); + $retailcrm_orders = $this->getRetailcrmOrders($retailcrm); + $upload_orders = $retailcrm_orders->ordersUpload(); + + if ($retailcrm) { + $this->assertInternalType('array', $upload_orders); + } else { + $this->assertEquals(null, $upload_orders); + } + } + + /** + * @param $retailcrm + * @param $apiVersion + * @dataProvider dataProviderRetailcrm + */ + public function test_order_create($retailcrm, $apiVersion) + { + if ($retailcrm) { + $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $responseMockCustomers = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + $responseMockCustomers->setResponse( + array('success' => true, + 'customers' => array( + array('externalId' => 1) + ) + ) + ); + + $retailcrm->expects($this->any()) + ->method('customersCreate') + ->willReturn($responseMock); + $retailcrm->expects($this->any()) + ->method('customersList') + ->willReturn($responseMockCustomers); + } + + $this->createTestOrder(); + $this->options = $this->setOptions($apiVersion); + $retailcrm_orders = $this->getRetailcrmOrders($retailcrm); + $order = $retailcrm_orders->orderCreate($this->order->get_id()); + $order_send = $retailcrm_orders->getOrder(); + + if ($retailcrm) { + $this->assertInstanceOf('WC_Order', $order); + $this->assertInternalType('array', $order_send); + $this->assertArrayHasKey('status', $order_send); + $this->assertArrayHasKey('externalId', $order_send); + $this->assertArrayHasKey('firstName', $order_send); + $this->assertArrayHasKey('lastName', $order_send); + $this->assertArrayHasKey('email', $order_send); + $this->assertArrayHasKey('delivery', $order_send); + $this->assertArrayHasKey('code', $order_send['delivery']); + $this->assertArrayHasKey('address', $order_send['delivery']); + $this->assertArrayHasKey('index', $order_send['delivery']['address']); + $this->assertArrayHasKey('city', $order_send['delivery']['address']); + $this->assertEquals($this->order->get_id(), $order_send['externalId']); + $this->assertEquals('status1', $order_send['status']); + $this->assertEquals('Jeroen', $order_send['firstName']); + $this->assertEquals('Sormani', $order_send['lastName']); + $this->assertEquals('admin@example.org', $order_send['email']); + $this->assertEquals('US', $order_send['countryIso']); + $this->assertEquals('123456', $order_send['delivery']['address']['index']); + $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']); + } + } else { + $this->assertEquals(null, $order); + } + } + + /** + * @param $isSuccessful + * @param $retailcrm + * @param $apiVersion + * @dataProvider dataProviderUpdateOrder + */ + public function test_update_order($isSuccessful, $retailcrm, $apiVersion) + { + $this->createTestOrder(); + $this->options = $this->setOptions($apiVersion); + + if ($retailcrm && $apiVersion == 'v5') { + $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn($isSuccessful); + + $retailcrm->expects($this->any()) + ->method('ordersEdit') + ->willReturn($responseMock); + + $retailcrm->expects($this->any()) + ->method('ordersPaymentDelete') + ->willReturn($responseMock); + + $response = $this->getResponseData($this->order->get_id()); + $responseMock->setResponse($response); + + $retailcrm->expects($this->any()) + ->method('ordersGet') + ->willReturn($responseMock); + } + + $retailcrm_orders = $this->getRetailcrmOrders($retailcrm); + $order = $retailcrm_orders->updateOrder($this->order->get_id()); + $order_send = $retailcrm_orders->getOrder(); + + if ($retailcrm) { + $this->assertInstanceOf('WC_Order', $order); + $this->assertInternalType('array', $order_send); + $this->assertArrayHasKey('status', $order_send); + $this->assertArrayHasKey('externalId', $order_send); + $this->assertArrayHasKey('firstName', $order_send); + $this->assertArrayHasKey('lastName', $order_send); + $this->assertArrayHasKey('email', $order_send); + $this->assertArrayHasKey('delivery', $order_send); + $this->assertArrayHasKey('code', $order_send['delivery']); + $this->assertArrayHasKey('address', $order_send['delivery']); + $this->assertArrayHasKey('index', $order_send['delivery']['address']); + $this->assertArrayHasKey('city', $order_send['delivery']['address']); + $this->assertEquals($this->order->get_id(), $order_send['externalId']); + $this->assertEquals('status1', $order_send['status']); + $this->assertEquals('Jeroen', $order_send['firstName']); + $this->assertEquals('Sormani', $order_send['lastName']); + $this->assertEquals('admin@example.org', $order_send['email']); + $this->assertEquals('US', $order_send['countryIso']); + $this->assertEquals('123456', $order_send['delivery']['address']['index']); + $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); + + if (!empty($payment)) { + $this->assertArrayHasKey('type', $payment); + $this->assertArrayHasKey('amount', $payment); + $this->assertArrayHasKey('order', $payment); + $this->assertArrayHasKey('externalId', $payment); + $this->assertEquals('payment1', $payment['type']); + } + } + } else { + $this->assertEquals(null, $order); + } + } + + public function dataProviderUpdateOrder() + { + $this->setUp(); + + return array( + array( + 'is_successful' => true, + 'retailcrm' => $this->apiMock, + 'api_version' => 'v5' + ), + array( + 'is_successful' => true, + 'retailcrm' => false, + 'api_version' => 'v5' + ), + array( + 'is_successful' => false, + 'retailcrm' => false, + 'api_version' => 'v5' + ), + 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' + ) + ); + } + + public function dataProviderRetailcrm() + { + $this->setUp(); + + return array( + array( + 'retailcrm' => $this->apiMock, + 'api_version' => 'v4' + ), + array( + 'retailcrm' => false, + 'api_version' => 'v4' + ), + array( + 'retailcrm' => $this->apiMock, + 'api_version' => 'v5' + ), + array( + 'retailcrm' => false, + 'api_version' => 'v5' + ) + ); + } + + private function createTestOrder() + { + /** @var WC_Order order */ + $this->order = WC_Helper_Order::create_order(0); + + foreach ($this->order->get_address('billing') as $prop => $value) { + if (method_exists($this->order, 'set_shipping_' . $prop)) { + $this->order->{'set_shipping_' . $prop}($value); + } + } + + $this->order->save(); + } + + private function getResponseData($externalId) + { + return array( + 'success' => true, + 'order' => array( + 'payments' => array( + array( + 'id' => 1, + 'externalId' => $externalId, + 'type' => 'payment2' + ) + ) + ) + ); + } + + /** + * @param $retailcrm + * + * @return WC_Retailcrm_Orders + */ + private function getRetailcrmOrders($retailcrm) + { + return new WC_Retailcrm_Orders( + $retailcrm, + $this->getOptions(), + new WC_Retailcrm_Order_Item($this->getOptions()), + new WC_Retailcrm_Order_Address, + new WC_Retailcrm_Customers( + $retailcrm, $this->getOptions(), new WC_Retailcrm_Customer_Address + ), + new WC_Retailcrm_Order($this->getOptions()), + new WC_Retailcrm_Order_Payment($this->getOptions()) + ); + } +} diff --git a/tests/phpunit/test-wc-retailcrm-plugin.php b/tests/phpunit/test-wc-retailcrm-plugin.php new file mode 100644 index 0000000..d762c2d --- /dev/null +++ b/tests/phpunit/test-wc-retailcrm-plugin.php @@ -0,0 +1,176 @@ +responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy') + ->disableOriginalConstructor() + ->setMethods(array( + 'marketplaceSettingsEdit' + )) + ->getMock(); + + parent::setUp(); + } + + /** + * @param $retailcrm + * @param $response + * @param $apiVersion + * + * @dataProvider dataProviderIntegrationModule + */ + public function test_integration_module($retailcrm,$response, $apiVersion) + { + $client_id = uniqid(); + $result = WC_Retailcrm_Plugin::integration_module($retailcrm, $client_id, $apiVersion); + + if (!$retailcrm || $response['success'] == false) { + $this->assertEquals(false, $result); + } else { + $this->assertEquals(true, $result); + } + } + + private function getResponseData() + { + return array( + 'v4' => array( + "true" => array( + "success" => true + ), + "false" => array( + "success" => false + ) + ), + 'v5' => array( + "true" => array( + "success" => true + ), + "false" => array( + "success" => false, + "errorMsg" => "Forbidden" + ) + ) + ); + } + + public function dataProviderIntegrationModule() + { + $this->setUp(); + + return array( + array( + 'retailcrm' => $this->getApiMock( + 'v4', + $this->getResponseData['v4']['true'] + ), + 'response' => $this->getResponseData['v4']['true'], + 'apiVersion' => 'v4' + ), + array( + 'retailcrm' => false, + 'response' => $this->getResponseData['v4']['true'], + 'apiVersion' => 'v4' + ), + array( + 'retailcrm' => $this->getApiMock( + 'v4', + $this->getResponseData['v4']['false'] + ), + 'response' => $this->getResponseData['v4']['false'], + 'apiVersion' => 'v4' + ), + 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' + ) + ); + } + + private function getApiMock($apiVersion, $response) + { + $responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(array( + 'isSuccessful' + )) + ->getMock(); + + if ($response['success'] == true) { + $responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn(true); + } elseif ($response['success'] == false) { + $responseMock->expects($this->any()) + ->method('isSuccessful') + ->willReturn(false); + } + + $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') + ->disableOriginalConstructor() + ->setMethods(array( + 'integrationModulesEdit' + )) + ->getMock(); + + $apiMock->expects($this->any()) + ->method('integrationModulesEdit') + ->willReturn($responseMock); + } + + return $apiMock; + } +} +