Search in sources :

Example 1 with BandedWeightFulfillmentOption

use of org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption in project BroadleafCommerce by BroadleafCommerce.

the class BandedPriceFulfillmentTest method testWeightBandsWithQuantities.

public void testWeightBandsWithQuantities() throws Exception {
    BandedWeightFulfillmentOption option = createWeightBands(new String[] { "50", "100", "65" }, new String[] { "30", "20", "10" }, new FulfillmentBandResultAmountType[] { FulfillmentBandResultAmountType.RATE, FulfillmentBandResultAmountType.RATE, FulfillmentBandResultAmountType.RATE });
    // 60lbs
    assertEquals(new Money("30"), calculationResponse(option, createCandidateOrder(new BigDecimal("18.00"), 3, null, new int[] { 2, 3, 5 }, option)));
    // 66lbs
    assertEquals(new Money("10"), calculationResponse(option, createCandidateOrder(new BigDecimal("18.00"), 6, null, new int[] { 4, 1, 2, 5, 5, 5 }, option)));
    // 120lbs
    assertEquals(new Money("20"), calculationResponse(option, createCandidateOrder(new BigDecimal("60.00"), 3, null, new int[] { 2, 3, 2 }, option)));
}
Also used : Money(org.broadleafcommerce.common.money.Money) BandedWeightFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption) BigDecimal(java.math.BigDecimal)

Example 2 with BandedWeightFulfillmentOption

use of org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption in project BroadleafCommerce by BroadleafCommerce.

the class BandedPriceFulfillmentTest method createWeightBands.

protected BandedWeightFulfillmentOption createWeightBands(String[] minimumAmounts, String[] resultAmounts, FulfillmentBandResultAmountType[] resultAmountTypes) {
    if ((minimumAmounts.length != resultAmounts.length) || (resultAmounts.length != resultAmountTypes.length)) {
        throw new IllegalStateException("All lists should be the same length");
    }
    List<FulfillmentWeightBand> bands = new ArrayList<FulfillmentWeightBand>();
    for (int i = 0; i < minimumAmounts.length; i++) {
        FulfillmentWeightBand band = new FulfillmentWeightBandImpl();
        band.setMinimumWeight(new BigDecimal(minimumAmounts[i]));
        band.setWeightUnitOfMeasure(WeightUnitOfMeasureType.POUNDS);
        band.setResultAmount(new BigDecimal(resultAmounts[i]));
        band.setResultAmountType(resultAmountTypes[i]);
        bands.add(band);
    }
    BandedWeightFulfillmentOption option = new BandedWeightFulfillmentOptionImpl();
    option.setBands(bands);
    return option;
}
Also used : FulfillmentWeightBandImpl(org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentWeightBandImpl) ArrayList(java.util.ArrayList) BandedWeightFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption) FulfillmentWeightBand(org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentWeightBand) BigDecimal(java.math.BigDecimal) BandedWeightFulfillmentOptionImpl(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOptionImpl)

Example 3 with BandedWeightFulfillmentOption

use of org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption in project BroadleafCommerce by BroadleafCommerce.

the class BandedFulfillmentPricingProvider method estimateCostForFulfillmentGroup.

