use of org.broadleafcommerce.core.order.domain.FulfillmentOption in project BroadleafCommerce by BroadleafCommerce.
the class FulfillmentPricingServiceImpl method estimateCostForFulfillmentGroup.
@Override
public FulfillmentEstimationResponse estimateCostForFulfillmentGroup(FulfillmentGroup fulfillmentGroup, Set<FulfillmentOption> options) throws FulfillmentPriceException {
FulfillmentEstimationResponse response = new FulfillmentEstimationResponse();
HashMap<FulfillmentOption, Money> prices = new HashMap<FulfillmentOption, Money>();
response.setFulfillmentOptionPrices(prices);
for (FulfillmentPricingProvider provider : providers) {
// to, then the response from the pricing provider should not include the options that it could not respond to.
try {
FulfillmentEstimationResponse processorResponse = provider.estimateCostForFulfillmentGroup(fulfillmentGroup, options);
if (processorResponse != null && processorResponse.getFulfillmentOptionPrices() != null && processorResponse.getFulfillmentOptionPrices().size() > 0) {
prices.putAll(processorResponse.getFulfillmentOptionPrices());
}
} catch (FulfillmentPriceException e) {
// Shouldn't completely fail the rest of the estimation on a pricing exception. Another provider might still
// be able to respond
String errorMessage = "FulfillmentPriceException thrown when trying to estimate fulfillment costs from ";
errorMessage += provider.getClass().getName();
errorMessage += ". Underlying message was: " + e.getMessage();
LOG.error(errorMessage);
}
}
return response;
}
use of org.broadleafcommerce.core.order.domain.FulfillmentOption in project BroadleafCommerce by BroadleafCommerce.
the class FixedPriceFulfillmentPricingProvider method estimateCostForFulfillmentGroup.
@Override
public FulfillmentEstimationResponse estimateCostForFulfillmentGroup(FulfillmentGroup fulfillmentGroup, Set<FulfillmentOption> options) throws FulfillmentPriceException {
FulfillmentEstimationResponse response = new FulfillmentEstimationResponse();
HashMap<FulfillmentOption, Money> shippingPrices = new HashMap<FulfillmentOption, Money>();
response.setFulfillmentOptionPrices(shippingPrices);
for (FulfillmentOption option : options) {
if (canCalculateCostForFulfillmentGroup(fulfillmentGroup, option)) {
Money price = ((FixedPriceFulfillmentOption) option).getPrice();
shippingPrices.put(option, price);
}
}
return response;
}
use of org.broadleafcommerce.core.order.domain.FulfillmentOption in project BroadleafCommerce by BroadleafCommerce.
the class OnePageCheckoutProcessor method populateFulfillmentOptionsAndEstimationOnModel.
/**
* A helper method to retrieve all fulfillment options for the cart and estimate the cost of applying
* fulfillment options on the first shippable fulfillment group.
*/
protected void populateFulfillmentOptionsAndEstimationOnModel(Map<String, Object> localVars) {
List<FulfillmentOption> fulfillmentOptions = fulfillmentOptionService.readAllFulfillmentOptions();
Order cart = CartState.getCart();
if (!(cart instanceof NullOrderImpl) && cart.getFulfillmentGroups().size() > 0 && hasPopulatedShippingAddress(cart)) {
Set<FulfillmentOption> options = new HashSet<>();
options.addAll(fulfillmentOptions);
FulfillmentEstimationResponse estimateResponse = null;
try {
estimateResponse = fulfillmentPricingService.estimateCostForFulfillmentGroup(fulfillmentGroupService.getFirstShippableFulfillmentGroup(cart), options);
} catch (FulfillmentPriceException e) {
}
localVars.put("estimateResponse", estimateResponse);
}
localVars.put("fulfillmentOptions", fulfillmentOptions);
}
use of org.broadleafcommerce.core.order.domain.FulfillmentOption in project BroadleafCommerce by BroadleafCommerce.
the class SkuImpl method createOrRetrieveCopyInstance.
@Override
public <G extends Sku> CreateResponse<G> createOrRetrieveCopyInstance(MultiTenantCopyContext context) throws CloneNotSupportedException {
CreateResponse<G> createResponse = context.createOrRetrieveCopyInstance(this);
if (createResponse.isAlreadyPopulated()) {
return createResponse;
}
Sku cloned = createResponse.getClone();
cloned.setRetailPrice(getRetailPrice());
cloned.setSalePrice(getSalePrice());
cloned.setName(name);
cloned.setActiveEndDate(activeEndDate);
cloned.setActiveStartDate(activeStartDate);
cloned.setCurrency(currency);
cloned.setQuantityAvailable(quantityAvailable);
cloned.setDescription(description);
cloned.setDimension(dimension);
cloned.setDiscountable(isDiscountable());
cloned.setDisplayTemplate(displayTemplate);
cloned.setExternalId(externalId);
cloned.setTaxable(isTaxable());
cloned.setTaxCode(taxCode);
cloned.setUrlKey(urlKey);
cloned.setInventoryType(getInventoryType());
cloned.setFulfillmentType(getFulfillmentType());
cloned.setIsMachineSortable(isMachineSortable);
cloned.setLongDescription(longDescription);
cloned.setUpc(upc);
if (product != null) {
cloned.setDefaultProduct(product.createOrRetrieveCopyInstance(context).getClone());
}
if (product != null) {
cloned.setProduct(product.createOrRetrieveCopyInstance(context).getClone());
}
for (Map.Entry<String, SkuAttribute> entry : getSkuAttributes().entrySet()) {
SkuAttribute clonedEntry = entry.getValue().createOrRetrieveCopyInstance(context).getClone();
cloned.getSkuAttributes().put(entry.getKey(), clonedEntry);
}
for (SkuProductOptionValueXref entry : productOptionValueXrefs) {
SkuProductOptionValueXref clonedEntry = entry.createOrRetrieveCopyInstance(context).getClone();
cloned.getProductOptionValueXrefs().add(clonedEntry);
}
for (Map.Entry<String, SkuMediaXref> entry : skuMedia.entrySet()) {
SkuMediaXrefImpl clonedEntry = ((SkuMediaXrefImpl) entry.getValue()).createOrRetrieveCopyInstance(context).getClone();
cloned.getSkuMediaXrefIgnoreDefaultSku().put(entry.getKey(), clonedEntry);
}
for (FulfillmentOption entry : excludedFulfillmentOptions) {
FulfillmentOption clonedEntry = entry.createOrRetrieveCopyInstance(context).getClone();
cloned.getExcludedFulfillmentOptions().add(clonedEntry);
}
for (Map.Entry<FulfillmentOption, BigDecimal> entry : fulfillmentFlatRates.entrySet()) {
FulfillmentOption clonedEntry = entry.getKey().createOrRetrieveCopyInstance(context).getClone();
cloned.getFulfillmentFlatRates().put(clonedEntry, entry.getValue());
}
return createResponse;
}
use of org.broadleafcommerce.core.order.domain.FulfillmentOption 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;
}
Aggregations