com.squarespace.template.plugins.platform.CommerceUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.squarespace.template.plugins.platform.CommerceUtils.java

Source

/**
 * Copyright (c) 2015 SQUARESPACE, Inc.
 *
 * Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.squarespace.template.plugins.platform;

import static com.squarespace.template.GeneralUtils.isTruthy;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.squarespace.cldr.CLDR;
import com.squarespace.template.JsonUtils;
import com.squarespace.template.plugins.PluginUtils;
import com.squarespace.template.plugins.platform.enums.ProductType;

/**
 * Extracted from Commons library at commit ab4ba7a6f2b872a31cb6449ae9e96f5f5b30f471
 */
public class CommerceUtils {

    private static final ArrayNode EMPTY_ARRAY = JsonUtils.createArrayNode();

    private static final String DEFAULT_CURRENCY = "USD";

    private static final BigDecimal DEFAULT_MONEY_AMOUNT = new BigDecimal(0);

    private static final JsonNode DEFAULT_MONEY_NODE = new ObjectMapper().createObjectNode().put("currency", "USD")
            .put("value", "0");

    private CommerceUtils() {
    }

    public static ProductType getProductType(JsonNode item) {
        JsonNode structuredContent = item.path("structuredContent");
        JsonNode node = structuredContent.path("productType");
        return ProductType.fromCode(node.asInt());
    }

    public static JsonNode getFromPriceMoneyNode(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");
        switch (type) {

        case PHYSICAL:
        case SERVICE:
        case GIFT_CARD:
            JsonNode variants = structuredContent.path("variants");
            if (variants.size() == 0) {
                return DEFAULT_MONEY_NODE;
            }

            JsonNode first = variants.get(0);
            JsonNode moneyNode = isTruthy(first.path("onSale")) ? first.path("salePriceMoney")
                    : first.path("priceMoney");
            BigDecimal price = getAmountFromMoneyNode(moneyNode);
            for (int i = 1; i < variants.size(); i++) {
                JsonNode var = variants.get(i);
                JsonNode currentMoneyNode = isTruthy(var.path("onSale")) ? var.path("salePriceMoney")
                        : var.path("priceMoney");

                BigDecimal current = getAmountFromMoneyNode(currentMoneyNode);
                if (current.compareTo(price) < 0) {
                    price = current;
                    moneyNode = currentMoneyNode;
                }
            }
            return moneyNode;

        case DIGITAL:
            JsonNode digitalMoneyNode = structuredContent.path("priceMoney");
            return digitalMoneyNode.isMissingNode() ? DEFAULT_MONEY_NODE : digitalMoneyNode;

        default:
            return DEFAULT_MONEY_NODE;
        }
    }

    public static JsonNode getNormalPriceMoneyNode(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");

        switch (type) {
        case PHYSICAL:
        case SERVICE:
        case GIFT_CARD:
            JsonNode variants = structuredContent.path("variants");
            if (variants.size() == 0) {
                return DEFAULT_MONEY_NODE;
            }
            JsonNode moneyNode = variants.get(0).path("priceMoney");
            BigDecimal price = getAmountFromMoneyNode(moneyNode);
            for (int i = 1; i < variants.size(); i++) {
                JsonNode currMoneyNode = variants.get(i).path("priceMoney");
                BigDecimal curr = getAmountFromMoneyNode(currMoneyNode);
                if (curr.compareTo(price) > 0) {
                    price = curr;
                    moneyNode = currMoneyNode;
                }
            }
            return moneyNode;

        case DIGITAL:
            JsonNode digitalMoneyNode = structuredContent.path("priceMoney");
            return digitalMoneyNode.isMissingNode() ? DEFAULT_MONEY_NODE : digitalMoneyNode;

        default:
            return DEFAULT_MONEY_NODE;
        }
    }