@Override
public FulfillmentEstimationResponse estimateCostForFulfillmentGroup(FulfillmentGroup fulfillmentGroup, Set<FulfillmentOption> options) throws FulfillmentPriceException {
    // Set up the response object
    FulfillmentEstimationResponse res = new FulfillmentEstimationResponse();
    HashMap<FulfillmentOption, Money> shippingPrices = new HashMap<FulfillmentOption, Money>();
    res.setFulfillmentOptionPrices(shippingPrices);
    for (FulfillmentOption option : options) {
        if (canCalculateCostForFulfillmentGroup(fulfillmentGroup, option)) {
            List<? extends FulfillmentBand> bands = null;
            if (option instanceof BandedPriceFulfillmentOption) {
                bands = ((BandedPriceFulfillmentOption) option).getBands();
            } else if (option instanceof BandedWeightFulfillmentOption) {
                bands = ((BandedWeightFulfillmentOption) option).getBands();
            }
            if (bands == null || bands.isEmpty()) {
                // Something is misconfigured. There are no bands associated with this fulfillment option
                throw new IllegalStateException("There were no Fulfillment Price Bands configured for a BandedPriceFulfillmentOption with ID: " + option.getId());
            }
            // Calculate the amount that the band will be applied to
            BigDecimal retailTotal = BigDecimal.ZERO;
            BigDecimal flatTotal = BigDecimal.ZERO;
            BigDecimal weightTotal = BigDecimal.ZERO;
            boolean foundCandidateForBand = false;
            for (FulfillmentGroupItem fulfillmentGroupItem : fulfillmentGroup.getFulfillmentGroupItems()) {
                // If this item has a Sku associated with it which also has a flat rate for this fulfillment option, don't add it to the price
                // or weight total but instead tack it onto the final rate
                boolean addToTotal = true;
                Sku sku = null;
                if (fulfillmentGroupItem.getOrderItem() instanceof DiscreteOrderItem) {
                    sku = ((DiscreteOrderItem) fulfillmentGroupItem.getOrderItem()).getSku();
                } else if (fulfillmentGroupItem.getOrderItem() instanceof BundleOrderItem) {
                    sku = ((BundleOrderItem) fulfillmentGroupItem.getOrderItem()).getSku();
                }
                if (sku != null && option.getUseFlatRates()) {
                    BigDecimal rate = sku.getFulfillmentFlatRates().get(option);
                    if (rate != null) {
                        addToTotal = false;
                        flatTotal = flatTotal.add(rate);
                    }
                }
                if (addToTotal) {
                    foundCandidateForBand = true;
                    BigDecimal price = (fulfillmentGroupItem.getTotalItemAmount() != null) ? fulfillmentGroupItem.getTotalItemAmount().getAmount() : null;
                    if (price == null) {
                        price = fulfillmentGroupItem.getOrderItem().getAveragePrice().getAmount().multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()));
                    }
                    retailTotal = retailTotal.add(price);
                    if (sku != null && sku.getWeight() != null && sku.getWeight().getWeight() != null) {
                        BigDecimal convertedWeight = convertWeight(sku.getWeight().getWeight(), sku.getWeight().getWeightUnitOfMeasure()).multiply(BigDecimal.valueOf(fulfillmentGroupItem.getQuantity()));
                        weightTotal = weightTotal.add(convertedWeight);
                    }
                }
            }
            // Used to keep track of the lowest price when there is are bands that have the same
            // minimum amount
            BigDecimal lowestBandFulfillmentPrice = null;
            // Used to keep track of the amount for the lowest band fulfillment price. Used to compare
            // if 2 bands are configured for the same minimum amount
            BigDecimal lowestBandFulfillmentPriceMinimumAmount = BigDecimal.ZERO;
            if (foundCandidateForBand) {
                for (FulfillmentBand band : bands) {
                    BigDecimal bandMinimumAmount = BigDecimal.ZERO;
                    boolean foundMatch = false;
                    if (band instanceof FulfillmentPriceBand) {
                        bandMinimumAmount = ((FulfillmentPriceBand) band).getRetailPriceMinimumAmount();
                        foundMatch = retailTotal.compareTo(bandMinimumAmount) >= 0;
                    } else if (band instanceof FulfillmentWeightBand) {
                        bandMinimumAmount = ((FulfillmentWeightBand) band).getMinimumWeight();
                        foundMatch = weightTotal.compareTo(bandMinimumAmount) >= 0;
                    }
                    if (foundMatch) {
                        // So far, we've found a potential match
                        // Now, determine if this is a percentage or actual amount
                        FulfillmentBandResultAmountType resultAmountType = band.getResultAmountType();
                        BigDecimal bandFulfillmentPrice = null;
                        if (FulfillmentBandResultAmountType.RATE.equals(resultAmountType)) {
                            bandFulfillmentPrice = band.getResultAmount();
                        } else if (FulfillmentBandResultAmountType.PERCENTAGE.equals(resultAmountType)) {
                            // Since this is a percentage, we calculate the result amount based on retailTotal and the band percentage
                            bandFulfillmentPrice = retailTotal.multiply(band.getResultAmount());
                        } else {
                            LOG.warn("Unknown FulfillmentBandResultAmountType: " + resultAmountType.getType() + " Should be RATE or PERCENTAGE. Ignoring.");
                        }
                        if (bandFulfillmentPrice != null) {
                            // haven't initialized the lowest price yet so just take on this one
                            if (lowestBandFulfillmentPrice == null) {
                                lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                            }
                            // is cheaper
                            if (lowestBandFulfillmentPriceMinimumAmount.compareTo(bandMinimumAmount) == 0) {
                                if (bandFulfillmentPrice.compareTo(lowestBandFulfillmentPrice) <= 0) {
                                    lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                    lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                                }
                            } else if (bandMinimumAmount.compareTo(lowestBandFulfillmentPriceMinimumAmount) > 0) {
                                lowestBandFulfillmentPrice = bandFulfillmentPrice;
                                lowestBandFulfillmentPriceMinimumAmount = bandMinimumAmount;
                            }
                        } else {
                            throw new IllegalStateException("Bands must have a non-null fulfillment price");
                        }
                    }
                }
            }
            // If I didn't find a valid band, initialize the fulfillment price to zero
            if (lowestBandFulfillmentPrice == null) {
                lowestBandFulfillmentPrice = BigDecimal.ZERO;
            }
            // add the flat rate amount calculated on the Sku
            lowestBandFulfillmentPrice = lowestBandFulfillmentPrice.add(flatTotal);
            shippingPrices.put(option, BroadleafCurrencyUtils.getMoney(lowestBandFulfillmentPrice, fulfillmentGroup.getOrder().getCurrency()));
        }
    }
    return res;
}
Also used : DiscreteOrderItem(org.broadleafcommerce.core.order.domain.DiscreteOrderItem) HashMap(java.util.HashMap) BandedPriceFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedPriceFulfillmentOption) BandedWeightFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption) FulfillmentOption(org.broadleafcommerce.core.order.domain.FulfillmentOption) BandedPriceFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedPriceFulfillmentOption) FulfillmentBand(org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentBand) BigDecimal(java.math.BigDecimal) FulfillmentPriceBand(org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentPriceBand) Money(org.broadleafcommerce.common.money.Money) BundleOrderItem(org.broadleafcommerce.core.order.domain.BundleOrderItem) FulfillmentGroupItem(org.broadleafcommerce.core.order.domain.FulfillmentGroupItem) FulfillmentBandResultAmountType(org.broadleafcommerce.core.order.service.type.FulfillmentBandResultAmountType) Sku(org.broadleafcommerce.core.catalog.domain.Sku) BandedWeightFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption) FulfillmentWeightBand(org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentWeightBand)

