Пример #1
0
        /// <summary>
        /// 先按BC方式拆单,BC拆完仍有剩余时,全部放到一个子订单中(里面的费用全设为MaxValue)
        /// </summary>
        /// <param name="productList"></param>
        /// <returns></returns>
        public SplitedOrder Split(List <ProductEntity> productList /*, int totalQuantity*/)
        {
            var result = new SplitedOrder();

            var peTuple = SplitProductEntity(productList, (decimal)this.BcConfig.TotalPriceLimit);

            // 额度(2万)以后按BC拆单
            var subOrder = CreateSubOrder();

            peTuple.Item1.ForEach(pe => subOrder.ProList.AddRange(pe.OrderInfo));
            subOrder.TaxCost = CalculateTax(peTuple.Item1);
            result.AddSubOrder(subOrder);

            if (peTuple.Item2.Count > 0)
            {
                // 超过额度的不拆了,卖不了
                var invalidSubOrder = new SubOrder("-1", null, null, null, null, null, peTuple.Item2.SelectMany(pe => pe.OrderInfo).ToList())
                {
                    LogisticsUnitPrice = int.MaxValue,
                    LogisticsCost      = int.MaxValue,
                    TaxCost            = int.MaxValue,
                };
                result.AddSubOrder(invalidSubOrder);
            }

            result.OrderList.ForEach(so => so.LogisticsCost = this.CalculateFreight(so.CalculateTotalWeight()));
            result.OrderList.ForEach(so => so.CalculateTotalPrice());
            return(result);
        }
Пример #2
0
        /// <summary>
        /// 根据给予的组合规则进行拆单操作
        /// </summary>
        /// <param name="productList">订单商品明细</param>
        /// <param name="rules">按层面整合的符合规则</param>
        /// <param name="withTax">是否收税</param>
        /// <returns>可拆解的订单,未能拆解的订单</returns>
        private Tuple <SplitedOrder, List <ProductEntity> > Split(List <ProductEntity> productList, List <List <IProductRuleEntity> > rules, bool withTax)
        {
            var result          = new SplitedOrder();
            var restProductList = productList;

            for (int i = 0; i < rules.Count && restProductList.Count > 0; i++)
            {
                var l = rules[i];
                for (int j = 0; j < l.Count && restProductList.Count > 0; j++)
                {
                    var r = l[j];
                    while (restProductList.Count > 0)
                    {
                        var so = r.Split(restProductList, withTax);
                        result.AddSubOrderRange(so.Item1);
                        if (so.Item1.OrderList.Count == 0 || so.Item2.Count <= 0)
                        {
                            // 拆不出来,此规则不适用 || 全拆完了
                            break;
                        }
                        restProductList = so.Item2;
                    }
                }
            }
            result.OrderList.ForEach(o => o.LogisticsCost = this.CalculateFreight(o.CalculateTotalWeight()));
            return(Tuple.Create(result, restProductList));
        }
Пример #3
0
        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);
        }
Пример #4
0
        public Tuple <string, SplitedOrder> SplitWithOrganization1(SplitWithExpRequest1 request)
        {
            var validResult = this.ValidRequire(request);

            if (!validResult.Item1)
            {
                return(Tuple.Create <string, SplitedOrder>(validResult.Item2, null));
            }
            LogHelper.Logger.Info("Call Spliter.SplitWithOrganization(): " + request);
            SplitedOrder result = this.spliter.SplitWithOrganization1(request.OrderId.ToString(), request.ProList, request.TotalQuantity, request.logistics);

            return(Tuple.Create(string.Empty, result));
        }
Пример #5
0
        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));
        }
Пример #6
0
        private SplitedOrder ReturnRemainPackage(List <ProductEntity> remainProducts)
        {
            var result          = new SplitedOrder();
            var productList     = remainProducts.SelectMany(o => o.OrderInfo).ToList();
            var invalidSubOrder = new SubOrder()
            {
                Id          = "-1",
                TotalWeight = productList.Sum(o => o.Weight * o.Quantity),
                TotalPrice  = productList.Sum(o => o.ProPrice * o.Quantity),
                ProList     = productList
            };

            result.AddSubOrder(invalidSubOrder);
            return(result);
        }
