1
0
mirror of synced 2025-01-18 08:51:41 +03:00

ref #68451 Added the ability to select CRM warehouses to synchronize the balance of offers

This commit is contained in:
Uryvskiy Dima 2023-07-10 09:58:23 +03:00 committed by GitHub
commit ad21aaf178
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 187 additions and 61 deletions

View File

@ -1,3 +1,6 @@
## 2023-06-27 4.6.8
* Added the ability to select CRM warehouses to synchronize the balance of offers
## 2023-06-27 4.6.7
* Fixed customer phone sending to crm when order will create by guest

View File

@ -1 +1 @@
4.6.7
4.6.8

View File

@ -6,19 +6,25 @@
Анализ работы по списанию остатков был произведен в задаче [#75178](https://redmine.retailcrm.tech/issues/75178).
**В версии 4.6.8** появилась возможность указать, с каких складов CRM выгружать остатки для торговых предложений. В блоке "Настройка управления остатками" добавлен мультисписок с доступными складами CRM. Для выбора нескольких складов зажмите CTRL (для Windows и Linux) или ⌘ Command (для MacOS).
Если в CRM несколько складов, а в настройках не выбрали склады для выгрузки, в таком случае остатки будут передаваться по всем складам.
#### На стороне WooCommerce
Если остатки **ведут на сайте**, то в этом случае, при оформлении заказа на сайте, остаток по товару сразу же списывается в WooCommerce. В CRM обновление остатков по товарам происходит в момент синхронизации ICML-файла каталога *(~ 4 часа)*.
| Кейс | Результат |
|--|--|
| Оформить заказ на сайте, после указать статус Отменен заказу на стороне WooCommerce | При оформлении заказа остатки сразу списываются, как в WooCommerce, так и в CRM; <br/> После указания отмены заказу, в WooCommerce остатки сразу возвращаются, в CRM, если настроена автоматическая отмена товара при отмене заказа, остатки возвращаются, иначе нужно ждать обновления каталога |
| Оформить заказ в CRM, после указать статус из группы Выполнен в CRM | В CRM по товарам остатки не списываются; <br/> В WooCommerce остаток по товару списывается, когда приходит статус Выполнен |
| Оформить заказ в CRM, после указать статус из группы Отмена в CRM | В CRM остатки не списываются *(в т.ч. и при установлении отмены статусу товара)*, в WooCommerce остатки по товару также не возвращаются |
| Кейс | Результат |
|----------|-------------|
| Оформить заказ на сайте, после указать статус Отменен заказу на стороне WooCommerce | При оформлении заказа остатки сразу списываются, как в WooCommerce, так и в CRM; <br/> После указания отмены заказу, в WooCommerce остатки сразу возвращаются, в CRM, если настроена автоматическая отмена товара при отмене заказа, остатки возвращаются, иначе нужно ждать обновления каталога |
| Оформить заказ в CRM, после указать статус из группы Выполнен в CRM | В CRM по товарам остатки не списываются; <br/> В WooCommerce остаток по товару списывается, когда приходит статус Выполнен |
| Оформить заказ в CRM, после указать статус из группы Отмена в CRM | В CRM остатки не списываются *(в т.ч. и при установлении отмены статусу товара)*, в WooCommerce остатки по товару также не возвращаются |
#### На стороне CRM
При ведении стока **на стороне CRM**, остаток по товару сразу списывается в CRM. На стороне WooCommerce остатки по товарам обновляются **раз в 15 минут**.
| Кейс | Результат |
|--|--|
| Оформить заказ в CRM, после указать статус в CRM, соответствующий в маппинге статусу Отмены заказа | Если данный статус в CRM не выставляет автоматически статус отмены товару, то в CRM остатки не возвращаются, также, как и на стороне WooCommerce <br/> Если будет выставлен статус отмены товару, остатки возвратятся в CRM и спустя 15 минут в WooCommerce |
| Оформить заказ в CRM, после указать в CRM **статус товару** из группы Отмена | В CRM остаток по товару возвращается, в WooCommerce сток обновляется через 15 минут |
| Оформить заказ на сайте в WooCommerce | Заказ выгружается в CRM, по нему списываются остатки по товару, данное списание передается на сторону WooCommerce |
| Оформить заказ на сайте в WooCommerce, после указать статус Отменен в админке сайта WooCommerce | В CRM приходит статус отмены заказа, если в CRM настроена опция автоматической отмены товара при отмене заказа, то остатки возвращаются в CRM, спустя время и в WooCommerce |
Если данный статус в CRM не выставляет автоматически статус отмены товару, то в CRM остатки не возвращаются, также, как и на стороне WooCommerce <br/> Если будет выставлен статус отмены товару, остатки возвратятся в CRM и спустя 15 минут в WooCommerce
| Кейс | Результат |
|------------------------------------------------------------------------------|-----------|
| Оформить заказ в CRM, после указать в CRM **статус товару** из группы Отмена | В CRM остаток по товару возвращается, в WooCommerce сток обновляется через 15 минут |
| Оформить заказ на сайте в WooCommerce | Заказ выгружается в CRM, по нему списываются остатки по товару, данное списание передается на сторону WooCommerce |
| Оформить заказ на сайте в WooCommerce, после указать статус Отменен в админке сайта WooCommerce | В CRM приходит статус отмены заказа, если в CRM настроена опция автоматической отмены товара при отмене заказа, то остатки возвращаются в CRM, спустя время и в WooCommerce |

View File

@ -414,3 +414,9 @@ msgstr "Región"
msgid "Standard CRM fields"
msgstr "Los campos del CRM por defecto"
msgid "Warehouses available in CRM"
msgstr "Almacenes disponibles en CRM"
msgid "Select warehouses to receive balances from CRM. To select several warehouses, hold down CTRL (for Windows and Linux) or ⌘ Command (for MacOS)"
msgstr "Selecciona los almacenes para recibir el stock desde CRM. Para seleccionar varios mantén pulsado CTRL (para Windows y Linux) o ⌘ Command (para MacOS)"

View File

@ -423,3 +423,9 @@ msgstr "Регион"
msgid "Standard CRM fields"
msgstr "Стандартные поля CRM"
msgid "Warehouses available in CRM"
msgstr "Склады, доступные в CRM"
msgid "Select warehouses to receive balances from CRM. To select several warehouses, hold down CTRL (for Windows and Linux) or ⌘ Command (for MacOS)"
msgstr "Выберите склады для получения остатков из CRM. Для выбора нескольких складов зажмите CTRL (для Windows и Linux) или ⌘ Command (для MacOS)"

View File

@ -157,9 +157,9 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration
$order_methods_option = [];
$order_methods_list = $this->apiClient->orderMethodsList();
if (!empty($order_methods_list) && $order_methods_list->isSuccessful()) {
if ($order_methods_list->isSuccessful() && !empty($order_methods_list['orderMethods'])) {
foreach ($order_methods_list['orderMethods'] as $order_method) {
if ($order_method['active'] == false) {
if (!$order_method['active']) {
continue;
}
@ -379,6 +379,32 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration
'description' => __('Enable this setting if you would like to get information on leftover stocks from Simla.com to the website', 'retailcrm')
];
$crmStores = [];
$crmStoresList = $this->apiClient->storesList();
if ($crmStoresList->isSuccessful() && !empty($crmStoresList['stores'])) {
foreach ($crmStoresList['stores'] as $store) {
if (!$store['active']) {
continue;
}
$crmStores[$store['code']] = $store['name'];
}
}
$this->form_fields['stores_for_uploading'] = [
'label' => ' ',
'title' => __('Warehouses available in CRM', 'retailcrm'),
'class' => '',
'type' => 'multiselect',
'options' => $crmStores,
'css' => 'min-height:100px;',
'select_buttons' => true,
'description' => __('Select warehouses to receive balances from CRM. To select several warehouses, hold down CTRL (for Windows and Linux) or ⌘ Command (for MacOS)',
'retailcrm'
),
];
/**
* UA options
*/

View File

@ -301,6 +301,7 @@ if (!class_exists('WC_Retailcrm_Base')) {
public function load_stocks()
{
$inventories = new WC_Retailcrm_Inventories($this->apiClient);
$inventories->updateQuantity();
}

View File

@ -55,6 +55,11 @@ if (!class_exists('WC_Retailcrm_History')) :
unset($this->retailcrmSettings['order_methods']);
}
// Because the orderHistory method uses array_flip, and the option with array called error
if (isset($this->retailcrmSettings['stores_for_uploading'])) {
unset($this->retailcrmSettings['stores_for_uploading']);
}
$this->retailcrm = $retailcrm;
$this->startDate = new DateTime('-1 days');
}

View File

@ -18,10 +18,10 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
protected $retailcrm;
/** @var array */
protected $retailcrm_settings;
protected $crmSettings;
/** @var string */
protected $bind_field = 'externalId';
protected $bindField = 'externalId';
/**
* WC_Retailcrm_Inventories constructor.
@ -29,13 +29,11 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
*/
public function __construct($retailcrm = false)
{
$this->retailcrm_settings = get_option(WC_Retailcrm_Base::$option_key);
$this->crmSettings = get_option(WC_Retailcrm_Base::$option_key);
$this->retailcrm = $retailcrm;
if (isset($this->retailcrm_settings['bind_by_sku'])
&& $this->retailcrm_settings['bind_by_sku'] == WC_Retailcrm_Base::YES
) {
$this->bind_field = 'xmlId';
if (!empty($this->crmSettings['bind_by_sku']) && $this->crmSettings['bind_by_sku'] === WC_Retailcrm_Base::YES) {
$this->bindField = 'xmlId';
}
}
@ -46,20 +44,19 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
*/
protected function load_stocks()
{
$success = array();
if (!$this->retailcrm instanceof WC_Retailcrm_Proxy) {
return null;
}
$page = 1;
$variationProducts = array();
$availableStores = $this->crmSettings['stores_for_uploading'] ?? null;
$variationProducts = [];
do {
/** @var WC_Retailcrm_Response $response */
$response = $this->retailcrm->storeInventories(array(), $page, 250);
$response = $this->retailcrm->storeInventories(['details' => true], $page, 250);
if (empty($response) || !$response->isSuccessful()) {
if (empty($response['offers']) || !$response->isSuccessful()) {
return null;
}
@ -67,11 +64,23 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
$page++;
foreach ($response['offers'] as $offer) {
if (isset($offer[$this->bind_field])) {
$product = retailcrm_get_wc_product($offer[$this->bind_field], $this->retailcrm_settings);
$offerQuantity = $offer['quantity'];
if (!empty($availableStores) && count($offer['stores']) > 1) {
$offerQuantity = 0;
foreach ($offer['stores'] as $store) {
if (in_array($store['store'], $availableStores, true)) {
$offerQuantity += $store['quantity'];
}
}
}
if (isset($offer[$this->bindField])) {
$product = retailcrm_get_wc_product($offer[$this->bindField], $this->crmSettings);
if ($product instanceof WC_Product) {
if ($product->get_type() == 'external') {
if ($product->get_type() === 'external') {
continue;
}
@ -80,15 +89,15 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
if (!empty($parentId)) {
if (isset($variationProducts[$parentId])) {
$variationProducts[$parentId] += $offer['quantity'];
$variationProducts[$parentId] += $offerQuantity;
} else {
$variationProducts[$parentId] = $offer['quantity'];
$variationProducts[$parentId] = $offerQuantity;
}
}
}
$product->set_manage_stock(true);
$product->set_stock_quantity($offer['quantity']);
$product->set_stock_quantity($offerQuantity);
$product->save();
}
}
@ -124,7 +133,7 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
*/
public function updateQuantity()
{
if ($this->retailcrm_settings['sync'] == WC_Retailcrm_Base::YES) {
if ($this->crmSettings['sync'] === WC_Retailcrm_Base::YES) {
$this->load_stocks();
}
}

Binary file not shown.

Binary file not shown.

View File

@ -4,8 +4,8 @@ Donate link: https://www.simla.com
Tags: Интеграция, Simla.com, simla
Requires PHP: 7.0
Requires at least: 5.3
Tested up to: 6.0
Stable tag: 4.6.7
Tested up to: 6.2
Stable tag: 4.6.8
License: GPLv1 or later
License URI: http://www.gnu.org/licenses/gpl-1.0.html
@ -82,6 +82,9 @@ Asegúrate de tener una clave API específica para cada tienda. Las siguientes i
== Changelog ==
= 4.6.8 =
* Added the ability to select CRM warehouses to synchronize the balance of offers
= 4.6.7 =
* Fixed customer phone sending to crm when order will create by guest

View File

@ -5,10 +5,10 @@
* Description: Integration plugin for WooCommerce & Simla.com
* Author: RetailDriver LLC
* Author URI: http://retailcrm.pro/
* Version: 4.6.7
* Tested up to: 6.0
* Version: 4.6.8
* Tested up to: 6.2
* WC requires at least: 5.4
* WC tested up to: 6.9
* WC tested up to: 7.8
* Text Domain: retailcrm
*/

View File

@ -16,7 +16,7 @@
*
* @link https://wordpress.org/plugins/woo-retailcrm/
*
* @version 4.6.7
* @version 4.6.8
*
* @package RetailCRM
*/

View File

@ -140,4 +140,28 @@ class DataBaseRetailCrm
]
];
}
public static function getResponseStoreList()
{
return [
'success' => true,
'stores' => [
[
'name' => 'main',
'code' => 'main',
'active' => true
],
[
'name' => 'woocommerce',
'code' => 'woocommerce',
'active' => true
],
[
'name' => 'prestashop',
'code' => 'prestashop',
'active' => true
]
]
];
}
}

View File

@ -16,21 +16,39 @@ namespace datasets;
class DataInventoriesRetailCrm {
public static function getResponseData()
{
return array(
return [
'success' => true,
'pagination' => array(
'pagination' => [
'limit' => 250,
'totalCount' => 1,
'currentPage' => 1,
'totalPageCount' => 1
),
'offers' => array(
array(
],
'offers' => [
[
'id' => 1,
'xmlId' => 'xmlId',
'quantity' => 10
)
)
);
'quantity' => 100,
'stores' => [
[
'quantity' => 25,
'purchasePrice' => 0,
'store' => 'main'
],
[
'quantity' => 25,
'purchasePrice' => 0,
'store' => 'woocommerce'
],
[
'quantity' => 50,
'purchasePrice' => 0,
'store' => 'prestashop'
],
]
]
]
];
}
}

View File

@ -51,7 +51,7 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
'whatsapp_active' => 'yes',
'whatsapp_location_icon' => 'yes',
'whatsapp_number' => '+79184567234',
'icml' => 'yes',
'icml' => 'yes',
'corporate_enabled' => 'yes',
'abandoned_carts_enabled' => 'yes',
'single_order' => '123',
@ -61,7 +61,7 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
'update_number' => 'yes',
'debug_mode' => 'yes',
'debug-info' => '',
'order-meta-data-retailcrm' => json_encode(
'order-meta-data-retailcrm' => json_encode(
[
'woo_order' => 'crm_order',
'crm_phone' => 'default-crm-field#phone',
@ -78,6 +78,7 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
]
),
'product_description' => 'full',
'stores_for_uploading' => ['woocommerce', 'main'],
];
update_option(WC_Retailcrm_Base::$option_key, $options);
@ -140,7 +141,7 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
protected function setMockResponse($mock, $method, $response)
{
$mock->expects($this->any())
->method($method)
->willReturn($response);
->method($method)
->willReturn($response);
}
}

View File

@ -16,6 +16,7 @@ use datasets\DataBaseRetailCrm;
class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
{
protected $apiMock;
protected $responseMockStoresList;
protected $responseMockOrderMethods;
protected $responseMockDeliveryTypes;
protected $responseMockPaymentTypes;
@ -31,6 +32,7 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
->disableOriginalConstructor()
->setMethods(
[
'storesList',
'orderMethodsList',
'deliveryTypesList',
'paymentTypesList',
@ -47,6 +49,7 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
$this->setMockPaymentTypes();
$this->setMockStatuses();
$this->setMockCustomFields();
$this->setMockStoresList();
$_GET['page'] = 'wc-settings';
$_GET['tab'] = 'integration';
@ -120,6 +123,7 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
//Other settings
$this->assertArrayHasKey('corporate_enabled', $this->baseRetailcrm->form_fields);
$this->assertArrayHasKey('stores_for_uploading', $this->baseRetailcrm->form_fields);
$this->assertArrayHasKey('abandoned_carts_enabled', $this->baseRetailcrm->form_fields);
$this->assertArrayHasKey('online_assistant', $this->baseRetailcrm->form_fields);
$this->assertArrayHasKey('deactivate_update_order', $this->baseRetailcrm->form_fields);
@ -395,6 +399,20 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper
return json_decode($matches[0], true);
}
private function setMockStoresList()
{
$this->responseMockStoresList = $this
->getMockBuilder('\WC_Retailcrm_Response_Helper')
->disableOriginalConstructor()
->setMethods(['isSuccessful'])
->getMock();
$this->setMockResponse($this->responseMockStoresList, 'isSuccessful', true);
$this->responseMockStoresList->setResponse(DataBaseRetailCrm::getResponseStoreList());
$this->setMockResponse($this->apiMock, 'storesList', $this->responseMockStoresList);
}
private function setMockOrderMethods()
{
$this->responseMockOrderMethods = $this

View File

@ -21,16 +21,16 @@ class WC_Retailcrm_Inventories_Test extends WC_Retailcrm_Test_Case_Helper
public function setUp()
{
$this->responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper')
->disableOriginalConstructor()
->setMethods(array('isSuccessful'))
->getMock();
->disableOriginalConstructor()
->setMethods(['isSuccessful'])
->getMock();
$this->setMockResponse($this->responseMock, 'isSuccessful', true);
$this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Proxy')
->disableOriginalConstructor()
->setMethods(array('storeInventories'))
->getMock();
->disableOriginalConstructor()
->setMethods(['storeInventories'])
->getMock();
parent::setUp();
}
@ -111,9 +111,9 @@ class WC_Retailcrm_Inventories_Test extends WC_Retailcrm_Test_Case_Helper
if ($retailcrm && null !== $response) {
$this->assertInstanceOf('WC_Product', $product);
$this->assertEquals($entity, $product->get_type());
$this->assertEquals(10, $product->get_stock_quantity());
$this->assertEquals(50, $product->get_stock_quantity());
} else {
$this->assertNotEquals(10, $product->get_stock_quantity());
$this->assertNotEquals(50, $product->get_stock_quantity());
}
}