From b8c26af50a7655f30ce9cb8e45a2f4ec92fb9681 Mon Sep 17 00:00:00 2001 From: Rahul Raina Date: Thu, 14 Dec 2023 13:51:38 +0800 Subject: [PATCH 1/3] Add support for syncing(creating/updating) single products using Catalog Batch API --- facebook-commerce.php | 110 ++++++++++++++- includes/Products/Sync/Background.php | 99 +------------ includes/fbutils.php | 122 ++++++++++++++++ .../WCFacebookCommerceIntegrationTest.php | 130 +++++++++++------- 4 files changed, 310 insertions(+), 151 deletions(-) diff --git a/facebook-commerce.php b/facebook-commerce.php index 53d2cef57..f95b1cd41 100644 --- a/facebook-commerce.php +++ b/facebook-commerce.php @@ -16,6 +16,7 @@ use WooCommerce\Facebook\Framework\Plugin\Exception as PluginException; use WooCommerce\Facebook\Products; use WooCommerce\Facebook\Products\Feed; +use WooCommerce\Facebook\Products\Sync; defined( 'ABSPATH' ) || exit; @@ -314,6 +315,8 @@ public function __construct( WC_Facebookcommerce $facebook_for_woocommerce ) { add_action( 'add_meta_boxes', 'WooCommerce\Facebook\Admin\Product_Sync_Meta_Box::register', 10, 1 ); + add_action( 'add_meta_boxes', [ $this, 'display_batch_api_completed' ], 10, 2 ); + add_action( 'wp_ajax_ajax_fb_toggle_visibility', array( $this, 'ajax_fb_toggle_visibility' ) @@ -1175,7 +1178,7 @@ public function on_simple_product_publish( $wp_id, $woo_product = null, &$parent if ( $fb_product_item_id ) { $woo_product->fb_visibility = Products::is_product_visible( $woo_product->woo_product ); - $this->update_product_item( $woo_product, $fb_product_item_id ); + $this->update_product_item_batch_api( $woo_product, $fb_product_item_id ); return $fb_product_item_id; } else { // Check if this is a new product item for an existing product group @@ -1232,8 +1235,7 @@ public function create_product_simple( WC_Facebook_Product $woo_product, string } if ( $fb_product_group_id ) { - $fb_product_item_id = $this->create_product_item( $woo_product, $retailer_id, $fb_product_group_id ); - return $fb_product_item_id; + return $this->create_product_item_batch_api( $woo_product, $retailer_id, $fb_product_group_id ); } return ''; } @@ -1339,6 +1341,35 @@ public function update_product_group( WC_Facebook_Product $woo_product ) { } } + /** + * Creates a product item using the facebook Catalog Batch API. This replaces existing functionality, + * which is currently using facebook Product Item API implemented by `WC_Facebookcommerce_Integration::create_product_item` + * + * @since x.x.x + * @param WC_Facebook_Product $woo_product + * @param string $retailer_id + **/ + public function create_product_item_batch_api( $woo_product, $retailer_id, $product_group_id ): string { + try { + $product_data = $woo_product->prepare_product( $retailer_id, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch( $product_data ); + $facebook_catalog_id = $this->get_product_catalog_id(); + $response = $this->facebook_for_woocommerce->get_api()->send_item_updates( $facebook_catalog_id, $requests ); + + if ( $response->handles ) { + return ''; + } else { + $this->display_error_message( + 'Updated product on Facebook has failed.' + ); + } + } catch ( ApiException $e ) { + $message = sprintf( 'There was an error trying to create a product item: %s', $e->getMessage() ); + WC_Facebookcommerce_Utils::log( $message ); + } + return ''; + } + public function create_product_item( $woo_product, $retailer_id, $product_group_id ): string { try { $product_data = $woo_product->prepare_product( $retailer_id ); @@ -1465,6 +1496,37 @@ private function get_product_variation_attributes( array $variation ): array { return $final_attributes; } + /** + * Update existing product using batch API. + * + * @param WC_Facebook_Product $woo_product + * @param string $fb_product_item_id + * @return void + */ + public function update_product_item_batch_api( WC_Facebook_Product $woo_product, string $fb_product_item_id ): void { + $product = $woo_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch( $product ); + + try { + $facebook_catalog_id = $this->get_product_catalog_id(); + $response = $this->facebook_for_woocommerce->get_api()->send_item_updates( $facebook_catalog_id, $requests ); + if ( $response->handles ) { + $this->display_success_message( + 'Updated product ' . $fb_product_item_id . ' on Facebook.' + ); + } else { + $this->display_error_message( + 'Updated product ' . $fb_product_item_id . ' on Facebook has failed.' + ); + } + } catch ( ApiException $e ) { + $message = sprintf( 'There was an error trying to update a product item: %s', $e->getMessage() ); + WC_Facebookcommerce_Utils::log( $message ); + } + } + /** * Update existing product. * @@ -1550,6 +1612,48 @@ public function delete_product_set_item( string $fb_product_set_id ) { } } + /** + * Displays Batch API completed message on simple_product_publish. + * This is called by the hook `add_meta_boxes` because that is sufficient time + * to retrieve product_item_id for the product item created via batch API. + * + * Some sanity checks are added before displaying the message after publish + * - product_item_id : if exists, means product was created else not and don't display + * - should_sync: Don't display if the product is not supposed to be synced. + * + * @param string $post_type Wordpress Post type + * @param WP_Post $post Wordpress Post + * @return void + */ + public function display_batch_api_completed( string $post_type, WP_Post $post ) { + $fb_product = new \WC_Facebook_Product( $post->ID ); + $fb_product_item_id = null; + $should_sync = true; + $no_sync_reason = ''; + + if ( $fb_product->woo_product instanceof \WC_Product ) { + try { + facebook_for_woocommerce()->get_product_sync_validator( $fb_product->woo_product )->validate(); + } catch ( \Exception $e ) { + $should_sync = false; + $no_sync_reason = $e->getMessage(); + } + } + if( $should_sync ) { + if ( $fb_product->woo_product->is_type( 'variable' ) ) { + $fb_product_item_id = $this->get_product_fbid( self::FB_PRODUCT_GROUP_ID, $post->ID, $fb_product->woo_product ); + } else { + $fb_product_item_id = $this->get_product_fbid( self::FB_PRODUCT_ITEM_ID, $post->ID, $fb_product->woo_product ); + } + } + if ( $fb_product_item_id ) { + $this->display_success_message( + 'Created product ' . $fb_product_item_id . ' on Facebook.' + ); + } + } + /** * Checks the feed upload status (FBE v1.0). diff --git a/includes/Products/Sync/Background.php b/includes/Products/Sync/Background.php index 0858fe524..ba8464e98 100644 --- a/includes/Products/Sync/Background.php +++ b/includes/Products/Sync/Background.php @@ -185,9 +185,9 @@ private function process_item_update( $prefixed_product_id ) { if ( ! Products::product_should_be_deleted( $product ) && Products::product_should_be_synced( $product ) ) { if ( $product->is_type( 'variation' ) ) { - $product_data = $this->prepare_product_variation_data( $product ); + $product_data = \WC_Facebookcommerce_Utils::prepare_product_variation_data_items_batch( $product ); } else { - $product_data = $this->prepare_product_data( $product ); + $product_data = \WC_Facebookcommerce_Utils::prepare_product_data_items_batch( $product ); } // extract the retailer_id @@ -217,98 +217,6 @@ private function process_item_update( $prefixed_product_id ) { return $request; } - /** - * Prepares the data for a product variation to be included in a sync request. - * - * @since 2.0.0 - * - * @param \WC_Product $product product object - * @return array - * @throws PluginException In case no product found. - */ - private function prepare_product_variation_data( $product ) { - $parent_product = wc_get_product( $product->get_parent_id() ); - - if ( ! $parent_product instanceof \WC_Product ) { - throw new PluginException( "No parent product found with ID equal to {$product->get_parent_id()}." ); - } - - $fb_parent_product = new \WC_Facebook_Product( $parent_product->get_id() ); - $fb_product = new \WC_Facebook_Product( $product->get_id(), $fb_parent_product ); - - $data = $fb_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); - - // product variations use the parent product's retailer ID as the retailer product group ID - // $data['retailer_product_group_id'] = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $parent_product ); - $data['item_group_id'] = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $parent_product ); - - return $this->normalize_product_data( $data ); - } - - /** - * Normalizes product data to be included in a sync request. /items_batch - * rather than /batch this time. - * - * @since 2.0.0 - * - * @param array $data product data. - * @return array - */ - private function normalize_product_data( $data ) { - // Allowed values are 'refurbished', 'used', and 'new', but the plugin has always used the latter. - $data['condition'] = 'new'; - // Attributes other than size, color, pattern, or gender need to be included in the additional_variant_attributes field. - if ( isset( $data['custom_data'] ) && is_array( $data['custom_data'] ) ) { - $attributes = []; - foreach ( $data['custom_data'] as $key => $val ) { - - /** - * Filter: facebook_for_woocommerce_variant_attribute_comma_replacement - * - * The Facebook API expects a comma-separated list of attributes in `additional_variant_attribute` field. - * https://developers.facebook.com/docs/marketing-api/catalog/reference/ - * This means that WooCommerce product attributes included in this field should avoid the comma (`,`) character. - * Facebook for WooCommerce replaces any `,` with a space by default. - * This filter allows a site to provide a different replacement string. - * - * @since 2.5.0 - * - * @param string $replacement The default replacement string (`,`). - * @param string $value Attribute value. - * @return string Return the desired replacement string. - */ - $attribute_value = str_replace( - ',', - apply_filters( 'facebook_for_woocommerce_variant_attribute_comma_replacement', ' ', $val ), - $val - ); - /** Force replacing , and : characters if those were not cleaned up by filters */ - $attributes[] = str_replace( [ ',', ':' ], ' ', $key ) . ':' . str_replace( [ ',', ':' ], ' ', $attribute_value ); - } - - $data['additional_variant_attribute'] = implode( ',', $attributes ); - unset( $data['custom_data'] ); - } - - return $data; - } - - /** - * Prepares the product data to be included in a sync request. - * - * @since 2.0.0 - * - * @param \WC_Product $product product object - * @return array - */ - private function prepare_product_data( $product ) { - $fb_product = new \WC_Facebook_Product( $product->get_id() ); - $data = $fb_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); - // products that are not variations use their retailer retailer ID as the retailer product group ID - $data['item_group_id'] = $data['retailer_id']; - return $this->normalize_product_data( $data ); - } - /** * Processes a DELETE sync request for the given product. * @@ -342,7 +250,8 @@ private function process_item_delete( $prefixed_retailer_id ) { private function send_item_updates( array $requests ): array { $facebook_catalog_id = facebook_for_woocommerce()->get_integration()->get_product_catalog_id(); $response = facebook_for_woocommerce()->get_api()->send_item_updates( $facebook_catalog_id, $requests ); - $handles = ( isset( $response->handles ) && is_array( $response->handles ) ) ? $response->handles : []; + $response_handles = $response->handles; + $handles = ( isset( $response_handles ) && is_array( $response_handles ) ) ? $response_handles : array(); return $handles; } } diff --git a/includes/fbutils.php b/includes/fbutils.php index 64f81c57e..3116e0949 100644 --- a/includes/fbutils.php +++ b/includes/fbutils.php @@ -14,6 +14,7 @@ use WooCommerce\Facebook\Events\AAMSettings; use WooCommerce\Facebook\Events\Normalizer; use WooCommerce\Facebook\Framework\Api\Exception as ApiException; +use WooCommerce\Facebook\Products\Sync; if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) : @@ -622,6 +623,127 @@ public static function get_cached_best_tip() { ); return $cached_best_tip; } + + /** + * Normalizes product data to be included in a sync request. /items_batch + * rather than /batch this time. + * + * @since x.x.x + * + * @param array $data product data. + * @return array + */ + public static function normalize_product_data_for_items_batch( $data ) { + // Allowed values are 'refurbished', 'used', and 'new', but the plugin has always used the latter. + $data['condition'] = 'new'; + // Attributes other than size, color, pattern, or gender need to be included in the additional_variant_attributes field. + if ( isset( $data['custom_data'] ) && is_array( $data['custom_data'] ) ) { + $attributes = []; + foreach ( $data['custom_data'] as $key => $val ) { + + /** + * Filter: facebook_for_woocommerce_variant_attribute_comma_replacement + * + * The Facebook API expects a comma-separated list of attributes in `additional_variant_attribute` field. + * https://developers.facebook.com/docs/marketing-api/catalog/reference/ + * This means that WooCommerce product attributes included in this field should avoid the comma (`,`) character. + * Facebook for WooCommerce replaces any `,` with a space by default. + * This filter allows a site to provide a different replacement string. + * + * @since 2.5.0 + * + * @param string $replacement The default replacement string (`,`). + * @param string $value Attribute value. + * @return string Return the desired replacement string. + */ + $attribute_value = str_replace( + ',', + apply_filters( 'facebook_for_woocommerce_variant_attribute_comma_replacement', ' ', $val ), + $val + ); + /** Force replacing , and : characters if those were not cleaned up by filters */ + $attributes[] = str_replace( [ ',', ':' ], ' ', $key ) . ':' . str_replace( [ ',', ':' ], ' ', $attribute_value ); + } + + $data['additional_variant_attribute'] = implode( ',', $attributes ); + unset( $data['custom_data'] ); + } + + return $data; + } + + /** + * Prepares the product data to be included in a sync request. + * + * @since x.x.x + * + * @param \WC_Product $product product object + * @return array + */ + public static function prepare_product_data_items_batch( $product ) { + $fb_product = new \WC_Facebook_Product( $product->get_id() ); + $data = $fb_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + // products that are not variations use their retailer retailer ID as the retailer product group ID + $data['item_group_id'] = $data['retailer_id']; + return self::normalize_product_data_for_items_batch( $data ); + } + + /** + * Prepares the requests array to be included in a batch api request. + * + * @since x.x.x + * + * @param array $product Array + * @return array + */ + public static function prepare_product_requests_items_batch( $product ) { + $product['item_group_id'] = $product['retailer_id']; + $product_data = self::normalize_product_data_for_items_batch( $product ); + + // extract the retailer_id + $retailer_id = $product_data['retailer_id']; + + // NB: Changing this to get items_batch to work + // retailer_id cannot be included in the data object + unset( $product_data['retailer_id'] ); + $product_data['id'] = $retailer_id; + + $requests = array([ + 'method' => Sync::ACTION_UPDATE, + 'data' => $product_data, + ]); + + return $requests; + } + + /** + * Prepares the data for a product variation to be included in a sync request. + * + * @since x.x.x + * + * @param \WC_Product $product product object + * @return array + * @throws PluginException In case no product found. + */ + public static function prepare_product_variation_data_items_batch( $product ) { + $parent_product = wc_get_product( $product->get_parent_id() ); + + if ( ! $parent_product instanceof \WC_Product ) { + throw new PluginException( "No parent product found with ID equal to {$product->get_parent_id()}." ); + } + + $fb_parent_product = new \WC_Facebook_Product( $parent_product->get_id() ); + $fb_product = new \WC_Facebook_Product( $product->get_id(), $fb_parent_product ); + + $data = $fb_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + + // product variations use the parent product's retailer ID as the retailer product group ID + // $data['retailer_product_group_id'] = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $parent_product ); + $data['item_group_id'] = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $parent_product ); + + return self::normalize_product_data_for_items_batch( $data ); + } + } endif; diff --git a/tests/Unit/WCFacebookCommerceIntegrationTest.php b/tests/Unit/WCFacebookCommerceIntegrationTest.php index 112fad037..cabb9837e 100644 --- a/tests/Unit/WCFacebookCommerceIntegrationTest.php +++ b/tests/Unit/WCFacebookCommerceIntegrationTest.php @@ -520,18 +520,23 @@ public function test_on_product_save_existing_simple_product_sync_enabled_update $product_to_update->set_meta_data( Products::VISIBILITY_META_KEY, true ); - $facebook_product = new WC_Facebook_Product( $product_to_update->get_id() ); - $facebook_product_data = $facebook_product->prepare_product(); - $facebook_product_data['additional_image_urls'] = ''; + $facebook_product = new WC_Facebook_Product( $product_to_update->get_id() ); + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $this->integration->product_catalog_id = '123123123123123123'; /* Data coming from _POST data. */ - $facebook_product_data['description'] = 'Facebook product description.'; - $facebook_product_data['price'] = 19900; - $facebook_product_data['category'] = 1718; + $facebook_product_data['description'] = 'Facebook product description.'; + $facebook_product_data['price'] = '199 USD'; + $facebook_product_data['google_product_category'] = 1718; + + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); $this->api->expects( $this->once() ) - ->method( 'update_product_item' ) - ->with( 'facebook-product-item-id', $facebook_product_data ) - ->willReturn( new API\ProductCatalog\Products\Update\Response( '{"success":true}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); $this->integration->on_product_save( $product_to_update->get_id() ); @@ -721,9 +726,11 @@ public function test_fb_change_product_published_status_for_simple_product() { ->method( 'is_connected' ) ->willReturn( true ); - $product = WC_Helper_Product::create_simple_product(); - $facebook_product = new WC_Facebook_Product( $product ); - $product_data = $facebook_product->prepare_product(); + $product = WC_Helper_Product::create_simple_product(); + $facebook_product = new WC_Facebook_Product( $product ); + $product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($product_data); + $this->integration->product_catalog_id = '123123123123123123'; if ( empty( $product_data['additional_image_urls'] ) ) { $product_data['additional_image_urls'] = ''; } @@ -737,9 +744,12 @@ public function test_fb_change_product_published_status_for_simple_product() { ->willReturn( $product_validator ); $this->api->expects( $this->once() ) - ->method( 'update_product_item' ) - ->with( 'facebook-product-id', $product_data ) - ->willReturn( new API\ProductCatalog\Products\Update\Response( '{"success":true}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); /* Statuses involved into logic: publish, trash */ $new_status = 'publish'; @@ -818,14 +828,19 @@ public function test_on_product_publish_simple_product() { ->with( $product ) ->willReturn( $validator ); + $this->integration->product_catalog_id = '123123123123123123'; $facebook_product = new WC_Facebook_Product( $product->get_id() ); - $facebook_product_data = $facebook_product->prepare_product(); - $facebook_product_data['additional_image_urls'] = ''; + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); $this->api->expects( $this->once() ) - ->method( 'update_product_item' ) - ->with( 'facebook-product-item-id', $facebook_product_data ) - ->willReturn( new API\ProductCatalog\Products\Update\Response( '{"success":true}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); $this->integration->on_product_publish( $product->get_id() ); } @@ -1043,12 +1058,18 @@ public function test_on_simple_product_publish_existing_product_updates_product( $facebook_product->woo_product->set_stock_status( 'instock' ); add_post_meta( $product->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_ITEM_ID, 'facebook-simple-product-item-id' ); - $facebook_product_data = $facebook_product->prepare_product(); - $facebook_product_data['additional_image_urls'] = ''; + $this->integration->product_catalog_id = '123123123123123123'; + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); + $this->api->expects( $this->once() ) - ->method( 'update_product_item' ) - ->with( 'facebook-simple-product-item-id', $facebook_product_data ) - ->willReturn( new API\ProductCatalog\Products\Update\Response( '{"success":true}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); $facebook_product_item_id = $this->integration->on_simple_product_publish( $product->get_id(), $facebook_product ); @@ -1063,8 +1084,10 @@ public function test_on_simple_product_publish_existing_product_updates_product( public function test_on_simple_product_publish_existing_product_creates_product() { add_option( WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID, '1234567891011121314' ); - $product = WC_Helper_Product::create_simple_product(); - $facebook_product = new WC_Facebook_Product( $product->get_id() ); + $product = WC_Helper_Product::create_simple_product(); + $facebook_product = new WC_Facebook_Product( $product->get_id() ); + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); /* Product should be synced with all its variations. So seven calls expected. */ $validator = $this->createMock( ProductValidator::class ); @@ -1087,16 +1110,15 @@ public function test_on_simple_product_publish_existing_product_creates_product( ) ->willReturn( new API\ProductCatalog\ProductGroups\Create\Response( '{"id":"facebook-simple-product-group-item-id"}' ) ); $this->api->expects( $this->once() ) - ->method( 'create_product_item' ) + ->method( 'send_item_updates' ) ->with( - 'facebook-simple-product-group-item-id', - $facebook_product->prepare_product( WC_Facebookcommerce_Utils::get_fb_retailer_id( $facebook_product ) ) + $this->integration->get_product_catalog_id(), + $requests ) - ->willReturn( new API\ProductCatalog\Products\Create\Response( '{"id":"facebook-simple-product-group-item-id"}' ) ); + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); - $facebook_product_item_id = $this->integration->on_simple_product_publish( $product->get_id(), $facebook_product ); + $this->integration->on_simple_product_publish( $product->get_id(), $facebook_product ); - $this->assertEquals( 'facebook-simple-product-group-item-id', $facebook_product_item_id ); $this->assertEquals( 'facebook-simple-product-group-item-id', get_post_meta( $facebook_product->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_GROUP_ID, true ) @@ -1154,9 +1176,11 @@ public function test_product_should_be_synced_calls_facebook_api_with_exception( public function test_create_product_simple_creates_product_group_before_creating_product_item() { add_option( WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID, '123456789101112' ); - $product = WC_Helper_Product::create_simple_product(); - $facebook_product = new WC_Facebook_Product( $product->get_id() ); - $retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $facebook_product ); + $product = WC_Helper_Product::create_simple_product(); + $facebook_product = new WC_Facebook_Product( $product->get_id() ); + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); + $retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $facebook_product ); $data = [ 'retailer_id' => $retailer_id, @@ -1166,17 +1190,17 @@ public function test_create_product_simple_creates_product_group_before_creating ->with( '123456789101112', $data ) ->willReturn( new API\ProductCatalog\ProductGroups\Create\Response( '{"id":"facebook-simple-product-group-id"}' ) ); - $data = $facebook_product->prepare_product( $retailer_id ); $this->api->expects( $this->once() ) - ->method( 'create_product_item' ) - ->with( 'facebook-simple-product-group-id', $data ) - ->willReturn( new API\ProductCatalog\Products\Create\Response( '{"id":"facebook-simple-product-item-id"}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); - $facebook_product_item_id = $this->integration->create_product_simple( $facebook_product ); + $this->integration->create_product_simple( $facebook_product ); $this->assertEquals( 'facebook-simple-product-group-id', get_post_meta( $facebook_product->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_GROUP_ID, true ) ); - $this->assertEquals( 'facebook-simple-product-item-id', get_post_meta( $facebook_product->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_ITEM_ID, true ) ); - $this->assertEquals( 'facebook-simple-product-item-id', $facebook_product_item_id ); } /** @@ -1187,20 +1211,20 @@ public function test_create_product_simple_creates_product_group_before_creating public function test_create_product_simple_creates_product_with_provided_product_group_id() { add_option( WC_Facebookcommerce_Integration::OPTION_PRODUCT_CATALOG_ID, '123456789101112' ); - $product = WC_Helper_Product::create_simple_product(); - $facebook_product = new WC_Facebook_Product( $product->get_id() ); - $retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $facebook_product ); + $product = WC_Helper_Product::create_simple_product(); + $facebook_product = new WC_Facebook_Product( $product->get_id() ); + $facebook_product_data = $facebook_product->prepare_product(null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch($facebook_product_data); - $data = $facebook_product->prepare_product( $retailer_id ); $this->api->expects( $this->once() ) - ->method( 'create_product_item' ) - ->with( 'facebook-simple-product-group-id', $data ) - ->willReturn( new API\ProductCatalog\Products\Create\Response( '{"id":"facebook-simple-product-item-id"}' ) ); + ->method( 'send_item_updates' ) + ->with( + $this->integration->get_product_catalog_id(), + $requests + ) + ->willReturn( new API\ProductCatalog\ItemsBatch\Create\Response( '{"handles":"abcxyz"}' ) ); $facebook_product_item_id = $this->integration->create_product_simple( $facebook_product, 'facebook-simple-product-group-id' ); - - $this->assertEquals( 'facebook-simple-product-item-id', get_post_meta( $facebook_product->get_id(), WC_Facebookcommerce_Integration::FB_PRODUCT_ITEM_ID, true ) ); - $this->assertEquals( 'facebook-simple-product-item-id', $facebook_product_item_id ); } /** From 19d2232e34264f2d1aad4658f9872b92d386224c Mon Sep 17 00:00:00 2001 From: Rahul Raina Date: Wed, 20 Dec 2023 19:35:50 +0800 Subject: [PATCH 2/3] Apply suggestions from code review Code format Co-authored-by: Kader Ibrahim S --- facebook-commerce.php | 2 +- includes/fbutils.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/facebook-commerce.php b/facebook-commerce.php index f95b1cd41..6289cfd1d 100644 --- a/facebook-commerce.php +++ b/facebook-commerce.php @@ -1504,7 +1504,7 @@ private function get_product_variation_attributes( array $variation ): array { * @return void */ public function update_product_item_batch_api( WC_Facebook_Product $woo_product, string $fb_product_item_id ): void { - $product = $woo_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); + $product = $woo_product->prepare_product( null, \WC_Facebook_Product::PRODUCT_PREP_TYPE_ITEMS_BATCH ); $requests = WC_Facebookcommerce_Utils::prepare_product_requests_items_batch( $product ); try { diff --git a/includes/fbutils.php b/includes/fbutils.php index 3116e0949..adc34b34b 100644 --- a/includes/fbutils.php +++ b/includes/fbutils.php @@ -698,7 +698,7 @@ public static function prepare_product_data_items_batch( $product ) { */ public static function prepare_product_requests_items_batch( $product ) { $product['item_group_id'] = $product['retailer_id']; - $product_data = self::normalize_product_data_for_items_batch( $product ); + $product_data = self::normalize_product_data_for_items_batch( $product ); // extract the retailer_id $retailer_id = $product_data['retailer_id']; @@ -708,10 +708,10 @@ public static function prepare_product_requests_items_batch( $product ) { unset( $product_data['retailer_id'] ); $product_data['id'] = $retailer_id; - $requests = array([ + $requests = array( [ 'method' => Sync::ACTION_UPDATE, 'data' => $product_data, - ]); + ] ); return $requests; } From f93922fabf61e261b3bf52273a166e805adc2764 Mon Sep 17 00:00:00 2001 From: Rahul Raina Date: Wed, 20 Dec 2023 20:10:19 +0800 Subject: [PATCH 3/3] Remove outdated docbloc --- facebook-commerce.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/facebook-commerce.php b/facebook-commerce.php index 6289cfd1d..bde685859 100644 --- a/facebook-commerce.php +++ b/facebook-commerce.php @@ -1225,7 +1225,7 @@ public function product_should_be_synced( WC_Product $product ): bool { * * @param WC_Facebook_Product $woo_product * @param string|null $fb_product_group_id - * @return string facebook product item id + * @return string */ public function create_product_simple( WC_Facebook_Product $woo_product, string $fb_product_group_id = null ): string { $retailer_id = WC_Facebookcommerce_Utils::get_fb_retailer_id( $woo_product );