Пример #7
0
        /// <summary>
        /// 循环拆解商品项
        /// </summary>
        /// <param name="productList"></param>
        /// <param name="withTax"></param>
        /// <returns>可拆解出的子订单,未能拆解的商品</returns>
        public Tuple <SplitedOrder, List <ProductEntity> > Split(List <ProductEntity> productList, bool withTax)
        {
            var result = new SplitedOrder();

            var productEntities = productList.Where(pe => ruleItemDic.ContainsKey(pe.PTId)).ToList();
            var subOrder        = SplitOneSubOrder(productEntities, withTax);

            while (subOrder != null && subOrder.ProList.Count > 0)
            {
                result.AddSubOrder(subOrder);
                subOrder = SplitOneSubOrder(productEntities, withTax);
            }

            productList.RemoveAll(pe => pe.OrderInfo.Count <= 0);

            result.OrderList.ForEach(so => so.CalculateTotalPrice());
            result.OrderList.Where(so => withTax).ToList().ForEach(so => CalculateTax(so));
            return(Tuple.Create(result, productList));
        }
Пример #8
0
        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));
        }
Пример #9
0
        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));
        }
Пример #10
0
        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);
        }
Пример #11
0
        // 拆包,把当前Rule能装的包全拆
        public Tuple <SplitedOrder, List <ProductEntity> > Split(List <ProductEntity> productList, bool withTax)
        {
            var result = new SplitedOrder();

            var index = productList.FindIndex(pe => pe.PTId == this.PTId);

            if (index >= 0)
            {
                var pe           = productList[index];
                var restProducts = new List <Product>();
                var subOrder     = CreateSubOrder();
                for (int j = 0; j < pe.OrderInfo.Count; j++)
                {
                    var restProduct = pe.OrderInfo[j];
                    while (restProduct.Quantity > 0)
                    {
                        var pl            = FindSubLevel(restProduct);
                        var quantityLimit = (pl != null ? pl.MaxQuantity : this.MaxQuantity) - subOrder.CalculateTotalQuantity();
                        var weightLimit   = (pl != null ? pl.MaxWeight : this.MaxWeight) - subOrder.CalculateTotalWeight();
                        var priceLimit    = (withTax ? this.MaxPrice : (pl != null ? (decimal)pl.MaxPrice : this.TaxThreshold)) - subOrder.CalculateTotalPrice();
                        var productTuple  = SplitProduct(restProduct, quantityLimit, weightLimit, priceLimit);
                        if (productTuple.Item1.Quantity <= 0)    // 一个都分配不出去,要么是当前Rule不满足,要么是当前SubOrder满了,测试一下是哪种情况
                        {
                            var testProduct = SplitProduct(restProduct, this.MaxQuantity, this.MaxWeight, this.MaxPrice);
                            if (testProduct.Item1.Quantity <= 0)    // Rule不满足
                            {
                                break;
                            }
                            else    // 满了,换下一个子包
                            {
                                result.AddSubOrder(subOrder);
                                subOrder = CreateSubOrder();
                            }
                        }
                        else    // 分配了部分或全部
                        {
                            subOrder.ProList.Add(productTuple.Item1);
                            restProduct = productTuple.Item2;
                            if (restProduct.Quantity > 0 || subOrder.CalculateTotalQuantity() >= this.MaxQuantity)    // 当前子包满了(有剩余,或者子包的数量达到上限)
                            {
                                result.AddSubOrder(subOrder);
                                subOrder = CreateSubOrder();
                            }
                        }
                    }
                    if (restProduct.Quantity > 0)    // 如果分配不出去了,但还有剩下,那放回原队列,分配给下一家物流
                    {
                        restProducts.Add(restProduct);
                    }
                }

                if (subOrder.ProList.Count > 0)
                {
                    result.AddSubOrder(subOrder);
                    subOrder = CreateSubOrder();
                }

                if (restProducts.Any())    // 最后还有剩余,把剩余放回队列
                {
                    productList[index].OrderInfo = restProducts;
                }
                else    // 没有剩余,从队列移除
                {
                    productList.RemoveAt(index);
                }
            }

            result.OrderList.ForEach(so => so.CalculateTotalPrice());
            result.OrderList.Where(so => withTax).ToList().ForEach(so => CalculateTax(so));
            return(Tuple.Create(result, productList));
        }