Tests orders and base
This commit is contained in:
parent
fd8e98ac63
commit
cdfad1ad6c
31 changed files with 559 additions and 209 deletions
|
@ -21,7 +21,6 @@
|
|||
<file>uninstall.php</file>
|
||||
<exclude>
|
||||
<directory suffix=".php">./include/api</directory>
|
||||
<file>./include/class-wc-retailcrm-base.php</file>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
|
|
@ -16,14 +16,16 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
|
||||
public static $option_key;
|
||||
|
||||
public $apiClient;
|
||||
protected $api_url;
|
||||
protected $api_key;
|
||||
|
||||
private $apiClient;
|
||||
|
||||
/**
|
||||
* Init and hook in the integration.
|
||||
* @param $retailcrm (default = false)
|
||||
*/
|
||||
public function __construct() {
|
||||
public function __construct($retailcrm = false) {
|
||||
//global $woocommerce;
|
||||
|
||||
if ( ! class_exists( 'WC_Retailcrm_Proxy' ) ) {
|
||||
|
@ -34,7 +36,12 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
$this->method_title = __('RetailCRM', 'retailcrm');
|
||||
$this->method_description = __('Integration with eComlogic managament system.', 'retailcrm');
|
||||
|
||||
$this->apiClient = $this->getApiClient();
|
||||
if ($retailcrm === false) {
|
||||
$this->apiClient = $this->getApiClient();
|
||||
} else {
|
||||
$this->apiClient = $retailcrm;
|
||||
}
|
||||
|
||||
self::$option_key = $this->get_option_key();
|
||||
// Load the settings.
|
||||
$this->init_form_fields();
|
||||
|
@ -419,8 +426,8 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
'id' => 'shipping_options'
|
||||
);
|
||||
|
||||
foreach ( $wc_shipping_list as $shipping_code => $shipping ) {
|
||||
if ( isset( $shipping['enabled'] ) && $shipping['enabled'] == 'yes' ) {
|
||||
foreach ($wc_shipping_list as $shipping_code => $shipping) {
|
||||
if (isset($shipping['enabled']) && $shipping['enabled'] == 'yes') {
|
||||
$this->form_fields[$shipping_code] = array(
|
||||
'title' => __($shipping['title'], 'woocommerce'),
|
||||
'description' => __($shipping['description'], 'woocommerce'),
|
||||
|
@ -445,7 +452,7 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
$payment_option_list[$retailcrm_payment_type['code']] = $retailcrm_payment_type['name'];
|
||||
}
|
||||
|
||||
$wc_payment = new WC_Payment_Gateways();
|
||||
$wc_payment = WC_Payment_Gateways::instance();
|
||||
|
||||
$this->form_fields[] = array(
|
||||
'title' => __('Payment methods', 'retailcrm'),
|
||||
|
@ -454,11 +461,9 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
'id' => 'payment_options'
|
||||
);
|
||||
|
||||
foreach ( $wc_payment->payment_gateways as $payment ) {
|
||||
if ( isset( $payment->enabled ) && $payment->enabled == 'yes' ) {
|
||||
$key = $payment->id;
|
||||
$name = $key;
|
||||
$this->form_fields[$name] = array(
|
||||
foreach ($wc_payment->get_available_payment_gateways() as $payment) {
|
||||
if (isset($payment->enabled) && $payment->enabled == 'yes') {
|
||||
$this->form_fields[$payment->id] = array(
|
||||
'title' => __($payment->method_title, 'woocommerce'),
|
||||
'description' => __($payment->method_description, 'woocommerce'),
|
||||
'css' => 'min-width:350px;',
|
||||
|
@ -491,7 +496,7 @@ if (!class_exists('WC_Retailcrm_Base')) {
|
|||
'id' => 'statuses_options'
|
||||
);
|
||||
|
||||
foreach ( $wc_statuses as $idx => $name ) {
|
||||
foreach ($wc_statuses as $idx => $name) {
|
||||
$uid = str_replace('wc-', '', $idx);
|
||||
$this->form_fields[$uid] = array(
|
||||
'title' => __($name, 'woocommerce'),
|
|
@ -37,7 +37,7 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
|
|||
$success = array();
|
||||
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$page = 1;
|
||||
|
@ -46,7 +46,7 @@ if (!class_exists('WC_Retailcrm_Inventories')) :
|
|||
$result = $this->retailcrm->storeInventories(array(), $page, 250);
|
||||
|
||||
if (!$result->isSuccessful()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$totalPageCount = $result['pagination']['totalPageCount'];
|
|
@ -17,6 +17,9 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
protected $retailcrm_settings;
|
||||
protected $retailcrm;
|
||||
|
||||
private $order = array();
|
||||
private $payment = array();
|
||||
|
||||
public function __construct($retailcrm = false)
|
||||
{
|
||||
$this->retailcrm_settings = get_option(WC_Retailcrm_Base::$option_key);
|
||||
|
@ -25,11 +28,13 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
|
||||
/**
|
||||
* Upload orders to CRM
|
||||
*
|
||||
* @return array $uploadOrders | null
|
||||
*/
|
||||
public function ordersUpload()
|
||||
{
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$orders = get_posts(array(
|
||||
|
@ -41,16 +46,15 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
$orders_data = array();
|
||||
|
||||
foreach ($orders as $data_order) {
|
||||
$order_data = $this->processOrder($data_order->ID);
|
||||
|
||||
$order = new WC_Order($data_order->ID);
|
||||
$order = wc_get_order($data_order->ID);
|
||||
$this->processOrder($order);
|
||||
$customer = $order->get_user();
|
||||
|
||||
if ($customer != false) {
|
||||
$order_data['customer']['externalId'] = $customer->get('ID');
|
||||
$this->order['customer']['externalId'] = $customer->get('ID');
|
||||
}
|
||||
|
||||
$orders_data[] = $order_data;
|
||||
$orders_data[] = $this->order;
|
||||
}
|
||||
|
||||
$uploadOrders = array_chunk($orders_data, 50);
|
||||
|
@ -58,22 +62,25 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
foreach ($uploadOrders as $uploadOrder) {
|
||||
$this->retailcrm->ordersUpload($uploadOrder);
|
||||
}
|
||||
|
||||
return $uploadOrders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create order
|
||||
*
|
||||
* @param $order_id
|
||||
*
|
||||
* @return WC_Order $order | null
|
||||
*/
|
||||
public function orderCreate($order_id)
|
||||
{
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$order_data = $this->processOrder($order_id);
|
||||
|
||||
$order = new WC_Order($order_id);
|
||||
$order = wc_get_order($order_id);
|
||||
$this->processOrder($order);
|
||||
$customer = $order->get_user();
|
||||
|
||||
if ($customer != false) {
|
||||
|
@ -82,123 +89,97 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
if (!$search->isSuccessful()) {
|
||||
$customer_data = array(
|
||||
'externalId' => $customer->get('ID'),
|
||||
'firstName' => $order_data['firstName'],
|
||||
'lastName' => $order_data['lastName'],
|
||||
'email' => $order_data['email']
|
||||
'firstName' => $this->order['firstName'],
|
||||
'lastName' => $this->order['lastName'],
|
||||
'email' => $this->order['email']
|
||||
);
|
||||
|
||||
$this->retailcrm->customersCreate($customer_data);
|
||||
} else {
|
||||
$order_data['customer']['externalId'] = $search['customer']['externalId'];
|
||||
$this->order['customer']['externalId'] = $search['customer']['externalId'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->retailcrm->ordersCreate($order_data);
|
||||
$this->retailcrm->ordersCreate($this->order);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update order status
|
||||
* Edit order in CRM
|
||||
*
|
||||
* @param $order_id
|
||||
* @param int $order_id
|
||||
*
|
||||
* @return WC_Order $order | null
|
||||
*/
|
||||
public function orderUpdateStatus($order_id)
|
||||
public function updateOrder($order_id)
|
||||
{
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$order = new WC_Order( $order_id );
|
||||
$order = wc_get_order($order_id);
|
||||
$this->processOrder($order, true);
|
||||
|
||||
$order_data = array(
|
||||
'externalId' => $order_id,
|
||||
'status' => $this->retailcrm_settings[$order->get_status()]
|
||||
);
|
||||
if ($this->retailcrm_settings['api_version'] == 'v4') {
|
||||
$this->order['paymentType'] = $this->retailcrm_settings[$order->get_payment_method()];
|
||||
}
|
||||
|
||||
$this->retailcrm->ordersEdit($order_data);
|
||||
$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 $order_id
|
||||
* @param WC_Order $order
|
||||
*
|
||||
* @return null
|
||||
* @return null | array $payment
|
||||
*/
|
||||
protected function orderUpdatePaymentType($order_id, $payment_method) {
|
||||
|
||||
if (!isset($this->retailcrm_settings[$payment_method])) {
|
||||
return;
|
||||
protected function orderUpdatePaymentType($order)
|
||||
{
|
||||
if (!isset($this->retailcrm_settings[$order->get_payment_method()])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->retailcrm_settings['api_version'] != 'v5') {
|
||||
$order_data = array(
|
||||
'externalId' => $order_id,
|
||||
'paymentType' => $this->retailcrm_settings[$payment_method]
|
||||
);
|
||||
$response = $this->retailcrm->ordersGet($order->get_id());
|
||||
|
||||
$this->retailcrm->ordersEdit($order_data);
|
||||
} else {
|
||||
$response = $this->retailcrm->ordersGet($order_id);
|
||||
if ($response->isSuccessful()) {
|
||||
$retailcrmOrder = $response['order'];
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
$order = $response['order'];
|
||||
}
|
||||
|
||||
foreach ($order['payments'] as $payment_data) {
|
||||
if ($payment_data['externalId'] == $order_id) {
|
||||
foreach ($retailcrmOrder['payments'] as $payment_data) {
|
||||
if ($payment_data['externalId'] == $order->get_id()) {
|
||||
$payment = $payment_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$order = new WC_Order($order_id);
|
||||
if (isset($payment) && $payment['type'] != $this->retailcrm_settings[$order->get_payment_method()]) {
|
||||
$response = $this->retailcrm->ordersPaymentDelete($payment['id']);
|
||||
|
||||
if (isset($payment) && $payment['type'] != $this->retailcrm_settings[$order->payment_method]) {
|
||||
$response = $this->retailcrm->ordersPaymentDelete($payment['id']);
|
||||
if ($response->isSuccessful()) {
|
||||
$payment = $this->createPayment($order);
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
$this->createPayment($order, $order_id);
|
||||
}
|
||||
return $payment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update order payment
|
||||
*
|
||||
* @param $order_id
|
||||
*/
|
||||
public function orderUpdatePayment($order_id)
|
||||
{
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->retailcrm_settings['api_version'] != 'v5') {
|
||||
$order_data = array(
|
||||
'externalId' => $order_id,
|
||||
'paymentStatus' => 'paid'
|
||||
);
|
||||
|
||||
$this->retailcrm->ordersEdit($order_data);
|
||||
} else {
|
||||
$payment = array(
|
||||
'externalId' => $order_id,
|
||||
'status' => 'paid'
|
||||
);
|
||||
|
||||
$this->retailcrm->ordersPaymentsEdit($payment);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order data
|
||||
*
|
||||
* @param int $order_id
|
||||
* @param WC_Order $order
|
||||
*
|
||||
* @return array $order_data_arr
|
||||
*/
|
||||
protected function getOrderData($order_id) {
|
||||
$order = new WC_Order( $order_id );
|
||||
protected function getOrderData($order) {
|
||||
$order_data_arr = array();
|
||||
$order_info = $order->get_data();
|
||||
|
||||
|
@ -215,19 +196,18 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
/**
|
||||
* process to combine order data
|
||||
*
|
||||
* @param int $order_id
|
||||
* @param WC_Order $order
|
||||
* @param boolean $update
|
||||
*
|
||||
* @return array $order_data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processOrder($order_id, $update = false)
|
||||
protected function processOrder($order, $update = false)
|
||||
{
|
||||
if ( !$order_id ){
|
||||
if (!$order instanceof WC_Order) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = new WC_Order( $order_id );
|
||||
$order_data_info = $this->getOrderData($order_id);
|
||||
$order_data_info = $this->getOrderData($order);
|
||||
$order_data = array();
|
||||
|
||||
$order_data['externalId'] = $order_data_info['id'];
|
||||
|
@ -235,13 +215,16 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
$order_data['createdAt'] = trim($order_data_info['date']);
|
||||
$order_data['customerComment'] = $order_data_info['customer_comment'];
|
||||
|
||||
if ( !empty( $order_data_info['payment_method'] ) && !empty($this->retailcrm_settings[$order_data_info['payment_method']]) && $this->retailcrm_settings['api_version'] != 'v5') {
|
||||
if (!empty($order_data_info['payment_method'])
|
||||
&& !empty($this->retailcrm_settings[$order_data_info['payment_method']])
|
||||
&& $this->retailcrm_settings['api_version'] != 'v5'
|
||||
) {
|
||||
$order_data['paymentType'] = $this->retailcrm_settings[$order_data_info['payment_method']];
|
||||
}
|
||||
|
||||
if ($order->get_items( 'shipping' )) {
|
||||
if ($order->get_items('shipping')) {
|
||||
$shippings = $order->get_items( 'shipping' );
|
||||
$shipping = end($shippings);
|
||||
$shipping = reset($shippings);
|
||||
$shipping_code = explode(':', $shipping['method_id']);
|
||||
|
||||
if (isset($this->retailcrm_settings[$shipping['method_id']])) {
|
||||
|
@ -337,11 +320,11 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
if ($this->retailcrm_settings['api_version'] == 'v5') {
|
||||
$payment = array(
|
||||
'amount' => $order->get_total(),
|
||||
'externalId' => $order_id
|
||||
'externalId' => $order->get_id()
|
||||
);
|
||||
|
||||
$payment['order'] = array(
|
||||
'externalId' => $order_id
|
||||
'externalId' => $order->get_id()
|
||||
);
|
||||
|
||||
if (!empty($order_data_info['payment_method']) && !empty($this->retailcrm_settings[$order_data_info['payment_method']])) {
|
||||
|
@ -359,12 +342,10 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
|
||||
if (!$update) {
|
||||
$order_data['payments'][] = $payment;
|
||||
} else {
|
||||
$this->editPayment($payment);
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters('retailcrm_process_order', $order_data);
|
||||
$this->order = apply_filters('retailcrm_process_order', $order_data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -373,21 +354,21 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
* @param WC_Order $order
|
||||
* @param int $order_id
|
||||
*
|
||||
* @return void
|
||||
* @return array $payment
|
||||
*/
|
||||
protected function createPayment($order, $order_id)
|
||||
protected function createPayment($order)
|
||||
{
|
||||
$payment = array(
|
||||
'amount' => $order->get_total(),
|
||||
'externalId' => $order_id
|
||||
'externalId' => $order->get_id()
|
||||
);
|
||||
|
||||
$payment['order'] = array(
|
||||
'externalId' => $order_id
|
||||
'externalId' => $order->get_id()
|
||||
);
|
||||
|
||||
if (!empty($order->payment_method) && !empty($this->retailcrm_settings[$order->payment_method])) {
|
||||
$payment['type'] = $this->retailcrm_settings[$order->payment_method];
|
||||
if (isset($this->retailcrm_settings[$order->get_payment_method()])) {
|
||||
$payment['type'] = $this->retailcrm_settings[$order->get_payment_method()];
|
||||
}
|
||||
|
||||
if ($order->is_paid()) {
|
||||
|
@ -400,42 +381,24 @@ if ( ! class_exists( 'WC_Retailcrm_Orders' ) ) :
|
|||
}
|
||||
|
||||
$this->retailcrm->ordersPaymentCreate($payment);
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit payment in CRM
|
||||
*
|
||||
* @param array $payment
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
protected function editPayment($payment)
|
||||
public function getOrder()
|
||||
{
|
||||
$this->retailcrm->ordersPaymentEdit($payment);
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit order in CRM
|
||||
*
|
||||
* @param int $order_id
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public function updateOrder($order_id)
|
||||
public function getPayment()
|
||||
{
|
||||
if (!$this->retailcrm) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = $this->processOrder($order_id, true);
|
||||
|
||||
$response = $this->retailcrm->ordersEdit($order);
|
||||
|
||||
$orderWc = new WC_Order($order_id);
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
$this->orderUpdatePaymentType($order_id, $orderWc->get_payment_method());
|
||||
}
|
||||
return $this->payment;
|
||||
}
|
||||
}
|
||||
endif;
|
BIN
src/languages/retailcrm-ru_RU.mo
Normal file
BIN
src/languages/retailcrm-ru_RU.mo
Normal file
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
if (!class_exists('WC_Retailcrm_Response')) {
|
||||
require_once dirname(__FILE__) . '/../../woo-retailcrm/include/api/class-wc-retailcrm-response.php';
|
||||
require_once dirname(__FILE__) . '/../../src/include/api/class-wc-retailcrm-response.php';
|
||||
}
|
||||
|
||||
class WC_Retailcrm_Response_Helper extends WC_Retailcrm_Response
|
||||
|
|
44
tests/helpers/class-wc-retailcrm-test-case-helper.php
Normal file
44
tests/helpers/class-wc-retailcrm-test-case-helper.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case
|
||||
{
|
||||
protected function setOptions($apiVesrion)
|
||||
{
|
||||
$options = array(
|
||||
'api_url' => 'https://example.retailcrm.ru',
|
||||
'api_key' => 'dhsHJGYdjkHHJKJSGjhasjhgajsgJGHsg',
|
||||
'api_version' => $apiVesrion,
|
||||
'p_draft' => 'no',
|
||||
'p_pending' => 'no',
|
||||
'p_private' => 'no',
|
||||
'p_publish' => 'no',
|
||||
'order_methods' => '',
|
||||
'flat_rate' => 'delivery',
|
||||
'flat_rate:1' => 'delivery1',
|
||||
'free_shipping:7' => 'delivery2',
|
||||
'flat_rate:8' => 'delivery3',
|
||||
'local_pickup:9' => 'delivery4',
|
||||
'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' => 'no',
|
||||
'ua_code' => '',
|
||||
'ua_custom' => '',
|
||||
'upload-button' => ''
|
||||
);
|
||||
|
||||
update_option(WC_Retailcrm_Base::$option_key, $options);
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
|
@ -10,13 +10,11 @@ require_once $_tests_dir . '/includes/functions.php';
|
|||
|
||||
function _manually_load_plugin() {
|
||||
$plugin_dir = dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/';
|
||||
// helpers
|
||||
require $plugin_dir . 'woocommerce-retailcrm/tests/helpers/class-wc-retailcrm-response-helper.php';
|
||||
|
||||
require $plugin_dir . 'woocommerce-retailcrm/woo-retailcrm/include/class-wc-retailcrm-orders.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/woo-retailcrm/include/class-wc-retailcrm-customers.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/woo-retailcrm/include/class-wc-retailcrm-inventories.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/woo-retailcrm/retailcrm.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/src/include/class-wc-retailcrm-orders.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/src/include/class-wc-retailcrm-customers.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/src/include/class-wc-retailcrm-inventories.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/src/retailcrm.php';
|
||||
require '/woocommerce/woocommerce.php';
|
||||
}
|
||||
|
||||
|
@ -34,4 +32,9 @@ require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-coupon.php
|
|||
require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-fee.php' );
|
||||
require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-shipping.php' );
|
||||
require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-customer.php' );
|
||||
require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-order.php' );
|
||||
require_once( $wc_tests_framework_base_dir . 'helpers/class-wc-helper-order.php' );
|
||||
|
||||
$plugin_dir = dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/';
|
||||
// helpers
|
||||
require $plugin_dir . 'woocommerce-retailcrm/tests/helpers/class-wc-retailcrm-response-helper.php';
|
||||
require $plugin_dir . 'woocommerce-retailcrm/tests/helpers/class-wc-retailcrm-test-case-helper.php';
|
||||
|
|
|
@ -1,18 +1,37 @@
|
|||
<?php
|
||||
|
||||
class WC_Retailcrm_Base_Test extends WC_Unit_Test_Case
|
||||
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->unit = new \WC_Retailcrm_Base();
|
||||
$this->unit->apiClient = $this->apiMock;
|
||||
$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()
|
||||
|
@ -27,5 +46,176 @@ class WC_Retailcrm_Base_Test extends WC_Unit_Test_Case
|
|||
$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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
class WC_Retailcrm_Inventories_Test extends WC_Unit_Test_Case
|
||||
class WC_Retailcrm_Inventories_Test extends WC_Retailcrm_Test_Case_Helper
|
||||
{
|
||||
protected $apiMock;
|
||||
protected $responseMock;
|
||||
|
@ -8,9 +8,6 @@ class WC_Retailcrm_Inventories_Test extends WC_Unit_Test_Case
|
|||
|
||||
public function setUp()
|
||||
{
|
||||
$this->offer = new WC_Product_Simple();
|
||||
$this->offer->save();
|
||||
|
||||
$this->responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array(
|
||||
|
@ -36,7 +33,11 @@ class WC_Retailcrm_Inventories_Test extends WC_Unit_Test_Case
|
|||
*/
|
||||
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);
|
||||
|
@ -82,7 +83,6 @@ class WC_Retailcrm_Inventories_Test extends WC_Unit_Test_Case
|
|||
'offers' => array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'externalId' => $this->offer->get_id(),
|
||||
'xmlId' => 'xmlId',
|
||||
'quantity' => 10
|
||||
)
|
||||
|
|
|
@ -1,20 +1,14 @@
|
|||
<?php
|
||||
|
||||
class WC_Retailcrm_Orders_Test extends WC_Unit_Test_Case
|
||||
class WC_Retailcrm_Orders_Test extends WC_Retailcrm_Test_Case_Helper
|
||||
{
|
||||
protected $apiMock;
|
||||
protected $responseMock;
|
||||
protected $order;
|
||||
protected $options;
|
||||
|
||||
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(
|
||||
|
@ -23,72 +17,160 @@ class WC_Retailcrm_Orders_Test extends WC_Unit_Test_Case
|
|||
'ordersCreate',
|
||||
'ordersEdit',
|
||||
'customersGet',
|
||||
'customersCreate'
|
||||
'customersCreate',
|
||||
'ordersPaymentCreate',
|
||||
'ordersPaymentDelete'
|
||||
))
|
||||
->getMock();
|
||||
|
||||
$this->apiMock->expects($this->any())
|
||||
->method('ordersEdit')
|
||||
->willReturn($this->responseMock);
|
||||
|
||||
$this->order = new WC_Order();
|
||||
$this->order->save();
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $retailcrm
|
||||
* @param $apiVersion
|
||||
* @dataProvider dataProviderRetailcrm
|
||||
*/
|
||||
public function test_order_upload($retailcrm)
|
||||
public function test_order_upload($retailcrm, $apiVersion)
|
||||
{
|
||||
$this->options = $this->setOptions($apiVersion);
|
||||
$retailcrm_orders = new WC_Retailcrm_Orders($retailcrm);
|
||||
$retailcrm_orders->ordersUpload();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $retailcrm
|
||||
* @param $apiVersion
|
||||
* @dataProvider dataProviderRetailcrm
|
||||
*/
|
||||
public function test_order_create($retailcrm)
|
||||
public function test_order_create($retailcrm, $apiVersion)
|
||||
{
|
||||
$this->createTestOrder();
|
||||
$this->options = $this->setOptions($apiVersion);
|
||||
$retailcrm_orders = new WC_Retailcrm_Orders($retailcrm);
|
||||
$retailcrm_orders->orderCreate($this->order->get_id());
|
||||
}
|
||||
$order = $retailcrm_orders->orderCreate($this->order->get_id());
|
||||
$order_send = $retailcrm_orders->getOrder();
|
||||
|
||||
/**
|
||||
* @param $retailcrm
|
||||
* @dataProvider dataProviderRetailcrm
|
||||
*/
|
||||
public function test_order_update_status($retailcrm)
|
||||
{
|
||||
$retailcrm_orders = new WC_Retailcrm_Orders($retailcrm);
|
||||
$retailcrm_orders->orderUpdateStatus($this->order->get_id());
|
||||
}
|
||||
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('testFirstName', $order_send['firstName']);
|
||||
$this->assertEquals('testLastName', $order_send['lastName']);
|
||||
$this->assertEquals('test@mail.com', $order_send['email']);
|
||||
$this->assertEquals('RU', $order_send['countryIso']);
|
||||
$this->assertEquals('111111', $order_send['delivery']['address']['index']);
|
||||
$this->assertEquals('testCity', $order_send['delivery']['address']['city']);
|
||||
$this->assertEquals('delivery', $order_send['delivery']['code']);
|
||||
|
||||
/**
|
||||
* @param $retailcrm
|
||||
* @dataProvider dataProviderRetailcrm
|
||||
*/
|
||||
public function test_order_update_payment($retailcrm)
|
||||
{
|
||||
$retailcrm_orders = new WC_Retailcrm_Orders($retailcrm);
|
||||
$retailcrm_orders->orderUpdatePayment($this->order->get_id());
|
||||
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->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)
|
||||
public function test_update_order($isSuccessful, $retailcrm, $apiVersion)
|
||||
{
|
||||
$this->responseMock->expects($this->any())
|
||||
->method('isSuccessful')
|
||||
->willReturn($isSuccessful);
|
||||
$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 = new WC_Retailcrm_Orders($retailcrm);
|
||||
$retailcrm_orders->updateOrder($this->order->get_id());
|
||||
$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('testFirstName', $order_send['firstName']);
|
||||
$this->assertEquals('testLastName', $order_send['lastName']);
|
||||
$this->assertEquals('test@mail.com', $order_send['email']);
|
||||
$this->assertEquals('RU', $order_send['countryIso']);
|
||||
$this->assertEquals('111111', $order_send['delivery']['address']['index']);
|
||||
$this->assertEquals('testCity', $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->assertEquals('payment1', $payment['type']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->assertEquals(null, $order);
|
||||
}
|
||||
}
|
||||
|
||||
public function dataProviderUpdateOrder()
|
||||
|
@ -98,19 +180,43 @@ class WC_Retailcrm_Orders_Test extends WC_Unit_Test_Case
|
|||
return array(
|
||||
array(
|
||||
'is_successful' => true,
|
||||
'retailcrm' => $this->apiMock
|
||||
),
|
||||
array(
|
||||
'is_successful' => false,
|
||||
'retailcrm' => $this->apiMock
|
||||
'retailcrm' => $this->apiMock,
|
||||
'api_version' => 'v5'
|
||||
),
|
||||
array(
|
||||
'is_successful' => true,
|
||||
'retailcrm' => false
|
||||
'retailcrm' => false,
|
||||
'api_version' => 'v5'
|
||||
),
|
||||
array(
|
||||
'is_successful' => false,
|
||||
'retailcrm' => 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'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -121,10 +227,50 @@ class WC_Retailcrm_Orders_Test extends WC_Unit_Test_Case
|
|||
|
||||
return array(
|
||||
array(
|
||||
'retailcrm' => $this->apiMock
|
||||
'retailcrm' => $this->apiMock,
|
||||
'api_version' => 'v4'
|
||||
),
|
||||
array(
|
||||
'retailcrm' => false
|
||||
'retailcrm' => false,
|
||||
'api_version' => 'v4'
|
||||
),
|
||||
array(
|
||||
'retailcrm' => $this->apiMock,
|
||||
'api_version' => 'v5'
|
||||
),
|
||||
array(
|
||||
'retailcrm' => false,
|
||||
'api_version' => 'v5'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function createTestOrder()
|
||||
{
|
||||
$this->order = new WC_Order();
|
||||
$this->order->set_payment_method('bacs');
|
||||
$this->order->set_billing_first_name('testFirstName');
|
||||
$this->order->set_billing_last_name('testLastName');
|
||||
$this->order->set_billing_country('RU');
|
||||
$this->order->set_billing_address_1('testAddress1');
|
||||
$this->order->set_billing_city('testCity');
|
||||
$this->order->set_billing_postcode('111111');
|
||||
$this->order->set_billing_email('test@mail.com');
|
||||
$this->order->save();
|
||||
}
|
||||
|
||||
private function getResponseData($externalId)
|
||||
{
|
||||
return array(
|
||||
'success' => true,
|
||||
'order' => array(
|
||||
'payments' => array(
|
||||
array(
|
||||
'id' => 1,
|
||||
'externalId' => $externalId,
|
||||
'type' => 'payment2'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue