package org.xmx0632.deliciousfruit.service;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xmx0632.deliciousfruit.api.v1.bo.Result;
import org.xmx0632.deliciousfruit.api.v1.bo.SettlementRequest;
import org.xmx0632.deliciousfruit.api.v1.bo.SettlementRequest.ShoppingItem;
import org.xmx0632.deliciousfruit.api.v1.bo.SettlementResponse;
import org.xmx0632.deliciousfruit.api.v1.bo.SettlementResponse.ProductFreeInfo;
import org.xmx0632.deliciousfruit.api.v1.bo.SettlementResponse.PromotionDetails;
import org.xmx0632.deliciousfruit.entity.FruitProduct;
import org.xmx0632.deliciousfruit.entity.FruitPromotion;
import org.xmx0632.deliciousfruit.entity.FruitSubPromotion;
import org.xmx0632.deliciousfruit.global.ConfigConstant;
import org.xmx0632.deliciousfruit.utilities.date.DateUtil;
/**
* 与客户端IOS的订购逻辑,客户端把商品加入购物车后,计算当前购物车中的商品总价,以及提示满足促销条件的差额信息
*
* @author xmx0632
*
*/
// Spring Bean的标识.
@Component
public class IosOrderService {
private static Logger log = LoggerFactory.getLogger(IosOrderService.class);
@Autowired
private FruitPromotionService fruitPromotionService;
@Autowired
private TransactionIDService transactionIDService;
@Autowired
private FruitProductService fruitProductService;
@Autowired
private DateUtil dateUtil;
@Autowired
private ConfigService configService;
// 优惠活动的粒度一般不会精确到分钟,查询粒度精确到小时便于有效利用查询缓存
private String pattern = "yyyy-MM-dd HH";
/**
* 按照促销规则,计算优惠信息
*
* @param settlementRequest
* @return
*/
public SettlementResponse caculatePromotionInfo(
SettlementRequest settlementRequest) {
String transactionID = StringUtils.isBlank(settlementRequest
.getTransactionID()) ? transactionIDService.getTransactionId()
: settlementRequest.getTransactionID();
log.debug("transactionID:{}", transactionID);
SettlementResponse response = new SettlementResponse();
response.setTransactionID(transactionID);
response.setResult(new Result(Result.SUCCESS, ""));
BigDecimal actualTotalPrice = new BigDecimal(0);
BigDecimal originalTotalPrice = new BigDecimal(0);
// 计算购物单价格
Date currentTime = dateUtil.getCurrentDate(pattern);
List<ShoppingItem> shopList = settlementRequest.getShoppingList();
for (ShoppingItem shoppingItem : shopList) {
String strProductId = shoppingItem.getProductId();
Long productId = Long.valueOf(strProductId);
int quantity = shoppingItem.getQuantity();
log.debug("productId:{},quantity:{}", strProductId, quantity);
// a)根据[商品*数量]计算对应的价格,
// 如果有对应的单品促销规则,重新按照单品促销规则计算优惠价格;如果未满足促销条件,则提示要满足促销条件的最低差额
FruitProduct fruitProduct = fruitProductService
.findByProductId(strProductId);
BigDecimal e6Price = fruitProduct.getE6Price();
BigDecimal currentTotalPrice = e6Price.multiply(BigDecimal
.valueOf(quantity));
originalTotalPrice = originalTotalPrice.add(currentTotalPrice);
// 单品第二件满就减
actualTotalPrice = deductForSecond(response, actualTotalPrice,
quantity, fruitProduct, e6Price, currentTotalPrice);
// 单品满就送
actualTotalPrice = giftProduct(response, actualTotalPrice,
currentTime, productId, quantity, fruitProduct,
currentTotalPrice);
}
String totalDeductFirst = configService
.getByName(ConfigConstant.TOTAL_DEDUCT_FIRST);
log.debug("totalDeductFirst:{}", totalDeductFirst);
if ("true".equalsIgnoreCase(totalDeductFirst)) {
// 全场满立减
actualTotalPrice = deductTotal(response, actualTotalPrice,
originalTotalPrice, currentTime);
// 全场送
giftTotal(response, actualTotalPrice, currentTime);
} else {
// 全场送
giftTotal(response, actualTotalPrice, currentTime);
// 全场满立减
actualTotalPrice = deductTotal(response, actualTotalPrice,
originalTotalPrice, currentTime);
}
boolean freightForFree = actualTotalPrice.compareTo(BigDecimal
.valueOf(100.0)) >= 0;
BigDecimal freightPay = freightForFree ? BigDecimal.valueOf(0.0)
: BigDecimal.valueOf(10.0);
response.setFreightPay(freightPay);
response.setActualAmount(actualTotalPrice);
response.setTotalPrice(originalTotalPrice);
return response;
}
private BigDecimal deductForSecond(SettlementResponse response,
BigDecimal actualTotalPrice, int quantity,
FruitProduct fruitProduct, BigDecimal e6Price,
BigDecimal currentTotalPrice) {
if (deductForSecondProduct(fruitProduct)) {
int deductPriceProductNum = quantity / 2;
int orginalPriceNum = isOdd(quantity) ? (deductPriceProductNum + 1)
: deductPriceProductNum;
BigDecimal orginalPrice = e6Price.multiply(BigDecimal
.valueOf(orginalPriceNum));
BigDecimal deductPrice = e6Price.subtract(
fruitProduct.getDeductForSecond()).multiply(
BigDecimal.valueOf(deductPriceProductNum));
BigDecimal actualProductPrice = orginalPrice.add(deductPrice);
actualTotalPrice = actualTotalPrice.add(actualProductPrice);
// 添加享受到的优惠信息
BigDecimal priceOff = currentTotalPrice
.subtract(actualProductPrice);
if (priceOff.compareTo(BigDecimal.ZERO) > 0) {
log.debug("deduct for 2nd product:[{}] {} times.",
fruitProduct.getProductName(), deductPriceProductNum);
PromotionDetails pdForProduct = response.getPromotionInfo()
.getPromotionForProduct();
pdForProduct.getProductsFree().add(
new ProductFreeInfo(fruitProduct.getProductName(),
deductPriceProductNum, fruitProduct.getUnit(),
fruitProduct.getSpec()));
pdForProduct.addPriceOff(priceOff);
}
// 第二件立减不需要提示促销信息
}
return actualTotalPrice;
}
private BigDecimal giftProduct(SettlementResponse response,
BigDecimal actualTotalPrice, Date currentTime, Long productId,
int quantity, FruitProduct fruitProduct,
BigDecimal currentTotalPrice) {
List<FruitPromotion> giftProductPromotions = fruitPromotionService
.getAvailablePromotionBy(currentTime,
FruitPromotion.PromotionType.PRODUCT_GIFT, productId);
log.debug("giftProductPromotions size:{}", giftProductPromotions.size());
// 如果不是第二件满立减,需要按照正常价格累加
if (!deductForSecondProduct(fruitProduct)) {
actualTotalPrice = actualTotalPrice.add(currentTotalPrice);
}
if (!giftProductPromotions.isEmpty()) {
// 遍历促销规则
for (FruitPromotion fruitPromotion : giftProductPromotions) {
int promotionThreshold = fruitPromotion.getFruitSubPromotion()
.getPromotionThreshold();
FruitProduct promotionProduct = fruitPromotion
.getFruitSubPromotion().getPromotionProduct();
log.debug("promotionThreshold:{}", promotionThreshold);
// 享受优惠的次数
int promotionProductNum = quantity / promotionThreshold;
log.debug("promotionProductNum:{}", promotionProductNum);
if (promotionProductNum > 0) {
if (promotionProduct != null) {
log.debug("gift product :[{}] {} times.",
promotionProduct.getProductName(),
promotionProductNum);
// 送礼
ProductFreeInfo gift = new ProductFreeInfo(
promotionProduct.getProductName(),
promotionProductNum,
promotionProduct.getUnit(),
promotionProduct.getSpec());
response.getPromotionInfo().getPromotionForProduct()
.addProductsFree(gift);
}
}
// 提示"购满2个苹果就送1个橘子,循环送哦亲"
String promotionTip = String.format("购满%s%s%s就送%s个%s,循环送哦亲.",
promotionThreshold, fruitProduct.getSpec(),
fruitProduct.getProductName(), "1",
promotionProduct.getProductName());
response.addPromotionTip(promotionTip);
}
}
return actualTotalPrice;
}
private BigDecimal deductTotal(SettlementResponse response,
BigDecimal actualTotalPrice, BigDecimal originalTotalPrice,
Date currentTime) {
List<FruitPromotion> deductTotalPromotions = fruitPromotionService
.getAvailablePromotionBy(currentTime,
FruitPromotion.PromotionType.TOTAL_DEDUCT);
log.debug("deductTotalPromotions size:{}", deductTotalPromotions.size());
if (!deductTotalPromotions.isEmpty()) {
// 计算
for (FruitPromotion fruitPromotion : deductTotalPromotions) {
BigDecimal promotionTotalPriceoff = fruitPromotion
.getTotalPriceoff();
BigDecimal promotionPriceOff = fruitPromotion.getPriceoff();
BigDecimal currentProductPriceoff = BigDecimal.ZERO;
// 全场满FruitPromotion.totalPriceoff,立减(FruitPromotion.priceoff)金额,跟FruitSubPromotion没关系
if (actualTotalPrice.compareTo(promotionTotalPriceoff) >= 0) {
int promotionProductNum = actualTotalPrice.divide(
promotionTotalPriceoff, BigDecimal.ROUND_HALF_UP)
.intValue();
// 开始减价
BigDecimal priceoffOfProduct = promotionPriceOff
.multiply(BigDecimal.valueOf(promotionProductNum));
currentProductPriceoff = currentProductPriceoff
.add(priceoffOfProduct);
actualTotalPrice = actualTotalPrice
.subtract(currentProductPriceoff);
log.debug("total deduct {}*{} = {} when exceed ${}",
promotionProductNum, promotionPriceOff,
priceoffOfProduct, promotionTotalPriceoff);
}
// 提示优惠规则
String promotionTip = String.format("购满%s元,立减%s元,循环减哦亲.",
promotionTotalPriceoff, promotionPriceOff);
response.addPromotionTip(promotionTip);
}
// 满立减多少元
response.getPromotionInfo().getPromotionForTotal()
.addPriceOff(originalTotalPrice.subtract(actualTotalPrice));
}
return actualTotalPrice;
}
private void giftTotal(SettlementResponse response,
BigDecimal actualTotalPrice, Date currentTime) {
List<FruitPromotion> giftTotalPromotions = fruitPromotionService
.getAvailablePromotionBy(currentTime,
FruitPromotion.PromotionType.TOTAL_GIFT);
log.debug("giftTotalPromotions size:{}", giftTotalPromotions.size());
if (!giftTotalPromotions.isEmpty()) {
for (FruitPromotion fruitPromotion : giftTotalPromotions) {
BigDecimal totalGift = fruitPromotion.getTotalGift();
FruitSubPromotion fruitSubPromotion = fruitPromotion
.getFruitSubPromotion();
// 全场满FruitPromotion.totalGift
// 送1单位(FruitSubPromotion.unit)FruitSubPromotion.promotionProductId对应的商品
if (actualTotalPrice.compareTo(totalGift) >= 0) {
int promotionProductNum = actualTotalPrice.divide(
totalGift, BigDecimal.ROUND_HALF_UP).intValue();
log.debug("gift total with product:[{}] {} times.",
fruitSubPromotion.getPromotionProductName(),
promotionProductNum);
// 送礼物
ProductFreeInfo gift = new ProductFreeInfo(
fruitSubPromotion.getPromotionProductName(),
promotionProductNum, fruitSubPromotion.getUnit(),
fruitSubPromotion.getSpec());
response.getPromotionInfo().getPromotionForProduct()
.addProductsFree(gift);
}
// 提示"购满X元就送1个橘子,循环送哦亲"
String unit = fruitSubPromotion.getUnit();
String promotionProductName = fruitSubPromotion
.getPromotionProductName();
String promotionTip = String.format("购满%s元,就送%s%s%s,循环送哦亲.",
totalGift.toString(), 1, unit, promotionProductName);
response.addPromotionTip(promotionTip);
}
}
}
// 单品第二件满就减(看产品表里第二件立减金额是不是大于0)
private boolean deductForSecondProduct(FruitProduct fruitProduct) {
return fruitProduct.getDeductForSecond().compareTo(BigDecimal.ZERO) > 0;
}
private boolean isOdd(int quantity) {
return quantity % 2 == 1;
}
}