use of com.commercetools.sync.commons.exceptions.SyncException in project commercetools-sync-java by commercetools.
the class ProductSyncIT method sync_withProductContainingAttributeChanges_shouldSyncProductCorrectly.
@Test
void sync_withProductContainingAttributeChanges_shouldSyncProductCorrectly() {
// preparation
final List<UpdateAction<Product>> updateActions = new ArrayList<>();
final TriConsumer<SyncException, Optional<ProductDraft>, Optional<ProductProjection>> warningCallBack = (exception, newResource, oldResource) -> warningCallBackMessages.add(exception.getMessage());
final ProductSyncOptions customOptions = ProductSyncOptionsBuilder.of(CTP_TARGET_CLIENT).errorCallback((exception, oldResource, newResource, actions) -> collectErrors(exception.getMessage(), exception.getCause())).warningCallback(warningCallBack).beforeUpdateCallback((actions, draft, old) -> {
updateActions.addAll(actions);
return actions;
}).build();
final ProductDraft productDraft = createProductDraftBuilder(PRODUCT_KEY_1_RESOURCE_PATH, ProductType.referenceOfId(productType.getKey())).categories(emptyList()).taxCategory(null).state(null).build();
// Creating the attribute draft with the changes
final AttributeDraft priceInfoAttrDraft = AttributeDraft.of("priceInfo", JsonNodeFactory.instance.textNode("100/kg"));
final AttributeDraft angebotAttrDraft = AttributeDraft.of("angebot", JsonNodeFactory.instance.textNode("big discount"));
final AttributeDraft unknownAttrDraft = AttributeDraft.of("unknown", JsonNodeFactory.instance.textNode("unknown"));
// Creating the product variant draft with the product reference attribute
final List<AttributeDraft> attributes = asList(priceInfoAttrDraft, angebotAttrDraft, unknownAttrDraft);
final ProductVariantDraft masterVariant = ProductVariantDraftBuilder.of(productDraft.getMasterVariant()).attributes(attributes).build();
final ProductDraft productDraftWithChangedAttributes = ProductDraftBuilder.of(productDraft).masterVariant(masterVariant).build();
// test
final ProductSync productSync = new ProductSync(customOptions);
final ProductSyncStatistics syncStatistics = executeBlocking(productSync.sync(singletonList(productDraftWithChangedAttributes)));
// assertion
assertThat(syncStatistics).hasValues(1, 0, 1, 0, 0);
final String causeErrorMessage = format(ATTRIBUTE_NOT_IN_ATTRIBUTE_METADATA, unknownAttrDraft.getName());
final String expectedErrorMessage = format(FAILED_TO_BUILD_ATTRIBUTE_UPDATE_ACTION, unknownAttrDraft.getName(), productDraft.getMasterVariant().getKey(), productDraft.getKey(), causeErrorMessage);
assertThat(errorCallBackExceptions).hasSize(1);
assertThat(errorCallBackExceptions.get(0).getMessage()).isEqualTo(expectedErrorMessage);
assertThat(errorCallBackExceptions.get(0).getCause().getMessage()).isEqualTo(causeErrorMessage);
assertThat(errorCallBackMessages).containsExactly(expectedErrorMessage);
assertThat(warningCallBackMessages).isEmpty();
assertThat(updateActions).filteredOn(updateAction -> !(updateAction instanceof SetTaxCategory)).filteredOn(updateAction -> !(updateAction instanceof RemoveFromCategory)).containsExactlyInAnyOrder(SetAttributeInAllVariants.of(priceInfoAttrDraft, true), SetAttribute.of(1, angebotAttrDraft, true), SetAttributeInAllVariants.ofUnsetAttribute("size", true), SetAttributeInAllVariants.ofUnsetAttribute("rinderrasse", true), SetAttributeInAllVariants.ofUnsetAttribute("herkunft", true), SetAttributeInAllVariants.ofUnsetAttribute("teilstueck", true), SetAttributeInAllVariants.ofUnsetAttribute("fuetterung", true), SetAttributeInAllVariants.ofUnsetAttribute("reifung", true), SetAttributeInAllVariants.ofUnsetAttribute("haltbarkeit", true), SetAttributeInAllVariants.ofUnsetAttribute("verpackung", true), SetAttributeInAllVariants.ofUnsetAttribute("anlieferung", true), SetAttributeInAllVariants.ofUnsetAttribute("zubereitung", true), SetAttribute.ofUnsetAttribute(1, "localisedText", true), Publish.of());
}
use of com.commercetools.sync.commons.exceptions.SyncException in project commercetools-sync-java by commercetools.
the class CategoryUpdateActionUtilsTest method buildChangeParentUpdateAction_WithNullValues_ShouldNotBuildUpdateActionAndCallCallback.
@Test
void buildChangeParentUpdateAction_WithNullValues_ShouldNotBuildUpdateActionAndCallCallback() {
when(MOCK_OLD_CATEGORY.getId()).thenReturn("oldCatId");
final CategoryDraft newCategory = mock(CategoryDraft.class);
when(newCategory.getParent()).thenReturn(null);
final ArrayList<Object> callBackResponse = new ArrayList<>();
final TriConsumer<SyncException, Optional<CategoryDraft>, Optional<Category>> updateActionWarningCallBack = (exception, newResource, oldResource) -> callBackResponse.add(exception.getMessage());
final CategorySyncOptions categorySyncOptions = CategorySyncOptionsBuilder.of(CTP_CLIENT).warningCallback(updateActionWarningCallBack).build();
final Optional<UpdateAction<Category>> changeParentUpdateAction = buildChangeParentUpdateAction(MOCK_OLD_CATEGORY, newCategory, categorySyncOptions);
assertThat(changeParentUpdateAction).isNotNull();
assertThat(changeParentUpdateAction).isNotPresent();
assertThat(callBackResponse).hasSize(1);
assertThat(callBackResponse.get(0)).isEqualTo("Cannot unset 'parent' field of category with id 'oldCatId'.");
}
use of com.commercetools.sync.commons.exceptions.SyncException in project commercetools-sync-java by commercetools.
the class ProductVariantPriceUpdateActionUtils method buildChangePriceUpdateAction.
/**
* Builds a {@link ChangePrice} action based on the comparison of the following fields of the
* supplied {@link Price} and {@link PriceDraft}:
*
* <ul>
* <li>{@link Price#getValue()} and {@link PriceDraft#getValue()}
* <li>{@link Price#getTiers()} and {@link PriceDraft#getTiers()}
* </ul>
*
* <p>If any of the aforementioned fields are different a {@link ChangePrice} update action will
* be returned in an {@link Optional}, otherwise if both are identical in the {@link Price} and
* the {@link PriceDraft}, then no update action is needed and hence an empty {@link Optional} is
* returned.
*
* @param oldPrice the price which should be updated.
* @param newPrice the price draft where we get the new name.
* @param syncOptions responsible for supplying the sync options to the sync utility method. It is
* used for triggering the error callback within the utility, in case of errors.
* @return A filled optional with the update action or an empty optional if the names are
* identical.
*/
@Nonnull
public static Optional<ChangePrice> buildChangePriceUpdateAction(@Nonnull final Price oldPrice, @Nonnull final PriceDraft newPrice, @Nonnull final ProductSyncOptions syncOptions) {
final MonetaryAmount oldPriceValue = oldPrice.getValue();
final MonetaryAmount newPriceValue = newPrice.getValue();
if (newPriceValue == null) {
syncOptions.applyWarningCallback(new SyncException(format(VARIANT_CHANGE_PRICE_EMPTY_VALUE, oldPrice.getId())), null, null);
return Optional.empty();
}
final Optional<ChangePrice> actionAfterValuesDiff = buildUpdateAction(oldPriceValue, newPriceValue, () -> ChangePrice.of(oldPrice, newPrice, true));
return actionAfterValuesDiff.map(Optional::of).orElseGet(() -> buildUpdateAction(oldPrice.getTiers(), newPrice.getTiers(), () -> ChangePrice.of(oldPrice, newPrice, true)));
}
use of com.commercetools.sync.commons.exceptions.SyncException in project commercetools-sync-java by commercetools.
the class ProductTypeSync method syncBatch.
/**
* Given a set of product type drafts, attempts to sync the drafts with the existing products
* types in the target CTP project. The product type and the draft are considered to match if they
* have the same key.
*
* <p>Note: In order to support syncing product types with nested references in any order, this
* method will remove any attribute which contains a nested reference on the drafts and keep track
* of it to be resolved as soon as the referenced product type becomes available.
*
* @param oldProductTypes old product types.
* @param newProductTypes drafts that need to be synced.
* @return a {@link CompletionStage} which contains an empty result after execution of the update
*/
@Nonnull
private CompletionStage<Void> syncBatch(@Nonnull final Set<ProductType> oldProductTypes, @Nonnull final Set<ProductTypeDraft> newProductTypes, @Nonnull final Map<String, String> keyToIdCache) {
final Map<String, ProductType> oldProductTypeMap = oldProductTypes.stream().collect(toMap(ProductType::getKey, identity()));
return CompletableFuture.allOf(newProductTypes.stream().map(newProductType -> removeAndKeepTrackOfMissingNestedAttributes(newProductType, keyToIdCache)).map(draftWithoutMissingRefAttrs -> referenceResolver.resolveReferences(draftWithoutMissingRefAttrs).thenCompose(resolvedDraft -> syncDraft(oldProductTypeMap, resolvedDraft)).exceptionally(completionException -> {
final String errorMessage = format(FAILED_TO_PROCESS, draftWithoutMissingRefAttrs.getKey(), completionException.getMessage());
handleError(new SyncException(errorMessage, completionException), 1);
return null;
})).map(CompletionStage::toCompletableFuture).toArray(CompletableFuture[]::new));
}
use of com.commercetools.sync.commons.exceptions.SyncException in project commercetools-sync-java by commercetools.
the class ProductTypeSync method removeAndKeepTrackOfMissingNestedAttribute.
/**
* Attempts to find a nested product type in the attribute type of {@code
* attributeDefinitionDraft}, if it has a nested type. It checks if the key, of the productType
* reference, is cached in {@code keyToIdCache}. If it is, then it means the referenced product
* type exists in the target project, so there is no need to remove or keep track of it. However,
* if it is not, it means it doesn't exist yet, which means we need to keep track of it as a
* missing reference and also remove this attribute definition from the supplied {@code draftCopy}
* to be able to create product type without this attribute containing the missing reference.
*
* <p>Note: This method mutates in the supplied {@code productTypeDraft} attribute definition list
* by removing the attribute containing a missing reference.
*
* @param attributeDefinitionDraft the attribute definition being checked for any product
* references.
* @param productTypeDraft the productTypeDraft containing the attribute which should be updated
* by removing the attribute which contains the missing reference.
* @param keyToIdCache a map of productType key to id. It represents a cache of the existing
* productTypes in the target project.
*/
@SuppressWarnings(// since the batch is validate before, key is assured to be non-blank
"ConstantConditions")
private // here.
void removeAndKeepTrackOfMissingNestedAttribute(@Nonnull final AttributeDefinitionDraft attributeDefinitionDraft, @Nonnull final ProductTypeDraft productTypeDraft, @Nonnull final Map<String, String> keyToIdCache) {
final AttributeType attributeType = attributeDefinitionDraft.getAttributeType();
try {
getProductTypeKey(attributeType).ifPresent(key -> {
if (!keyToIdCache.keySet().contains(key)) {
productTypeDraft.getAttributes().remove(attributeDefinitionDraft);
statistics.putMissingNestedProductType(key, productTypeDraft.getKey(), attributeDefinitionDraft);
}
});
} catch (InvalidReferenceException invalidReferenceException) {
handleError(new SyncException("This exception is unexpectedly thrown since the draft batch has been" + "already validated for blank keys at an earlier stage, which means this draft should" + " have a valid reference. Please communicate this error with the maintainer of the library.", invalidReferenceException), 1);
}
}
Aggregations