    public static JsonNode getSalePriceMoneyNode(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");
        switch (type) {
        case PHYSICAL:
        case SERVICE:
            JsonNode variants = structuredContent.path("variants");
            if (variants.size() == 0) {
                return DEFAULT_MONEY_NODE;
            }
            BigDecimal salePrice = null;
            JsonNode salePriceNode = null;
            for (int i = 0; i < variants.size(); i++) {
                JsonNode variant = variants.path(i);
                JsonNode priceMoney = variant.path("salePriceMoney");
                BigDecimal price = getAmountFromMoneyNode(priceMoney);
                if (isTruthy(variant.path("onSale")) && (salePriceNode == null || price.compareTo(salePrice) < 0)) {
                    salePrice = price;
                    salePriceNode = priceMoney;
                }
            }
            return (salePriceNode == null) ? DEFAULT_MONEY_NODE : salePriceNode;

        case DIGITAL:
            JsonNode digitalMoneyNode = structuredContent.path("salePriceMoney");
            return digitalMoneyNode.isMissingNode() ? DEFAULT_MONEY_NODE : digitalMoneyNode;

        case GIFT_CARD:
            // this should never happen

        default:
            return DEFAULT_MONEY_NODE;
        }
    }

    public static BigDecimal getAmountFromMoneyNode(JsonNode moneyNode) {
        String value = StringUtils.trimToNull(moneyNode.path("value").asText());
        return value == null ? DEFAULT_MONEY_AMOUNT : new BigDecimal(value);
    }

    public static String getCurrencyFromMoneyNode(JsonNode moneyNode) {
        String currency = StringUtils.trimToNull(moneyNode.path("currency").asText());
        return currency == null ? DEFAULT_CURRENCY : currency;
    }

    public static double getLegacyPriceFromMoneyNode(JsonNode moneyNode) {
        BigDecimal price = getAmountFromMoneyNode(moneyNode);
        return price.movePointRight(2).doubleValue();
    }

    public static double getTotalStockRemaining(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");

        if (EnumSet.of(ProductType.DIGITAL, ProductType.GIFT_CARD).contains(type)) {
            return Double.POSITIVE_INFINITY;
        } else {
            int total = 0;
            JsonNode variants = structuredContent.path("variants");
            for (int i = 0; i < variants.size(); i++) {
                JsonNode variant = variants.get(i);
                if (isTruthy(variant.path("unlimited"))) {
                    return Double.POSITIVE_INFINITY;
                } else {
                    total += variant.path("qtyInStock").asLong();
                }
            }
            return total;
        }
    }

    public static boolean hasVariedPrices(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");

        switch (type) {
        case PHYSICAL:
        case SERVICE:
        case GIFT_CARD:
            JsonNode variants = structuredContent.path("variants");
            JsonNode first = variants.get(0);
            for (int i = 1; i < variants.size(); i++) {
                JsonNode var = variants.get(i);
                boolean flag1 = !var.path("onSale").equals(first.path("onSale"));
                boolean flag2 = isTruthy(first.path("onSale"))
                        && !var.path("salePrice").equals(first.path("salePrice"));
                boolean flag3 = !var.path("price").equals(first.path("price"));
                if (flag1 || flag2 || flag3) {
                    return true;
                }
            }
            return false;
        case DIGITAL:
        default:
            return false;
        }
    }

    public static boolean hasVariants(JsonNode item) {
        JsonNode structuredContent = item.path("structuredContent");
        JsonNode variants = structuredContent.path("variants");
        ProductType type = getProductType(item);
        return type.equals(ProductType.DIGITAL) ? false : variants.size() > 1;
    }

    public static boolean isOnSale(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");

        switch (type) {
        case PHYSICAL:
        case SERVICE:
            JsonNode variants = structuredContent.path("variants");
            int size = variants.size();
            for (int i = 0; i < size; i++) {
                JsonNode variant = variants.get(i);
                if (isTruthy(variant.path("onSale"))) {
                    return true;
                }
            }
            break;

        case DIGITAL:
            return isTruthy(structuredContent.path("onSale"));

        case GIFT_CARD:
        default:
            break;
        }
        return false;
    }

