/// <summary> /// 获取促销结果 /// </summary> /// <param name="origComboList"></param> /// <param name="soInfo"></param> /// <param name="soItemList"></param> /// <param name="promotionInfoList"></param> protected virtual void GetPromotionListForSO(List <ComboInfo> origComboList, SOInfo soInfo, ref List <SOItemInfo> soItemList, ref List <SOPromotionInfo> promotionInfoList) { //1.取当前订单商品有效的Combo List <ComboInfo> validComboList = GetValidComboList(origComboList, soItemList); if (validComboList.Count == 0) { return; } //2.按照这些可以参与活动的Combo列表,得到所有的折扣列表: 遵循最大Combo折扣优先原则,而不是客户最大折扣优先原则 List <ComboApplyInstance> comboApplyList = new List <ComboApplyInstance>(); foreach (ComboInfo combo in validComboList) { ComboApplyInstance comboApply = new ComboApplyInstance(); ComboInfo comboClone = SerializationUtility.DeepClone <ComboInfo>(combo); comboApply.ComboSysNo = comboClone.SysNo.Value; //获取当前Combo在订单中最多可以存在多少套: 取订单中满足该Combo商品中最小数量 int maxCount = int.MaxValue; foreach (ComboItem comboItem in comboClone.Items) { SOItemInfo soItem = soItemList.Find(f => f.ProductSysNo == comboItem.ProductSysNo); int curCount = soItem.Quantity.Value / comboItem.Quantity.Value; if (curCount < maxCount) { maxCount = curCount; } } comboApply.Qty = maxCount; decimal totalDiscount = 0.00m; foreach (ComboItem comboItem in comboClone.Items) { totalDiscount += Math.Round(comboItem.Discount.Value * comboItem.Quantity.Value * maxCount, 2); } //取Combo Total Discount的绝对值 comboApply.TotalDiscount = Math.Abs(totalDiscount); comboApplyList.Add(comboApply); } //3.得到折扣从大到小排序的列表 var comboApplySortList = from p in comboApplyList orderby p.TotalDiscount descending select p; //4.取最大折扣的Combo ComboApplyInstance maxDiscountComboApply = comboApplySortList.First(); ComboInfo curCombo = validComboList.Find(f => f.SysNo.Value == maxDiscountComboApply.ComboSysNo); SOPromotionInfo promotionInfo = GetPromotionInfoForCurrentCombo(curCombo, maxDiscountComboApply, ref soItemList, promotionInfoList.Count + 1, soInfo.SysNo); if (promotionInfo != null) { promotionInfoList.Add(promotionInfo); } //5.轮询调用剩下的订单商品 GetPromotionListForSO(validComboList, soInfo, ref soItemList, ref promotionInfoList); }
/// <summary> /// 赠品方面的赠送处理 /// </summary> /// <param name="promotionInfo"></param> /// <param name="soInfo"></param> /// <param name="canPromotionSOItemList"></param> /// <param name="rule"></param> protected void CalcGiftItemRule(SOPromotionInfo promotionInfo, SOInfo soInfo, List <SOItemInfo> canPromotionSOItemList, PSGiftItemRule rule) { //如果是只有1个主商品进行赠品,那么赠品可以全部绑定在这个这主商品下 //如果是满足多个主商品才进行赠品,那么赠品无法绑定到各主商品下 if (promotionInfo.SOPromotionDetails.Count == 1) { SOPromotionDetailInfo detail = promotionInfo.SOPromotionDetails[0]; int masterProductSysNo = rule.MasterProductSysNoList[0].Value; // (detail.MasterProductSysNo.Value == masterProductSysNo) //{ //detail.GiftList = new List<SOPromotionInfo.GiftInfo>(); //rule.GiftItemSysNoList.ForEach(f => detail.GiftList.Add( // new SOPromotionInfo.GiftInfo() // { // ProductSysNo = f.GiftItemSysNo.Value, // Quantity = f.GiftItemCount.HasValue ? f.GiftItemCount.Value : 1 // })); //} } rule.GiftItemSysNoList.ForEach(f => promotionInfo.GiftList.Add( new SOPromotionInfo.GiftInfo() { ProductSysNo = f.GiftItemSysNo.Value, Quantity = f.GiftItemCount.HasValue ? f.GiftItemCount.Value : 1 })); }
private void CalcRecursive(List <SaleDiscountRule> allValidRule, List <SOItemInfo> itemList, int soSysNo, List <SOPromotionInfo> alreadyApplyPromoList, ref List <SOPromotionInfo> promoInfoList) { if (itemList.Count == 0) { return; } List <SOPromotionInfo> allPromoList = new List <SOPromotionInfo>(); //加上其它已有优惠信息 allPromoList.AddRange(alreadyApplyPromoList); //加上本类促销的优惠信息 allPromoList.AddRange(promoInfoList); List <SOPromotionInfo> tempList = new List <SOPromotionInfo>(); foreach (var rule in allValidRule) { SOPromotionInfo promotionInfo = ApplyingRule(rule, itemList, soSysNo, allPromoList); if (promotionInfo != null) { tempList.Add(promotionInfo); } } if (tempList.Count > 0) { //找出最优惠的活动 var promoSortList = tempList.OrderBy(p => p.DiscountAmount); SOPromotionInfo bestPromotionInfo = promoSortList.First(); //将最优的活动添加到应用列表中 promoInfoList.Add(bestPromotionInfo); //移除已参与应用的商品 foreach (var promoItem in bestPromotionInfo.SOPromotionDetails) { itemList.RemoveAll(item => item.ProductSysNo == promoItem.MasterProductSysNo); } //移除已参与的活动 allValidRule.RemoveAll(rule => rule.SysNo == bestPromotionInfo.PromotionSysNo); } else { return; } //继续递归应用 CalcRecursive(allValidRule, itemList, soSysNo, alreadyApplyPromoList, ref promoInfoList); }
/// <summary> /// 优惠券方面的赠送处理 /// </summary> /// <param name="promotionInfo"></param> /// <param name="soInfo"></param> /// <param name="canPromotionSOItemList"></param> /// <param name="rule"></param> protected void CalcCouponCodeRule(SOPromotionInfo promotionInfo, SOInfo soInfo, List <SOItemInfo> canPromotionSOItemList, PSCouponsRebateRule rule) { //如果是只有1个主商品进行赠送优惠券,那么赠送的优惠券可以全部绑定在这个这主商品下 //如果是满足多个主商品才进行赠送优惠券,那么赠送的优惠券无法绑定到各主商品下 if (promotionInfo.SOPromotionDetails.Count == 1) { if (!string.IsNullOrEmpty(rule.CouponCode)) { SOPromotionDetailInfo detail = promotionInfo.SOPromotionDetails[0]; //detail.CouponCodeList.Add(rule.CouponCode); } } if (!string.IsNullOrEmpty(rule.CouponCode)) { promotionInfo.CouponCodeList.Add(rule.CouponCode); } }
/// <summary> /// 积分方面的赠送处理 /// </summary> /// <param name="promotionInfo"></param> /// <param name="soInfo"></param> /// <param name="canPromotionSOItemList"></param> /// <param name="rule"></param> protected void CalcPointRule(SOPromotionInfo promotionInfo, SOInfo soInfo, List <SOItemInfo> canPromotionSOItemList, PSPointScoreRule rule) { if (!rule.PointScore.HasValue) { return; } int canSendPoint = rule.PointScore.Value; //开始分摊积分 decimal sumAmount = 0.00m; //能够参与活动的商品总金额 foreach (SOItemInfo item in canPromotionSOItemList) { sumAmount += Math.Round(item.OriginalPrice.Value * ((decimal)item.Quantity.Value), 2); } int allocatedPoint = 0; for (int i = 0; i < promotionInfo.SOPromotionDetails.Count; i++) { SOPromotionDetailInfo detail = promotionInfo.SOPromotionDetails[i]; if (i < promotionInfo.SOPromotionDetails.Count - 1) { SOItemInfo item = soInfo.Items.Find(f => f.ProductSysNo == detail.MasterProductSysNo); int currentPoint = Convert.ToInt32(canSendPoint * (item.OriginalPrice.Value * item.Quantity.Value / sumAmount)); detail.GainPoint = currentPoint; allocatedPoint += currentPoint; } else { detail.GainPoint = canSendPoint - allocatedPoint; } } }
/// <summary> /// 子订单促销活动分摊 /// </summary> /// <param name="masterSOInfo"></param> /// <param name="subSOInfo"></param> private void AssignSubSOPromotion(SOInfo subSOInfo) { #region 拆分订单的促销活动. //拆分订单的促销活动. if (CurrentSO.SOPromotions != null && CurrentSO.SOPromotions.Count > 0) { CurrentSO.SOPromotions.ForEach(promotion => { SOPromotionInfo promotionInfo = SerializationUtility.DeepClone(promotion); promotionInfo.SOSysNo = subSOInfo.SysNo; switch (promotion.PromotionType) { case SOPromotionType.Combo: break; case SOPromotionType.Coupon: if (promotionInfo.SOPromotionDetails != null && promotionInfo.SOPromotionDetails.Count > 0) { //移出主商品不在子订单中的促销明细 promotionInfo.SOPromotionDetails.RemoveAll(d => { return(!subSOInfo.Items.Exists(subSOItem => { return subSOItem.ProductSysNo == d.MasterProductSysNo; })); }); //计算子订单的总折扣 promotionInfo.DiscountAmount = promotionInfo.SOPromotionDetails.Sum <SOPromotionDetailInfo>(d => d.DiscountAmount); } if (promotionInfo.DiscountAmount == 0) { promotionInfo = null; } break; case SOPromotionType.SelfGift: //子订单中是否包含有赠品,没有就将促销设置为null. if (!promotionInfo.GiftList.Exists(g => { return(subSOInfo.Items.Exists(item => { return item.ProductType == SOProductType.SelfGift && g.ProductSysNo == item.ProductSysNo; })); })) { promotionInfo = null; } break; case SOPromotionType.VendorGift: case SOPromotionType.Accessory: //子订单是否包含附件或厂商赠品,如果没有就设置为null if (promotionInfo.SOPromotionDetails != null && promotionInfo.GiftList.Count > 0) { //移出不在子订单中的附件 promotionInfo.GiftList.RemoveAll(g => { return(!subSOInfo.Items.Exists(subSOItem => { return promotion.PromotionType == SOPromotionType.Accessory ? (subSOItem.ProductSysNo == g.ProductSysNo && subSOItem.ProductType == SOProductType.Accessory) : (subSOItem.ProductSysNo == g.ProductSysNo && subSOItem.ProductType == SOProductType.Gift); })); }); ////移出附件不在子订单中的附件明细 //if (promotionInfo.GiftList.Count < 1) //{ // promotionInfo.SOPromotionDetails.RemoveAll(d => // { // d.GiftList.RemoveAll(dg => // { // return !promotionInfo.GiftList.Exists(g => // { // return g.ProductSysNo == dg.ProductSysNo; // }); // }); // return d.GiftList.Count == 0; // }); //} } if (promotionInfo.GiftList.Count == 0) { promotionInfo = null; } break; } if (promotionInfo != null) { subSOInfo.SOPromotions.Add(promotionInfo); } }); } #endregion }
private SOPromotionInfo ApplyingRule(SaleDiscountRule rule, List <SOItemInfo> itemList, int soSysNo, List <SOPromotionInfo> alreadyApplyPromoList) { List <SOPromotionDetailInfo> promoDetailList = new List <SOPromotionDetailInfo>(); decimal totalAmt = 0; int totalQty = 0; List <SOItemInfo> matchedItemList = new List <SOItemInfo>(itemList.Count); foreach (var item in itemList) { //判断三级类别,品牌,商品ID条件满足 bool isItemMatch = IsCategoryBrandMatch(rule, item); if (isItemMatch) { //加入到匹配商品列表 matchedItemList.Add(item); if (!rule.IsSingle) { //计算商品已有折扣 decimal discountAmt = GetItemDiscount(item, alreadyApplyPromoList); //非单品标记时,计算总金额和总数量 totalAmt += item.Quantity.Value * item.Price.Value - discountAmt; totalQty += item.Quantity.Value; } } } //应用规则 if (rule.IsSingle) { foreach (var item in matchedItemList) { //计算商品已有折扣 decimal discountAmt = GetItemDiscount(item, alreadyApplyPromoList); int matchedTimes = IsSingleMatch(rule, item, discountAmt); if (matchedTimes > 0) { var promoDetail = CalcSingleDiscount(rule, item, matchedTimes); promoDetailList.Add(promoDetail); } } } else { //非单品,根据规则类型进一步判断 if (totalAmt > 0 && totalQty > 0) { int matchedTimes = 0; if (rule.RuleType == SaleDiscountRuleType.AmountRule) { matchedTimes = CalcTimesByAmt(rule, totalAmt); } else { matchedTimes = CalcTimesByQty(rule, totalQty); } if (matchedTimes > 0) { var detailList = CalcNotSingleDiscount(rule, matchedItemList, totalAmt, totalQty, matchedTimes, alreadyApplyPromoList); promoDetailList.AddRange(detailList); } } } SOPromotionInfo promotionInfo = null; if (promoDetailList.Count > 0) { //生成SOPromotionInfo信息 promotionInfo = new SOPromotionInfo(); promotionInfo.PromotionType = SOPromotionType.SaleDiscountRule; promotionInfo.PromotionSysNo = rule.SysNo; promotionInfo.PromotionName = rule.ActivityName; promotionInfo.DiscountAmount = -1 * promoDetailList.Sum(item => item.DiscountAmount.Value); promotionInfo.GainPoint = 0; promotionInfo.Priority = 0; promotionInfo.Time = 1; promotionInfo.SOSysNo = soSysNo; promotionInfo.VendorSysNo = rule.VendorSysNo ?? 0; promotionInfo.PromoRuleData = SerializationUtility.XmlSerialize(rule); promotionInfo.Discount = promotionInfo.DiscountAmount; promotionInfo.SOPromotionDetails = promoDetailList; } return(promotionInfo); }
/// <summary> /// 根据当前Combo,得到该Combo在订单中的SOPromotionInfo /// </summary> /// <param name="curCombo"></param> /// <param name="comboApply"></param> /// <param name="soItemList"></param> /// <param name="priority"></param> /// <param name="soSysNo"></param> /// <returns></returns> protected virtual SOPromotionInfo GetPromotionInfoForCurrentCombo(ComboInfo curCombo, ComboApplyInstance comboApply, ref List <SOItemInfo> soItemList, int priority, int?soSysNo) { SOPromotionInfo promotionInfo = null; int maxCount = comboApply.Qty; if (maxCount > 0) { //说明当前订单剩余商品还可以满足这个Combo promotionInfo = new SOPromotionInfo(); promotionInfo.PromotionType = SOPromotionType.Combo; promotionInfo.Combo = curCombo; promotionInfo.PromotionSysNo = curCombo.SysNo.Value; promotionInfo.PromotionName = curCombo.Name != null ? curCombo.Name.Content : null; promotionInfo.DiscountAmount = -Math.Abs(comboApply.TotalDiscount); promotionInfo.GainPoint = 0; promotionInfo.Priority = priority; promotionInfo.SOSysNo = soSysNo; promotionInfo.Time = maxCount; if (promotionInfo.Time > 0) { promotionInfo.Discount = promotionInfo.DiscountAmount / promotionInfo.Time; } StringBuilder promotionNote = new StringBuilder(); promotionInfo.SOPromotionDetails = new List <SOPromotionDetailInfo>(); foreach (ComboItem comboItem in curCombo.Items) { SOPromotionDetailInfo promotionDetail = new SOPromotionDetailInfo(); promotionDetail.DiscountAmount = Math.Abs(Math.Round(comboItem.Discount.Value * comboItem.Quantity.Value * maxCount, 2)); promotionDetail.GainPoint = 0; promotionDetail.MasterProductQuantity = comboItem.Quantity.Value * maxCount; promotionDetail.MasterProductSysNo = comboItem.ProductSysNo.Value; //promotionDetail.MasterProductType = SOProductType.Product; promotionInfo.SOPromotionDetails.Add(promotionDetail); promotionNote.AppendFormat("{0},{1},-{2};", promotionDetail.MasterProductQuantity, promotionDetail.MasterProductSysNo, promotionDetail.DiscountAmount); //最重要的一点:要从soItemList中减掉这些已经做了折扣的商品及数量 //如果数量没减完,则在soItemList中保留该Item,但是数量要减掉;如果数量减完,则从soItemList中Remove掉改Item List <SOItemInfo> needRemoveSOItemList = new List <SOItemInfo>(); foreach (SOItemInfo soItem in soItemList) { if (soItem.ProductSysNo == comboItem.ProductSysNo) { soItem.OriginalPrice = soItem.OriginalPrice + comboItem.Discount; //有折扣总价减去折扣 Bug:89610 if (soItem.Quantity > comboItem.Quantity.Value * maxCount) { soItem.Quantity = soItem.Quantity - comboItem.Quantity.Value * maxCount; } else { needRemoveSOItemList.Add(soItem); } } } foreach (SOItemInfo soItem in needRemoveSOItemList) { soItemList.Remove(soItem); } } promotionInfo.Note = promotionNote.ToString(); } return(promotionInfo); }
/// <summary> /// 金额方面的折扣处理:目前价格方面的折扣与总金额方面的折扣不可并存 /// </summary> /// <param name="promotionInfo"></param> /// <param name="soInfo"></param> /// <param name="canPromotionSOItemList"></param> protected void CalcAmountRule(SOPromotionInfo promotionInfo, SOInfo soInfo, List <SOItemInfo> canPromotionSOItemList, CouponsInfo couponsInfo) { PSOrderAmountDiscountRule ruleAmount = couponsInfo.OrderAmountDiscountRule; List <PSPriceDiscountRule> rulePriceList = couponsInfo.PriceDiscountRule; decimal sumAllItemPriceAmount = 0.00m; //能够参与活动的商品总金额,所有商品原价乘以数量的总金额 decimal sumAllOrderItemAmount = 0.00m; //所有订单商品的商品总金额,用于计算优惠券平摊金额 decimal saleRulePromotionAmount = 0.00m; //除去优惠券后,其它优惠金额总额 decimal soItemAmount = soInfo.BaseInfo.SOAmount.Value; //订单商品实际总金额,已经扣去了Combo等折扣 decimal?orderMaxDiscount = null; //本活动中设置的每单折扣上限 decimal calcDiscountAmount = 0.00m; //计算出来的折扣 foreach (SOItemInfo item in canPromotionSOItemList) { sumAllItemPriceAmount += Math.Round(item.OriginalPrice.Value * ((decimal)item.Quantity.Value), 2); } foreach (var item in soInfo.Items) { if (item.ProductType.Value == SOProductType.Product || item.ProductType.Value == SOProductType.ExtendWarranty) { sumAllOrderItemAmount += item.OriginalPrice.Value * ((decimal)item.Quantity.Value); saleRulePromotionAmount += item.PromotionAmount ?? 0.00M; } } #region 计算总金额方面的折扣 if (ruleAmount != null && ruleAmount.OrderAmountDiscountRank != null && ruleAmount.OrderAmountDiscountRank.Count > 0) { calcDiscountAmount = 0.00m; orderMaxDiscount = ruleAmount.OrderMaxDiscount; if (ruleAmount.OrderAmountDiscountRank != null && ruleAmount.OrderAmountDiscountRank.Count > 0) { //首先确认取折扣信息时,根据限定金额Amount倒序 var ruleAmountDiscountRankNew = from p in ruleAmount.OrderAmountDiscountRank orderby p.OrderMinAmount descending select p; foreach (OrderAmountDiscountRank rank in ruleAmountDiscountRankNew) { decimal minAmount = rank.OrderMinAmount.HasValue ? rank.OrderMinAmount.Value : 0.00m; if (couponsInfo.ProductRangeType == CouponsProductRangeType.AllProducts && sumAllItemPriceAmount < minAmount) { //普通订单商品(SOItemInfo.ProductType==SOProductType.Product的商品)的总金额与限定金额值比较,跳过不满足条件价格条件。 continue; } if (soItemAmount >= minAmount) { if (rank.DiscountType.Value == PSDiscountTypeForOrderAmount.OrderAmountPercentage) { calcDiscountAmount = Math.Round(soItemAmount * rank.DiscountValue.Value, 2); } if (rank.DiscountType.Value == PSDiscountTypeForOrderAmount.OrderAmountDiscount) { calcDiscountAmount = Math.Round(rank.DiscountValue.Value, 2); } break; } } } } #endregion #region 计算商品价格方面的折扣 if (rulePriceList != null && rulePriceList.Count > 0) { calcDiscountAmount = 0.00m; List <PSPriceDiscountRule> discountList = rulePriceList.FindAll(f => f.DiscountType == PSDiscountTypeForProductPrice.ProductPriceDiscount); List <PSPriceDiscountRule> finalList = rulePriceList.FindAll(f => f.DiscountType == PSDiscountTypeForProductPrice.ProductPriceFinal); //如果商品价格是直接折扣 if (discountList != null && discountList.Count > 0) { var discountListNew = from p in discountList orderby p.MinQty descending select p; foreach (SOItemInfo item in canPromotionSOItemList) { foreach (PSPriceDiscountRule prule in discountListNew) { int minQty = prule.MinQty.HasValue ? prule.MinQty.Value : 1; if (item.Quantity >= minQty) { calcDiscountAmount += Math.Round(prule.DiscountValue.Value * item.Quantity.Value, 2); break; } } } } //如果是最终售价 if (finalList != null && finalList.Count > 0) { var finalListNew = from p in finalList orderby p.MinQty descending select p; foreach (SOItemInfo item in canPromotionSOItemList) { foreach (PSPriceDiscountRule prule in finalListNew) { int minQty = prule.MinQty.HasValue ? prule.MinQty.Value : 1; if (item.Quantity >= minQty) { //当单个商品 最终售价大于商品售价时 if (prule.DiscountValue.Value >= item.Price.Value) { calcDiscountAmount += 0.00m; } else { calcDiscountAmount += Math.Round((item.Price.Value - prule.DiscountValue.Value) * item.Quantity.Value, 2); } break; } } } } } #endregion #region 得到真正最终可以折扣的金额 decimal canDiscountAmount = calcDiscountAmount; if (orderMaxDiscount.HasValue) { if (calcDiscountAmount <= orderMaxDiscount.Value) { canDiscountAmount = calcDiscountAmount; } else { canDiscountAmount = Math.Round(orderMaxDiscount.Value, 2); } } promotionInfo.DiscountAmount = Math.Abs(canDiscountAmount); #endregion #region 开始分摊折扣金额 if (promotionInfo.DiscountAmount == 0.00m) { return; } //最后一个Item要特殊处理,要用总折扣减去前边所有item的折扣合 decimal allocatedDiscount = 0.00m; decimal actualAllItemPriceAmount = sumAllOrderItemAmount + saleRulePromotionAmount; if (actualAllItemPriceAmount != 0) { for (int i = 0; i < promotionInfo.SOPromotionDetails.Count; i++) { SOPromotionDetailInfo detail = promotionInfo.SOPromotionDetails[i]; SOItemInfo item = soInfo.Items.Find(f => f.ProductSysNo == detail.MasterProductSysNo); //除去套餐优惠金额 decimal pTotal = item.OriginalPrice.Value * item.Quantity.Value + item.PromotionAmount ?? 0; if (i < promotionInfo.SOPromotionDetails.Count - 1) { //decimal currentDiscount=decimal.Floor((canDiscountAmount * (pTotal / sumAllItemPriceAmount)) * 100) / 100; decimal currentDiscount = canDiscountAmount * (pTotal / actualAllItemPriceAmount); //只保留小数点后两位,Bug:89610 currentDiscount = Math.Abs(currentDiscount); currentDiscount = Math.Min(currentDiscount, pTotal); detail.DiscountAmount = currentDiscount; allocatedDiscount += currentDiscount; } else { detail.DiscountAmount = Math.Abs(canDiscountAmount - allocatedDiscount); detail.DiscountAmount = Math.Min(detail.DiscountAmount.Value, pTotal); } } } #endregion }