// 根据拆分规则及商品列表取得可能的Rule列表(排序后的)(商品列表中任一商品都不支持的Rule不返回) public List <List <RuleEntity> > GetRuleEntities(SplitPrinciple splitPrinciple, List <ProductEntity> pel) { return(GetRuleEntities(ruleEntityList, pel)); }
// TODO(liuxin)(算法升级):把所有可能全返回,外层在此基础上再跑,最终把所有可能全集中到一起判断最优解 public Tuple <SplitedOrder, List <ProductEntity> > Split(List <ProductEntity> productList, /*int totalQuantity, */ SplitPrinciple splitPrinciple, bool withTax) { var result = Tuple.Create(new SplitedOrder(), productList); if ((productList == null) || (productList.Count <= 0) || splitPrinciple == SplitPrinciple.SpeedFirst) { // 无单可拆,直接返回 return(result); } var productListCount = productList.Count; var resultGroups = getEntities(productList).Select(l => Split(SplitPackage.SplitV1.Common.Common.CloneProductEntityList(productList), l, withTax)).ToList(); var msgs = Enumerable.Repeat(string.Format("RuleEntity.Split({0}, {1}, {2}) alternative:", "productList.Count=" + productListCount, "splitPrinciple=" + splitPrinciple, "withTax=" + withTax), 1) .Concat(resultGroups.Select(ret => string.Format(" ({0}, {1})", ret.Item1, "[" + string.Join(", ", ret.Item2) + "]"))); LogHelper.Logger.Info(string.Join(Environment.NewLine, msgs)); var resultGroup = resultGroups.GroupBy(t => t.Item2.Count).OrderBy(g => g.Key).FirstOrDefault(); if (resultGroup != null) { switch (splitPrinciple) { case SplitPrinciple.QuanlityFirst: result = resultGroup.OrderBy(t => t.Item1.OrderList.Count).FirstOrDefault() ?? result; break; case SplitPrinciple.PriceFirst: case SplitPrinciple.LogisticsFirst: default: result = resultGroup.OrderBy(t => t.Item1.CalculateLogisticsCost()).FirstOrDefault() ?? result; break; } } return(result); }
private Tuple <SplitedOrder, List <ProductEntity> > SplitOnceWithOrganization(List <ProductEntity> productList, List <RuleEntity> rules, SplitPrinciple splitPrinciple) { var splitedOrder = new SplitedOrder(); var restProductList = productList; for (int i = 0; i < rules.Count && restProductList.Count > 0; i++) { var tuple = rules[i].Split(restProductList, splitPrinciple, false); splitedOrder.AddSubOrderRange(tuple.Item1); restProductList = tuple.Item2; } return(Tuple.Create(splitedOrder, restProductList)); }
private Tuple <SplitedOrder, bool, List <ProductEntity> > SplitOnce(List <ProductEntity> productList, List <RuleEntity> rules, SplitPrinciple splitPrinciple) { var splitedOrder = new SplitedOrder(); var restProductList = productList; for (int i = 0; i < rules.Count && restProductList.Count > 0; i++) { var tuple = rules[i].Split(restProductList, splitPrinciple, false); splitedOrder.AddSubOrderRange(tuple.Item1); restProductList = tuple.Item2; } bool isTax = false; if (splitPrinciple != SplitPrinciple.LogisticsFirst && restProductList.Count > 0) { // 没拆完,按含税方式拆一遍 //for (int i = 0; i < rules.Count && restProductList.Count > 0; i++) //{ // var tuple = rules[i].Split(restProductList, splitPrinciple, true); // isTax |= tuple.Item1.OrderList.Count > 0; // splitedOrder.AddSubOrderRange(tuple.Item1); // restProductList = tuple.Item2; //} //if (restProductList.Count > 0) { // 还有剩余就按BC拆 isTax = true; //var subOrder = new SubOrder("-1", null, null, null, null, restProductList.SelectMany(pe => pe.OrderInfo).ToList()) //{ // LogisticsUnitPrice = decimal.MaxValue, // LogisticsCost = decimal.MaxValue, // TaxCost = decimal.MaxValue, //}; //splitedOrder.AddSubOrder(subOrder); splitedOrder.AddSubOrderRange(bcRuleEntity.Split(restProductList)); restProductList.Clear(); } } return(Tuple.Create(splitedOrder, isTax, restProductList)); }
private SplitedOrder SplitOrder(string orderId, List <ProductEntity> productList, List <Product> badProductList, int totalQuantity, SplitPrinciple splitPrinciple) { Debug.Assert(splitPrinciple != SplitPrinciple.LogisticsFirst); var result = new SplitedOrder(); List <List <RuleEntity> > ruleOptions = null; switch (splitPrinciple) { case SplitPrinciple.SpeedFirst: // BC break; //case SplitPrinciple.LogisticsFirst: case SplitPrinciple.QuanlityFirst: case SplitPrinciple.PriceFirst: default: ruleOptions = splitConfig.GetRuleEntities(splitPrinciple, productList); break; } if (ruleOptions != null && ruleOptions.Count > 0) { var splitResults = ruleOptions.Select(rules => SplitOnce(SplitPackage.Split.Common.Common.CloneProductEntityList(productList), rules, splitPrinciple)).ToList(); var msgs = Enumerable.Repeat(string.Format("Spliter.SplitOrder({0}, {1}, {2}, {3}) alternative:", "orderId=" + orderId, "productList.Count=" + productList.Count, "totalQuantity=" + totalQuantity, "splitPrinciple=" + splitPrinciple), 1) .Concat(splitResults.Select(ret => string.Format(" ({0}, {1}, {2})", ret.Item1, ret.Item2, "[" + string.Join(", ", ret.Item3) + "]"))); LogHelper.Logger.Info(string.Join(Environment.NewLine, msgs)); Tuple <SplitedOrder, bool, List <ProductEntity> > optimal = null; switch (splitPrinciple) { case SplitPrinciple.QuanlityFirst: optimal = splitResults.OrderBy(t => t.Item2 ? 0 : 1) .ThenBy(t => t.Item1.OrderList.Count) .ThenBy(t => t.Item1.CalculateLogisticsAndTaxCost()) .FirstOrDefault(); break; case SplitPrinciple.PriceFirst: case SplitPrinciple.LogisticsFirst: default: optimal = splitResults.OrderBy(t => t.Item2 ? 0 : 1) .ThenBy(t => t.Item1.CalculateLogisticsAndTaxCost()) .ThenBy(t => t.Item1.OrderList.Count) .FirstOrDefault(); break; } result = optimal != null ? optimal.Item1 : result; } else { // BC方式,计算跨境综合税 result = bcRuleEntity.Split(productList); } if (badProductList != null && badProductList.Any()) { var subOrder = new SubOrder("-2", null, null, null, null, null, badProductList) { LogisticsUnitPrice = int.MaxValue, LogisticsCost = int.MaxValue, TaxCost = int.MaxValue, }; result.AddSubOrder(subOrder); } result.OrderId = orderId; return(result); }
private Tuple <SplitedOrder, bool, List <ProductEntity> > SplitOnce(List <ProductEntity> productList, List <RuleEntity> rules, SplitPrinciple splitPrinciple) { var splitedOrder = new SplitedOrder(); var restProductList = productList; for (int i = 0; i < rules.Count && restProductList.Count > 0; i++) { var tuple = rules[i].Split(restProductList, splitPrinciple, false); splitedOrder.AddSubOrderRange(tuple.Item1); restProductList = tuple.Item2; } bool isTax = false; if (splitPrinciple != SplitPrinciple.LogisticsFirst && restProductList.Count > 0) { isTax = true; splitedOrder.AddSubOrderRange(this.ReturnRemainPackage(restProductList)); restProductList.Clear(); } return(Tuple.Create(splitedOrder, isTax, restProductList)); }
private SplitedOrder SplitOrder(string orderId, List <ProductEntity> productList, List <Product> badProductList, int totalQuantity, SplitPrinciple splitPrinciple) { Debug.Assert(splitPrinciple != SplitPrinciple.LogisticsFirst); var result = new SplitedOrder(); List <List <RuleEntity> > ruleOptions = null; switch (splitPrinciple) { case SplitPrinciple.SpeedFirst: break; case SplitPrinciple.QuanlityFirst: case SplitPrinciple.PriceFirst: default: ruleOptions = splitConfig.GetRuleEntities(splitPrinciple, productList); break; } if (ruleOptions != null && ruleOptions.Count > 0) { var splitResults = ruleOptions.Select(rules => SplitOnce(SplitPackage.SplitV1.Common.Common.CloneProductEntityList(productList), rules, splitPrinciple)).ToList(); Tuple <SplitedOrder, bool, List <ProductEntity> > optimal = null; switch (splitPrinciple) { case SplitPrinciple.QuanlityFirst: optimal = splitResults.OrderBy(t => t.Item2 ? 0 : 1) .ThenBy(t => t.Item1.OrderList.Count) .ThenBy(t => t.Item1.CalculateLogisticsAndTaxCost()) .FirstOrDefault(); break; case SplitPrinciple.PriceFirst: case SplitPrinciple.LogisticsFirst: default: optimal = splitResults.OrderBy(t => t.Item2 ? 0 : 1) .ThenBy(t => t.Item1.CalculateLogisticsAndTaxCost()) .ThenBy(t => t.Item1.OrderList.Count) .FirstOrDefault(); break; } result = optimal != null ? optimal.Item1 : result; } else { // BC方式,计算跨境综合税 result = this.ReturnRemainPackage(productList); } if (badProductList != null && badProductList.Any()) { var subOrder = new SubOrder("-2", null, null, null, null, null, badProductList) { LogisticsUnitPrice = int.MaxValue, LogisticsCost = int.MaxValue, TaxCost = int.MaxValue, }; result.AddSubOrder(subOrder); } result.OrderId = orderId; return(result); }