1
0
mirror of synced 2025-02-21 09:23:14 +03:00
This commit is contained in:
Круглов Дмитрий 2019-04-25 15:16:46 +03:00
commit 65fcb2ed46
65 changed files with 13351 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/nbproject/
/vendor/

36
.travis.yml Normal file
View File

@ -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"

100
CHANGELOG.md Normal file
View File

@ -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
* Исправлен неверный подсчет скидки на товары

21
LICENSE Normal file
View File

@ -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.

22
Makefile Normal file
View File

@ -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

10
README.md Normal file
View File

@ -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)

1
VERSION Normal file
View File

@ -0,0 +1 @@
3.4.5

16
composer.json Normal file
View File

@ -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.*"
}
}

1481
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

29
phpunit.xml.dist Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="tests/phpunit/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
verbose="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="true"
>
<testsuites>
<testsuite name="Retailcrm WooCommerce Test Suite">
<directory suffix=".php">tests/phpunit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/include</directory>
<exclude>
<directory suffix=".php">src/include/api</directory>
<file>src/retailcrm.php</file>
<file>src/uninstall.php</file>
</exclude>
</whitelist>
</filter>
</phpunit>

5
resources/bin/pot_compile.sh Executable file
View File

@ -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

View File

@ -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"

View File

@ -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 "Ключ сайта"

106
src/config/objects.xml Normal file
View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<options>
<fields>
<field id="id" group="customer">id</field>
<field id="first_name" group="customer">firstName</field>
<field id="last_name" group="customer">lastName</field>
<field id="patronymic" group="customer">patronymic</field>
<field id="email" group="customer">email</field>
<field id="birthday" group="customer">birthday</field>
<field id="phones" group="customer">phones</field>
<field id="manager" group="customer">manager</field>
<field id="commentary" group="customer">commentary</field>
<field id="external_id" group="customer">externalId</field>
<field id="cumulative_discount" group="customer">cumulativeDiscount</field>
<field id="personal_discount" group="customer">personalDiscount</field>
<field id="discount_card_number" group="customer">discountCardNumber</field>
<field id="address.index" group="customerAddress">index</field>
<field id="address.country" group="customerAddress">country</field>
<field id="address.region" group="customerAddress">region</field>
<field id="address.city" group="customerAddress">city</field>
<field id="address.street" group="customerAddress">street</field>
<field id="address.building" group="customerAddress">building</field>
<field id="address.house" group="customerAddress">house</field>
<field id="address.block" group="customerAddress">block</field>
<field id="address.flat" group="customerAddress">flat</field>
<field id="address.floor" group="customerAddress">floor</field>
<field id="address.intercom_code" group="customerAddress">intercomCode</field>
<field id="address.metro" group="customerAddress">metro</field>
<field id="address.notes" group="customerAddress">notes</field>
<field id="contragent.contragent_type" group="customerContragent">contragentType</field>
<field id="contragent.legal_name" group="customerContragent">legalName</field>
<field id="contragent.legal_address" group="customerContragent">legalAddress</field>
<field id="contragent.certificate_number" group="customerContragent">certificateNumber</field>
<field id="contragent.certificate_date" group="customerContragent">certificateDate</field>
<field id="contragent.bank" group="customerContragent">bank</field>
<field id="contragent.bank_address" group="customerContragent">bankAddress</field>
<field id="contragent.corr_account" group="customerContragent">corrAccount</field>
<field id="contragent.bank_account" group="customerContragent">bankAccount</field>
<field id="id" group="order">id</field>
<field id="created_at" group="order">createdAt</field>
<field id="order_type" group="order">orderType</field>
<field id="order_method" group="order">orderMethod</field>
<field id="site" group="order">site</field>
<field id="status" group="order">status</field>
<field id="manager" group="order">manager</field>
<field id="first_name" group="order">firstName</field>
<field id="last_name" group="order">lastName</field>
<field id="patronymic" group="order">patronymic</field>
<field id="phone" group="order">phone</field>
<field id="additional_phone" group="order">additionalPhone</field>
<field id="email" group="order">email</field>
<field id="payment_type" group="order">paymentType</field>
<field id="payment_status" group="order">paymentStatus</field>
<field id="discount" group="order">discount</field>
<field id="discount_percent" group="order">discountPercent</field>
<field id="prepay_sum" group="order">prepaySum</field>
<field id="customer_comment" group="order">customerComment</field>
<field id="manager_comment" group="order">managerComment</field>
<field id="shipment_store" group="order">shipmentStore</field>
<field id="shipment_date" group="order">shipmentDate</field>
<field id="shipped" group="order">shipped</field>
<!--<field id="order_product" group="order">item</field>-->
<field id="payment" group="order">payment</field>
<field id="payments.amount" group="order">amount</field>
<field id="payments.paid_at" group="order">paidAt</field>
<field id="payments.comment" group="order">comment</field>
<field id="payments.type" group="order">type</field>
<field id="payments.status" group="order">status</field>
<field id="order_product.id" group="item">id</field>
<field id="order_product.initial_price" group="item">initialPrice</field>
<field id="order_product.discount" group="item">discount</field>
<field id="order_product.discount_percent" group="item">discountPercent</field>
<field id="order_product.quantity" group="item">quantity</field>
<field id="order_product.status" group="item">status</field>
<field id="order_product.summ" group="item">summ</field>
<field id="delivery_type" group="delivery">code</field>
<field id="delivery_service" group="delivery">service</field>
<field id="delivery_date" group="delivery">date</field>
<field id="delivery_time" group="delivery">time</field>
<field id="delivery_cost" group="delivery">cost</field>
<field id="delivery_net_cost" group="delivery">netCost</field>
<field id="delivery_address.country" group="orderAddress">country</field>
<field id="delivery_address.index" group="orderAddress">index</field>
<field id="delivery_address.region" group="orderAddress">region</field>
<field id="delivery_address.city" group="orderAddress">city</field>
<field id="delivery_address.street" group="orderAddress">street</field>
<field id="delivery_address.building" group="orderAddress">building</field>
<field id="delivery_address.house" group="orderAddress">house</field>
<field id="delivery_address.block" group="orderAddress">block</field>
<field id="delivery_address.flat" group="orderAddress">flat</field>
<field id="delivery_address.floor" group="orderAddress">floor</field>
<field id="delivery_address.intercom_code" group="orderAddress">intercomCode</field>
<field id="delivery_address.metro" group="orderAddress">metro</field>
<field id="delivery_address.notes" group="orderAddress">notes</field>
<field id="integration_delivery_data.status" group="integrationDelivery">status</field>
<field id="integration_delivery_data.track_number" group="integrationDelivery">trackNumber</field>
<field id="integration_delivery_data.courier" group="integrationDelivery">courier</field>
</fields>
</options>

