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; } }