Skip to content
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions includes/Handlers/Category.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,54 @@ public static function get_square_category_id( $catalog_item ) {

return $catalog_category_id;
}

/**
* Get the WooCommerce category IDs from a catalog item.
*
Comment thread
iamdharmesh marked this conversation as resolved.
* @param \Square\Models\CatalogItem $catalog_item the catalog item object
* @return array
*/
public static function get_category_ids_from_catalog_item( $catalog_item ) {
$category_ids = array();
$missing_category_ids = array();

if ( empty( $catalog_item ) ) {
return $category_ids;
}

if ( $catalog_item->getCategories() && is_array( $catalog_item->getCategories() ) ) {
Comment thread
iamdharmesh marked this conversation as resolved.
foreach ( $catalog_item->getCategories() as $category ) {
if ( $category instanceof \Square\Models\CatalogObjectCategory ) {
$category_id = self::get_category_id_by_square_id( $category->getId() );
if ( $category_id ) {
$category_ids[] = $category_id;
} else {
$missing_category_ids[] = $category->getId();
}
}
}
}
Comment thread
iamdharmesh marked this conversation as resolved.

// Fetch and import missing categories.
if ( ! empty( $missing_category_ids ) ) {
try {
$response = wc_square()->get_api()->batch_retrieve_catalog_objects( $missing_category_ids );
Comment thread
iamdharmesh marked this conversation as resolved.
if ( $response->get_data() instanceof \Square\Models\BatchRetrieveCatalogObjectsResponse ) {
$missing_categories = $response->get_data()->getObjects();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if getObjects() returns an empty array (e.g. deleted/invalid IDs), we only log on exception. Should we consider logging when some IDs were requested but none returned, for “category still missing” cases?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We log exception if we didn't get a proper response, but not logging for the empty array? Could you please provide more information on what we want to do here? Thanks

if ( $missing_categories && is_array( $missing_categories ) ) {
foreach ( $missing_categories as $missing_category ) {
$imported_category_id = self::import_or_update( $missing_category );
if ( $imported_category_id ) {
$category_ids[] = $imported_category_id;
}
}
}
}
} catch ( \Exception $e ) {
wc_square()->log( 'Error fetching missing categories for product ' . $catalog_item->getName() . ': ' . $e->getMessage() );
}
}

return array_unique( $category_ids );
}
}
30 changes: 4 additions & 26 deletions includes/Handlers/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,33 +230,11 @@ public static function update_from_square( \WC_Product $product, \Square\Models\
$product->set_description( $product_description );
}

$square_category_id = Category::get_square_category_id( $catalog_item );
$category_id = Category::get_category_id_by_square_id( $square_category_id );
$category_ids = Category::get_category_ids_from_catalog_item( $catalog_item );

