org.yes.cart.shoppingcart.impl.WeightBasedPriceListDeliveryCostCalculationStrategy.java Source code

Java tutorial

Introduction

Here is the source code for org.yes.cart.shoppingcart.impl.WeightBasedPriceListDeliveryCostCalculationStrategy.java

Source

/*
 * Copyright 2009 Denys Pavlov, Igor Azarnyi
 *
 *    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 org.yes.cart.shoppingcart.impl;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yes.cart.constants.AttributeNamesKeys;
import org.yes.cart.constants.Constants;
import org.yes.cart.domain.entity.CarrierSla;
import org.yes.cart.domain.entity.Product;
import org.yes.cart.domain.entity.SkuPrice;
import org.yes.cart.domain.i18n.impl.FailoverStringI18NModel;
import org.yes.cart.domain.misc.Pair;
import org.yes.cart.service.domain.CarrierSlaService;
import org.yes.cart.service.domain.ProductService;
import org.yes.cart.service.order.DeliveryBucket;
import org.yes.cart.shoppingcart.*;
import org.yes.cart.util.MoneyUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: denispavlov
 * Date: 13-10-20
 * Time: 6:07 PM
 */
public class WeightBasedPriceListDeliveryCostCalculationStrategy implements DeliveryCostCalculationStrategy {

    private static final Logger LOG = LoggerFactory
            .getLogger(WeightBasedPriceListDeliveryCostCalculationStrategy.class);

    private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(Constants.DEFAULT_SCALE,
            BigDecimal.ROUND_HALF_UP);

    private static final BigDecimal QTY = new BigDecimal(1).setScale(Constants.DEFAULT_SCALE,
            BigDecimal.ROUND_HALF_UP);

    private static final BigDecimal MAX = new BigDecimal(Integer.MAX_VALUE);

    private final CarrierSlaService carrierSlaService;
    private final ProductService productService;
    private final DeliveryCostRegionalPriceResolver deliveryCostRegionalPriceResolver;
    private final PricingPolicyProvider pricingPolicyProvider;

    public WeightBasedPriceListDeliveryCostCalculationStrategy(final CarrierSlaService carrierSlaService,
            final ProductService productService, final PricingPolicyProvider pricingPolicyProvider,
            final DeliveryCostRegionalPriceResolver deliveryCostRegionalPriceResolver) {
        this.carrierSlaService = carrierSlaService;
        this.productService = productService;
        this.deliveryCostRegionalPriceResolver = deliveryCostRegionalPriceResolver;
        this.pricingPolicyProvider = pricingPolicyProvider;
    }

