/*
* #%L
* BroadleafCommerce Framework
* %%
* Copyright (C) 2009 - 2013 Broadleaf Commerce
* %%
* 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.
* #L%
*/
package org.broadleafcommerce.core.offer.service.discount.domain;
import org.broadleafcommerce.common.money.Money;
import org.broadleafcommerce.core.offer.domain.Offer;
import org.broadleafcommerce.core.offer.service.type.OfferDiscountType;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class PromotableOrderAdjustmentImpl implements PromotableOrderAdjustment {
private static final long serialVersionUID = 1L;
protected PromotableCandidateOrderOffer promotableCandidateOrderOffer;
protected PromotableOrder promotableOrder;
protected Money adjustmentValue;
protected Offer offer;
protected boolean roundOfferValues = true;
protected int roundingScale = 2;
protected RoundingMode roundingMode = RoundingMode.HALF_EVEN;
public PromotableOrderAdjustmentImpl(PromotableCandidateOrderOffer promotableCandidateOrderOffer, PromotableOrder promotableOrder) {
assert (promotableOrder != null);
assert (promotableCandidateOrderOffer != null);
this.promotableCandidateOrderOffer = promotableCandidateOrderOffer;
this.promotableOrder = promotableOrder;
this.offer = promotableCandidateOrderOffer.getOffer();
computeAdjustmentValue();
}
public PromotableOrderAdjustmentImpl(PromotableCandidateOrderOffer promotableCandidateOrderOffer,
PromotableOrder promotableOrder, Money adjustmentValue) {
this(promotableCandidateOrderOffer, promotableOrder);
if (promotableOrder.isIncludeOrderAndItemAdjustments()) {
this.adjustmentValue = adjustmentValue;
}
}
@Override
public PromotableOrder getPromotableOrder() {
return promotableOrder;
}
@Override
public Offer getOffer() {
return offer;
}
/*
* Calculates the value of the adjustment by first getting the current value of the order and then
* calculating the value of this adjustment.
*
* If this adjustment value is greater than the currentOrderValue (e.g. would make the order go negative
* then the adjustment value is set to the value of the order).
*/
protected void computeAdjustmentValue() {
adjustmentValue = new Money(promotableOrder.getOrderCurrency());
Money currentOrderValue = promotableOrder.calculateSubtotalWithAdjustments();
// We also need to consider order offers that have been applied when figuring out if the current value of this
// adjustment will be more than the current subtotal of the order
currentOrderValue = currentOrderValue.subtract(promotableOrder.calculateOrderAdjustmentTotal());
// Note: FIXED_PRICE not calculated as this is not a valid option for offers.
if (offer.getDiscountType().equals(OfferDiscountType.AMOUNT_OFF)) {
adjustmentValue = new Money(offer.getValue(), promotableOrder.getOrderCurrency());
} else if (offer.getDiscountType().equals(OfferDiscountType.PERCENT_OFF)) {
BigDecimal offerValue = currentOrderValue.getAmount().multiply(offer.getValue().divide(new BigDecimal("100"), 5, RoundingMode.HALF_EVEN));
if (isRoundOfferValues()) {
offerValue = offerValue.setScale(roundingScale, roundingMode);
}
adjustmentValue = new Money(offerValue, promotableOrder.getOrderCurrency(), 5);
}
if (currentOrderValue.lessThan(adjustmentValue)) {
adjustmentValue = currentOrderValue;
}
}
@Override
public Money getAdjustmentValue() {
return adjustmentValue;
}
/**
* It is sometimes problematic to offer percentage-off offers with regards to rounding. For example,
* consider an item that costs 9.99 and has a 50% promotion. To be precise, the offer value is 4.995,
* but this may be a strange value to display to the user depending on the currency being used.
*/
public boolean isRoundOfferValues() {
return roundOfferValues;
}
/**
* @see #isRoundOfferValues()
*
* @param roundingScale
*/
public void setRoundingScale(int roundingScale) {
this.roundingScale = roundingScale;
}
public int getRoundingScale() {
return roundingScale;
}
/**
* @see #isRoundOfferValues()
*
* @param roundingMode
*/
public void setRoundingMode(RoundingMode roundingMode) {
this.roundingMode = roundingMode;
}
public RoundingMode getRoundingMode() {
return roundingMode;
}
@Override
public boolean isCombinable() {
Boolean combinable = offer.isCombinableWithOtherOffers();
return (combinable != null && combinable);
}
@Override
public boolean isTotalitarian() {
Boolean totalitarian = offer.isTotalitarianOffer();
return (totalitarian != null && totalitarian.booleanValue());
}
}