Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*******************************************************************************
*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*
******************************************************************************/

package com.adobe.cq.commerce.core.components.internal.models.v1.product;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;

import com.adobe.cq.commerce.core.components.internal.models.v1.Utils;
import com.adobe.cq.commerce.core.components.models.product.Price;
import com.adobe.cq.commerce.magento.graphql.PriceRange;

public class PriceImpl implements Price {

private NumberFormat priceFormatter;

private Locale locale;

private String currency;

private Double regularPriceMin;
private Double regularPriceMax;

private Double finalPriceMin;
private Double finalPriceMax;

private Double discountAmountMin;
private Double discountAmountMax;

private Double discountPercentMin;
private Double discountPercentMax;

private Boolean isDiscounted;
private Boolean isRange;

public PriceImpl(PriceRange range, Locale locale) {
this.locale = locale;
this.currency = range.getMinimumPrice().getFinalPrice().getCurrency().toString();

this.regularPriceMin = range.getMinimumPrice().getRegularPrice().getValue();
this.finalPriceMin = range.getMinimumPrice().getFinalPrice().getValue();
this.discountAmountMin = range.getMinimumPrice().getDiscount().getAmountOff();
this.discountPercentMin = range.getMinimumPrice().getDiscount().getPercentOff();

if (range.getMaximumPrice() != null) {
this.regularPriceMax = range.getMaximumPrice().getRegularPrice().getValue();
this.finalPriceMax = range.getMaximumPrice().getFinalPrice().getValue();
this.discountAmountMax = range.getMaximumPrice().getDiscount().getAmountOff();
this.discountPercentMax = range.getMaximumPrice().getDiscount().getPercentOff();
}
}

private NumberFormat getPriceFormatter() {
if (priceFormatter == null) {
priceFormatter = Utils.buildPriceFormatter(locale, currency);
}
return priceFormatter;
}

@Override
public Boolean isRange() {
if (isRange == null) {
isRange = finalPriceMin != null && finalPriceMax != null && new BigDecimal(finalPriceMin).compareTo(new BigDecimal(
finalPriceMax)) != 0;
}
return isRange;
}

@Override
public Boolean isDiscounted() {
if (isDiscounted == null) {
// discountAmountMin > 0
isDiscounted = discountAmountMin != null && BigDecimal.ZERO.compareTo(new BigDecimal(discountAmountMin)) < 0;
}

return isDiscounted;
}

@Override
public String getCurrency() {
return currency;
}

@Override
public Double getRegularPrice() {
return regularPriceMin;
}

@Override
public String getFormattedRegularPrice() {
return getPriceFormatter().format(regularPriceMin);
}

@Override
public Double getFinalPrice() {
return finalPriceMin;
}

@Override
public String getFormattedFinalPrice() {
return getPriceFormatter().format(finalPriceMin);
}

@Override
public Double getDiscountAmount() {
return discountAmountMin;
}

@Override
public String getFormattedDiscountAmount() {
return getPriceFormatter().format(discountAmountMin);
}

@Override
public Double getDiscountPercent() {
return discountPercentMin;
}

@Override
public Double getRegularPriceMax() {
return isRange() ? regularPriceMax : Double.NaN;
}

@Override
public String getFormattedRegularPriceMax() {
return isRange() ? getPriceFormatter().format(regularPriceMax) : "";
}

@Override
public Double getFinalPriceMax() {
return isRange() ? finalPriceMax : Double.NaN;
}

@Override
public String getFormattedFinalPriceMax() {
return isRange() ? getPriceFormatter().format(finalPriceMax) : "";
}

@Override
public Double getDiscountAmountMax() {
return isRange() ? discountAmountMax : Double.NaN;
}

@Override
public String getFormattedDiscountAmountMax() {
return isRange() ? getPriceFormatter().format(discountAmountMax) : "";
}

@Override
public Double getDiscountPercentMax() {
return isRange() ? discountPercentMax : Double.NaN;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package com.adobe.cq.commerce.core.components.internal.models.v1.product;

import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
Expand All @@ -38,8 +37,8 @@
import org.slf4j.LoggerFactory;

import com.adobe.cq.commerce.core.components.client.MagentoGraphqlClient;
import com.adobe.cq.commerce.core.components.internal.models.v1.Utils;
import com.adobe.cq.commerce.core.components.models.product.Asset;
import com.adobe.cq.commerce.core.components.models.product.Price;
import com.adobe.cq.commerce.core.components.models.product.Product;
import com.adobe.cq.commerce.core.components.models.product.Variant;
import com.adobe.cq.commerce.core.components.models.product.VariantAttribute;
Expand Down Expand Up @@ -96,17 +95,20 @@ public class ProductImpl implements Product {
@Inject
private XSSAPI xssApi;

private NumberFormat priceFormatter;
private Boolean configurable;
private Boolean loadClientPrice;

private AbstractProductRetriever productRetriever;

private Locale locale;

@PostConstruct
private void initModel() {
// Parse slug from URL
String slug = parseProductSlug();

locale = currentPage.getLanguage(false);

// Get MagentoGraphqlClient from the resource.
MagentoGraphqlClient magentoGraphqlClient = MagentoGraphqlClient.create(resource);

Expand Down Expand Up @@ -147,12 +149,17 @@ public String getSku() {

@Override
public String getCurrency() {
return productRetriever.fetchProduct().getPrice().getRegularPrice().getAmount().getCurrency().toString();
return getPriceRange().getCurrency();
}

@Override
public Double getPrice() {
return productRetriever.fetchProduct().getPrice().getRegularPrice().getAmount().getValue();
return getPriceRange().getFinalPrice();
}

@Override
public Price getPriceRange() {
return new PriceImpl(productRetriever.fetchProduct().getPriceRange(), locale);
}

@Override
Expand Down Expand Up @@ -233,7 +240,7 @@ public Boolean loadClientPrice() {

@Override
public String getFormattedPrice() {
return getPriceFormatter().format(getPrice());
return getPriceRange().getFormattedFinalPrice();
}

@Override
Expand All @@ -242,7 +249,6 @@ public AbstractProductRetriever getProductRetriever() {
}

/* --- Mapping methods --- */

private Variant mapVariant(ConfigurableVariant variant) {
SimpleProduct product = variant.getProduct();

Expand All @@ -251,9 +257,7 @@ private Variant mapVariant(ConfigurableVariant variant) {
productVariant.setDescription(safeDescription(product));
productVariant.setSku(product.getSku());
productVariant.setColor(product.getColor());
productVariant.setCurrency(product.getPrice().getRegularPrice().getAmount().getCurrency().toString());
productVariant.setPrice(product.getPrice().getRegularPrice().getAmount().getValue());
productVariant.setFormattedPrice(getPriceFormatter().format(productVariant.getPrice()));
productVariant.setPriceRange(new PriceImpl(product.getPriceRange(), locale));
productVariant.setInStock(ProductStockStatus.IN_STOCK.equals(product.getStockStatus()));

// Map variant attributes
Expand Down Expand Up @@ -322,17 +326,6 @@ private String parseProductSlug() {
return request.getRequestPathInfo().getSelectorString();
}

private NumberFormat getPriceFormatter() {
if (priceFormatter == null) {
// Initialize NumberFormatter with locale from current page.
// Alternatively, the locale can potentially be retrieved via
// the storeConfig query introduced with Magento 2.3.1
Locale locale = currentPage.getLanguage(false);
priceFormatter = Utils.buildPriceFormatter(locale, productRetriever.fetchProduct() != null ? getCurrency() : null);
}
return priceFormatter;
}

private String safeDescription(ProductInterface product) {
ComplexTextValue description = product.getDescription();
if (description == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import com.adobe.cq.commerce.magento.graphql.ProductAttributeFilterInput;
import com.adobe.cq.commerce.magento.graphql.ProductInterface;
import com.adobe.cq.commerce.magento.graphql.ProductInterfaceQueryDefinition;
import com.adobe.cq.commerce.magento.graphql.ProductPricesQueryDefinition;
import com.adobe.cq.commerce.magento.graphql.ProductPriceQueryDefinition;
import com.adobe.cq.commerce.magento.graphql.ProductsQueryDefinition;
import com.adobe.cq.commerce.magento.graphql.Query;
import com.adobe.cq.commerce.magento.graphql.QueryQuery;
Expand Down Expand Up @@ -71,12 +71,17 @@ protected String generateQuery(String slug) {
.storeConfig(generateStoreConfigQuery())).toString();
}

private ProductPricesQueryDefinition generatePriceQuery() {
private ProductPriceQueryDefinition generatePriceQuery() {
return q -> q
.regularPrice(rp -> rp
.amount(a -> a
.currency()
.value()));
.regularPrice(r -> r
.value()
.currency())
.finalPrice(f -> f
.value()
.currency())
.discount(d -> d
.amountOff()
.percentOff());
}

private SimpleProductQueryDefinition generateSimpleProductQuery() {
Expand All @@ -89,7 +94,8 @@ private SimpleProductQueryDefinition generateSimpleProductQuery() {
.urlKey()
.stockStatus()
.color()
.price(generatePriceQuery())
.priceRange(r -> r
.minimumPrice(generatePriceQuery()))
.mediaGalleryEntries(g -> g
.disabled()
.file()
Expand All @@ -114,14 +120,16 @@ protected ProductInterfaceQueryDefinition generateProductQuery() {
.thumbnail(t -> t.label().url())
.urlKey()
.stockStatus()
.price(generatePriceQuery())
.mediaGalleryEntries(g -> g
.disabled()
.file()
.label()
.position()
.mediaType())
.onConfigurableProduct(cp -> cp
.priceRange(r -> r
.maximumPrice(generatePriceQuery())
.minimumPrice(generatePriceQuery()))
.configurableOptions(o -> o
.label()
.attributeCode()
Expand All @@ -132,7 +140,10 @@ protected ProductInterfaceQueryDefinition generateProductQuery() {
.attributes(a -> a
.code()
.valueIndex())
.product(generateSimpleProductQuery())));
.product(generateSimpleProductQuery())))
.onSimpleProduct(sp -> sp
.priceRange(r -> r
.minimumPrice(generatePriceQuery())));

// Apply product query hook
if (productQueryHook != null) {
Expand Down
Loading