if ( $category_id ) {
wp_set_object_terms( $product->get_id(), intval( $category_id ), 'product_cat' );
} else {
$message = sprintf(
/* translators: Placeholder: %s category ID */
__( 'Square category with id (%s) was not imported to your Store. Please run Import Products from Square settings.', 'woocommerce-square' ),
$square_category_id
);

$records = Records::get_records();
foreach ( $records as $record ) {
if ( $record->get_message() === $message ) {
$is_recorded = true;
}
}

if ( ! isset( $is_recorded ) ) {
Records::set_record(
array(
'type' => 'alert',
'message' => $message,
)
);
}
if ( ! empty( $category_ids ) ) {
$term_ids = array_unique( array_map( 'intval', $category_ids ) );
wp_set_object_terms( $product->get_id(), $term_ids, 'product_cat' );
Comment thread
iamdharmesh marked this conversation as resolved.
Outdated
}

if ( $catalog_id ) {
Expand Down
39 changes: 1 addition & 38 deletions includes/Sync/Product_Import.php
Original file line number Diff line number Diff line change
Expand Up @@ -613,44 +613,7 @@ public function extract_product_data( $catalog_object, $product = null ) {
);

// Process multiple categories from Square.
$item_data = $catalog_object->getItemData();
$categories = array();
$missing_category_ids = array();

if ( $item_data->getCategories() && is_array( $item_data->getCategories() ) ) {
foreach ( $item_data->getCategories() as $category ) {
if ( $category instanceof \Square\Models\CatalogObjectCategory ) {
$category_id = Category::get_category_id_by_square_id( $category->getId() );
if ( $category_id ) {
$categories[] = $category_id;
} else {
$missing_category_ids[] = $category->getId();
}
}
}
}

// Fetch and import missing categories.
if ( ! empty( $missing_category_ids ) ) {
try {
$response = wc_square()->get_api()->batch_retrieve_catalog_objects( $missing_category_ids );
if ( $response->get_data() instanceof \Square\Models\BatchRetrieveCatalogObjectsResponse ) {
$missing_categories = $response->get_data()->getObjects();
if ( $missing_categories && is_array( $missing_categories ) ) {
foreach ( $missing_categories as $missing_category ) {
$imported_category_id = Category::import_or_update( $missing_category );
if ( $imported_category_id ) {
$categories[] = $imported_category_id;
}
}
}
}
} catch ( \Exception $e ) {
wc_square()->log( 'Error fetching missing categories for product ' . $product_name . ': ' . $e->getMessage() );
}
}

$data['categories'] = array_unique( $categories );
$data['categories'] = Category::get_category_ids_from_catalog_item( $catalog_object->getItemData() );

// variable product
if ( 'variable' === $data['type'] ) {
Expand Down
9 changes: 8 additions & 1 deletion tests/e2e/specs/c2.woo-sor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ test.beforeAll( 'Setup', async ( { baseURL } ) => {
page, {
name: 'iPhone Pro',
content: 'iPhone Pro content',
category: 'Mobiles',
category: 'Mobiles, Phones',
regularPrice: '499',
sku: 'iphone',
},
Expand Down Expand Up @@ -70,6 +70,7 @@ test( 'iPhone Pro pushed to Square @sync', async ( { page } ) => {
variations,
description,
category,
categories: categoriesIds,
} = extractCatalogInfo( result.objects[0] );

expect( name ).toEqual( 'iPhone Pro' );
Expand All @@ -78,15 +79,21 @@ test( 'iPhone Pro pushed to Square @sync', async ( { page } ) => {
expect(description).toEqual('iPhone Pro content');

let categoryName = '';
let categoriesNames = [];
if (category) {
const categories = await listCategories();
if (categories.objects) {
categoryName = categories.objects
.filter((cat) => cat.id === category)
.map((cat) => cat.category_data.name)[0];
categoriesNames = categories.objects
.filter((cat) => categoriesIds.includes(cat.id))
.map((cat) => cat.category_data.name);
}
}
expect(categoryName).toEqual('Mobiles');
expect(categoriesNames).toContain('Mobiles');
Comment thread
iamdharmesh marked this conversation as resolved.
expect(categoriesNames).toContain('Phones');

const inventory = await retrieveInventoryCount( variations[ 0 ].id );

Expand Down
15 changes: 12 additions & 3 deletions tests/e2e/specs/c4.product-import.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,18 @@ test.beforeAll( 'Setup', async () => {

await deleteAllProducts( page );
await deleteAllCatalogItems();
const categoryResponse = await createCategory('Hats');
const categoryResponse = await createCategory( 'Hats' );
const categoryId = categoryResponse.catalog_object?.id || '';
const response = await createCatalogObject( 'Cap', 'cap', 1350, 'This is a very good cap, no cap.', categoryId );
const categoryResponse2 = await createCategory( 'Hats2' );
const categoryId2 = categoryResponse2.catalog_object?.id || '';
const response = await createCatalogObject(
'Cap',
'cap',
1350,
'This is a very good cap, no cap.',
categoryId,
categoryId2
);
itemId = response.catalog_object.item_data.variations[0].id;

await updateCatalogItemInventory( itemId, '53' );
Expand Down Expand Up @@ -70,7 +79,7 @@ test( 'Import Cap from Square @sync', async ( { page, baseURL } ) => {
await expect( await page.locator( '.entry-summary .sku_wrapper' ) ).toHaveText( 'SKU: cap-regular' );
await expect( await page.getByText( 'This is a very good cap, no cap.' ) ).toBeVisible();
await expect( await page.getByText( '53 in stock' ) ).toBeVisible();
await expect( await page.getByText( 'Category: Hats' ) ).toBeVisible();
await expect( await page.getByText( 'Categories: Hats, Hats2' ) ).toBeVisible();
Comment thread
iamdharmesh marked this conversation as resolved.
} );

test('Sync Inventory stock from Square on the product edit screen - (SOR Square) @sync', async ({
Expand Down
16 changes: 8 additions & 8 deletions tests/e2e/specs/d8.square-sor-multiple-variations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,25 @@ test( '[Square SOR] Import multiple variations products from Square @sync', asyn
await page.locator( 'li.variations_tab a' ).click();
await expect(
page.locator( 'select[name="attribute_pa_color[0]"]' )
).toHaveValue( 'blue' );
).toHaveValue( 'red' );
Comment thread
iamdharmesh marked this conversation as resolved.
await expect(
page.locator( 'select[name="attribute_pa_size[0]"]' )
).toHaveValue( 'm' );
await expect(
page.locator( 'select[name="attribute_pa_color[1]"]' )
).toHaveValue( 'blue' );
).toHaveValue( 'red' );
await expect(
page.locator( 'select[name="attribute_pa_size[1]"]' )
).toHaveValue( 's' );
await expect(
page.locator( 'select[name="attribute_pa_color[2]"]' )
).toHaveValue( 'red' );
).toHaveValue( 'blue' );
await expect(
page.locator( 'select[name="attribute_pa_size[2]"]' )
).toHaveValue( 'm' );
await expect(
page.locator( 'select[name="attribute_pa_color[3]"]' )
).toHaveValue( 'red' );
).toHaveValue( 'blue' );
await expect(
page.locator( 'select[name="attribute_pa_size[3]"]' )
).toHaveValue( 's' );
Expand Down Expand Up @@ -153,7 +153,7 @@ test( '[Square SOR] Import multiple variations products from Square @sync', asyn
await page.locator( 'li.variations_tab a' ).click();
await expect(
page.locator( 'select[name="attribute_pa_color[0]"]' )
).toHaveValue( 'blue' );
).toHaveValue( 'red' );
await expect(
page.locator( 'select[name="attribute_pa_size[0]"]' )
).toHaveValue( 'm' );
Expand All @@ -162,7 +162,7 @@ test( '[Square SOR] Import multiple variations products from Square @sync', asyn
).toHaveValue( 'Cotton' );
await expect(
page.locator( 'select[name="attribute_pa_color[1]"]' )
).toHaveValue( 'blue' );
).toHaveValue( 'red' );
await expect(
page.locator( 'select[name="attribute_pa_size[1]"]' )
).toHaveValue( 's' );
Expand All @@ -171,7 +171,7 @@ test( '[Square SOR] Import multiple variations products from Square @sync', asyn
).toHaveValue( 'Cotton' );
await expect(
page.locator( 'select[name="attribute_pa_color[2]"]' )
).toHaveValue( 'red' );
).toHaveValue( 'blue' );
await expect(
page.locator( 'select[name="attribute_pa_size[2]"]' )
).toHaveValue( 'm' );
Expand All @@ -180,7 +180,7 @@ test( '[Square SOR] Import multiple variations products from Square @sync', asyn
).toHaveValue( 'Cotton' );
await expect(
page.locator( 'select[name="attribute_pa_color[3]"]' )
).toHaveValue( 'red' );
).toHaveValue( 'blue' );
await expect(
page.locator( 'select[name="attribute_pa_size[3]"]' )
).toHaveValue( 's' );
Expand Down
24 changes: 21 additions & 3 deletions tests/e2e/utils/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,27 @@ export async function createProduct( page, product, save = true, newEditor = fal

if ( product.category ) {
await page.locator('#product_cat-add-toggle').click();
await page.locator('#newproduct_cat').fill( product.category );
await page.locator('#product_cat-add-submit').click();
await page.waitForTimeout( 2000 );
const categories = product.category
.split( ',' )
.map( ( c ) => c.trim() )
.filter( Boolean );
for ( const category of categories ) {
if (
await page
.locator( '#product_catchecklist' )
.getByText( category )
.isVisible()
) {
await page
.locator( '#product_catchecklist' )
.getByText( category )
.click();
} else {
await page.locator('#newproduct_cat').fill( category );
await page.locator('#product_cat-add-submit').click();
await page.waitForTimeout( 2000 );
}
}
}

if ( save ) {
Expand Down
20 changes: 17 additions & 3 deletions tests/e2e/utils/square-sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ export function extractCatalogInfo( catalogObject = {} ) {
category = catalogObject.categories[ 0 ]?.id;
}

const categories =
( catalogObject.item_data?.categories || [] )
.map( ( cat ) => cat?.id || '' )
.filter( ( cat ) => cat !== '' );

const variations = catalogObject.item_data.variations.map(
( variation ) => {
return {
Expand All @@ -149,6 +154,7 @@ export function extractCatalogInfo( catalogObject = {} ) {
catalogId,
name,
category,
categories,
description,
variations,
};
Expand All @@ -159,14 +165,18 @@ export function extractCatalogInfo( catalogObject = {} ) {
* @param {string} name Name of the variation.
* @param {string} sku SKU.
* @param {string} price Price of the variation.
* @return {Object}
* @param {string} description Description of the variation.
* @param {string} categoryId Category ID.
* @param {string} categoryId2 Category ID 2.
* @return {Object} Response object.
*/
export async function createCatalogObject(
name,
sku,
price,
description = '',
categoryId = ''
categoryId = '',
categoryId2 = ''
) {
const url = 'https://connect.squareupsandbox.com/v2/catalog/object';
const method = 'POST';
Expand Down Expand Up @@ -204,7 +214,11 @@ export async function createCatalogObject(
};

if ( categoryId ) {
data.object.item_data.categories = [ { id: categoryId } ];
const categories = [ { id: categoryId } ];
if ( categoryId2 ) {
categories.push( { id: categoryId2 } );
}
data.object.item_data.categories = categories;
data.object.item_data.reporting_category = { id: categoryId };
}

Expand Down
Loading