package productcatalog.pages; import common.contexts.PriceFinderFactory; import common.contexts.UserContext; import common.pages.DetailData; import common.pages.ImageData; import common.pages.ReverseRouter; import common.pages.SelectableData; import common.prices.PriceFinder; import common.utils.PriceFormatter; import io.sphere.sdk.models.LocalizedEnumValue; import io.sphere.sdk.models.LocalizedString; import io.sphere.sdk.productdiscounts.DiscountedPrice; import io.sphere.sdk.products.*; import io.sphere.sdk.products.attributes.Attribute; import io.sphere.sdk.products.attributes.AttributeAccess; import java.util.List; import java.util.Optional; import java.util.Set; import static java.util.Collections.emptySet; import static java.util.stream.Collectors.toList; public class ProductDataFactory { private static final AttributeAccess<String> TEXT_ATTR_ACCESS = AttributeAccess.ofText(); private static final AttributeAccess<LocalizedEnumValue> LENUM_ATTR_ACCESS = AttributeAccess.ofLocalizedEnumValue(); private static final AttributeAccess<Set<LocalizedString>> LENUM_SET_ATTR_ACCESS = AttributeAccess.ofLocalizedStringSet(); private final UserContext userContext; private final PriceFormatter priceFormatter; private final PriceFinder priceFinder; private final ReverseRouter reverseRouter; private ProductDataFactory(final UserContext userContext, final ReverseRouter reverseRouter) { this.userContext = userContext; this.priceFormatter = PriceFormatter.of(userContext.locale()); this.priceFinder = PriceFinderFactory.create(userContext); this.reverseRouter = reverseRouter; } public static ProductDataFactory of(final UserContext userContext, final ReverseRouter reverseRouter) { return new ProductDataFactory(userContext, reverseRouter); } public ProductData create(final ProductProjection product, final ProductVariant variant) { final String name = product.getName().find(userContext.locales()).orElse(""); final String sku = Optional.ofNullable(variant.getSku()).orElse(""); final String slug = product.getSlug().find(userContext.locales()).orElse(""); final String url = reverseRouter.product(userContext.locale().toLanguageTag(), slug, sku).url(); final String description = Optional.ofNullable(product.getDescription()).flatMap(d -> d.find(userContext.locales())).orElse(""); final String price = getPrice(variant); final String priceOld = getOldPrice(variant); final Integer variantId = variant.getId(); final String id = product.getId(); return new ProductData(name, sku, description, price, priceOld, getImages(variant), getColors(product), getSizes(product), getDetails(variant), variantId, slug, id, url); } public String getOldPrice(final ProductVariant variant) { return getPriceOld(priceFinder.findPrice(variant.getPrices())).map(p -> priceFormatter.format(p.getValue())).orElse(""); } public String getPrice(final ProductVariant variant) { return getPriceCurrent(priceFinder.findPrice(variant.getPrices())) .map(p -> priceFormatter.format(p.getValue())) .orElse(""); } private List<ImageData> getImages(final ProductVariant productVariant) { final List<ImageData> images = productVariant.getImages().stream().map(ImageData::of).collect(toList()); if(images.isEmpty()) { images.add(getPlaceholderImage()); } return images; } private ImageData getPlaceholderImage() { return ImageData.of(Image.of("//placehold.it/300x400", ImageDimensions.of(300, 400))); } private List<SelectableData> getColors(final ProductProjection product) { return getColorInAllVariants(product).stream() .map(this::colorToSelectableItem) .collect(toList()); } private List<SelectableData> getSizes(final ProductProjection product) { return getSizeInAllVariants(product).stream() .map(this::sizeToSelectableItem) .collect(toList()); } private List<DetailData> getDetails(final ProductVariant variant) { return variant.findAttribute("details", LENUM_SET_ATTR_ACCESS).orElse(emptySet()).stream() .map(this::localizedStringsToDetailData) .collect(toList()); } private List<Attribute> getColorInAllVariants(final ProductProjection product) { return getAttributeInAllVariants(product, "color"); } private List<Attribute> getSizeInAllVariants(final ProductProjection product) { return getAttributeInAllVariants(product, "size"); } private List<Attribute> getAttributeInAllVariants(final ProductProjection product, final String attributeName) { return product.getAllVariants().stream() .map(variant -> Optional.ofNullable(variant.getAttribute(attributeName))) .filter(Optional::isPresent) .map(Optional::get) .distinct() .collect(toList()); } private SelectableData colorToSelectableItem(final Attribute color) { final String colorLabel = color.getValue(LENUM_ATTR_ACCESS).getLabel().find(userContext.locales()).orElse(""); return new SelectableData(colorLabel, color.getName(), "", "", false); } private SelectableData sizeToSelectableItem(final Attribute size) { final String sizeLabel = size.getValue(TEXT_ATTR_ACCESS); return new SelectableData(sizeLabel, sizeLabel, "", "", false); } private DetailData localizedStringsToDetailData(final LocalizedString localizedStrings) { final String label = localizedStrings.find(userContext.locales()).orElse(""); return new DetailData(label, ""); } private Optional<Price> getPriceOld(final Optional<Price> priceOpt) { return priceOpt.flatMap(price -> Optional.ofNullable(price.getDiscounted()).map(discountedPrice -> price)); } private Optional<Price> getPriceCurrent(final Optional<Price> priceOpt) { return priceOpt.map(price -> Optional.ofNullable(price.getDiscounted()).map(DiscountedPrice::getValue) .orElse(price.getValue())) .map(Price::of); } }