From 0efa62d67fc9ac326c4639c9586da4acd352ed0c Mon Sep 17 00:00:00 2001 From: Antony I <1852897+uptimizt@users.noreply.github.com> Date: Sun, 31 Mar 2024 19:34:15 +0300 Subject: [PATCH] release 9.11 (#535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * Несовместим с включенной функцией WooCommerce #539 * readme and wf gh * Bug: Не синхронизируются товары #524 * log data for sync stock * updates ProductStocks * add Helper trait * Helper remake as class * clean code * improved ProductStocks * improved ProductStocks * improved reports * added wooms_updated_timestamp to product widget * logger * small fixes * small fixes * remove deprecated hook filter - wooms_product_save * small fixes * улучшен лог - Сохранены атрибуты для вариации * small fixes * code clean * add Settings - get_config_name * clean code * Журнал обработки - ProductsHider * clean code * clean code * readme updated * readme updated * update links * small updates --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- includes/Helper.php | 111 ++++++++++ includes/MenuTools.php | 151 +++++++------- includes/ProductStocks.php | 342 +++++++++++++++++-------------- includes/ProductVariable.php | 159 ++++---------- includes/Products.php | 126 ++++-------- includes/ProductsHiding.php | 20 +- includes/Settings.php | 166 ++++++++------- readme.txt | 12 +- wooms.php | 273 ++++++++++++------------ 10 files changed, 701 insertions(+), 661 deletions(-) create mode 100644 includes/Helper.php diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 34a86ce..3fa722d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,5 +9,5 @@ ## Чек лист - [ ] проверка локально -- [ ] тест на стенде https://wmstst.wpcraft.ru/ +- [ ] тест на стенде https://wooms.wpcraft.ru/ - [ ] В changelog добавлено описание изменений diff --git a/includes/Helper.php b/includes/Helper.php new file mode 100644 index 0000000..e5d3289 --- /dev/null +++ b/includes/Helper.php @@ -0,0 +1,111 @@ + [ 'product', 'product_variation' ], + 'meta_key' => 'wooms_id_' . $uuid, + ] ); + + if ( isset( $posts[0]->ID ) ) { + return $posts[0]->ID; + } + + $posts = get_posts( [ + 'post_type' => [ 'product', 'product_variation' ], + 'meta_key' => 'wooms_id', + 'meta_value' => $uuid + ] ); + + if ( empty( $posts[0]->ID ) ) { + return false; + } else { + return $posts[0]->ID; + } + } + + public static function log( string $message, $class = 'WooMS', array $data = [] ) { + if ( ! Logger::is_enable() ) { + return; + } + + if ( ! empty( $data ) ) { + + if ( is_array( $data ) ) { + $data = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); + } else { + $data = wc_print_r( $data, true ); + } + + $data = wp_trim_words( $data, 300 ); + $message .= PHP_EOL . '-' . PHP_EOL . $data; + } + + $source = str_replace( '\\', '-', $class ); + + $logger = wc_get_logger(); + $context = array( 'source' => $source ); + $logger->info( $message, $context ); + } + + public static function log_error( string $message, $class = 'WooMS', array $data = [] ) { + + if ( ! Logger::is_enable() ) { + return; + } + + if ( ! empty( $data ) ) { + + if ( is_array( $data ) ) { + $data = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); + } else { + $data = wc_print_r( $data, true ); + } + + $data = wp_trim_words( $data, 300 ); + $message .= PHP_EOL . '-' . PHP_EOL . $data; + } + + $source = str_replace( '\\', '-', $class ); + + $logger = wc_get_logger(); + $context = array( 'source' => $source ); + $logger->error( $message, $context ); + + } + + + public static function get_timestamp_last_job_by_hook($hook){ + $store = \ActionScheduler::store(); + $data = $store->query_actions([ + 'hook' => $hook, + 'orderby' => 'date', + 'order' => 'DESC', + ]); + + if(empty($data[0])){ + return null; + } + + $date = $store->get_date($data[0]); + $date->setTimezone(new \DateTimeZone(wp_timezone_string())); + return $date->format('Y-m-d H:i:s'); + } +} diff --git a/includes/MenuTools.php b/includes/MenuTools.php index 41fdb38..4f6d097 100644 --- a/includes/MenuTools.php +++ b/includes/MenuTools.php @@ -1,85 +1,88 @@ %s', 'Управление МойСклад'); - $items = [ - ' - Начало работы - ', - sprintf('Настройки', admin_url("admin.php?page=mss-settings") ), - 'Вход в МойСклад', - sprintf('Диагностика проблем', admin_url("site-health.php") ), - 'Рекомендуемые хостинги', - 'Контакты', - ]; - - printf( '

%s

', implode(' | ', $items) ); - - if(empty(get_option('woomss_pass'))){ - printf('

Укажите логин и пароль на странице настроек

', admin_url('admin.php?page=mss-settings')); - } else { - if( empty($_GET['a']) ){ - - do_action('wooms_tools_sections'); - - // deprecated - do_action('woomss_tool_actions_btns'); - - } else { - - printf('Вернуться...', remove_query_arg( 'a', self::$url)); - do_action('woomss_tool_actions'); - do_action('woomss_tool_actions_' . $_GET['a']); - - } - } - - - } + /** + * URL action + */ + public static $url; + + /** + * The Init + */ + public static function init() { + + self::$url = $_SERVER['REQUEST_URI']; + + add_action( + 'admin_menu', + function () { + + if ( current_user_can( 'manage_woocommerce' ) ) { + add_menu_page( + $page_title = 'МойСклад', + $menu_title = 'МойСклад', + $capability = 'manage_woocommerce', + $menu_slug = 'moysklad', + $function = array ( __CLASS__, 'display_ui' ), + $icon = 'dashicons-forms', + '57.5' + ); + } + + } + ); + + + } + + /** + * Display UI + */ + public static function display_ui() { + printf( '

%s

', 'Управление МойСклад' ); + $items = [ + sprintf( 'Настройки', admin_url( "admin.php?page=mss-settings" ) ), + 'Вход в МойСклад', + sprintf( 'Здоровье сайта', admin_url( "site-health.php" ) ), + 'Рекомендуемые хостинги', + 'Контакты', + ]; + ?> +
+ Решаем проблемы +
+ %s

', implode( ' | ', $items ) ); ?> +
+ Укажите логин и пароль на странице настроек

', admin_url( 'admin.php?page=mss-settings' ) ); + } else { + if ( empty( $_GET['a'] ) ) { + + do_action( 'wooms_tools_sections' ); + + // deprecated + do_action( 'woomss_tool_actions_btns' ); + + } else { + + printf( 'Вернуться...', remove_query_arg( 'a', self::$url ) ); + do_action( 'woomss_tool_actions' ); + do_action( 'woomss_tool_actions_' . $_GET['a'] ); + + } + } + + + } } diff --git a/includes/ProductStocks.php b/includes/ProductStocks.php index dfa5125..b17828f 100644 --- a/includes/ProductStocks.php +++ b/includes/ProductStocks.php @@ -2,8 +2,11 @@ namespace WooMS; +use WC_Product; use function WooMS\request; +use function WooMS\get_config as get_config; +use function WooMS\get_config_name as get_config_name; defined( 'ABSPATH' ) || exit; // Exit if accessed directly @@ -26,6 +29,22 @@ class ProductStocks { public static function init() { + // add_action( 'init', function () { + // if ( ! isset ( $_GET['test_ProductStocks'] ) ) { + // return; + // } + + // // do_action('wooms_assortment_sync'); + // // var_dump(1); exit; + + // $meta = get_post_meta( 68934 ); + // echo '
';
+		// 	var_dump( $meta );
+		// 	exit;
+		// } );
+
+		add_filter( 'wooms_stock_product_save', [ __CLASS__, 'update_manage_stock' ], 10, 2 );
+
 		add_action( 'wooms_assortment_sync', [ __CLASS__, 'batch_handler' ] );
 
 		add_filter( 'wooms_product_update', array( __CLASS__, 'update_product' ), 30, 2 );
@@ -36,22 +55,17 @@ public static function init() {
 
 		add_action( 'wooms_variations_batch_end', [ __CLASS__, 'restart_after_batch' ] );
 		add_action( 'wooms_products_batch_end', [ __CLASS__, 'restart_after_batch' ] );
-		add_action( 'wooms_main_walker_started', [ __CLASS__, 'restart' ] );
 
-		add_action( 'admin_init', [__CLASS__, 'add_settings'], 30 );
+		add_action( 'admin_init', [ __CLASS__, 'add_settings' ], 30 );
 		add_action( 'wooms_tools_sections', array( __CLASS__, 'display_state' ), 17 );
 
-		add_filter( 'wooms_stock_type', array( __CLASS__, 'select_type_stock' ) );
+		// add_filter( 'wooms_stock_type', array( __CLASS__, 'select_type_stock' ) );
 
-		//need for disable reset state for base plugin
-		add_filter( 'wooms_reset_state_products', function ($reset) {
-			return false;
-		} );
 	}
 
 
-	public static function batch_handler($state = []) {
-		if(empty($state)){
+	public static function batch_handler( $state = [] ) {
+		if ( empty( $state ) ) {
 			$state = [
 				'count' => 0
 			];
@@ -73,17 +87,21 @@ public static function batch_handler($state = []) {
 		);
 
 		$products = get_posts( $args );
-		if ( empty($products) ) {
-			self::set_state( 'finish_timestamp', time() );
+
+		if ( empty( $products ) ) {
 			return false;
 		}
 
-		$filters = [];
+		$filters_by_id = [];
 		foreach ( $products as $product ) {
-			$filters[] = 'id=' . get_post_meta( $product->ID, 'wooms_id', true );
+			$filters_by_id[] = 'id=' . get_post_meta( $product->ID, 'wooms_id', true );
+			delete_post_meta( $product->ID, self::$walker_hook_name );
 		}
 
-		// todo - переписать это как то лучше
+		$filters = [
+			implode( ';', $filters_by_id )
+		];
+
 		$url = 'https://api.moysklad.ru/api/remap/1.2/entity/assortment';
 
 		$filters = apply_filters( 'wooms_assortment_sync_filters', $filters );
@@ -100,39 +118,42 @@ public static function batch_handler($state = []) {
 
 		$data = request( $url );
 
+		// var_dump($data); exit;
+
 		if ( empty( $data['rows'] ) ) {
 			return false;
 		}
 
-
-		$ids = self::process_rows($data['rows']);
-		if($ids){
+		$ids = self::process_rows( $data['rows'] );
+		if ( $ids ) {
 			$state['last_ids'] = $ids;
 		}
 
-		$state['count'] += count($data['rows']);
+		$state['count'] += count( $data['rows'] );
 
-		return as_schedule_single_action( time(), self::$walker_hook_name, [$state], 'WooMS' );
+		return as_schedule_single_action( time(), self::$walker_hook_name, [ $state ], 'WooMS' );
 
 	}
 
-	public static function process_rows($rows){
+	public static function process_rows( $rows ) {
 
 		$ids = [];
 		foreach ( $rows as $row ) {
 
-			if ( ! $product_id = self::get_product_id_by_uuid( $row['id'] ) ) {
+			if ( ! $product_id = Helper::get_product_id_by_uuid( $row['id'] ) ) {
+				Helper::log_error( 'Не нашли продукт по uuid', __CLASS__, $row );
 				continue;
 			}
 
 			if ( ! $product = wc_get_product( $product_id ) ) {
+				Helper::log_error( 'Не нашли продукт по $product_id', __CLASS__, $row );
 				continue;
 			}
 
 			$product = self::update_stock( $product, $row );
 
 			$product->update_meta_data( 'wooms_assortment_data', self::get_stock_data_log( $row, $product_id ) );
-			$product->delete_meta_data( self::$walker_hook_name );
+
 
 			/**
 			 * manage stock save
@@ -141,6 +162,7 @@ public static function process_rows($rows){
 			 */
 			$product = apply_filters( 'wooms_stock_product_save', $product, $row );
 
+
 			$ids[] = $product->save();
 		}
 
@@ -148,112 +170,144 @@ public static function process_rows($rows){
 
 	}
 
-	/**
-	 * get_stock_data_log
-	 * for save log data to product meta
-	 */
-	public static function get_stock_data_log( $row = [], $product_id = 0 ) {
-		$data = [
-			"stock" => $row['stock'],
-			"reserve" => $row['reserve'],
-			"inTransit" => $row['inTransit'],
-			"quantity" => $row['quantity'],
-		];
-
-		$data = apply_filters( 'wooms_stock_log_data', $data, $product_id, $row );
 
-		$data = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
-
-		return $data;
-	}
+	public static function update_stock( WC_Product $product, $data_api ): WC_Product {
 
-	public static function update_stock( $product, $data_api ) {
-		$product = wc_get_product( $product );
-
-		$product_id = $product->get_id();
+		//если продукт вариативный, то его наличие определяется его вариациями и это отдельный поток хуков
+		if ( $product->get_type() === 'variable' ) {
+			return $product;
+		}
 
 		/**
 		 * Поле по которому берем остаток?
 		 * quantity = это доступные остатки за вычетом резервов
 		 * stock = это все остатки без уета резерва
 		 */
-		$stock_type = apply_filters( 'wooms_stock_type', 'quantity' );
-
-		$stock = 0;
-
-		if ( empty( $data_api[ $stock_type ] ) ) {
-			$stock = 0;
+		if(get_config('stock_and_reserve')){
+			$stock = (int) $data_api['quantity'] ?? 0;
 		} else {
-			$stock = (int) $data_api[ $stock_type ];
+			$stock = (int) $data_api['stock'] ?? 0;
 		}
 
-		if ( get_option( 'wooms_stock_empty_backorder' ) ) {
-			$product->set_backorders( 'notify' );
+		if ( $stock > 0 ) {
+			$product->set_stock_quantity( $stock );
+			$product->set_stock_status( 'instock' );
 		} else {
-			$product->set_backorders( 'no' );
+			$product->set_stock_quantity( 0 );
+			$product->set_stock_status( 'outofstock' );
 		}
 
-		if ( empty( get_option( 'wooms_warehouse_count' ) ) ) {
-			$product->set_manage_stock( false );
-		} else {
-			if ( $product->is_type( 'variable' ) ) {
-				//для вариативных товаров доступность определяется наличием вариаций
-				$product->set_manage_stock( false );
-			} else {
-				$product->set_manage_stock( true );
-			}
-		}
+		$log_data = [
+			'stock' => $data_api['stock'],
+			'quantity' => $data_api['quantity'],
+			'type' => $product->get_type(),
+		];
 
-		if ( $stock <= 0 ) {
-			if ( ! $product->is_type( 'variable' ) ) {
-				$product->set_stock_quantity( 0 );
-				$product->set_stock_status( 'outofstock' );
-			}
-		} else {
-			$product->set_stock_quantity( $stock );
-			$product->set_stock_status( 'instock' );
+		if ( $product->get_type() === 'variation' ) {
+			$log_data['product_parent'] = $product->get_parent_id();
 		}
 
-		do_action(
-			'wooms_logger',
+		Helper::log( sprintf(
+			'Остатки для продукта "%s" (ИД %s) = %s', $product->get_name(), $product->get_id(), $product->get_stock_quantity() ),
 			__CLASS__,
-			sprintf( 'Остатки для продукта "%s" = %s (ИД %s)', $product->get_name(), $stock, $product_id ),
-			sprintf( 'stock %s, quantity %s', $data_api['stock'], $data_api['quantity'] )
+			$log_data
 		);
 
 		return $product;
 	}
 
+
 	/**
-	 * restart walker after added tast to queue
+	 * Если у сайта включена опция управление остатками - установить остатки для товара
+	 *
+	 * @todo вероятно опция типа wooms_warehouse_count - более не нужна
 	 */
-	public static function restart() {
-		self::set_state( 'finish_timestamp', 0 );
-		self::set_state( 'count_all', 0 );
-		self::set_state( 'count_save', 0 );
-	}
+	public static function update_manage_stock( WC_Product $product, $data_api ): WC_Product {
 
+		if ( ! get_option( 'woocommerce_manage_stock' ) ) {
+			return $product;
+		}
 
-	public static function restart_after_batch() {
-		if(as_has_scheduled_action(self::$walker_hook_name)){
-			return;
+		if ( ! $product->get_manage_stock() ) {
+			$product->set_manage_stock( true );
+			Helper::log( sprintf(
+				'Включили управление запасами для продукта: %s (ИД %s)', $product->get_name(), $product->get_id() ),
+				__CLASS__
+			);
 		}
 
-		as_schedule_single_action( time(), self::$walker_hook_name, [], 'WooMS' );
-	}
+		//для вариативных товаров доступность определяется наличием вариаций
+		if ( $product->get_type() === 'variation' ) {
+
+			$parent_id = $product->get_parent_id();
+			$parent_product = wc_get_product( $parent_id );
+			if ( empty( $parent_product ) ) {
+				Helper::log_error( "Не нашли родительский продукт: {$parent_id}, вариация: {$product->get_id()}",
+					__CLASS__
+				);
+				return $product;
+			}
+			if ( $parent_product->get_manage_stock() ) {
+
+				Helper::log( sprintf(
+					'У основного продукта отключили управление остатками: %s (ИД %s)', $parent_product->get_name(), $parent_id ),
+					__CLASS__
+				);
+				$parent_product->set_manage_stock( false );
+
+				$parent_product->save();
+			}
+
+		}
+
+		/**
+		 * это похоже надо выпилить
+		 *
+		 * потому что это не относится к синку МС и должно управляться как то иначе
+		 *
+		 * если это тут оставлять, то эта отметка должна быть на стороне МС
+		 */
+		// if ( get_option( 'wooms_stock_empty_backorder' ) ) {
+		// $product->set_backorders( 'notify' );
+		// } else {
+		// $product->set_backorders( 'no' );
+		// }
 
 
+		return $product;
 
+	}
 
 	/**
-	 * check is wait
+	 * get_stock_data_log
+	 * for save log data to product meta
 	 */
-	public static function is_wait() {
-		if ( self::get_state( 'finish_timestamp' ) ) {
-			return true;
+	public static function get_stock_data_log( $row = [], $product_id = 0 ) {
+		$data = [
+			"stock" => $row['stock'],
+			"reserve" => $row['reserve'],
+			"inTransit" => $row['inTransit'],
+			"quantity" => $row['quantity'],
+		];
+
+		$data = apply_filters( 'wooms_stock_log_data', $data, $product_id, $row );
+
+		$data = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
+
+		return $data;
+	}
+
+
+	public static function restart_after_batch() {
+		if ( ! self::is_enable() ) {
+			return;
 		}
 
-		return false;
+		if ( as_has_scheduled_action( self::$walker_hook_name ) ) {
+			return;
+		}
+
+		as_schedule_single_action( time(), self::$walker_hook_name, [], 'WooMS' );
 	}
 
 
@@ -278,11 +332,6 @@ public static function get_state( $key = '' ) {
 	}
 
 
-
-
-	/**
-	 * set state data
-	 */
 	public static function set_state( $key, $value ) {
 
 		if ( ! $state = get_transient( self::$state_transient_key ) ) {
@@ -372,27 +421,17 @@ public static function assortment_add_filter_by_warehouse_id( $filter ) {
 		return $filter;
 	}
 
-	/**
-	 * Select type stock
-	 */
-	public static function select_type_stock( $type_stock ) {
-		if ( get_option( 'wooms_stocks_without_reserve' ) ) {
-			$type_stock = 'stock';
-		}
-
-		return $type_stock;
-	}
 
 	/**
 	 * Update stock for variation
 	 */
-	public static function update_variation( $variation, $data_api ) {
+	public static function update_variation( \WC_Product_Variation $variation, $data_api ) {
 		if ( self::is_enable() ) {
 			$variation->update_meta_data( self::$walker_hook_name, 1 );
 		} else {
 			$variation->set_catalog_visibility( 'visible' );
 			$variation->set_stock_status( 'instock' );
-			$variation->set_manage_stock( 'no' );
+			$variation->set_manage_stock( false );
 			$variation->set_status( 'publish' );
 		}
 
@@ -409,7 +448,7 @@ public static function update_product( $product, $data_api ) {
 		} else {
 			$product->set_catalog_visibility( 'visible' );
 			$product->set_stock_status( 'instock' );
-			$product->set_manage_stock( 'no' );
+			$product->set_manage_stock( false );
 			$product->set_status( 'publish' );
 		}
 
@@ -437,32 +476,38 @@ public static function add_settings() {
 			$section = 'woomss_section_warehouses'
 		);
 
-		register_setting( 'mss-settings', 'wooms_stocks_without_reserve' );
 		add_settings_field(
-			$id = 'wooms_stocks_without_reserve',
-			$title = 'Остатки без резерва',
-			$callback = array( __CLASS__, 'display_field_wooms_stocks_without_reserve' ),
-			$page = 'mss-settings',
-			$section = 'woomss_section_warehouses'
-		);
+			$id = 'stock_and_reserve',
+			$title = 'Учитывать остатки с резервом',
+			$callback = function ($args) {
+				printf( '', $args['name'], $args['value'] );
 
-		register_setting( 'mss-settings', 'wooms_warehouse_count' );
-		add_settings_field(
-			$id = 'wooms_warehouse_count',
-			$title = 'Управление запасами на уровне товаров',
-			$callback = array( __CLASS__, 'display_wooms_warehouse_count' ),
+			},
 			$page = 'mss-settings',
-			$section = 'woomss_section_warehouses'
+			$section,
+			$args = [
+				'name' => get_config_name( 'stock_and_reserve' ),
+				'value' => checked( 1, get_config( 'stock_and_reserve' ) ),
+			]
 		);
 
-		register_setting( 'mss-settings', 'wooms_stock_empty_backorder' );
-		add_settings_field(
-			$id = 'wooms_stock_empty_backorder',
-			$title = 'Разрешать предзаказ при 0 остатке',
-			$callback = array( __CLASS__, 'display_wooms_stock_empty_backorder' ),
-			$page = 'mss-settings',
-			$section = 'woomss_section_warehouses'
-		);
+		// register_setting( 'mss-settings', 'wooms_warehouse_count' );
+		// add_settings_field(
+		// 	$id = 'wooms_warehouse_count',
+		// 	$title = 'Управление запасами на уровне товаров',
+		// 	$callback = array( __CLASS__, 'display_wooms_warehouse_count' ),
+		// 	$page = 'mss-settings',
+		// 	$section = 'woomss_section_warehouses'
+		// );
+
+		// register_setting( 'mss-settings', 'wooms_stock_empty_backorder' );
+		// add_settings_field(
+		// 	$id = 'wooms_stock_empty_backorder',
+		// 	$title = 'Разрешать предзаказ при 0 остатке',
+		// 	$callback = array( __CLASS__, 'display_wooms_stock_empty_backorder' ),
+		// 	$page = 'mss-settings',
+		// 	$section = 'woomss_section_warehouses'
+		// );
 
 		self::add_setting_warehouse_id();
 	}
@@ -481,7 +526,7 @@ public static function add_setting_warehouse_id() {
 
 				$url = 'entity/store';
 				$data = request( $url );
-				if ( empty( $data['rows'] ) ) {
+				if ( empty ( $data['rows'] ) ) {
 					echo 'Система не смогла получить список складов из МойСклад';
 					return;
 				}
@@ -546,14 +591,6 @@ public static function display_wooms_stock_empty_backorder() {
 		echo '

Если включить опцию то система будет разрешать предзаказ при 0 остатках

'; } - /** - * display_field_wooms_stocks_without_reserve - */ - public static function display_field_wooms_stocks_without_reserve() { - $option = 'wooms_stocks_without_reserve'; - printf( '', $option, checked( 1, get_option( $option ), false ) ); - echo '

Если включить опцию то на сайте будут учитываться остатки без учета резерва

'; - } /** * Display field @@ -593,30 +630,23 @@ public static function display_state() { $strings[] = sprintf( 'Статус: %s', 'в ожидании задач' ); } - if ( $end_timestamp = self::get_state( 'finish_timestamp' ) ) { - $end_timestamp = date( 'Y-m-d H:i:s', $end_timestamp ); - $strings[] = sprintf( 'Последняя успешная синхронизация (отметка времени UTC): %s', $end_timestamp ); - } - $strings[] = sprintf( 'Очередь задач: открыть', admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=wooms_assortment_sync&orderby=schedule&order=desc' ) ); + $strings[] = sprintf( 'Последняя успешная синхронизация: %s', Helper::get_timestamp_last_job_by_hook( self::$walker_hook_name ) ) ?? 'Нет данных'; + $strings[] = sprintf( 'Очередь задач: открыть', admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=wooms_assortment_sync&orderby=schedule&order=desc' ) ); - if ( defined( 'WC_LOG_HANDLER' ) && 'WC_Log_Handler_DB' == WC_LOG_HANDLER ) { - $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs&source=WooMS-ProductStocks' ) ); - } else { - $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs' ) ); - } + $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs&source=WooMS-ProductStocks' ) ); ?>

Остатки

-
- %s

', $string ); - } - ?> -
+ + %s

', $string ); + } + ?> +
getMessage() - ); + + Helper::log_error( $e->getMessage(), __CLASS__ ); return false; } } @@ -141,13 +136,19 @@ public static function process_rows( $rows ) { $i = 0; foreach ( $rows as $key => $row ) { - if ( $row["meta"]["type"] != 'variant' ) { - continue; - } + try { + if ( $row["meta"]["type"] != 'variant' ) { + continue; + } + + $i++; - $i++; + self::update_variation( $row ); - self::update_variation( $row ); + } catch (\Exception $e) { + Helper::log_error( $e->getMessage(), __CLASS__ ); + continue; + } } @@ -159,7 +160,7 @@ public static function process_rows( $rows ) { */ public static function set_wait() { as_unschedule_all_actions( self::$walker_hook_name ); - self::set_state( 'end_timestamp', time() ); + } @@ -329,12 +330,12 @@ public static function save_attributes_for_variation( \WC_Product_Variation $var $variation->set_attributes( $attributes ); - do_action( - 'wooms_logger', - __CLASS__, - sprintf( 'Сохранены атрибуты для вариации %s (продукт: %s)', $variation_id, $product_id ), - wc_print_r( $attributes, true ) - ); + Helper::log('Сохранены атрибуты для вариации', __CLASS__, [ + 'name' => $variation->get_name(), + 'variation_id' => $variation_id, + 'product_id' => $product_id, + 'attributes' => $attributes, + ]); return $variation; } @@ -349,7 +350,7 @@ public static function update_variation( $row ) { } if ( ! empty( $row['archived'] ) ) { - return null; + return; } if(empty($row['product']['meta']['href'])){ @@ -357,29 +358,24 @@ public static function update_variation( $row ) { } $product_href = $row['product']['meta']['href']; - $product_id = self::get_product_id_by_uuid( $product_href ); + $product_id = Helper::get_product_id_by_uuid( $product_href ); $product_parent = wc_get_product( $product_id ); if(empty($product_parent)){ - do_action( - 'wooms_logger_error', - __CLASS__, - sprintf( 'Нет базового продукта для вариации. %s', json_encode( ['product_id' => $product_id, '$row id' => $row ] ) ) - ); - - return null; - + /** + * так бывает + * мы получаем вариации всей пачкой и для каких то может не быть базового продукта + * чаще всего это не ошибка, но может быть и она + */ + Helper::log('Нет базового продукта для вариации', __CLASS__, $row); + return; } if ( ! $product_parent->is_type( 'variable' ) ) { $product_parent = new \WC_Product_Variable( $product_parent ); $product_parent->save(); - do_action( - 'wooms_logger_error', - __CLASS__, - sprintf( 'Снова сохранили продукт как вариативный %s', $product_id ) - ); + Helper::log(sprintf( 'Снова сохранили продукт как вариативный %s', $product_id ), __CLASS__); } if ( empty( $product_id ) ) { @@ -432,6 +428,7 @@ public static function update_variation( $row ) { } $variation = apply_filters( 'wooms_variation_save', $variation, $row, $product_id ); + $variation = apply_filters( 'wooms_variation_update', $variation, $row, $product_id ); $variation_id = $variation->save(); @@ -545,8 +542,7 @@ public static function start_manually() { * Stopping walker imports from MoySklad */ public static function walker_finish() { - self::set_state( 'end_timestamp', time() ); - self::set_state( 'lock', 0 ); + do_action( 'wooms_wakler_variations_finish' ); @@ -597,26 +593,6 @@ public static function get_attribute_id_by_label( $label = '' ) { return false; } - - public static function is_wait() { - //check run main walker - if ( as_next_scheduled_action( 'wooms_products_walker_batch' ) ) { - return true; - } - - //check end pause - if ( ! empty( self::get_state( 'end_timestamp' ) ) ) { - return true; - } - - return false; - } - - - - /** - * display_state - */ public static function display_state() { if ( ! self::is_enable() ) { @@ -643,19 +619,13 @@ public static function display_state() { $strings[] = sprintf( 'Статус: %s', 'Выполняется очередями в фоне' ); } else { - $strings[] = sprintf( 'Статус: %s', 'в ожидании задач' ); - $strings[] = sprintf( 'Последняя успешная синхронизация: %s', wooms_get_timestamp_last_job_by_hook( self::$walker_hook_name ) ); + $strings[] = sprintf( 'Статус: %s', 'Завершено' ); + $strings[] = sprintf( 'Последняя успешная синхронизация: %s', Helper::get_timestamp_last_job_by_hook( self::$walker_hook_name ) ) ?? 'Нет данных'; } - $strings[] = sprintf( 'Очередь задач: открыть', admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=wooms_variables_walker_batch&orderby=schedule&order=desc' ) ); - - if ( defined( 'WC_LOG_HANDLER' ) && 'WC_Log_Handler_DB' == WC_LOG_HANDLER ) { - $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs&source=WooMS-ProductVariable' ) ); - } else { - $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs' ) ); - } + $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs&source=WooMS-ProductVariable' ) ); ?>
@@ -766,51 +736,6 @@ public static function update_product( $product, $data_api ) { return $product; } - - - /** - * get state data - */ - public static function get_state( $key = '' ) { - if ( ! $state = get_option( self::$state_transient_key ) ) { - $state = []; - update_option( self::$state_transient_key, $state ); - } - - if ( empty( $key ) ) { - return $state; - } - - if ( empty( $state[ $key ] ) ) { - return null; - } - - return $state[ $key ]; - } - - /** - * set state data - */ - public static function set_state( $key, $value = null ) { - if ( $value === null && is_array( $key ) ) { - update_option( self::$state_transient_key, $key, false ); - return; - } - - if ( ! $state = get_option( self::$state_transient_key ) ) { - $state = []; - } - - if ( is_array( $state ) ) { - $state[ $key ] = $value; - } else { - $state = []; - $state[ $key ] = $value; - } - - update_option( self::$state_transient_key, $state, false ); - } - /** * show wooms_id for variation in admin */ diff --git a/includes/Products.php b/includes/Products.php index 891f07d..5167cc8 100644 --- a/includes/Products.php +++ b/includes/Products.php @@ -4,7 +4,7 @@ use function WooMS\request; use function Testeroid\ddcli; -use Error, Throwable, WC_Product; +use Error, Throwable, WC_Product, WooMS\Helper; defined( 'ABSPATH' ) || exit; @@ -60,7 +60,7 @@ function walker( $args = [] ) { $url = apply_filters( 'wooms_url_get_products', $url ); $filters = [ - // 'pathName~=Диваны', + 'archived=false' ]; $filters = apply_filters( 'wooms_url_get_products_filters', $filters ); @@ -103,46 +103,26 @@ function walker( $args = [] ) { } function process_rows( $rows = [] ) { + $ids = []; + foreach ( $rows as $row ) { + $ids[] = $row['id']; - try { - - if ( empty( $rows ) ) { - throw new Error('$rows is empty'); + if ( apply_filters( 'wooms_skip_product_import', false, $row ) ) { + continue; } - $ids = []; - foreach ( $rows as $row ) { - $ids[] = $row['id']; - - if ( apply_filters( 'wooms_skip_product_import', false, $row ) ) { - continue; - } - - /** - * в выдаче могут быть не только товары, но и вариации и мб что-то еще - * птм нужна проверка что это точно продукт - */ - if ( 'variant' == $row["meta"]["type"] ) { - continue; - } - - $data = apply_filters( 'wooms_product_data', [], $row ); - - product_update( $row, $data ); + /** + * в выдаче могут быть не только товары, но и вариации и мб что-то еще + * птм нужна проверка что это точно продукт + */ + if ( 'variant' == $row["meta"]["type"] ) { + continue; } + $data = apply_filters( 'wooms_product_data', [], $row ); - return true; - } catch (Throwable $e) { - - $message = sprintf("wooms process fails: %s, ids: %s, code: %s", $e->getMessage(), json_encode($ids), $e->getCode()); - do_action( 'wooms_logger_error', __NAMESPACE__, $message ); - error_log($message); - - return false; + product_update( $row, $data ); } - - } @@ -222,7 +202,7 @@ function product_update( array $row, array $data = [] ) { $product_id = 0; - $product_id = get_product_id_by_uuid( $row['id'] ); + $product_id = Helper::get_product_id_by_uuid( $row['id'] ); if ( ! empty( $row['archived'] ) ) { if ( $product_id ) { @@ -247,12 +227,8 @@ function product_update( array $row, array $data = [] ) { if ( empty( intval( $product_id ) ) ) { - do_action( - 'wooms_logger_error', - __NAMESPACE__, - 'Ошибка определения и добавления ИД продукта', - $row - ); + Helper::log_error('Ошибка определения и добавления ИД продукта', __NAMESPACE__, $row); + return false; } @@ -263,16 +239,6 @@ function product_update( array $row, array $data = [] ) { */ $data_api = $row; - $product->update_meta_data( 'wooms_id_' . $row['id'], 1 ); - - /** - * Хук позволяет работать с методами WC_Product - * Сохраняет в БД все изменения за 1 раз - * Снижает нагрузку на БД - * - * DEPRECATED - */ - $product = apply_filters( 'wooms_product_save', $product, $data_api, $product_id ); //save data of source if ( apply_filters( 'wooms_logger_enable', false ) ) { @@ -289,9 +255,6 @@ function product_update( array $row, array $data = [] ) { } $product->update_meta_data( 'wooms_updated_timestamp', date( "Y-m-d H:i:s" ) ); - - $product->update_meta_data( 'wooms_id', $data_api['id'] ); - $product->update_meta_data( 'wooms_updated_from_api', $data_api['updated'] ); //update title @@ -336,24 +299,22 @@ function product_update( array $row, array $data = [] ) { $product->set_regular_price( $price ); } - // issue https://github.com/wpcraft-ru/wooms/issues/302 - $product->set_catalog_visibility( 'visible' ); + $product->update_meta_data( 'wooms_id', $data_api['id'] ); + $product->update_meta_data( 'wooms_id_' . $data_api['id'], 1 ); - if ( apply_filters( 'wooms_reset_state_products', true ) ) { - $product->set_stock_status( 'instock' ); - $product->set_manage_stock( false ); - $product->set_status( 'publish' ); - } + /** + * reset state product + * + * @issue https://github.com/wpcraft-ru/wooms/issues/302 + */ + $product->set_catalog_visibility( 'visible' ); + $product->set_status( 'publish' ); $product = apply_filters( 'wooms_product_update', $product, $row, $data ); $product_id = $product->save(); - do_action( - 'wooms_logger', - __NAMESPACE__, - sprintf( 'Продукт: %s (%s) сохранен', $product->get_title(), $product_id ) - ); + Helper::log(sprintf( 'Продукт: %s (%s) сохранен', $product->get_title(), $product_id ), __NAMESPACE__); return $product_id; @@ -474,7 +435,6 @@ function walker_started() { 'session_id' => $now, 'timestamp' => $now, 'query_arg' => $query_arg_default, - 'end_timestamp' => 0, ]; set_state( $state ); @@ -483,29 +443,9 @@ function walker_started() { do_action( 'wooms_logger', __NAMESPACE__, 'Старт основного волкера: ' . $now ); } -// function auto_start() { - -// $end_timestamp = get_state( 'end_timestamp' ); -// if( empty($end_timestamp)){ -// return false; -// } - -// if ( empty( get_option( 'woomss_pass' ) ) ) { -// return false; -// } - -// if ( as_next_scheduled_action( HOOK_NAME ) ) { -// return; -// } - - - -// return as_schedule_single_action( time(), HOOK_NAME, [], 'WooMS' ); -// } - function render_ui() { - printf( '

%s

', 'Каталог' ); + printf( '

%s

', 'Каталог и базовые продукты' ); $strings = []; if ( as_next_scheduled_action( HOOK_NAME ) ) { @@ -515,7 +455,7 @@ function render_ui() { } else { $strings[] = sprintf( 'Статус: %s', 'Завершено' ); - $strings[] = sprintf( 'Время последнего завершения: %s', wooms_get_timestamp_last_job_by_hook( HOOK_NAME ) ); + $strings[] = sprintf( 'Последняя успешная синхронизация: %s', Helper::get_timestamp_last_job_by_hook( HOOK_NAME ) ) ?? 'Нет данных'; printf( 'Запустить синхронизацию продуктов вручную', add_query_arg( 'a', 'wooms_products_start_import', admin_url( 'admin.php?page=moysklad' ) ) @@ -524,6 +464,7 @@ function render_ui() { } $strings[] = sprintf( 'Очередь задач: открыть', admin_url( 'admin.php?page=wc-status&tab=action-scheduler&s=wooms_products_walker&orderby=schedule&order=desc' ) ); + foreach ( $strings as $string ) { printf( '

%s

', $string ); } @@ -568,6 +509,7 @@ function display_metabox_for_product() { $data_id = get_post_meta( $post->ID, 'wooms_id', true ); $data_meta = get_post_meta( $post->ID, 'wooms_meta', true ); $data_updated = get_post_meta( $post->ID, 'wooms_updated', true ); + $wooms_updated_timestamp = get_post_meta( $post->ID, 'wooms_updated_timestamp', true ); if ( $data_id ) { printf( '
ID товара в МойСклад:
%s
', $data_id ); } else { @@ -582,5 +524,9 @@ function display_metabox_for_product() { printf( '
Дата последнего обновления товара в МойСклад: %s
', $data_updated ); } + if ( $data_updated ) { + printf( '
Дата последнего обновления из API МойСклад: %s
', $wooms_updated_timestamp ); + } + do_action( 'wooms_display_product_metabox', $post->ID ); } diff --git a/includes/ProductsHiding.php b/includes/ProductsHiding.php index ee961e2..348e6c1 100644 --- a/includes/ProductsHiding.php +++ b/includes/ProductsHiding.php @@ -2,6 +2,8 @@ namespace WooMS\ProductsHider; +use WooMS\Helper; + const HOOK_NAME = 'wooms_schedule_clear_old_products_walker'; add_action('init', function () { @@ -42,18 +44,13 @@ function walker($state = []) $product = wc_get_product($product_id); $ids[] = $product_id; - if ($product->get_type() == 'variable') { - // $product->set_manage_stock('yes'); - } + $product->set_status('draft'); $product->set_catalog_visibility('hidden'); $product->save(); - do_action( - 'wooms_logger', - __NAMESPACE__, - sprintf('Скрытие продукта: %s', $product_id) - ); + Helper::log(sprintf('Скрытие продукта: %s', $product_id), __NAMESPACE__); + } $state['ids'] = $ids; @@ -101,10 +98,13 @@ function get_products_old_session() return false; } + $args = array( - 'post_type' => ['product', 'product_variation'], + 'post_type' => ['product'], + 'post_status' => 'publish', 'numberposts' => 30, 'fields' => 'ids', + 'tax_query' => array( array( 'taxonomy' => 'product_visibility', @@ -161,6 +161,8 @@ function display_state() $strings[] = sprintf('Очередь задач: открыть', admin_url('admin.php?page=wc-status&tab=action-scheduler&s=wooms_schedule_clear_old_products_walker&orderby=schedule&order=desc')); + $strings[] = sprintf( 'Журнал обработки: открыть', admin_url( 'admin.php?page=wc-status&tab=logs&source=WooMS-ProductsHider' ) ); + echo '

Скрытие продуктов

'; foreach ($strings as $string) { printf('

%s

', $string); diff --git a/includes/Settings.php b/includes/Settings.php index 5792993..0edf96a 100644 --- a/includes/Settings.php +++ b/includes/Settings.php @@ -2,39 +2,45 @@ namespace WooMS; -if (!defined('ABSPATH')) { +if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } const OPTION_KEY = 'wooms_config'; const OPTIONS_PAGE = 'mss-settings'; -function get_config($key = null){ - $config = get_option(OPTION_KEY, []); - if(empty($key)){ - return $config; - } - return $config[$key] ?? null; +function get_config( $key = null ) { + $config = get_option( OPTION_KEY, [] ); + if ( empty( $key ) ) { + return $config; + } + return $config[ $key ] ?? null; +} + +/** + * Get name of form field by key + */ +function get_config_name( $key ) { + + return OPTION_KEY . '[' . $key . ']'; } -function set_config($key, $value){ - $config = get_option(OPTION_KEY, []); - $config[$key] = $value; - return update_option(OPTION_KEY, $config, false); +function set_config( $key, $value ) { + $config = get_option( OPTION_KEY, [] ); + $config[ $key ] = $value; + return update_option( OPTION_KEY, $config, false ); } /** * Settings */ -class Settings -{ +class Settings { /** * The Init */ - public static function init() - { + public static function init() { add_action( 'admin_menu', @@ -53,30 +59,40 @@ function () { 'Настройки', 'manage_options', 'mss-settings', - array(__CLASS__, 'display_settings') + array ( __CLASS__, 'display_settings' ) ); }, 30 ); - add_action('admin_init', array(__CLASS__, 'settings_general'), $priority = 5, $accepted_args = 1); - add_action('admin_init', array(__CLASS__, 'settings_other'), $priority = 100, $accepted_args = 1); + add_action( 'admin_init', array( __CLASS__, 'settings_general' ), $priority = 5, $accepted_args = 1 ); + add_action( 'admin_init', array( __CLASS__, 'settings_other' ), $priority = 100, $accepted_args = 1 ); - add_action('wooms_settings_after_header', [__CLASS__, 'render_nav_menu']); + add_action( 'wooms_settings_after_header', [ __CLASS__, 'render_nav_menu' ] ); } - public static function render_nav_menu(){ + public static function render_nav_menu() { $nav_items = [ - 'getting-started' => sprintf('%s', 'https://github.com/wpcraft-ru/wooms/wiki/GettingStarted', 'С чего начать?'), - 'diagnostic' => sprintf('%s', admin_url('site-health.php'), 'Диагностика проблем'), - 'ms' => sprintf('%s', 'https://online.moysklad.ru/', 'Вход в МойСклад'), + 'dev' => sprintf( '%s', 'https://github.com/wpcraft-ru/wooms/', 'Разработка и решение проблем' ), + 'docs' => sprintf( '%s', 'https://github.com/wpcraft-ru/wooms/wiki', 'Документация' ), + + 'ms' => sprintf( '%s', 'https://online.moysklad.ru/', 'Вход в МойСклад' ), ]; - $nav_items = apply_filters('wooms_settings_nav_items', $nav_items); + $nav_items = apply_filters( 'wooms_settings_nav_items', $nav_items ); + + ?> +
+ Помощь с настройками +
+
+ +
+ ', get_option('woomss_pass')); + public static function display_form_pass() { + printf( '', get_option( 'woomss_pass' ) ); } /** * display_form_login */ - public static function display_form_login() - { - printf('', get_option('woomss_login')); + public static function display_form_login() { + printf( '', get_option( 'woomss_login' ) ); - printf('

%s

', 'Вводить нужно только логин и пароль здесь. На стороне МойСклад ничего настраивать не нужно.'); + printf( '

%s

', 'Вводить нужно только логин и пароль здесь. На стороне МойСклад ничего настраивать не нужно.' ); } /** * Settings - Other */ - public static function settings_other() - { - add_settings_section('woomss_section_other', 'Прочие настройки', null, 'mss-settings'); + public static function settings_other() { + add_settings_section( 'woomss_section_other', 'Прочие настройки', null, 'mss-settings' ); - register_setting('mss-settings', 'wooms_use_uuid'); + register_setting( 'mss-settings', 'wooms_use_uuid' ); add_settings_field( $id = 'wooms_use_uuid', $title = 'Использование UUID', - $callback = array(__CLASS__, 'display_field_wooms_use_uuid'), + $callback = array( __CLASS__, 'display_field_wooms_use_uuid' ), $page = 'mss-settings', $section = 'woomss_section_other' ); - register_setting('mss-settings', 'wooms_replace_title'); + register_setting( 'mss-settings', 'wooms_replace_title' ); add_settings_field( $id = 'wooms_replace_title', $title = 'Замена заголовка при обновлении', - $callback = array(__CLASS__, 'display_wooms_replace_title'), + $callback = array( __CLASS__, 'display_wooms_replace_title' ), $page = 'mss-settings', $section = 'woomss_section_other' ); - register_setting('mss-settings', 'wooms_replace_description'); + register_setting( 'mss-settings', 'wooms_replace_description' ); add_settings_field( $id = 'wooms_replace_description', $title = 'Замена описания при обновлении', - $callback = array(__CLASS__, 'display_wooms_replace_desc'), + $callback = array( __CLASS__, 'display_wooms_replace_desc' ), $page = 'mss-settings', $section = 'woomss_section_other' ); @@ -166,85 +178,81 @@ public static function settings_other() /** * display_wooms_replace_desc */ - public static function display_wooms_replace_desc() - { + public static function display_wooms_replace_desc() { $option_name = 'wooms_replace_description'; - printf('', $option_name, checked(1, get_option($option_name), false)); -?> + printf( '', $option_name, checked( 1, get_option( $option_name ), false ) ); + ?>

Если включить опцию, то плагин будет обновлять описание продукта из МойСклад всегда.

- ', $option_name, checked(1, get_option($option_name), false)); - ?> + printf( '', $option_name, checked( 1, get_option( $option_name ), false ) ); + ?>

- Если включить опцию, то плагин будет обновлять заголовки продукта из МойСклад. Иначе при наличии заголовока он не будет обновлен. + Если включить опцию, то плагин будет обновлять заголовки продукта из МойСклад. Иначе при наличии заголовока + он не будет обновлен.

- ', $option_name, checked(1, get_option($option_name), false)); - ?> + printf( '', $option_name, checked( 1, get_option( $option_name ), false ) ); + ?>

Если товары не попадают из МойСклад на сайт - попробуйте включить эту опцию.

- По умолчанию используется связь продуктов по артикулу. Это позволяет обеспечить синхронизацию без удаления всех продуктов с сайта при их наличии. Но без артикула - товары не будут синхронизироваться. Если товаров на сайте нет, либо их можно удалить без вреда, то можно включить синхронизацию по UUID. В этом случае артикулы + По умолчанию используется связь продуктов по артикулу. Это позволяет обеспечить синхронизацию без удаления + всех продуктов с сайта при их наличии. Но без артикула + товары не будут синхронизироваться. Если товаров на сайте нет, либо их можно удалить без вреда, то можно + включить синхронизацию по UUID. В этом случае артикулы будут не нужны.
При создании записи о продукте произойдет связка по UUID (meta_key = wooms_id)

- + ?>

Настройки интеграции МойСклад

- +
-Управление синхронизацией

', admin_url('admin.php?page=moysklad')); - printf('

Расширения и дополнения

', "https://github.com/topics/wooms"); - printf('

Предложения по улучшению и запросы на доработку

', "https://github.com/wpcraft-ru/wooms/issues"); - printf('

Рекомендуемые хостинги

', "https://wpcraft.ru/hosting-wordpress-woocommerce/"); - printf('

Контакты

', "https://wpcraft.ru/wooms/"); + printf( '

Управление синхронизацией

', admin_url( 'admin.php?page=moysklad' ) ); + printf( '

Помощь с настройкой

', "https://wpcraft.ru/wooms/?utm_source=wooms_plugin_settings_page" ); } } diff --git a/readme.txt b/readme.txt index ec4ba9b..c836b77 100644 --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,6 @@ === WooMS === Contributors: casepress -Donate link: https://wpcraft.ru/product/wooms-extra/ +Donate link: https://wpcraft.ru/pay/ Tags: moysklad, woocommerce, sync, integration Requires at least: 6.0 Tested up to: 6.4.2 @@ -23,7 +23,7 @@ Integration WooCommerce & MoySklad http://moysklad.ru (for Russia) * Загрузка картинок * Гибкие настройки -[Руководство по быстрому началу работы](https://github.com/wpcraft-ru/wooms/wiki/GettingStarted) +[Руководство по быстрому началу работы](https://wpcraft.ru/wooms/) Исходники для желающих принять участие в разработке: [https://github.com/wpcraft-ru/wooms/](https://github.com/wpcraft-ru/wooms/) @@ -76,9 +76,15 @@ PHP 7.0 == Changelog == += 9.11 = +- Тест совместимости WooCommerce 8.7.0 +- Улучшена синхронизация остатков +- Не обновляются остатки по товарам https://github.com/wpcraft-ru/wooms/issues/544 https://github.com/wpcraft-ru/wooms/issues/524 +- Совместимость: 'Высокопроизводительное хранилище заказов' https://github.com/wpcraft-ru/wooms/issues/539 + = 9.10 = - Исправлена ошибка с версией -- Обновдены авто тесты +- Обновлены авто тесты = 9.9 = - Исправление RC 2: Перестала работать синхронизация на версии 9.6 https://github.com/wpcraft-ru/wooms/issues/522 diff --git a/wooms.php b/wooms.php index bff310d..0d4892e 100644 --- a/wooms.php +++ b/wooms.php @@ -19,90 +19,89 @@ * WC requires at least: 7.0 * WC tested up to: 8.4.0 * - * Version: 9.10 + * Version: 9.11 */ namespace WooMS; // Exit if accessed directly -defined('ABSPATH') || exit; +defined( 'ABSPATH' ) || exit; /** * Add hook for activate plugin */ -register_activation_hook(__FILE__, function () { - do_action('wooms_activate'); -}); +register_activation_hook( __FILE__, function () { + do_action( 'wooms_activate' ); +} ); -register_deactivation_hook(__FILE__, function () { - do_action('wooms_deactivate'); -}); +register_deactivation_hook( __FILE__, function () { + do_action( 'wooms_deactivate' ); +} ); require_once __DIR__ . '/includes/functions.php'; -add_action('plugins_loaded', function () { - if (!wooms_can_start()) { - return; - } +add_action( 'plugins_loaded', function () { + if ( ! wooms_can_start() ) { + return; + } - $files = glob(__DIR__ . '/includes/*.php'); - foreach ($files as $file) { - require_once $file; - } - add_action('admin_enqueue_scripts', __NAMESPACE__ . '\\' . 'admin_styles'); - add_action('save_post', 'wooms_id_check_if_unique', 10, 3); -}); + $files = glob( __DIR__ . '/includes/*.php' ); + foreach ( $files as $file ) { + require_once $file; + } + add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\\' . 'admin_styles' ); + add_action( 'save_post', 'wooms_id_check_if_unique', 10, 3 ); +} ); -add_filter('plugin_row_meta', __NAMESPACE__ . '\\add_wooms_plugin_row_meta', 10, 2); +add_filter( 'plugin_row_meta', __NAMESPACE__ . '\\add_wooms_plugin_row_meta', 10, 2 ); -add_filter( "plugin_action_links_" . plugin_basename(__FILE__), function($links){ +add_filter( "plugin_action_links_" . plugin_basename( __FILE__ ), function ($links) { $mng_link = 'Управление'; $settings_link = 'Настройки'; - array_unshift($links, $mng_link); - array_unshift($links, $settings_link); - return $links; -}); + array_unshift( $links, $mng_link ); + array_unshift( $links, $settings_link ); + return $links; +} ); /** * сообщяем про то что Extra плагин более не актуален */ -add_action('after_plugin_row_wooms-extra/wooms-extra.php', function($data, $response){ +add_action( 'after_plugin_row_wooms-extra/wooms-extra.php', function ($data, $response) { - $wp_list_table = _get_list_table('WP_Plugins_List_Table'); + $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' ); printf( - ' + '
Этот плагин следует удалить. Теперь все работает на базе 9й версии и в одном плагине
', - $wp_list_table->get_column_count() + $wp_list_table->get_column_count() ); -}, 10, 2); -add_filter('wooms_xt_load', '__return_false'); +}, 10, 2 ); +add_filter( 'wooms_xt_load', '__return_false' ); /** * Add GettingStarted link in row meta at pligins list */ -function add_wooms_plugin_row_meta($links, $file) -{ - if (strpos($file, 'wooms.php') !== false) { - $new_links = array( - 'Руководство по началу работы', - 'Консультации', - 'Задачи', - ); - - $links = array_merge($links, $new_links); - } - - return $links; +function add_wooms_plugin_row_meta( $links, $file ) { + if ( strpos( $file, 'wooms.php' ) !== false ) { + $new_links = array( + 'Руководство по началу работы', + 'Консультации', + 'Задачи', + ); + + $links = array_merge( $links, $new_links ); + } + + return $links; } @@ -111,103 +110,113 @@ function add_wooms_plugin_row_meta($links, $file) * * @return void */ -function admin_styles() -{ - $admin_style = plugin_dir_url(__FILE__) . 'css/admin.css'; +function admin_styles() { + $admin_style = plugin_dir_url( __FILE__ ) . 'css/admin.css'; - wp_enqueue_style('wooms_styles', $admin_style, array()); + wp_enqueue_style( 'wooms_styles', $admin_style, array() ); } -function get_api_url($path){ +function get_api_url( $path ) { return $url = 'https://api.moysklad.ru/api/remap/1.2/' . $path; } -function request($path = '', $data = array(), $type = 'GET'){ - // https://api.moysklad.ru/api/remap/1.2/ - - - if (empty($path)) { - return false; - } - - if(str_contains($path, 'https://api.moysklad.ru/api/remap/1.2/')){ - $url = $path; - } else { - $url = 'https://api.moysklad.ru/api/remap/1.2/' . $path; - } - - - - //@link https://github.com/wpcraft-ru/wooms/issues/177 - $url = str_replace('product_id', 'product.id', $url); - $url = str_replace('store_id', 'store.id', $url); - $url = str_replace('consignment_id', 'consignment.id', $url); - $url = str_replace('variant_id', 'variant.id', $url); - $url = str_replace('productFolder_id', 'productFolder.id', $url); - - if (!empty($data) && 'GET' == $type) { - $type = 'POST'; - } - if ('GET' == $type) { - $data = null; - } else { - $data = json_encode($data); - } - - $args = array( - 'method' => $type, - 'timeout' => 45, - 'redirection' => 5, - 'headers' => array( - "Content-Type" => 'application/json;charset=utf-8', - "Accept-Encoding" => "gzip", - 'Authorization' => 'Basic ' . - base64_encode(get_option('woomss_login') . ':' . get_option('woomss_pass')), - ), - 'body' => $data, - ); - - $request = wp_remote_request($url, $args); - if (is_wp_error($request)) { - do_action( - 'wooms_logger_error', - $type = 'WooMS-Request', - $title = 'Ошибка REST API WP Error', - $desc = $request->get_error_message() - ); - - return false; - } - - if (empty($request['body'])) { - do_action( - 'wooms_logger_error', - $type = 'WooMS-Request', - $title = 'REST API вернулся без требуемых данных' - ); - - return false; - } - - $response = json_decode($request['body'], true); - - if (!empty($response["errors"]) and is_array($response["errors"])) { - foreach ($response["errors"] as $error) { - do_action( - 'wooms_logger_error', - $type = 'WooMS-Request', - $title = $url, - $response - ); - } - } - - return $response; +function request( $path = '', $data = array(), $type = 'GET' ) { + // https://api.moysklad.ru/api/remap/1.2/ + + + if ( empty ( $path ) ) { + return false; + } + + if ( str_contains( $path, 'https://api.moysklad.ru/api/remap/1.2/' ) ) { + $url = $path; + } else { + $url = 'https://api.moysklad.ru/api/remap/1.2/' . $path; + } + + + + //@link https://github.com/wpcraft-ru/wooms/issues/177 + $url = str_replace( 'product_id', 'product.id', $url ); + $url = str_replace( 'store_id', 'store.id', $url ); + $url = str_replace( 'consignment_id', 'consignment.id', $url ); + $url = str_replace( 'variant_id', 'variant.id', $url ); + $url = str_replace( 'productFolder_id', 'productFolder.id', $url ); + + if ( ! empty ( $data ) && 'GET' == $type ) { + $type = 'POST'; + } + if ( 'GET' == $type ) { + $data = null; + } else { + $data = json_encode( $data ); + } + + $args = array( + 'method' => $type, + 'timeout' => 45, + 'redirection' => 5, + 'headers' => array( + "Content-Type" => 'application/json;charset=utf-8', + "Accept-Encoding" => "gzip", + 'Authorization' => 'Basic ' . + base64_encode( get_option( 'woomss_login' ) . ':' . get_option( 'woomss_pass' ) ), + ), + 'body' => $data, + ); + + $request = wp_remote_request( $url, $args ); + if ( is_wp_error( $request ) ) { + do_action( + 'wooms_logger_error', + $type = 'WooMS-Request', + $title = 'Ошибка REST API WP Error', + $desc = $request->get_error_message() + ); + + return false; + } + + if ( empty ( $request['body'] ) ) { + do_action( + 'wooms_logger_error', + $type = 'WooMS-Request', + $title = 'REST API вернулся без требуемых данных' + ); + + return false; + } + + $response = json_decode( $request['body'], true ); + + if ( ! empty ( $response["errors"] ) and is_array( $response["errors"] ) ) { + foreach ( $response["errors"] as $error ) { + do_action( + 'wooms_logger_error', + $type = 'WooMS-Request', + $title = $url, + $response + ); + } + } + + return $response; } -function get_session_id(){ - return \WooMS\Products\get_session_id(); +function get_session_id() { + return \WooMS\Products\get_session_id(); } + +/** + * doc https://github.com/woocommerce/woocommerce/wiki/High-Performance-Order-Storage-Upgrade-Recipe-Book + * doc https://woo.com/document/high-performance-order-storage/ + * issue https://github.com/wpcraft-ru/wooms/issues/539 + */ +add_action( 'before_woocommerce_init', function () { + if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class) ) { + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true ); + } +} );