Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
49 changes: 49 additions & 0 deletions includes/Handlers/Category.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,53 @@ public static function get_square_category_id( $catalog_item ) {

return $catalog_category_id;
}

/**
* Get the WooCommerce category IDs from a catalog item.
*
* @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();

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

if ( $catalog_item->getCategories() && is_array( $catalog_item->getCategories() ) ) {
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();
}
}
}
}

// 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 = 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' );
}

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');
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();
} );

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' );
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
21 changes: 18 additions & 3 deletions tests/e2e/utils/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,24 @@ 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(',');
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
17 changes: 14 additions & 3 deletions tests/e2e/utils/square-sandbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ 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 +151,7 @@ export function extractCatalogInfo( catalogObject = {} ) {
catalogId,
name,
category,
categories,
description,
variations,
};
Expand All @@ -159,14 +162,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 +211,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