55import com .commercetools .sync .products .ProductSyncOptionsBuilder ;
66import com .commercetools .sync .products .SyncFilter ;
77import com .commercetools .sync .products .helpers .ProductSyncStatistics ;
8+ import com .fasterxml .jackson .databind .node .JsonNodeFactory ;
89import com .fasterxml .jackson .databind .node .ObjectNode ;
910import io .sphere .sdk .categories .Category ;
1011import io .sphere .sdk .channels .Channel ;
1920import io .sphere .sdk .products .ProductVariantDraftBuilder ;
2021import io .sphere .sdk .products .attributes .AttributeDraft ;
2122import io .sphere .sdk .products .commands .ProductCreateCommand ;
23+ import io .sphere .sdk .products .commands .updateactions .SetAttribute ;
2224import io .sphere .sdk .products .commands .updateactions .SetAttributeInAllVariants ;
25+ import io .sphere .sdk .products .queries .ProductByKeyGet ;
2326import io .sphere .sdk .producttypes .ProductType ;
2427import io .sphere .sdk .states .State ;
2528import io .sphere .sdk .states .StateType ;
5760import static com .commercetools .sync .integration .commons .utils .TaxCategoryITUtils .createTaxCategory ;
5861import static com .commercetools .sync .integration .inventories .utils .InventoryITUtils .SUPPLY_CHANNEL_KEY_1 ;
5962import static com .commercetools .sync .products .ActionGroup .ATTRIBUTES ;
63+ import static com .commercetools .sync .products .ProductSyncMockUtils .PRODUCT_KEY_1_CHANGED_ATTRIBUTES_RESOURCE_PATH ;
6064import static com .commercetools .sync .products .ProductSyncMockUtils .PRODUCT_KEY_1_CHANGED_RESOURCE_PATH ;
6165import static com .commercetools .sync .products .ProductSyncMockUtils .PRODUCT_KEY_1_CHANGED_WITH_PRICES_RESOURCE_PATH ;
6266import static com .commercetools .sync .products .ProductSyncMockUtils .PRODUCT_KEY_1_RESOURCE_PATH ;
@@ -284,6 +288,7 @@ public void sync_withPriceReferences_ShouldUpdateProducts() {
284288
285289 @ Test
286290 public void sync_withProductTypeReference_ShouldUpdateProducts () {
291+ // Preparation
287292 // Create custom options with whitelisting and action filter callback..
288293 final ProductSyncOptions customSyncOptions =
289294 ProductSyncOptionsBuilder .of (CTP_TARGET_CLIENT )
@@ -294,8 +299,6 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
294299 .build ();
295300 final ProductSync customSync = new ProductSync (customSyncOptions );
296301
297-
298-
299302 // Create 3 existing products in target project with keys (productKey1, productKey2 and productKey3)
300303 final ProductDraft existingProductDraft = createProductDraft (PRODUCT_KEY_1_RESOURCE_PATH ,
301304 targetProductType .toReference (), targetTaxCategory .toReference (), targetProductState .toReference (),
@@ -305,14 +308,14 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
305308 final ProductDraft existingProductDraft2 = createProductDraft (PRODUCT_KEY_2_RESOURCE_PATH ,
306309 targetProductType .toReference (), targetTaxCategory .toReference (), targetProductState .toReference (),
307310 targetCategoryReferencesWithIds , createRandomCategoryOrderHints (targetCategoryReferencesWithIds ));
308- final Product targetProductWithKey2 = CTP_TARGET_CLIENT .execute (ProductCreateCommand .of (existingProductDraft2 ))
309- .toCompletableFuture ().join ();
311+ CTP_TARGET_CLIENT .execute (ProductCreateCommand .of (existingProductDraft2 ))
312+ .toCompletableFuture ().join ();
310313
311314 final ProductDraft existingProductDraft3 = createProductDraftBuilder (PRODUCT_KEY_2_RESOURCE_PATH ,
312315 targetProductType .toReference ())
313316 .slug (LocalizedString .ofEnglish ("newSlug3" ))
314317 .key ("productKey3" )
315- .masterVariant (ProductVariantDraftBuilder .of ().key ("v3" ).build ())
318+ .masterVariant (ProductVariantDraftBuilder .of ().key ("v3" ).sku ( "s3" ). build ())
316319 .taxCategory (null )
317320 .state (null )
318321 .categories (Collections .emptySet ())
@@ -325,7 +328,7 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
325328 sourceProductType .toReference (), sourceTaxCategory .toReference (), sourceProductState .toReference (),
326329 sourceCategoryReferencesWithIds , createRandomCategoryOrderHints (sourceCategoryReferencesWithIds ));
327330 final Product product2 = CTP_SOURCE_CLIENT .execute (ProductCreateCommand .of (newProductDraft2 ))
328- .toCompletableFuture ().join ();
331+ .toCompletableFuture ().join ();
329332 final ProductDraft newProductDraft3 = createProductDraftBuilder (PRODUCT_KEY_2_RESOURCE_PATH ,
330333 sourceProductType .toReference ())
331334 .slug (LocalizedString .ofEnglish ("newSlug3" ))
@@ -337,25 +340,27 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
337340 .categoryOrderHints (null )
338341 .build ();
339342 final Product product3 = CTP_SOURCE_CLIENT .execute (ProductCreateCommand .of (newProductDraft3 ))
340- .toCompletableFuture ().join ();
343+ .toCompletableFuture ().join ();
341344
342345
346+ // Create existing product with productKey1 in source project that has references to products with keys
347+ // (productKey2 and productKey3).
348+
343349 final ObjectNode productReferenceValue1 = getProductReferenceWithId (product2 .getId ());
344350 final ObjectNode productReferenceValue2 = getProductReferenceWithId (product3 .getId ());
345351
346352 final AttributeDraft productRefAttr = AttributeDraft .of ("product-reference" , productReferenceValue1 );
347353 final AttributeDraft productSetRefAttr =
348354 getProductReferenceSetAttributeDraft ("product-reference-set" , productReferenceValue1 ,
349355 productReferenceValue2 );
350- final List <AttributeDraft > attributeDrafts = Arrays .asList (productRefAttr , productSetRefAttr );
356+ final List <AttributeDraft > attributeDrafts = existingProductDraft .getMasterVariant ().getAttributes ();
357+ attributeDrafts .addAll (Arrays .asList (productRefAttr , productSetRefAttr ));
351358
352359 final ProductVariantDraft masterVariant = ProductVariantDraftBuilder .of ()
353360 .key ("v1" )
354361 .sku ("s1" )
355362 .attributes (attributeDrafts ).build ();
356363
357- // Create existing product with productKey1 in source project that has references to products with keys
358- // (productKey2 and productKey3).
359364 final ProductDraft newProductDraftWithProductReference =
360365 createProductDraftBuilder (PRODUCT_KEY_1_CHANGED_RESOURCE_PATH , sourceProductType .toReference ())
361366 .masterVariant (masterVariant )
@@ -367,31 +372,107 @@ public void sync_withProductTypeReference_ShouldUpdateProducts() {
367372 CTP_SOURCE_CLIENT .execute (ProductCreateCommand .of (newProductDraftWithProductReference ))
368373 .toCompletableFuture ().join ();
369374
375+
376+ // Test
370377 final List <Product > products = CTP_SOURCE_CLIENT .execute (buildProductQuery ())
371378 .toCompletableFuture ().join ().getResults ();
372-
373379 final List <ProductDraft > productDrafts = replaceProductsReferenceIdsWithKeys (products );
374-
375380 final ProductSyncStatistics syncStatistics = customSync .sync (productDrafts ).toCompletableFuture ().join ();
376381
382+
383+ // Assertion
377384 assertThat (syncStatistics ).hasValues (3 , 0 , 1 , 0 );
378385 assertThat (errorCallBackMessages ).isEmpty ();
379386 assertThat (errorCallBackExceptions ).isEmpty ();
380387 assertThat (warningCallBackMessages ).isEmpty ();
381- assertThat (updateActions ).hasSize (2 );
382-
383- final UpdateAction <Product > productReferenceAction = updateActions .get (0 );
384- assertThat (productReferenceAction ).isExactlyInstanceOf (SetAttributeInAllVariants .class );
385- final SetAttributeInAllVariants action1 = (SetAttributeInAllVariants ) productReferenceAction ;
386- assertThat (action1 .getName ()).isEqualTo ("product-reference" );
387- assertThat (action1 .getValue ()).isNotNull ();
388- assertThat (action1 .getValue ().get ("id" ).asText ()).isEqualTo (targetProductWithKey2 .getId ());
389-
390- final UpdateAction <Product > productReferenceSetAction = updateActions .get (1 );
391- assertThat (productReferenceSetAction ).isExactlyInstanceOf (SetAttributeInAllVariants .class );
392- final SetAttributeInAllVariants action2 = (SetAttributeInAllVariants ) productReferenceSetAction ;
393- assertThat (action2 .getName ()).isEqualTo ("product-reference-set" );
394- assertThat (action2 .getValue ()).isNotNull ();
395- assertThat (action2 .getValue ().isArray ()).isTrue ();
388+
389+ final Product targetProduct2 = CTP_TARGET_CLIENT .execute (ProductByKeyGet .of ("productKey2" ))
390+ .toCompletableFuture ()
391+ .join ();
392+
393+ final Product targetProduct3 = CTP_TARGET_CLIENT .execute (ProductByKeyGet .of ("productKey3" ))
394+ .toCompletableFuture ()
395+ .join ();
396+
397+ final ObjectNode targetProductReferenceValue2 = getProductReferenceWithId (targetProduct2 .getId ());
398+ final ObjectNode targetProductReferenceValue3 = getProductReferenceWithId (targetProduct3 .getId ());
399+
400+ final AttributeDraft targetProductRefAttr =
401+ AttributeDraft .of ("product-reference" , targetProductReferenceValue2 );
402+ final AttributeDraft targetProductSetRefAttr =
403+ getProductReferenceSetAttributeDraft ("product-reference-set" , targetProductReferenceValue2 ,
404+ targetProductReferenceValue3 );
405+
406+ assertThat (updateActions ).containsExactlyInAnyOrder (
407+ SetAttributeInAllVariants .of (targetProductRefAttr .getName (), targetProductRefAttr .getValue (), true ),
408+ SetAttributeInAllVariants .of (targetProductSetRefAttr .getName (), targetProductSetRefAttr .getValue (), true )
409+ );
410+ }
411+
412+ @ Test
413+ public void sync_withChangedAttributes_ShouldUpdateProducts () {
414+ // Preparation
415+ // Create custom options with whitelisting and action filter callback..
416+ final ProductSyncOptions customSyncOptions =
417+ ProductSyncOptionsBuilder .of (CTP_TARGET_CLIENT )
418+ .errorCallback (this ::errorCallback )
419+ .warningCallback (warningCallBackMessages ::add )
420+ .beforeUpdateCallback (this ::beforeUpdateCallback )
421+ .syncFilter (SyncFilter .ofWhiteList (ATTRIBUTES ))
422+ .build ();
423+ final ProductSync customSync = new ProductSync (customSyncOptions );
424+
425+ // Create existing products in target project with keys (productKey1)
426+ final ProductDraft existingProductDraft = createProductDraft (PRODUCT_KEY_1_RESOURCE_PATH ,
427+ targetProductType .toReference (), targetTaxCategory .toReference (), targetProductState .toReference (),
428+ targetCategoryReferencesWithIds , createRandomCategoryOrderHints (targetCategoryReferencesWithIds ));
429+ CTP_TARGET_CLIENT .execute (ProductCreateCommand .of (existingProductDraft )).toCompletableFuture ().join ();
430+
431+
432+ // Create existing product with productKey1 in source project with changed attributes
433+ final ProductDraft newProductDraftWithProductReference =
434+ createProductDraftBuilder (PRODUCT_KEY_1_CHANGED_ATTRIBUTES_RESOURCE_PATH , sourceProductType .toReference ())
435+ .taxCategory (sourceTaxCategory .toReference ())
436+ .state (sourceProductState .toReference ())
437+ .categories (Collections .emptySet ())
438+ .categoryOrderHints (null )
439+ .build ();
440+ CTP_SOURCE_CLIENT .execute (ProductCreateCommand .of (newProductDraftWithProductReference ))
441+ .toCompletableFuture ().join ();
442+
443+
444+ // Test
445+ final List <Product > products = CTP_SOURCE_CLIENT .execute (buildProductQuery ())
446+ .toCompletableFuture ().join ().getResults ();
447+ final List <ProductDraft > productDrafts = replaceProductsReferenceIdsWithKeys (products );
448+ final ProductSyncStatistics syncStatistics = customSync .sync (productDrafts ).toCompletableFuture ().join ();
449+
450+
451+ // Assertion
452+ assertThat (syncStatistics ).hasValues (1 , 0 , 1 , 0 );
453+ assertThat (errorCallBackMessages ).isEmpty ();
454+ assertThat (errorCallBackExceptions ).isEmpty ();
455+ assertThat (warningCallBackMessages ).isEmpty ();
456+
457+ final AttributeDraft priceInfoAttrDraft =
458+ AttributeDraft .of ("priceInfo" , JsonNodeFactory .instance .textNode ("100/kg" ));
459+ final AttributeDraft angebotAttrDraft =
460+ AttributeDraft .of ("angebot" , JsonNodeFactory .instance .textNode ("big discount" ));
461+
462+ assertThat (updateActions ).containsExactlyInAnyOrder (
463+ SetAttributeInAllVariants .of (priceInfoAttrDraft , true ),
464+ SetAttribute .of (1 , angebotAttrDraft , true ),
465+ SetAttributeInAllVariants .ofUnsetAttribute ("size" , true ),
466+ SetAttributeInAllVariants .ofUnsetAttribute ("rinderrasse" , true ),
467+ SetAttributeInAllVariants .ofUnsetAttribute ("herkunft" , true ),
468+ SetAttributeInAllVariants .ofUnsetAttribute ("teilstueck" , true ),
469+ SetAttributeInAllVariants .ofUnsetAttribute ("fuetterung" , true ),
470+ SetAttributeInAllVariants .ofUnsetAttribute ("reifung" , true ),
471+ SetAttributeInAllVariants .ofUnsetAttribute ("haltbarkeit" , true ),
472+ SetAttributeInAllVariants .ofUnsetAttribute ("verpackung" , true ),
473+ SetAttributeInAllVariants .ofUnsetAttribute ("anlieferung" , true ),
474+ SetAttributeInAllVariants .ofUnsetAttribute ("zubereitung" , true ),
475+ SetAttribute .ofUnsetAttribute (1 , "localisedText" , true )
476+ );
396477 }
397478}
0 commit comments