Example 4 with BandedWeightFulfillmentOption

use of org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption in project BroadleafCommerce by BroadleafCommerce.

the class BandedPriceFulfillmentTest method createCandidateOrder.

/**
 * @param total - this number divided by the number of items to create is the value of either the weight or the price
 * (depending on which <b>option</b> is being passed in) for a single order item. Note that the final price of each item
 * will be: (<b>total</b> / <b>orderItemsToCreate</b>) * <b>quantity</b>
 * @param orderItemsToCreate - the number of order items to split the retail total across
 * @param flatRates - the flat rates to assign to the OrderItems that are created. To have an Order that is mixed between OrderItems and
 * DiscreteOrderItems (which are created for flat rates) ensure that the size of this array is less than <b>orderItemsToCreate</b>
 * @param quantities - the quantities to assign to each OrderItem. If specified, this should be equal to the number of
 * items to create
 * @param option - the option to associate with the flat rates
 * @return
 */
protected Order createCandidateOrder(BigDecimal total, int orderItemsToCreate, String[] flatRates, int[] quantities, FulfillmentOption option) {
    if (flatRates != null && flatRates.length > orderItemsToCreate) {
        throw new IllegalStateException("Flat rates for Skus should be less than or equal to the number of order items being created");
    }
    if (quantities != null && quantities.length != orderItemsToCreate) {
        throw new IllegalStateException("Quantities for Skus should be less than or equal to the number of order items being created");
    }
    Order result = new OrderImpl();
    List<FulfillmentGroupItem> fulfillmentItems = new ArrayList<FulfillmentGroupItem>();
    for (int i = 0; i < orderItemsToCreate; i++) {
        DiscreteOrderItem orderItem = new DiscreteOrderItemImpl();
        Sku sku = new SkuImpl();
        // set the sku price to some arbitrary amount - won't matter because the test is based on order item price
        sku.setRetailPrice(new Money("1"));
        orderItem.setSku(sku);
        if (flatRates != null && i < flatRates.length) {
            sku.getFulfillmentFlatRates().put(option, new BigDecimal(flatRates[i]));
        }
        if (option instanceof BandedPriceFulfillmentOption) {
            orderItem.setPrice(new Money(total.divide(new BigDecimal(orderItemsToCreate))));
        } else if (option instanceof BandedWeightFulfillmentOption) {
            Weight weight = new Weight();
            weight.setWeight(total.divide(new BigDecimal(orderItemsToCreate)));
            weight.setWeightUnitOfMeasure(WeightUnitOfMeasureType.POUNDS);
            orderItem.getSku().setWeight(weight);
            orderItem.setPrice(new Money(BigDecimal.ZERO));
        }
        orderItem.setOrder(result);
        FulfillmentGroupItem fulfillmentItem = new FulfillmentGroupItemImpl();
        fulfillmentItem.setOrderItem(orderItem);
        if (quantities == null) {
            fulfillmentItem.setQuantity(1);
        } else {
            fulfillmentItem.setQuantity(quantities[i]);
        }
        fulfillmentItems.add(fulfillmentItem);
    }
    FulfillmentGroup group = new FulfillmentGroupImpl();
    group.setOrder(result);
    group.setFulfillmentGroupItems(fulfillmentItems);
    List<FulfillmentGroup> groups = new ArrayList<FulfillmentGroup>();
    groups.add(group);
    result.setFulfillmentGroups(groups);
    return result;
}
Also used : Order(org.broadleafcommerce.core.order.domain.Order) DiscreteOrderItem(org.broadleafcommerce.core.order.domain.DiscreteOrderItem) FulfillmentGroupImpl(org.broadleafcommerce.core.order.domain.FulfillmentGroupImpl) DiscreteOrderItemImpl(org.broadleafcommerce.core.order.domain.DiscreteOrderItemImpl) ArrayList(java.util.ArrayList) BandedPriceFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedPriceFulfillmentOption) BigDecimal(java.math.BigDecimal) Weight(org.broadleafcommerce.core.catalog.domain.Weight) Money(org.broadleafcommerce.common.money.Money) SkuImpl(org.broadleafcommerce.core.catalog.domain.SkuImpl) FulfillmentGroupItem(org.broadleafcommerce.core.order.domain.FulfillmentGroupItem) OrderImpl(org.broadleafcommerce.core.order.domain.OrderImpl) FulfillmentGroup(org.broadleafcommerce.core.order.domain.FulfillmentGroup) Sku(org.broadleafcommerce.core.catalog.domain.Sku) BandedWeightFulfillmentOption(org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption) FulfillmentGroupItemImpl(org.broadleafcommerce.core.order.domain.FulfillmentGroupItemImpl)