View File

@ -0,0 +1,30 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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' => '',
);
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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);
}
}

View File

@ -0,0 +1,705 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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');
?>
<script type="text/javascript">
jQuery('#uploads-retailcrm').bind('click', function() {
jQuery.ajax({
type: "POST",
url: '<?php echo $ajax_url; ?>?action=do_upload',
success: function (response) {
alert('<?php echo __('Customers and orders were uploaded', 'retailcrm'); ?>');
console.log('AJAX response : ',response);
}
});
});
</script>
<?php
}
public function ajax_generate_icml()
{
$ajax_url = admin_url('admin-ajax.php');
?>
<script type="text/javascript">
jQuery('#icml-retailcrm, #wp-admin-bar-retailcrm_ajax_generate_icml').bind('click', function() {
jQuery.ajax({
type: "POST",
url: '<?php echo $ajax_url; ?>?action=generate_icml',
success: function (response) {
alert('<?php echo __('Catalog was generated', 'retailcrm'); ?>');
console.log('AJAX response : ', response);
}
});
});
</script>
<?php
}
public function ajax_selected_order()
{
$ajax_url = admin_url('admin-ajax.php');
$ids = $this->plugin_id . $this->id . '_single_order';
?>
<script type="text/javascript">
jQuery('#single_order_btn').bind('click', function() {
if (jQuery('#<?php echo $ids; ?>').val() == '') {
alert('<?php echo __('The field cannot be empty, enter the order ID', 'retailcrm'); ?>');
} else {
jQuery.ajax({
type: "POST",
url: '<?php echo $ajax_url; ?>?action=order_upload&order_ids_retailcrm=' + jQuery('#<?php echo $ids; ?>').val(),
success: function (response) {
alert('<?php echo __('Orders were uploaded', 'retailcrm'); ?>');
}
});
}
});
</script>
<?php
}
/**
* Initialize integration settings form fields.
*/
public function init_form_fields()
{
$this->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();
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
<?php echo $this->get_tooltip_html( $data ); ?>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['label'] ); ?></span></legend>
<button id="<?php echo $data['id']; ?>" class="<?php echo esc_attr( $data['class'] ); ?>" type="button" name="<?php echo esc_attr( $field ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php echo $this->get_custom_attribute_html( $data ); ?>><?php echo wp_kses_post( $data['label'] ); ?></button>
<?php echo $this->get_description_html( $data ); ?>
</fieldset>
</td>
</tr>
<?php
return ob_get_clean();
}
/**
* Generate html title block settings
*
* @param string $key
* @param array $data
*
* @return string
*/
public function generate_heading_html($key, $data)
{
$field_key = $this->get_field_key( $key );
$defaults = array(
'title' => '',
'class' => '',
);
$data = wp_parse_args( $data, $defaults );
ob_start();
?>
</table>
<h2 class="wc-settings-sub-title retailcrm_hidden <?php echo esc_attr( $data['class'] ); ?>" id="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?> <span style="opacity:0.5;float: right;">&#11015;</span></h2>
<?php if ( ! empty( $data['description'] ) ) : ?>
<p><?php echo wp_kses_post( $data['description'] ); ?></p>
<?php endif; ?>
<table class="form-table" style="display: none;">
<?php
return ob_get_clean();
}
/**
* Validate API version
*
* @param string $key
* @param string $value
*
* @return string
*/
public function validate_api_version_field($key, $value)
{
$post = $this->get_post_data();
$versionMap = array(
'v4' => '4.0',
'v5' => '5.0'
);
$api = new WC_Retailcrm_Proxy(
$post[$this->plugin_id . $this->id . '_api_url'],
$post[$this->plugin_id . $this->id . '_api_key']
);
$response = $api->apiVersions();
if ($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()
{
?>
<script type="text/javascript">
jQuery('h2.retailcrm_hidden').hover().css({
'cursor':'pointer',
'width':'310px'
});
jQuery('h2.retailcrm_hidden').toggle(
function() {
jQuery(this).next('table.form-table').show(100);
jQuery(this).find('span').html('&#11014;');
},
function() {
jQuery(this).next('table.form-table').hide(100);
jQuery(this).find('span').html('&#11015;');
}
);
</script>
<?php
}
/**
* Add button in admin
*/
function add_retailcrm_button() {
global $wp_admin_bar;
if ( !is_super_admin() || !is_admin_bar_showing() || !is_admin())
return;
$wp_admin_bar->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&section=integration-retailcrm',
'parent' => 'retailcrm_top_menu',
'class' => 'retailcrm_ajax_settings'
)
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<?php
/**
* PHP version 5.3
*
* WC_Retailcrm_Exception_Curl class
*
* @category RetailCRM
* @package WC_Retailcrm_Exception_Curl
* @author RetailCRM <dev@retailcrm.ru>
* @license https://opensource.org/licenses/MIT MIT License
* @link http://retailcrm.ru/docs/Developers/ApiVersion4
*/
class WC_Retailcrm_Exception_Curl extends \RuntimeException
{
}

View File

@ -0,0 +1,16 @@
<?php
/**
* PHP version 5.3
*
* WC_Retailcrm_Exception_Json class
*
* @category RetailCRM
* @package WC_Retailcrm_Exception_Json
* @author RetailCRM <dev@retailcrm.ru>
* @license https://opensource.org/licenses/MIT MIT License
*/
class WC_Retailcrm_Exception_Json extends \DomainException
{
}

View File

@ -0,0 +1,78 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Proxy
* @category Integration
* @author RetailCRM
*/
if ( ! class_exists( 'WC_Retailcrm_Proxy' ) ) :
/**
* Class WC_Retailcrm_Proxy
*/
class WC_Retailcrm_Proxy
{
protected $retailcrm;
protected $logger;
public function __construct($api_url, $api_key, $api_vers = null)
{
$this->logger = new WC_Logger();
if ( ! class_exists( 'WC_Retailcrm_Client_V4' ) ) {
include_once( __DIR__ . '/class-wc-retailcrm-client-v4.php' );
}
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;

View File

@ -0,0 +1,116 @@
<?php
/**
* PHP version 5.3
*
* Request class
*
* @category Integration
* @package WC_Retailcrm_Request
* @author RetailCRM <dev@retailcrm.ru>
* @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);
}
}

View File

@ -0,0 +1,169 @@
<?php
/**
* PHP version 5.3
*
* Response class
*
* @category Integration
* @package WC_Retailcrm_Response
* @author RetailCRM <dev@retailcrm.ru>
* @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];
}
}

View File

@ -0,0 +1 @@
<?php // Silence is golden

View File

@ -0,0 +1,380 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Base
* @category Integration
* @author RetailCRM
*/
if (!class_exists('WC_Retailcrm_Base')) {
/**
* Class WC_Retailcrm_Base
*/
class WC_Retailcrm_Base extends WC_Retailcrm_Abstracts_Settings
{
protected $api_url;
protected $api_key;
protected $apiClient;
protected $order_item;
protected $order_address;
protected $customers;
protected $orders;
/**
* Init and hook in the integration.
* @param $retailcrm (default = false)
*/
public function __construct($retailcrm = false) {
parent::__construct();
if (!class_exists( 'WC_Retailcrm_Proxy')) {
include_once(__DIR__ . '/api/class-wc-retailcrm-proxy.php');
}
if ($retailcrm === false) {
$this->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);
}
}
}
}
}

View File

@ -0,0 +1,238 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Customers
* @category Integration
* @author RetailCRM
*/
if (!class_exists('WC_Retailcrm_Customers')) :
/**
* Class WC_Retailcrm_Customers
*/
class WC_Retailcrm_Customers {
const CUSTOMER_ROLE = 'customer';
/** @var bool | WC_Retailcrm_Proxy */
protected $retailcrm;
/** @var array */
protected $retailcrm_settings = array();
/** @var WC_Retailcrm_Customer_Address */
protected $customer_address;
/** @var array */
private $customer = array();
/**
* WC_Retailcrm_Customers constructor.
*
* @param bool | WC_Retailcrm_Proxy $retailcrm
* @param array $retailcrm_settings
* @param WC_Retailcrm_Customer_Address $customer_address
*/
public function __construct($retailcrm = false, $retailcrm_settings, $customer_address)
{
$this->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;

View File

@ -0,0 +1,106 @@
<?php
if (!defined('ABSPATH')) {
exit;
}
class WC_Retailcrm_Daemon_Collector {
/** @var self $instance */
private static $instance;
/** @var array $options */
private $options;
/** @var string $code */
private $code = '';
/**
* @param array $options
*
* @return WC_Retailcrm_Daemon_Collector
*/
public static function getInstance($options = array())
{
if (self::$instance === null) {
self::$instance = new self($options);
}
return self::$instance;
}
/**
* WC_Retailcrm_Daemon_Collector constructor.
*
* @param array $options
*/
private function __construct($options = array())
{
$this->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 = <<<EOF
<script type="text/javascript">
(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
_rc('send', 'pageView');
</script>
EOF;
$this->code .= $footer;
return $this;
}
}

View File

@ -0,0 +1,125 @@
<?php
if (!class_exists('WC_Retailcrm_Google_Analytics')) {
class WC_Retailcrm_Google_Analytics {
private static $instance;
private $options;
/**
* @param array $options
*
* @return WC_Retailcrm_Google_Analytics
*/
public static function getInstance($options = array())
{
if (self::$instance === null) {
self::$instance = new self($options);
}
return self::$instance;
}
/**
* WC_Retailcrm_Google_Analytics constructor.
*
* @param array $options
*/
private function __construct($options = array())
{
$this->options = $options;
}
/**
* @return string
*/
public function initialize_analytics() {
return apply_filters('retailcrm_initialize_analytics' ,"
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '" . $this->options['ua_code'] . "', 'auto');
function getRetailCrmCookie(name) {
var matches = document.cookie.match(new RegExp(
'(?:^|; )' + name + '=([^;]*)'
));
return matches ? decodeURIComponent(matches[1]) : '';
}
ga('set', 'dimension" . $this->options['ua_custom'] ."', getRetailCrmCookie('_ga'));
ga('send', 'pageview');
</script>
");
}
/**
* @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 .= "
<script type=\"text/javascript\">
ga('require', 'ecommerce', 'ecommerce.js');
ga('ecommerce:addTransaction', {
'id':" . $order->get_id() . ",
'affiliation':'" . $domain . "',
'revenue':" . $order->get_total() . ",
'shipping':" . $order->get_total_tax() . ",
'tax':" . $order->get_shipping_total() . "
});
";
foreach ($order_items as $item) {
$js .= "
ga('ecommerce:addItem', {
'id':" . $order->get_id() . ",
'sku':" . $item['id'] . ",
'name': '" . $item['name'] . "',
'price': " . $item['price'] . ",
'quantity': " . $item['quantity'] . "
});
";
}
$js .= "ga('ecommerce:send');
</script>";
return apply_filters('retailcrm_send_analytics', $js);
}
}
}

View File

@ -0,0 +1,740 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_History
* @category Integration
* @author RetailCRM
*/
if ( ! class_exists( 'WC_Retailcrm_History' ) ) :
/**
* Class WC_Retailcrm_History
*/
class WC_Retailcrm_History
{
protected $startDateOrders;
protected $startDateCustomers;
protected $startDate;
protected $retailcrm_settings;
protected $retailcrm;
protected $order_methods = array();
protected $bind_field = 'externalId';
/**
* WC_Retailcrm_History constructor.
* @param $retailcrm (default = false)
*/
public function __construct($retailcrm = false)
{
$this->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;

View File

@ -0,0 +1,545 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Icml
* @category Integration
* @author RetailCRM
*/
if ( ! class_exists( 'WC_Retailcrm_Icml' ) ) :
/**
* Class WC_Retailcrm_Icml
*/
class WC_Retailcrm_Icml
{
protected $shop;
protected $file;
protected $tmpFile;
protected $properties = array(
'name',
'productName',
'price',
'purchasePrice',
'vendor',
'picture',
'url',
'xmlId',
'productActivity'
);
protected $xml;
/** @var SimpleXMLElement $categories */
protected $categories;
/** @var SimpleXMLElement $categories */
protected $offers;
protected $chunk = 500;
protected $fileLifeTime = 3600;
/** @var array */
protected $settings;
/**
* WC_Retailcrm_Icml constructor.
*
*/
public function __construct()
{
$this->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(
'<?xml version="1.0" encoding="UTF-8"?><yml_catalog date="%s"><shop><name>%s</name><categories/><offers/></shop></yml_catalog>',
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;

View File

@ -0,0 +1,102 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Inventories
* @category Integration
* @author RetailCRM
*/
if (!class_exists('WC_Retailcrm_Inventories')) :
/**
* Class WC_Retailcrm_Inventories
*/
class WC_Retailcrm_Inventories
{
/** @var WC_Retailcrm_Client_V5 */
protected $retailcrm;
/** @var array */
protected $retailcrm_settings;
/** @var string */
protected $bind_field = 'externalId';
/**
* WC_Retailcrm_Inventories constructor.
* @param bool $retailcrm
*/
public function __construct($retailcrm = false)
{
$this->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;

View File

@ -0,0 +1,352 @@
<?php
/**
* RetailCRM Integration.
*
* @package WC_Retailcrm_Orders
* @category Integration
* @author RetailCRM
*/
if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
/**
* Class WC_Retailcrm_Orders
*/
class WC_Retailcrm_Orders
{
/** @var bool|WC_Retailcrm_Proxy */
protected $retailcrm;
/** @var array */
protected $retailcrm_settings;
/** @var WC_Retailcrm_Order_Item */
protected $order_item;
/** @var WC_Retailcrm_Order_Address */
protected $order_address;
/** @var WC_Retailcrm_Order_Payment */
protected $order_payment;
/** @var WC_Retailcrm_Customers */
protected $customers;
/** @var WC_Retailcrm_Order */
protected $orders;
/** @var array */
private $order = array();
/** @var array */
private $payment = array();
public function __construct(
$retailcrm = false,
$retailcrm_settings,
$order_item,
$order_address,
$customers,
$orders,
$order_payment
) {
$this->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;

View File

@ -0,0 +1,139 @@
<?php
class WC_Retailcrm_Plugin {
public $file;
public static $history_run = false;
private static $instance = null;
const MARKETPLACE_LOGO = 'https://s3.eu-central-1.amazonaws.com/retailcrm-billing/images/5b69ce4bda663-woocommercesvg2.svg';
const INTEGRATION_CODE = 'woocommerce';
public static function getInstance($file) {
if (self::$instance === null) {
self::$instance = new self($file);
}
return self::$instance;
}
private function __construct($file) {
$this->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;
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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;
}
}

100
src/include/functions.php Normal file
View File

@ -0,0 +1,100 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
function get_wc_shipping_methods_by_zones($enhanced = false) {
$result = array();
$shippingZones = WC_Shipping_Zones::get_zones();
$defaultZone = WC_Shipping_Zones::get_zone_by();
$shippingZones[$defaultZone->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);
}

1
src/include/index.php Normal file
View File

@ -0,0 +1 @@
<?php // Silence is golden

View File

@ -0,0 +1,46 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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;
}
}

View File

@ -0,0 +1,127 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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
);
}
}

View File

@ -0,0 +1,98 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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()
);
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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' => ''
);
}
}

1
src/index.php Normal file
View File

@ -0,0 +1 @@
<?php // Silence is golden

2
src/languages/index.php Normal file
View File

@ -0,0 +1,2 @@
<?php // Silence is golden

Binary file not shown.

Binary file not shown.

273
src/readme.txt Normal file
View File

@ -0,0 +1,273 @@
=== Woocommerce RetailCRM ===
Contributors: retailCRM
Donate link: http://retailcrm.ru/
Tags: Интеграция, Retailcrm
Requires PHP: 5.3
Requires at least: 4.7
Tested up to: 4.9.5
Stable tag: 4.9
License: GPLv1 or later
License URI: http://www.gnu.org/licenses/gpl-1.0.html
== Description ==
= Возможности плагина =
Плагин для интеграции Woocommerce и Retailcrm. Плагин позволяет сгенерировать каталог товаров для выгрузки в Retailcrm, настроить двусторонний обмен заказами Woocommerce и Retailcrm, отправлять и принимать изменения по заказам, выгружать остатки из Retailcrm в магазин. При включении функции выгрузки остатков каждые 15 минут остатки по товарам будут выгружаться в магазин (настройка имеет смысл при включении ручного редактирования остатков в Retailcrm, остатки из магазина выгружаются вместе с каталогом товаров каждые 4 часа). Внимание!!! При включении выгрузки остатков плагин включит управление остатками для товаров. Товары, отсутствующие на складе будут скрыты на сайте для посетителей.
= Выгрузка изменений из Retailcrm =
Каждые 5 минут плагин подгружает изменения из Retailcrm в Woocommerce.
= Кастомизация =
Вы можете вносить изменения в базовые классы плагина, разместив копию класса из дериктории include в директории wp-content/retailcrm-custom.
== Installation ==
= Активация и настройка =
После активации плагина необходимо открыть настройки Woocommerce, выбрать вкладку "Интеграция" и в настройках RetailCRM указать адрес CRM (например https://example.retailcrm.ru) и API-ключ, сгенерированный в CRM (инструкция по добавлению ключа в CRM - http://www.retailcrm.ru/docs/Users/ApiKeys), выбрать желаемую версию API (API v5 доступна только c версии Retailcrm 6.0 и выше)
== Frequently Asked Questions ==
= Нет списка справочников для настройки соответствия =
Проверьте, что для созданного API-ключа доступны все методы
= Заказы не попадают в Retailcrm =
API-ключ должен быть для отдельного магазина
== Screenshots ==
1. Введите адрес CRM, API-ключ и выберите версию API, нажмите на кнопку сохраниения настроек. Если после сохранения не появилось никаких других настроек, обновите страницу.
2. В появившихся списках справочников настройте соответствие способов доставки и оплаты, а так же статусов заказов. Отметьте галочку "Выгружать остатки", если хотите выгружать остатки из Retailcrm в магазин (подробнее смотрите в описании).
== Changelog ==
= 3.4.5 =
* Исправлен баг с добавлением скидки при уменьшении количества товара в retailCRM
= 3.4.4 =
* Добавлена генерация уникального id к внешнему id отправляемой оплаты при использовании 5 версии api
= 3.4.3 =
* Исправлено сохранение типа оплаты при создании заказа при обработке истории изменений на стороне WC
* Исправлено сохранение типа оплаты при ризменении заказа при обработке истории изменений на стороне WC
= 3.4.2 =
* Исправлено изменение типа оплаты на стороне WC
* Добавлен вывод неактивных типов оплаты в настройках
= 3.4.1 =
* Исправлены некоторые ошибки
= 3.4.0 =
* Добавлена настройка Daemon Collector
* Изменена логика передачи данных по заказам и клиентам. Данные доставки передаются в заказ, данные оплаты в карточку клиента.
= 3.3.8 =
* Добавлена выгрузка картинок для категорий товаров в ICML
= 3.3.7 =
* Исправлен баг активации модуля интеграции
= 3.3.6 =
* Исправлена активация модуля в маркетплейсе retailCRM при использовании api v4
= 3.3.5 =
* Добавлена активация модуля в маркетплейсе retailCRM
= 3.3.4 =
* Улучшена обработка истории заказов
= 3.3.3 =
* Добавлены кнопки для перехода в настройки плагина и для генерации каталога в админ-панели wordpress
* Улучшена механика передачи данных оплаты заказа
= 3.3.2 =
* Задачи в wp-cron теперь активируются в настройках плагина
= 3.3.1 =
* Исправлена ошибка с дублированием товаров с WC
= 3.3.0 =
* Переработана механика обработки истории изменений
= 3.2.0 =
* Улучшен метод выборки данных о доставках и оплатах в настройках плагина
* Исправлены ошибки при обработке истории изменений
* Добавлены тесты для обработки истории изменений
= 3.1.1 =
* Исправлен код отправки данных в UA
* Добавлены новые фильтры, добавлена передача новых параметров в существущие
= 3.1.0 =
* В интерфейс настроек плагина добавлена возможность ручной выгрузки заказов
* Исправлена инициализация кода UA для отправки заказов на всех страницах
= 3.0.0 =
* Произведен рефакторинг кода
= 2.1.4 =
* Исправлена ошибка при активированном модуле без настроек
* Добавлен фильтр при формировании массива заказа
* Исправлена генерация icml с неполной картинкой товара
= 2.1.3 =
* Исправлена ошибка на php5.3
= 2.1.2 =
* Добавлена локализация плагина
* Добавлена интеграция с UA
= 2.1.1 =
* Исправлена ошибка с редактированием клиента
= 2.1.0 =
* Переработана механика генерации icml каталога товаров
* В icml каталог добавлена выгрузка налоговой ставки
* Исправлен пересчет итогов после изменения количества товара в RetailCRM
= 2.0.6 =
* Исправлено возникновение Warning на PHP 7.2 при генерации каталога товаров
* Добавлена настройка выгрузки заказов из RetailCRM с определенными способами оформления
* Выгрузка изменений из RetailCRM осуществляется по sinceId
= 2.0.5 =
* Исправлен неверный подсчет скидки на товары
= 2.0.4 =
* Улучшена механика пакетной выгрузки клиентов и заказов
* Добавлена возможность выгрузки заказов с товарами, которые уже удалены с сайта
= 2.0.3 =
* Изменен механизм рассчета стоимости товара в заказе
* Улучшена передача информации об изменениях в заказе
* Устранены мелкие баги
= 2.0.2 =
* Изменен механизм передачи скидок в CRM
= 2.0.1 =
* Добавлена выгрузка размеров товаров
* Улучшена выгрузка веса товаров
* Улучшена механика выгрузки заказов из CRM
= 2.0.0 =
* Улучшен поиск типов доставок на сайте
* Добавлена кнопка генерации icml каталога в настройках плагина
* Переработан механизм выгрузки заказов из CRM
* Улучшена генерация каталога, добавлена выгрузка размеров
= 1.2.3 =
* Добален опциональный выбор статусов товаров, выгружаемых в каталоге
* Улучшен механизм формирования цены товара в заказе (с учетом скидок и налогов)
= 1.2.2 =
* Исправлены ошибки
= 1.2.1 =
* Доработана система кастомизации.
= 1.2.0 =
* Улучшена возможность кастомизации плагина.
* Добавлена возможность кастомизации обработки остатков, клиентов и истории.
= 1.1 =
* Добавлена возможность выбора версии API.
* Исправелены ошибки.
== Upgrade Notice ==
= 3.4.2 =
Исправлено изменение типа оплаты на стороне WC
Добавлен вывод неактивных типов оплаты в настройках
= 3.4.0 =
Внедрен Daemon Collector
= 3.3.5 =
После обновления плагина необходимо пересохранить настройки для того, чтобы активировать модуль в маркетплейсе retailCRM
= 3.3.4 =
Улучшена обработка истории заказов
= 3.3.3 =
Добавлены кнопки для перехода в настройки плагина и для генерации каталога в админ-панели wordpress
Улучшена механика передачи данных оплаты заказа
= 3.3.2 =
Добавлена настройка для активации задач в wp-cron
= 3.3.1 =
Исправлена ошибка с дублированием товаров с WC
= 3.3.0 =
Переработана механика обработки истории изменений
= 3.2.0 =
Улучшен метод выборки данных о доставках и оплатах в настройках плагина
Исправлены ошибки при обработке истории изменений
Добавлены тесты для обработки истории изменений
= 3.1.1 =
Исправлен код отправки данных в UA
Добавлены новые фильтры, добавлена передача новых параметров в существущие
= 3.1.0 =
В интерфейс настроек плагина добавлена возможность ручной выгрузки заказов
= 3.0.0 =
Произведен рефакторинг кода
= 2.1.4 =
Исправлена ошибка при активированном модуле без настроек
Добавлен фильтр при формировании массива заказа
Исправлена генерация icml с неполной картинкой товара
= 2.1.3 =
Исправлена ошибка на php5.3
= 2.1.2 =
Добавлена локализация плагина
Добавлена интеграция с UA
= 2.1.1 =
Исправлена ошибка с редактированием клиента
= 2.1.0 =
Переработана механика генерации icml каталога товаров
В icml каталог добавлена выгрузка налоговой ставки
Исправлен пересчет итогов после изменения количества товара в RetailCRM
= 2.0.6 =
Исправлено возникновение Warning на PHP 7.2 при генерации каталога товаров
Добавлена настройка выгрузки заказов из RetailCRM с определенными способами оформления
= 2.0.4 =
Улучшена механика пакетной выгрузки клиентов и заказов
Добавлена возможность выгрузки заказов с товарами, которые уже удалены с сайта
= 2.0.3 =
Изменен механизм рассчета стоимости товара в заказе
Улучшена передача информации об изменениях в заказе
Устранены мелкие баги
= 2.0.2 =
Изменен механизм передачи скидок в CRM
= 2.0.1 =
Добавлена выгрузка размеров товаров
Улучшена выгрузка веса товаров
Улучшена механика выгрузки заказов из CRM
= 2.0.0 =
Улучшен поиск типов доставок на сайте
Добавлена кнопка генерации icml каталога в настройках плагина
Переработан механизм выгрузки заказов из CRM
Улучшена генерация каталога, добавлена выгрузка размеров
= 1.2.3 =
Исправлены ошибки, доработан функционал

88
src/retailcrm.php Normal file
View File

@ -0,0 +1,88 @@
<?php
/**
* Version: 3.4.5
* WC requires at least: 3.0
* WC tested up to: 3.5.5
* Plugin Name: WooCommerce RetailCRM
* Plugin URI: https://wordpress.org/plugins/woo-retailcrm/
* Description: Integration plugin for WooCommerce & RetailCRM
* Author: RetailDriver LLC
* Author URI: http://retailcrm.pro/
* Text Domain: retailcrm
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if (!class_exists( 'WC_Integration_Retailcrm')) :
/**
* Class WC_Integration_Retailcrm
*/
class WC_Integration_Retailcrm {
private static $instance;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Construct the plugin.
*/
public function __construct() {
$this->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 '<div class="error"><p>Woocommerce is not installed</p></div>';
}
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;

46
src/uninstall.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Fired when the plugin is uninstalled.
*
* When populating this file, consider the following flow
* of control:
*
* - This method should be static
* - Check if the $_REQUEST content actually is the plugin name
* - Run an admin referrer check to make sure it goes through authentication
* - Verify the output of $_GET makes sense
* - Repeat with other user roles. Best directly by using the links/query string parameters.
* - Repeat things for multisite. Once for a single site in the network, once sitewide.
*
*
* @link https://wordpress.org/plugins/woo-retailcrm/
* @version 3.4.5
*
* @package RetailCRM
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
// If uninstall not called from WordPress, then exit.
if (!defined('WP_UNINSTALL_PLUGIN')) {
exit;
}
global $wpdb;
wp_clear_scheduled_hook('retailcrm_icml');
wp_clear_scheduled_hook('retailcrm_history');
wp_clear_scheduled_hook('retailcrm_inventories');
// Delete options.
$wpdb->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();

137
tests/bin/install.sh Executable file
View File

@ -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-name> <db-user> <db-pass> [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

8
tests/bin/script.sh Normal file
View File

@ -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

View File

@ -0,0 +1,13 @@
<?php
if (!class_exists('WC_Retailcrm_Response')) {
require_once dirname(__FILE__) . '/../../src/include/api/class-wc-retailcrm-response.php';
}
class WC_Retailcrm_Response_Helper extends WC_Retailcrm_Response
{
public function setResponse($response)
{
$this->response = $response;
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Class WC_Retailcrm_Test_Case_Helper
*/
class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
{
/**
* @param string $apiVersion
*
* @return array
*/
protected function setOptions($apiVersion = 'v5')
{
$options = array(
'api_url' => '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);
}
}

View File

@ -0,0 +1,30 @@
<?php
$_tests_dir = getenv('WP_TESTS_DIR');
if (!$_tests_dir) {
$_tests_dir = '/tmp/wordpress-tests-lib';
}
require_once $_tests_dir . '/includes/functions.php';
function _manually_load_plugin() {
$plugin_dir = dirname(dirname(dirname(__FILE__))) . '/';
require $plugin_dir . 'src/include/class-wc-retailcrm-orders.php';
require $plugin_dir . 'src/include/class-wc-retailcrm-customers.php';
require $plugin_dir . 'src/include/class-wc-retailcrm-inventories.php';
require $plugin_dir . 'src/include/class-wc-retailcrm-ga.php';
require $plugin_dir . 'src/include/class-wc-retailcrm-daemon-collector.php';
require $plugin_dir . 'src/include/class-wc-retailcrm-history.php';
require $plugin_dir . 'src/retailcrm.php';
}
tests_add_filter('muplugins_loaded', '_manually_load_plugin');
require '/tmp/woocommerce/tests/bootstrap.php';
$plugin_dir = dirname(dirname(dirname(__FILE__))) . '/';
// helpers
require $plugin_dir . 'tests/helpers/class-wc-retailcrm-response-helper.php';
require $plugin_dir . 'tests/helpers/class-wc-retailcrm-test-case-helper.php';

View File

@ -0,0 +1,39 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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']);
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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);
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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);
}
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* PHP version 5.3
*
* @category Integration
* @author RetailCRM <integration@retailcrm.ru>
* @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()
)
);
}
}

View File

@ -0,0 +1,221 @@
<?php
class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $responseMockOrderMethods;
protected $responseMockDeliveryTypes;
protected $responseMockPaymentTypes;
protected $responseMockStatuses;
private $unit;
public function setUp()
{
$this->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);
}
}

View File

@ -0,0 +1,151 @@
<?php
class WC_Retailcrm_Customers_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $responseMock;
protected $customer;
public function setUp()
{
$this->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()
);
}
}

View File

@ -0,0 +1,30 @@
<?php
class WC_Retailcrm_Daemon_Collector_Test extends WC_Retailcrm_Test_Case_Helper
{
private $daemonCollector;
private $options;
public function setUp()
{
$this->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('<script', $js);
$this->assertContains('</script>', $js);
$this->assertContains('_rc(\'create\',', $js);
}
}

View File

@ -0,0 +1,61 @@
<?php
class WC_Retailcrm_Google_Analytics_Test extends WC_Retailcrm_Test_Case_Helper
{
private $ga;
private $options;
private $order;
private $orderKey;
public function setUp()
{
$this->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
)
);
}
}

View File

@ -0,0 +1,452 @@
<?php
class WC_Retailcrm_History_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $customersHistoryResponse;
protected $ordersHistoryResponse;
const STATUS_1 = 'status1';
const STATUS_2 = 'status4';
public function setUp()
{
$this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy')
->disableOriginalConstructor()
->setMethods(array(
'ordersHistory',
'customersHistory'
))
->getMock();
$this->customersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper')
->disableOriginalConstructor()
->setMethods(array(
'isSuccessful'
))
->getMock();
$this->ordersHistoryResponse = $this->getMockBuilder('\WC_Retailcrm_Response_Helper')
->disableOriginalConstructor()
->setMethods(array(
'isSuccessful'
))
->getMock();
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;
}
}

View File

@ -0,0 +1,123 @@
<?php
class WC_Retailcrm_Inventories_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $responseMock;
protected $offer;
public function setUp()
{
$this->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']
)
);
}
}

View File

@ -0,0 +1,335 @@
<?php
class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $order;
protected $options;
public function setUp()
{
$this->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())
);
}
}

View File

@ -0,0 +1,176 @@
<?php
class WC_Retailcrm_Plugin_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $responseMock;
public function setUp()
{
$this->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;
}
}