    /** {@inheritDoc} */
    public Total calculate(final MutableShoppingCart cart) {

        if (!cart.getCarrierSlaId().isEmpty()) {

            Total total = null;

            for (final Map.Entry<String, Long> supplierCarrierSla : cart.getCarrierSlaId().entrySet()) {

                final Map<DeliveryBucket, List<CartItem>> cartBuckets = new HashMap<DeliveryBucket, List<CartItem>>();
                for (final Map.Entry<DeliveryBucket, List<CartItem>> bucket : cart.getCartItemMap().entrySet()) {
                    // Add shipping line for every bucket by this supplier (e.g. if we have multi delivery)
                    if (bucket.getKey().getSupplier().equals(supplierCarrierSla.getKey())) {
                        cartBuckets.put(bucket.getKey(), bucket.getValue());
                    }

                }

                if (cartBuckets.isEmpty()) {
                    continue; // no buckets for this selection
                }

                final CarrierSla carrierSla = carrierSlaService.getById(supplierCarrierSla.getValue());
                if (carrierSla != null && CarrierSla.WEIGHT_VOLUME.equals(carrierSla.getSlaType())) {

                    final String carrierSlaGUID = carrierSla.getGuid();
                    final String carrierSlaName = new FailoverStringI18NModel(carrierSla.getDisplayName(),
                            carrierSla.getName()).getValue(cart.getCurrentLocale());

                    final PricingPolicyProvider.PricingPolicy policy = pricingPolicyProvider.determinePricingPolicy(
                            cart.getShoppingContext().getShopCode(), cart.getCurrencyCode(),
                            cart.getCustomerEmail(), cart.getShoppingContext().getCountryCode(),
                            cart.getShoppingContext().getStateCode());

                    final BigDecimal qty = QTY;

                    for (final Map.Entry<DeliveryBucket, List<CartItem>> bucketAndItems : cartBuckets.entrySet()) {
                        // Add shipping line for every bucket by this supplier (e.g. if we have multi delivery)

                        final Pair<BigDecimal, BigDecimal> weightAndVolume = determineProductWeightAndVolume(
                                bucketAndItems.getValue());

                        final boolean useWeight = MoneyUtils.isFirstBiggerThanSecond(weightAndVolume.getFirst(),
                                BigDecimal.ZERO);
                        final boolean useVolume = MoneyUtils.isFirstBiggerThanSecond(weightAndVolume.getSecond(),
                                BigDecimal.ZERO);

                        final SkuPrice priceByWeightMax = useWeight
                                ? getSkuPrice(cart, carrierSlaGUID + "_KGMAX", policy, MAX)
                                : null;
                        final SkuPrice priceByWeight = useWeight && isValidPrice(priceByWeightMax)
                                && MoneyUtils.isFirstBiggerThanOrEqualToSecond(priceByWeightMax.getQuantity(),
                                        weightAndVolume.getFirst())
                                                ? getSkuPrice(cart, carrierSlaGUID + "_KG", policy,
                                                        weightAndVolume.getFirst())
                                                : null;
                        final SkuPrice priceByVolumeMax = useVolume
                                ? getSkuPrice(cart, carrierSlaGUID + "_M3MAX", policy, MAX)
                                : null;
                        final SkuPrice priceByVolume = useVolume && isValidPrice(priceByVolumeMax)
                                && MoneyUtils.isFirstBiggerThanOrEqualToSecond(priceByVolumeMax.getQuantity(),
                                        weightAndVolume.getSecond())
                                                ? getSkuPrice(cart, carrierSlaGUID + "_M3", policy,
                                                        weightAndVolume.getSecond())
                                                : null;

                        SkuPrice price = null;
                        if (useWeight && useVolume) {

                            if (isValidPrice(priceByWeight) && isValidPrice(priceByVolume)) {
                                // Assign price only if we have both valid prices

                                final BigDecimal salePriceByWeight = MoneyUtils.minPositive(
                                        priceByWeight.getRegularPrice(),
                                        priceByWeight.getSalePriceForCalculation());
                                final BigDecimal salePriceByVolume = MoneyUtils.minPositive(
                                        priceByVolume.getRegularPrice(),
                                        priceByVolume.getSalePriceForCalculation());

                                if (MoneyUtils.isFirstBiggerThanOrEqualToSecond(salePriceByVolume,
                                        salePriceByWeight)) {
                                    // Volume has higher cost
                                    price = priceByVolume;
                                } else {
                                    // Weight has higher cost
                                    price = priceByWeight;
                                }

                            }

                        } else if (useWeight) {
                            // Only weight is available
                            price = priceByWeight;
                        } else if (useVolume) {
                            // Only volume is available
                            price = priceByVolume;
                        }

                        if (isValidPrice(price)) {

                            final BigDecimal salePrice = MoneyUtils.minPositive(price.getRegularPrice(),
                                    price.getSalePriceForCalculation());

                            cart.addShippingToCart(bucketAndItems.getKey(), carrierSlaGUID, carrierSlaName, qty);
                            cart.setShippingPrice(carrierSlaGUID, bucketAndItems.getKey(), salePrice, salePrice);
                            final BigDecimal deliveryCost = salePrice.multiply(qty)
                                    .setScale(Constants.DEFAULT_SCALE, RoundingMode.HALF_UP);

                            final Total bucketTotal = new TotalImpl(Total.ZERO, Total.ZERO, Total.ZERO, Total.ZERO,
                                    false, null, Total.ZERO, Total.ZERO, Total.ZERO, deliveryCost, deliveryCost,
                                    false, null, Total.ZERO, deliveryCost, deliveryCost, Total.ZERO, deliveryCost,
                                    deliveryCost);

                            // Add bucket total to delivery cost
                            total = total == null ? bucketTotal : total.add(bucketTotal);

                        } else {
                            // If at least one bucket cannot be delivered, none should
                            return null;

                        }
                    }

                }
            }

            return total;
        }
        return null;
    }

    boolean isValidPrice(SkuPrice price) {
        return price != null && price.getSkuPriceId() > 0L;
    }

    protected Pair<BigDecimal, BigDecimal> determineProductWeightAndVolume(List<CartItem> cartItems) {

        BigDecimal weight = BigDecimal.ZERO;
        BigDecimal volume = BigDecimal.ZERO;

        for (final CartItem cartItem : cartItems) {

            Product product = productService.getProductBySkuCode(cartItem.getProductSkuCode());

            if (product != null) {

                try {
                    product = productService.getProductById(product.getProductId(), true);
                    final String kgSetting = product
                            .getAttributeValueByCode(AttributeNamesKeys.Product.PRODUCT_WEIGHT_KG);
                    if (StringUtils.isNotBlank(kgSetting)) {
                        final BigDecimal kg = new BigDecimal(kgSetting);
                        weight = weight.add(kg.multiply(cartItem.getQty()));
                    }
                } catch (Exception exp) {
                    LOG.error("Product {} does not have valid weight");
                }

                try {
                    final String m3Setting = product
                            .getAttributeValueByCode(AttributeNamesKeys.Product.PRODUCT_VOLUME_M3);
                    if (StringUtils.isNotBlank(m3Setting)) {
                        final BigDecimal m3 = new BigDecimal(m3Setting);
                        volume = volume.add(m3.multiply(cartItem.getQty()));
                    }
                } catch (Exception exp) {
                    LOG.error("Product {} does not have valid volume");
                }

            }
        }

        return new Pair<BigDecimal, BigDecimal>(weight, volume);
    }

    protected SkuPrice getSkuPrice(final MutableShoppingCart cart, final String carrierSlaId,
            final PricingPolicyProvider.PricingPolicy policy, final BigDecimal qty) {

        return deliveryCostRegionalPriceResolver.getSkuPrice(cart, carrierSlaId, policy, qty);

    }

}