Aggregations

BigDecimal (java.math.BigDecimal)4 BandedWeightFulfillmentOption (org.broadleafcommerce.core.order.fulfillment.domain.BandedWeightFulfillmentOption)4 Money (org.broadleafcommerce.common.money.Money)3 ArrayList (java.util.ArrayList)2 Sku (org.broadleafcommerce.core.catalog.domain.Sku)2 DiscreteOrderItem (org.broadleafcommerce.core.order.domain.DiscreteOrderItem)2 FulfillmentGroupItem (org.broadleafcommerce.core.order.domain.FulfillmentGroupItem)2 BandedPriceFulfillmentOption (org.broadleafcommerce.core.order.fulfillment.domain.BandedPriceFulfillmentOption)2 FulfillmentWeightBand (org.broadleafcommerce.core.order.fulfillment.domain.FulfillmentWeightBand)2 HashMap (java.util.HashMap)1 SkuImpl (org.broadleafcommerce.core.catalog.domain.SkuImpl)1 Weight (org.broadleafcommerce.core.catalog.domain.Weight)1 BundleOrderItem (org.broadleafcommerce.core.order.domain.BundleOrderItem)1 DiscreteOrderItemImpl (org.broadleafcommerce.core.order.domain.DiscreteOrderItemImpl)1 FulfillmentGroup (org.broadleafcommerce.core.order.domain.FulfillmentGroup)1 FulfillmentGroupImpl (org.broadleafcommerce.core.order.domain.FulfillmentGroupImpl)1 FulfillmentGroupItemImpl (org.broadleafcommerce.core.order.domain.FulfillmentGroupItemImpl)1 FulfillmentOption (org.broadleafcommerce.core.order.domain.FulfillmentOption)1 Order (org.broadleafcommerce.core.order.domain.Order)1 OrderImpl (org.broadleafcommerce.core.order.domain.OrderImpl)1