    public static boolean isSoldOut(JsonNode item) {
        ProductType type = getProductType(item);
        JsonNode structuredContent = item.path("structuredContent");

        switch (type) {
        case PHYSICAL:
        case SERVICE:
            JsonNode variants = structuredContent.path("variants");
            int size = variants.size();
            for (int i = 0; i < size; i++) {
                JsonNode variant = variants.get(i);
                if (isTruthy(variant.path("unlimited")) || variant.path("qtyInStock").asInt() > 0) {
                    return false;
                }
            }
            return true;

        case DIGITAL:
        case GIFT_CARD:
            return false;

        default:
            return true;
        }
    }

    /**
     * Format money using legacy currency formatter
     */
    public static void writeLegacyMoneyString(double value, StringBuilder buf) {
        String formatted = PluginUtils.formatMoney(value, Locale.US);
        buf.append("<span class=\"sqs-money-native\">").append(formatted).append("</span>");
    }

    /**
     * Format money using CLDR currency formatter
     */
    public static String getCLDRMoneyString(BigDecimal amount, String currencyCode, CLDR.Locale locale) {
        return PluginUtils.formatMoney(amount, currencyCode, locale);
    }

    public static void writeVariantFormat(JsonNode variant, StringBuilder buf) {
        ArrayNode optionValues = (ArrayNode) variant.get("optionValues");
        if (optionValues == null) {
            return;
        }

        Iterator<JsonNode> iterator = optionValues.elements();
        List<String> values = new ArrayList<>();

        while (iterator.hasNext()) {
            JsonNode option = iterator.next();
            values.add(option.get("value").asText());
        }

        int size = values.size();
        for (int i = 0; i < size; i++) {
            if (i > 0) {
                buf.append(" / ");
            }
            buf.append(values.get(i));
        }
    }

    public static ArrayNode getItemVariantOptions(JsonNode item) {
        JsonNode structuredContent = item.path("structuredContent");
        JsonNode variants = structuredContent.path("variants");
        if (variants.size() <= 1) {
            return EMPTY_ARRAY;
        }

        ArrayNode userDefinedOptions = JsonUtils.createArrayNode();
        JsonNode ordering = structuredContent.path("variantOptionOrdering");
        for (int i = 0; i < ordering.size(); i++) {
            String optionName = ordering.path(i).asText();
            ObjectNode option = JsonUtils.createObjectNode();
            option.put("name", optionName);
            option.put("values", JsonUtils.createArrayNode());
            userDefinedOptions.add(option);
        }

        for (int i = 0; i < variants.size(); i++) {
            JsonNode variant = variants.path(i);
            JsonNode attributes = variant.get("attributes");
            if (attributes == null) {
                continue;
            }
            Iterator<String> fields = attributes.fieldNames();

            while (fields.hasNext()) {
                String field = fields.next();

                String variantOptionValue = attributes.get(field).asText();
                ObjectNode userDefinedOption = null;

                for (int j = 0; j < userDefinedOptions.size(); j++) {
                    ObjectNode current = (ObjectNode) userDefinedOptions.get(j);
                    if (current.get("name").asText().equals(field)) {
                        userDefinedOption = current;
                    }
                }

                if (userDefinedOption != null) {
                    boolean hasOptionValue = false;
                    ArrayNode optionValues = (ArrayNode) userDefinedOption.get("values");
                    for (int k = 0; k < optionValues.size(); k++) {
                        String optionValue = optionValues.get(k).asText();
                        if (optionValue.equals(variantOptionValue)) {
                            hasOptionValue = true;
                            break;
                        }
                    }

                    if (!hasOptionValue) {
                        optionValues.add(variantOptionValue);
                    }
                }
            }
        }
        return userDefinedOptions;
    }

    public static boolean isMultipleQuantityAllowedForServices(JsonNode websiteSettings) {

        boolean defaultValue = true;
        String fieldName = "multipleQuantityAllowedForServices";

        JsonNode storeSettings = websiteSettings.get("storeSettings");

        if (storeSettings == null || !storeSettings.hasNonNull(fieldName)) {
            return defaultValue;
        }

        return storeSettings.get(fieldName).asBoolean(defaultValue);
    }

}