using BBWY.Common.Extensions;
using BBWY.Common.Http;
using BBWY.Common.Models;
using BBWY.Server.Business.Extensions;
using BBWY.Server.Model;
using BBWY.Server.Model.Db;
using BBWY.Server.Model.Db.Mds;
using BBWY.Server.Model.Dto;
using FreeSql;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using Yitter.IdGenerator;

namespace BBWY.Server.Business
{
    public class OrderBusiness : BasePlatformRelayBusiness, IDenpendency
    {
        private IFreeSql fsql;

        private IIdGenerator idGenerator;

        private Lazy<ProductBusiness> productBusinessLazy;
        private ProductBusiness productBusiness => productBusinessLazy.Value;

        private Lazy<FreeSqlMultiDBManager> freeSqlMultiDBManagerLazy;
        private FreeSqlMultiDBManager freeSqlMultiDBManager => freeSqlMultiDBManagerLazy.Value;

        private Lazy<VenderBusiness> venderBusinessLazy;
        private VenderBusiness venderBusiness => venderBusinessLazy.Value;

        private IMemoryCache memoryCache;
        private static TimeSpan sdGroupExpirationTimeSpan = TimeSpan.FromMinutes(20);

        public OrderBusiness(RestApiService restApiService,
                             IFreeSql fsql,
                             IIdGenerator idGenerator,
                             IOptions<GlobalConfig> options,
                             IServiceProvider serviceProvider,
                             IMemoryCache memoryCache, YunDingBusiness yunDingBusiness) : base(restApiService, options, yunDingBusiness)
        {
            this.fsql = fsql;
            this.idGenerator = idGenerator;
            this.memoryCache = memoryCache;
            freeSqlMultiDBManagerLazy = new Lazy<FreeSqlMultiDBManager>(() => serviceProvider.GetService<FreeSqlMultiDBManager>());
            productBusinessLazy = new Lazy<ProductBusiness>(() => serviceProvider.GetService<ProductBusiness>());
            venderBusinessLazy = new Lazy<VenderBusiness>(() => serviceProvider.GetService<VenderBusiness>());
        }

        private ISelect<Order, OrderConsignee, OrderCost, Storehouse> GetOrderListQueryConditions(SearchOrderRequest searchOrderRequest)
        {
            var select = fsql.Select<Order, OrderConsignee, OrderCost, Storehouse>().LeftJoin((o, ocs, oct, sh) => o.Id == ocs.OrderId)
                                                                                    .LeftJoin((o, ocs, oct, sh) => o.Id == oct.OrderId)
                                                                                    .LeftJoin((o, ocs, oct, sh) => o.StoreId == sh.Id);
            if (!string.IsNullOrEmpty(searchOrderRequest.OrderId))
            {
                select = select.Where((o, ocs, oct, sh) => o.Id == searchOrderRequest.OrderId);
            }
            else
            {
                if (!string.IsNullOrEmpty(searchOrderRequest.Sku) || !string.IsNullOrEmpty(searchOrderRequest.ProductNo) || !string.IsNullOrEmpty(searchOrderRequest.ProductId))
                {
                    var childSelect = fsql.Select<OrderSku>().As("osku")
                                          .WhereIf(!string.IsNullOrEmpty(searchOrderRequest.Sku), osku => osku.SkuId == searchOrderRequest.Sku)
                                          .WhereIf(!string.IsNullOrEmpty(searchOrderRequest.ProductId), osku => osku.ProductId == searchOrderRequest.ProductId)
                                          .WhereIf(!string.IsNullOrEmpty(searchOrderRequest.ProductNo), osku => osku.ProductNo == searchOrderRequest.ProductNo);
                    select = select.Where((o, ocs, oct, sh) => childSelect.Where(osku => osku.OrderId == o.Id).Any());
                }

                select = select.WhereIf(searchOrderRequest.OrderState != null, (o, ocs, oct, sh) => o.OrderState == searchOrderRequest.OrderState)
                               .WhereIf(searchOrderRequest.StartDate != null, (o, ocs, oct, sh) => o.StartTime >= searchOrderRequest.StartDate)
                               .WhereIf(searchOrderRequest.EndDate != null, (o, ocs, oct, sh) => o.StartTime <= searchOrderRequest.EndDate)
                               .WhereIf(searchOrderRequest.IncludeExceptionOrder,
                                        (o, ocs, oct, sh) => o.OrderState != Enums.OrderState.已取消 &&
                                                         ((o.StorageType != Enums.StorageType.SD && o.StorageType != null && oct.PurchaseAmount == 0M) ||
                                                         (o.StorageType != Enums.StorageType.SD && oct.PurchaseAmount + oct.DeliveryExpressFreight > o.OrderSellerPrice + o.FreightPrice) ||
                                                         (o.StorageType == null && o.OrderState != Enums.OrderState.等待采购)))
                               .WhereIf(searchOrderRequest.OnlyDF, (o, ocs, oct, sh) => o.StorageType == Enums.StorageType.代发)
                               .WhereIf(searchOrderRequest.ExcludeCanceled, (o, ocs, oct, sh) => o.OrderState != Enums.OrderState.已取消)
                               .WhereIf(searchOrderRequest.ExcludeSD && !searchOrderRequest.OnlyDF, (o, ocs, oct, sh) => o.StorageType == null || o.StorageType != Enums.StorageType.SD)
                               .WhereIf(string.IsNullOrEmpty(searchOrderRequest.ContactName) == false, (o, ocs, oct, sh) => ocs.ContactName == searchOrderRequest.ContactName)
                               .WhereIf(string.IsNullOrEmpty(searchOrderRequest.Waybill) == false, (o, ocs, oct, sh) => o.WaybillNo == searchOrderRequest.Waybill);
            }

            select = select.WhereIf(searchOrderRequest.ShopId != null, (o, ocs, oct, sh) => o.ShopId == searchOrderRequest.ShopId)
                           .WhereIf(!string.IsNullOrEmpty(searchOrderRequest.SDOperator), (o, ocs, oct, sh) => o.SDOperator == searchOrderRequest.SDOperator)
                           .Where((o, ocs, oct, sh) => o.IsGift == false);

            //select = select.Where((o, ocs, oct) => o.ShopId == searchOrderRequest.ShopId);

            return select;
        }

        private Expression<Func<Order, OrderConsignee, OrderCost, Storehouse, Order>> GetOrderListField()
        {
            return (o, ocs, oct, sh) => new Order()
            {
                Id = o.Id,
                BuyerRemark = o.BuyerRemark,
                EndTime = o.EndTime,
                FreightPrice = o.FreightPrice,
                ModifyTime = o.ModifyTime,
                OrderPayment = o.OrderPayment,
                OrderSellerPrice = o.OrderSellerPrice,
                OrderState = o.OrderState,
                OrderTotalPrice = o.OrderTotalPrice,
                OrderType = o.OrderType,
                PayType = o.PayType,
                Platform = o.Platform,
                ShopId = o.ShopId,
                StartTime = o.StartTime,
                StorageType = o.StorageType,
                StoreId = o.StoreId,
                StoreOrder = o.StoreOrder,
                VenderRemark = o.VenderRemark,
                PurchaseRemark = o.PurchaseRemark,
                WaybillNo = o.WaybillNo,
                Flag = o.Flag,
                SDType = o.SDType,
                SDKey = o.SDKey,
                SDOperator = o.SDOperator,
                SDPayBillNo = o.SDPayBillNo,
                SDPayChannel = o.SDPayChannel,
                IsAfterSaleOrder = o.IsAfterSaleOrder,
                SellerPreferentialAmount = o.SellerPreferentialAmount,
                PreferentialAmount = o.PreferentialAmount,

                ContactName = ocs.ContactName,
                Address = ocs.Address,
                Province = ocs.Province,
                County = ocs.County,
                Town = ocs.Town,
                City = ocs.City,
                IsDecode = ocs.IsDecode,
                Mobile = ocs.Mobile,
                TelePhone = ocs.TelePhone,

                DeliveryExpressFreight = oct.DeliveryExpressFreight,
                PlatformCommissionAmount = oct.PlatformCommissionAmount,
                PlatformCommissionRatio = oct.PlatformCommissionRatio,
                //PreferentialAmount = oct.PreferentialAmount,
                Profit = oct.Profit,
                PurchaseAmount = oct.PurchaseAmount,
                IsManualEdited = oct.IsManualEdited,
                SDCommissionAmount = oct.SDCommissionAmount,
                SDOrderAmount = oct.SDOrderAmount,
                RefundAmount = oct.RefundAmount,
                RefundPurchaseAmount = oct.RefundPurchaseAmount,
                AfterTotalCost = oct.AfterTotalCost,

                StoreName = sh.Name
            };
        }

        public OrderListResponse GetOrderList(SearchOrderRequest searchOrderRequest)
        {
            if (searchOrderRequest.OrderState == Enums.OrderState.已取消)
                searchOrderRequest.ExcludeCanceled = false;
            if (searchOrderRequest.EndDate != null)
                searchOrderRequest.EndDate = searchOrderRequest.EndDate.Value.Date.AddDays(1).AddSeconds(-1);


            //var noCancelSelect = GetOrderListQueryConditions(searchOrderRequest);
            //var currentConditionsTotalProfit = noCancelSelect.Where((o, ocs, oct) => o.OrderState != Enums.OrderState.已取消).ToAggregate((o, ocs, oct) => oct.Sum(oct.Key.Profit));

            var select = GetOrderListQueryConditions(searchOrderRequest).OrderByDescending((o, ocs, oct, sh) => o.StartTime)
                                                                        .Count(out var total)
                                                                        .Page(searchOrderRequest.PageIndex, searchOrderRequest.PageSize);

            var orderSourceList = select.ToList(GetOrderListField());
            var orderList = orderSourceList.Map<IList<OrderResponse>>();

            if (orderList.Count > 0)
            {
                var orderIdList = orderList.Select(o => o.Id).ToList();

                #region 处理代发信息
                var orderDropShippingList = fsql.Select<OrderDropShipping>().Where(ods => orderIdList.Contains(ods.OrderId))
                                                                            .ToList()
                                                                            .Map<IList<OrderDropShippingResponse>>();
                foreach (var order in orderList)
                {
                    order.OrderDropShippingList = orderDropShippingList.Where(ods => ods.OrderId == order.Id && ods.IsHistory == false).ToList();
                    order.HistoryOrderDropShippingList = orderDropShippingList.Where(ods => ods.OrderId == order.Id && ods.IsHistory).ToList();
                }

                #endregion

                #region 处理Sku
                var orderSkuList = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 &&
                                                                         orderIdList.Contains(osku.OrderId)).ToList()
                                                                                                            .Map<IList<OrderSkuResponse>>();
                foreach (var order in orderList)
                {
                    order.ItemList = orderSkuList.Where(osku => osku.OrderId == order.Id).ToList();
                    if (order.StorageType == Enums.StorageType.代发)
                    {
                        foreach (var orderSku in order.ItemList)
                        {
                            if (orderSku.OrderDropShippingId == null && (order.OrderDropShippingList?.Count() ?? 0) > 0)
                                orderSku.OrderDropShippingId = order.OrderDropShippingList[0].Id;
                        }
                    }
                }

                #endregion

                #region 处理优惠券
                var orderCouponList = fsql.Select<OrderCoupon>().Where(oc => orderIdList.Contains(oc.OrderId)).ToList().Map<IList<OrderCouponResponse>>();
                foreach (var order in orderList)
                    order.OrderCouponList = orderCouponList.Where(oc => oc.OrderId == order.Id).ToList();
                #endregion

                #region 处理订单成本明细
                var orderCostDetailList = fsql.Select<OrderCostDetail>().Where(ocd => orderIdList.Contains(ocd.OrderId) && ocd.IsEnabled == true).ToList().Map<IList<OrderCostDetailResponse>>();
                foreach (var order in orderList)
                    order.OrderCostDetailList = orderCostDetailList.Where(ocd => ocd.OrderId == order.Id).ToList();
                #endregion

                #region 处理售后信息
                var afterSaleOrderList = fsql.Select<AfterSaleOrder>().Where(aso => orderIdList.Contains(aso.OrderId)).ToList<AfterSaleOrderResponse>();
                foreach (var order in orderList)
                    order.AfterSaleOrderList = afterSaleOrderList.Where(aso => aso.OrderId == order.Id).ToList();
                #endregion

                //#region 翻译仓库Id
                //foreach (var order in orderList)
                //    order.StoreName = globalConfig.Stores.FirstOrDefault(s => s.StoreId == order.StoreId)?.StoreName ?? order.StoreId;
                //#endregion
            }

            var response = new OrderListResponse()
            {
                Count = total,
                Items = orderList,
                //CurrentConditionsTotalProfit = currentConditionsTotalProfit
            };
            return response;
        }

        public IList<ExportOrderResponse> ExportOrderList(SearchOrderRequest searchOrderRequest)
        {
            if (searchOrderRequest.OrderState == Enums.OrderState.已取消)
                searchOrderRequest.ExcludeCanceled = false;
            if (searchOrderRequest.EndDate != null)
                searchOrderRequest.EndDate = searchOrderRequest.EndDate.Value.Date.AddDays(1).AddSeconds(-1);

            var select = fsql.Select<Order, OrderConsignee, OrderCost>().LeftJoin((o, ocs, oct) => o.Id == ocs.OrderId)
                                                                        .LeftJoin((o, ocs, oct) => o.Id == oct.OrderId);

            if (!string.IsNullOrEmpty(searchOrderRequest.OrderId))
            {
                select = select.Where((o, ocs, oct) => o.Id == searchOrderRequest.OrderId);
            }
            else
            {
                if (!string.IsNullOrEmpty(searchOrderRequest.Sku) || !string.IsNullOrEmpty(searchOrderRequest.ProductNo))
                {
                    var childSelect = fsql.Select<OrderSku>().As("osku")
                                          .WhereIf(string.IsNullOrEmpty(searchOrderRequest.Sku) == false, osku => osku.SkuId == searchOrderRequest.Sku)
                                          .WhereIf(string.IsNullOrEmpty(searchOrderRequest.ProductNo) == false, osku => osku.ProductNo == searchOrderRequest.ProductNo);
                    select = select.Where((o, ocs, oct) => childSelect.Where(osku => osku.OrderId == o.Id).Any());
                }

                select = select.WhereIf(searchOrderRequest.OrderState != null, (o, ocs, oct) => o.OrderState == searchOrderRequest.OrderState)
                               .WhereIf(searchOrderRequest.StartDate != null, (o, ocs, oct) => o.StartTime >= searchOrderRequest.StartDate)
                               .WhereIf(searchOrderRequest.EndDate != null, (o, ocs, oct) => o.StartTime <= searchOrderRequest.EndDate)
                               .WhereIf(searchOrderRequest.OnlyDF, (o, ocs, oct) => o.StorageType == Enums.StorageType.代发)
                               .WhereIf(searchOrderRequest.ExcludeCanceled, (o, ocs, oct) => o.OrderState != Enums.OrderState.已取消)
                               .WhereIf(searchOrderRequest.ExcludeSD && !searchOrderRequest.OnlyDF, (o, ocs, oct) => o.StorageType == null || o.StorageType != Enums.StorageType.SD)
                               .WhereIf(string.IsNullOrEmpty(searchOrderRequest.ContactName) == false, (o, ocs, oct) => ocs.ContactName == searchOrderRequest.ContactName)
                               .WhereIf(string.IsNullOrEmpty(searchOrderRequest.Waybill) == false, (o, ocs, oct) => o.WaybillNo == searchOrderRequest.Waybill);
            }

            select = select.WhereIf(searchOrderRequest.ShopId != null, (o, ocs, oct) => o.ShopId == searchOrderRequest.ShopId)
                           .WhereIf(!string.IsNullOrEmpty(searchOrderRequest.SDOperator), (o, ocs, oct) => o.SDOperator == searchOrderRequest.SDOperator)
                           .Where((o, ocs, oct) => o.IsGift == false)
                           .OrderByDescending((o, ocs, oct) => o.StartTime);

            var orderSourceList = select.ToList((o, ocs, oct) => new ExportOrderResponse()
            {
                OrderId = o.Id,
                FreightPrice = o.FreightPrice,
                OrderTotalPrice = o.OrderTotalPrice,
                OrderStartTime = o.StartTime.Value,
                StorageType = o.StorageType,
                ConsigneeStr = ocs.ContactName + "|" + ocs.Mobile + "|" + ocs.Province + ocs.City + ocs.County + ocs.Address,
                DeliveryExpressFreight = oct.DeliveryExpressFreight,
                PlatformCommissionAmount = oct.PlatformCommissionAmount,
                Profit = oct.Profit,
                TotalCost = oct.SDCommissionAmount + oct.SDOrderAmount + oct.PlatformCommissionAmount + oct.PurchaseAmount + oct.DeliveryExpressFreight,
                //PurchaseOrderIds = ods.PurchaseOrderId,
                OrderState = o.OrderState.Value,
                VenderRemark = o.VenderRemark,
                OrderPayment = o.OrderPayment,
                OrderSellerPrice = o.OrderSellerPrice,
                SDOrderAmount = oct.SDOrderAmount
            });

            var orderIdList = orderSourceList.Select(o => o.OrderId).ToList();
            List<OrderSku> orderSkuList = null;
            if (orderIdList.Count() < 2000)
            {
                orderSkuList = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 && orderIdList.Contains(osku.OrderId))
                                                         .ToList(osku => new OrderSku
                                                         {
                                                             Id = osku.Id,
                                                             OrderId = osku.OrderId,
                                                             SkuId = osku.SkuId
                                                         });
            }
            else
            {
                orderSkuList = fsql.Select<OrderSku, Order>().InnerJoin((osku, o) => osku.OrderId == o.Id)
                                                             .Where((osku, o) => o.ShopId == searchOrderRequest.ShopId.Value &&
                                                                              o.StartTime >= searchOrderRequest.StartDate &&
                                                                              o.StartTime <= searchOrderRequest.EndDate)
                                                             .ToList((osku, o) => new OrderSku
                                                             {
                                                                 Id = osku.Id,
                                                                 OrderId = osku.OrderId,
                                                                 SkuId = osku.SkuId
                                                             });
            }

            IList<OrderCostDetail> orderCostDetailGroup = null;
            if (orderIdList.Count() < 2000)
            {
                orderCostDetailGroup = fsql.Select<OrderCostDetail>().Where(ocd => orderIdList.Contains(ocd.OrderId) && ocd.IsEnabled == true)
                                                                     .GroupBy(ocd => ocd.OrderId).ToList(g => new OrderCostDetail
                                                                     {
                                                                         OrderId = g.Key,
                                                                         SkuAmount = g.Sum(g.Value.SkuAmount),
                                                                         FirstFreight = g.Sum(g.Value.FirstFreight),
                                                                         StorageAmount = g.Sum(g.Value.StorageAmount),
                                                                         PurchaseFreight = g.Sum(g.Value.PurchaseFreight),
                                                                         ConsumableAmount = g.Sum(g.Value.ConsumableAmount),
                                                                         InStorageAmount = g.Sum(g.Value.InStorageAmount),
                                                                         OutStorageAmount = g.Sum(g.Value.OutStorageAmount)
                                                                     });
            }
            else
            {
                orderCostDetailGroup = fsql.Select<OrderCostDetail, Order>().InnerJoin((ocd, o) => ocd.OrderId == o.Id)
                                                                            .Where((ocd, o) => o.ShopId == searchOrderRequest.ShopId.Value &&
                                                                              o.StartTime >= searchOrderRequest.StartDate &&
                                                                              o.StartTime <= searchOrderRequest.EndDate &&
                                                                              ocd.IsEnabled == true)
                                                                     .GroupBy((ocd, o) => ocd.OrderId).ToList(g => new OrderCostDetail
                                                                     {
                                                                         OrderId = g.Key,
                                                                         SkuAmount = g.Sum(g.Value.Item1.SkuAmount),
                                                                         FirstFreight = g.Sum(g.Value.Item1.FirstFreight),
                                                                         StorageAmount = g.Sum(g.Value.Item1.StorageAmount),
                                                                         PurchaseFreight = g.Sum(g.Value.Item1.PurchaseFreight),
                                                                         ConsumableAmount = g.Sum(g.Value.Item1.ConsumableAmount),
                                                                         InStorageAmount = g.Sum(g.Value.Item1.InStorageAmount),
                                                                         OutStorageAmount = g.Sum(g.Value.Item1.OutStorageAmount)
                                                                     });
            }


            var orderDropShippingList = fsql.Select<OrderDropShipping>().Where(ods => orderIdList.Contains(ods.OrderId) && ods.IsHistory == false).ToList();

            foreach (var order in orderSourceList)
            {
                var statistics = orderCostDetailGroup.FirstOrDefault(g => g.OrderId == order.OrderId);
                order.FirstFreight = statistics?.FirstFreight ?? 0M;
                order.PurchaseSkuAmount = statistics?.SkuAmount ?? 0M;
                order.PurchaseFreight = statistics?.PurchaseFreight ?? 0M;
                order.StorageAmount = statistics?.StorageAmount ?? 0M;
                order.SkuIds = string.Join("|", orderSkuList.Where(osku => osku.OrderId == order.OrderId).Select(osku => osku.SkuId));
                order.ProfitRatio = order.TotalCost == 0 ? 0 : Math.Round(order.Profit / order.TotalCost * 100, 2);
                order.ConsumableAmount = statistics?.ConsumableAmount ?? 0M;
                order.InStorageAmount = statistics?.InStorageAmount ?? 0M;
                order.OutStorageAmount = statistics?.OutStorageAmount ?? 0M;
                if (order.StorageType == Enums.StorageType.代发)
                {
                    var pids = orderDropShippingList.Where(ods => ods.OrderId == order.OrderId).Select(ods => ods.PurchaseOrderId).ToList();
                    if (pids.Count() > 1)
                        order.PurchaseOrderIds = string.Join("|", pids);
                    else if (pids.Count() == 1)
                        order.PurchaseOrderIds = $"'{pids[0]}";
                }
            }
            return orderSourceList;

        }

        public OrderResponse GetOrderById(string orderId)
        {
            var order = fsql.Select<Order, OrderConsignee, OrderCost, Storehouse>().LeftJoin((o, ocs, oct, sh) => o.Id == ocs.OrderId)
                                                                                   .LeftJoin((o, ocs, oct, sh) => o.Id == oct.OrderId)
                                                                                   .Where((o, ocs, oct, sh) => o.Id == orderId)
                                                                                   .ToOne(GetOrderListField());
            if (order == null)
                throw new BusinessException("订单不存在");

            var orderResponse = order.Map<OrderResponse>();
            var orderSkuList = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 && osku.OrderId == orderId).ToList().Map<IList<OrderSkuResponse>>();
            var orderCouponList = fsql.Select<OrderCoupon>().Where(oc => oc.OrderId == orderId).ToList().Map<IList<OrderCouponResponse>>();
            var orderCostDetailList = fsql.Select<OrderCostDetail>().Where(ocd => ocd.OrderId == orderId && ocd.IsEnabled == true).ToList().Map<IList<OrderCostDetailResponse>>();
            var orderDropShippingList = fsql.Select<OrderDropShipping>().Where(ods => ods.OrderId == orderId).ToList().Map<IList<OrderDropShippingResponse>>();

            if (order.IsAfterSaleOrder)
                orderResponse.AfterSaleOrderList = fsql.Select<AfterSaleOrder>().Where(aso => aso.OrderId == orderId).ToList<AfterSaleOrderResponse>();

            //orderResponse.OrderDropShippingList = orderDropShippingList;
            orderResponse.OrderDropShippingList = orderDropShippingList.Where(ods => ods.IsHistory == false).ToList();
            orderResponse.HistoryOrderDropShippingList = orderDropShippingList.Where(ods => ods.IsHistory).ToList();
            orderResponse.ItemList = orderSkuList;
            if (order.StorageType == Enums.StorageType.代发)
            {
                foreach (var orderSku in orderResponse.ItemList)
                {
                    if (orderSku.OrderDropShippingId == null && (orderResponse.OrderDropShippingList?.Count() ?? 0) > 0)
                        orderSku.OrderDropShippingId = orderResponse.OrderDropShippingList[0].Id;
                }
            }

            orderResponse.OrderCouponList = orderCouponList;
            orderResponse.OrderCostDetailList = orderCostDetailList;
            //orderResponse.StoreName = globalConfig.Stores.FirstOrDefault(s => s.StoreId == orderResponse.StoreId)?.StoreName ?? order.StoreId;
            return orderResponse;
        }

        public IList<OrderBelongShopResponse> GetOrderBelongShop(IList<string> orderIdList)
        {
            var orderGroups = fsql.Select<Order>().Where(o => orderIdList.Contains(o.Id)).ToList(o => new { o.ShopId, OrderId = o.Id }).GroupBy(o => o.ShopId);
            var shopIdList = orderGroups.Select(o => o.Key.ToString()).ToList();
            var shops = freeSqlMultiDBManager.MDSfsql.Select<Shops>().Where(s => shopIdList.Contains(s.ShopId)).ToList(s => new { s.ShopId, s.ShopName });
            var list = new List<OrderBelongShopResponse>();
            foreach (var orderGroup in orderGroups)
            {
                var shop = shops.FirstOrDefault(s => s.ShopId == orderGroup.Key.ToString());
                if (shop == null)
                    continue;
                var orderBelongShop = new OrderBelongShopResponse()
                {
                    ShopId = orderGroup.Key,
                    ShopName = shop.ShopName,
                    OrderIdList = orderGroup.Select(x => x.OrderId).ToList()
                };
                list.Add(orderBelongShop);
            }
            return list;
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="decryptConsigneeRequest"></param>
        /// <returns></returns>
        /// <exception cref="BusinessException"></exception>
        public ConsigneeSimpleResponse DecryptConsignee(DecryptConsigneeRequest decryptConsigneeRequest)
        {
            var relayAPIHost = GetPlatformRelayAPIHost(decryptConsigneeRequest.Platform);
            var sendResult = restApiService.SendRequest(relayAPIHost, "api/PlatformSDK/DecryptConsignee", decryptConsigneeRequest, GetYunDingRequestHeader(), HttpMethod.Post);
            if (sendResult.StatusCode != System.Net.HttpStatusCode.OK)
                throw new BusinessException(sendResult.Content) { Code = (int)sendResult.StatusCode };
            var response = JsonConvert.DeserializeObject<ApiResponse<ConsigneeSimpleResponse>>(sendResult.Content);
            if (!response.Success)
                throw new BusinessException(response.Msg) { Code = response.Code };

            if (!string.IsNullOrEmpty(decryptConsigneeRequest.PlaintextMobile))
                response.Data.Mobile = decryptConsigneeRequest.PlaintextMobile;

            //将解密后的收货人信息存至数据库
            if (decryptConsigneeRequest.SaveDb)
            {
                fsql.Update<OrderConsignee>(decryptConsigneeRequest.OrderId).Set(oc => oc.ContactName, response.Data.ContactName)
                                                                            .Set(oc => oc.Address, response.Data.Address)
                                                                            .SetIf(!string.IsNullOrEmpty(response.Data.Mobile), oc => oc.Mobile, response.Data.Mobile)
                                                                            .SetIf(!string.IsNullOrEmpty(response.Data.TelePhone), oc => oc.TelePhone, response.Data.TelePhone)
                                                                            .Set(oc => oc.IsDecode, true)
                                                                            .ExecuteAffrows();
            }
            return response.Data;
        }

        /// <summary>
        /// 自动计算成本
        /// </summary>
        /// <param name="autoCalculationCostRequest"></param>
        public void AutoCalculationCost(AutoCalculationCostRequest autoCalculationCostRequest)
        {
            if (autoCalculationCostRequest.PlatformCommissionRatio == 0M)
                autoCalculationCostRequest.PlatformCommissionRatio = 0.05M;

            var dbOrder = fsql.Select<Order>(autoCalculationCostRequest.OrderId).ToOne();
            if (dbOrder == null)
                throw new BusinessException($"订单号{autoCalculationCostRequest.OrderId}不存在");

            var orderSkus = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 && osku.OrderId == autoCalculationCostRequest.OrderId).ToList();
            var orderSkuIds = orderSkus.Select(osku => osku.SkuId).ToList();
            var purchaserOrders = fsql.Select<PurchaseOrder>().Where(po => po.StorageType == autoCalculationCostRequest.StorageType &&
                                                                           po.RemainingQuantity != 0 &&
                                                                           orderSkuIds.Contains(po.SkuId)).ToList();
            if (purchaserOrders.Count() == 0)
                throw new BusinessException("库存为零不能自动计算成本");
            var dbAfterSaleOrderList = fsql.Select<AfterSaleOrder>().Where(aso => aso.OrderId == autoCalculationCostRequest.OrderId).ToList();

            var orderCost = fsql.Select<OrderCost>(autoCalculationCostRequest.OrderId).ToOne();
            var orderCostDetails = fsql.Select<OrderCostDetail>().Where(ocd => ocd.OrderId == autoCalculationCostRequest.OrderId && ocd.IsEnabled == true).ToList();

            IUpdate<Order> orderUpdate = null;
            IUpdate<OrderCost> updateOrderCost = null;
            IInsert<OrderCost> insertOrderCost = null;
            IList<IUpdate<PurchaseOrder>> updatePurchaseOrderList = new List<IUpdate<PurchaseOrder>>();
            List<OrderCostDetail> insertOrderCostDetailList = new List<OrderCostDetail>();

            if (autoCalculationCostRequest.IsSetStorageType)
                orderUpdate = fsql.Update<Order>(autoCalculationCostRequest.OrderId)
                                  .Set(o => o.StorageType, autoCalculationCostRequest.StorageType)
                                  .SetIf(dbOrder.OrderState == Enums.OrderState.等待采购, o => o.OrderState, Enums.OrderState.待出库);

            var orderCostPurchaseAmount = 0M;
            var orderDeliveryExpressFreight = 0M; //发货总运费,sku购买数量第二个开始半价

            var avgPreferential = dbOrder.PreferentialAmount / orderSkus.Count();
            foreach (var orderSku in orderSkus)
            {
                //查询该sku的扣减明细
                var currentOrderSkuCostDetails = orderCostDetails.Where(ocd => ocd.SkuId == orderSku.SkuId);
                //已扣减数量
                var deductedQuantity = currentOrderSkuCostDetails.Count() == 0 ? 0 : currentOrderSkuCostDetails.Sum(ocd => ocd.DeductionQuantity);
                //剩余扣减数量
                var noDeductionQuantity = orderSku.ItemTotal.Value - deductedQuantity;
                if (noDeductionQuantity <= 0)
                    continue;

                //是否多次扣减库存
                var isReduceMultiTimes = false;
                if (currentOrderSkuCostDetails.Count() > 0)
                    isReduceMultiTimes = true;  //之前有过扣减记录,发货运费按半价计算

                while (noDeductionQuantity != 0)
                {
                    var purchaseOrder = purchaserOrders.FirstOrDefault(po => po.StorageType == autoCalculationCostRequest.StorageType &&
                                                                                               po.RemainingQuantity != 0 &&
                                                                                               po.SkuId == orderSku.SkuId);
                    if (purchaseOrder == null)
                        break; //没有库存了


                    //本次扣减数量
                    var deductionQuantity = purchaseOrder.RemainingQuantity >= noDeductionQuantity ? noDeductionQuantity : purchaseOrder.RemainingQuantity;
                    //本次扣减量的采购成本
                    var currentPurchaseAmount = purchaseOrder.UnitCost * deductionQuantity;
                    //本次扣减量的发货运费
                    var currentSkuDeliveryFreight = isReduceMultiTimes ?
                                                    (purchaseOrder.SingleDeliveryFreight / 2 * deductionQuantity) :
                                                    (purchaseOrder.SingleDeliveryFreight + purchaseOrder.SingleDeliveryFreight / 2 * (deductionQuantity - 1));
                    isReduceMultiTimes = true;

                    noDeductionQuantity -= deductionQuantity;
                    purchaseOrder.RemainingQuantity -= deductionQuantity;

                    //累计采购成本
                    orderCostPurchaseAmount += currentPurchaseAmount;
                    //累计发货运费(销售运费)
                    orderDeliveryExpressFreight += currentSkuDeliveryFreight;

                    var updateSql = fsql.Update<PurchaseOrder>(purchaseOrder.Id).Set(po => po.RemainingQuantity - deductionQuantity);
                    updatePurchaseOrderList.Add(updateSql);

                    var orderCostDetail = new OrderCostDetail()
                    {
                        Id = idGenerator.NewLong(),
                        OrderId = autoCalculationCostRequest.OrderId,
                        ProductId = orderSku.ProductId,
                        SkuId = orderSku.SkuId,
                        CreateTime = DateTime.Now,
                        PurchaseOrderPKId = purchaseOrder.Id,
                        //UnitCost = purchaseOrder.UnitCost,
                        DeductionQuantity = deductionQuantity,
                        DeliveryExpressFreight = currentSkuDeliveryFreight,
                        //TotalCost = currentPurchaseAmount,
                        ConsumableAmount = purchaseOrder.SingleConsumableAmount * deductionQuantity,
                        FirstFreight = purchaseOrder.SingleFirstFreight * deductionQuantity,
                        InStorageAmount = purchaseOrder.SingleInStorageAmount * deductionQuantity,
                        OutStorageAmount = purchaseOrder.SingleOutStorageAmount * deductionQuantity,
                        //OperationAmount = purchaseOrder.SingleOperationAmount * deductionQuantity,
                        PurchaseFreight = purchaseOrder.SingleFreight * deductionQuantity,
                        SkuAmount = purchaseOrder.SingleSkuAmount * deductionQuantity,
                        StorageAmount = purchaseOrder.SingleStorageAmount * deductionQuantity
                    };
                    orderCostDetail.SkuGrossProfit = orderSku.Price.Value * deductionQuantity - avgPreferential - (orderCostDetail.TotalCost + orderCostDetail.DeliveryExpressFreight) - orderSku.Price.Value * deductionQuantity * autoCalculationCostRequest.PlatformCommissionRatio;
                    insertOrderCostDetailList.Add(orderCostDetail);
                }
            }

            if (orderCost == null)
            {
                #region 计算成本
                orderCost = new OrderCost()
                {
                    OrderId = autoCalculationCostRequest.OrderId,
                    PlatformCommissionRatio = autoCalculationCostRequest.PlatformCommissionRatio,
                    PreferentialAmount = dbOrder.PreferentialAmount,
                    Profit = 0,
                    PurchaseAmount = orderCostPurchaseAmount,
                    DeliveryExpressFreight = orderDeliveryExpressFreight,
                    CreateTime = DateTime.Now
                };
                orderCost.CalculationOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                insertOrderCost = fsql.Insert(orderCost);
                #endregion
            }
            else
            {
                orderCost.PurchaseAmount += orderCostPurchaseAmount;
                orderCost.DeliveryExpressFreight += orderDeliveryExpressFreight;
                orderCost.CalculationOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                updateOrderCost = fsql.Update<OrderCost>().SetSource(orderCost);
            }

            fsql.Transaction(() =>
            {
                orderUpdate?.ExecuteAffrows();
                updateOrderCost?.ExecuteAffrows();
                insertOrderCost?.ExecuteAffrows();
                if (updatePurchaseOrderList.Count > 0)
                {
                    foreach (var update in updatePurchaseOrderList)
                        update.ExecuteAffrows();
                }
                if (insertOrderCostDetailList.Count > 0)
                    fsql.Insert(insertOrderCostDetailList).ExecuteAffrows();
            });
        }

        /// <summary>
        /// 手动计算成本
        /// </summary>
        /// <param name="manualCalculationCostRequest"></param>
        /// <exception cref="BusinessException"></exception>
        public void ManualCalculationCost(ManualCalculationCostRequest manualCalculationCostRequest)
        {
            if (manualCalculationCostRequest.PlatformCommissionRatio == 0M)
                manualCalculationCostRequest.PlatformCommissionRatio = 0.05M;
            var dbOrder = fsql.Select<Order>(manualCalculationCostRequest.OrderId).ToOne();
            if (dbOrder == null)
                throw new BusinessException($"订单号{manualCalculationCostRequest.OrderId}不存在");
            if (manualCalculationCostRequest.OrderCostDetailList == null || manualCalculationCostRequest.OrderCostDetailList.Count() == 0)
                throw new BusinessException($"缺少明细信息");

            IUpdate<Order> orderUpdate = null;
            IUpdate<OrderCost> updateOrderCost = null;
            IInsert<OrderCost> insertOrderCost = null;
            List<OrderCostDetail> insertOrderCostDetailList = new List<OrderCostDetail>();
            var orderSkuList = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 && osku.OrderId == manualCalculationCostRequest.OrderId).ToList(osku => new
            {
                osku.SkuId,
                osku.Price,
                osku.ItemTotal
            });
            var avgPreferential = dbOrder.PreferentialAmount / orderSkuList.Count();

            var dbAfterSaleOrderList = fsql.Select<AfterSaleOrder>().Where(aso => aso.OrderId == manualCalculationCostRequest.OrderId).ToList();

            if (manualCalculationCostRequest.IsSetStorageType)
                orderUpdate = fsql.Update<Order>(manualCalculationCostRequest.OrderId)
                                  .Set(o => o.StorageType, manualCalculationCostRequest.StorageType)
                                  .SetIf(dbOrder.OrderState == Enums.OrderState.等待采购, o => o.OrderState, Enums.OrderState.待出库);

            insertOrderCostDetailList.AddRange(manualCalculationCostRequest.OrderCostDetailList.Map<IList<OrderCostDetail>>());
            foreach (var orderCostDetail in insertOrderCostDetailList)
            {
                orderCostDetail.Id = idGenerator.NewLong();
                orderCostDetail.CreateTime = DateTime.Now;
                orderCostDetail.OrderId = manualCalculationCostRequest.OrderId;
                orderCostDetail.PurchaseOrderPKId = 0;

                var osku = orderSkuList.FirstOrDefault(o => o.SkuId == orderCostDetail.SkuId);
                if (osku != null)
                {
                    orderCostDetail.SkuGrossProfit = osku.Price.Value * orderCostDetail.DeductionQuantity - avgPreferential -
                                                     (orderCostDetail.TotalCost + orderCostDetail.DeliveryExpressFreight) -
                                                     osku.Price.Value * orderCostDetail.DeductionQuantity * manualCalculationCostRequest.PlatformCommissionRatio;
                }
            }

            var totalPurchaseCost = insertOrderCostDetailList.Sum(ocd => ocd.TotalCost);
            var totalDeliveryExpressFreight = insertOrderCostDetailList.Sum(ocd => ocd.DeliveryExpressFreight);

            var orderCost = fsql.Select<OrderCost>(manualCalculationCostRequest.OrderId).ToOne();
            if (orderCost == null)
            {
                orderCost = new OrderCost()
                {
                    OrderId = manualCalculationCostRequest.OrderId,
                    PlatformCommissionRatio = manualCalculationCostRequest.PlatformCommissionRatio,
                    PreferentialAmount = dbOrder.PreferentialAmount,
                    Profit = 0,
                    PurchaseAmount = totalPurchaseCost,
                    DeliveryExpressFreight = totalDeliveryExpressFreight,
                    CreateTime = DateTime.Now,
                    IsManualEdited = true
                };
                //orderCost.PlatformCommissionAmount = dbOrder.OrderSellerPrice * orderCost.PlatformCommissionRatio;
                //orderCost.Profit = dbOrder.OrderSellerPrice +
                //                   dbOrder.FreightPrice -
                //                   orderCost.PurchaseAmount -
                //                   orderCost.DeliveryExpressFreight -
                //                   orderCost.PlatformCommissionAmount;
                orderCost.CalculationOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                insertOrderCost = fsql.Insert(orderCost);
            }
            else
            {
                orderCost.PurchaseAmount = totalPurchaseCost;
                orderCost.DeliveryExpressFreight = totalDeliveryExpressFreight;
                //orderCost.Profit = dbOrder.OrderSellerPrice +
                //                   dbOrder.FreightPrice -
                //                   orderCost.PurchaseAmount -
                //                   orderCost.DeliveryExpressFreight -
                //                   orderCost.PlatformCommissionAmount;
                orderCost.CalculationOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                orderCost.IsManualEdited = true;
                updateOrderCost = fsql.Update<OrderCost>().SetSource(orderCost);
            }

            fsql.Transaction(() =>
            {
                fsql.Update<OrderCostDetail>().Set(ocd => ocd.IsEnabled, false).Where(ocd => ocd.OrderId == manualCalculationCostRequest.OrderId).ExecuteAffrows();
                orderUpdate?.ExecuteAffrows();
                insertOrderCost?.ExecuteAffrows();
                updateOrderCost?.ExecuteAffrows();
                fsql.Insert(insertOrderCostDetailList).ExecuteAffrows();
            });
        }

        /// <summary>
        /// 刷单计算成本
        /// </summary>
        /// <param name="sdCalculationCostRequest"></param>
        /// <exception cref="BusinessException"></exception>
        public void SDCalculationCost(SDCalculationCostRequest sdCalculationCostRequest)
        {
            var dbOrder = fsql.Select<Order>(sdCalculationCostRequest.OrderId).ToOne();
            if (dbOrder == null)
            {
                //待付款订单SD埋点
                //memoryCache.Remove(sdCalculationCostRequest.OrderId);
                memoryCache.Set(sdCalculationCostRequest.OrderId, sdCalculationCostRequest, sdGroupExpirationTimeSpan);
                return;
            }

            //修改平台订单备注
            var relayAPIHost = GetPlatformRelayAPIHost(sdCalculationCostRequest.Platform);
            var editApiResult = restApiService.SendRequest(relayAPIHost, "/Api/PlatformSDK/EditVenderRemark", new EditVenderRemarkRequest()
            {
                AppKey = sdCalculationCostRequest.AppKey,
                AppSecret = sdCalculationCostRequest.AppSecret,
                AppToken = sdCalculationCostRequest.AppToken,
                Flag = sdCalculationCostRequest.Flag,
                OrderId = sdCalculationCostRequest.OrderId,
                Platform = sdCalculationCostRequest.Platform,
                VenderRemark = sdCalculationCostRequest.VenderRemark
            }, GetYunDingRequestHeader(), HttpMethod.Post);
            if (editApiResult.StatusCode != System.Net.HttpStatusCode.OK)
                throw new BusinessException($"修改商家备注失败 {editApiResult.Content}") { Code = (int)editApiResult.StatusCode };
            var editResponse = JsonConvert.DeserializeObject<ApiResponse>(editApiResult.Content);
            if (!editResponse.Success)
                throw new BusinessException(editResponse.Msg);

            IUpdate<Order> orderUpdate = null;
            IUpdate<OrderCost> updateOrderCost = null;
            IInsert<OrderCost> insertOrderCost = null;

            var dbAfterSaleOrderList = fsql.Select<AfterSaleOrder>().Where(aso => aso.OrderId == sdCalculationCostRequest.OrderId).ToList();

            orderUpdate = fsql.Update<Order>(sdCalculationCostRequest.OrderId).Set(o => o.SDType, sdCalculationCostRequest.SDType)
                                                                              .Set(o => o.Flag, sdCalculationCostRequest.Flag)
                                                                              .Set(o => o.VenderRemark, sdCalculationCostRequest.VenderRemark)
                                                                              .Set(o => o.SDKey, sdCalculationCostRequest.SDKey)
                                                                              .Set(o => o.SDPayBillNo, sdCalculationCostRequest.SDPayBillNo)
                                                                              .Set(o => o.SDOperator, sdCalculationCostRequest.SDOperator)
                                                                              .SetIf(sdCalculationCostRequest.SDPayChannel != null, o => o.SDPayChannel, sdCalculationCostRequest.SDPayChannel);
            if (sdCalculationCostRequest.IsSetStorageType)
                orderUpdate = orderUpdate.Set(o => o.StorageType, Enums.StorageType.SD)
                                         .SetIf(dbOrder.OrderState == Enums.OrderState.等待采购, o => o.OrderState, Enums.OrderState.待出库);

            var orderCost = fsql.Select<OrderCost>(sdCalculationCostRequest.OrderId).ToOne();
            if (orderCost == null)
            {
                if (sdCalculationCostRequest.PlatformCommissionRatio == 0M)
                    sdCalculationCostRequest.PlatformCommissionRatio = 0.05M;
                orderCost = new OrderCost()
                {
                    OrderId = sdCalculationCostRequest.OrderId,
                    PlatformCommissionRatio = sdCalculationCostRequest.PlatformCommissionRatio,
                    PreferentialAmount = dbOrder.PreferentialAmount,
                    Profit = 0,
                    DeliveryExpressFreight = sdCalculationCostRequest.DeliveryExpressFreight,
                    CreateTime = DateTime.Now,
                    IsManualEdited = true,
                    SDCommissionAmount = sdCalculationCostRequest.SDCommissionAmount,
                    SDOrderAmount = sdCalculationCostRequest.SDOrderAmount
                };
                //orderCost.PlatformCommissionAmount = dbOrder.OrderSellerPrice * orderCost.PlatformCommissionRatio;
                //orderCost.Profit = (orderCost.SDCommissionAmount + orderCost.DeliveryExpressFreight + orderCost.PlatformCommissionAmount) * -1;
                orderCost.CalculationSDOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                insertOrderCost = fsql.Insert(orderCost);
            }
            else
            {
                orderCost.SDCommissionAmount = sdCalculationCostRequest.SDCommissionAmount;
                orderCost.SDOrderAmount = sdCalculationCostRequest.SDOrderAmount;
                orderCost.DeliveryExpressFreight = sdCalculationCostRequest.DeliveryExpressFreight;
                //orderCost.Profit = (orderCost.SDCommissionAmount + orderCost.DeliveryExpressFreight + orderCost.PlatformCommissionAmount) * -1;
                orderCost.CalculationSDOrderProfitAndCost(dbOrder, dbAfterSaleOrderList);
                orderCost.IsManualEdited = true;
                updateOrderCost = fsql.Update<OrderCost>().SetSource(orderCost);
            }

            fsql.Transaction(() =>
            {
                orderUpdate?.ExecuteAffrows();
                updateOrderCost?.ExecuteAffrows();
                insertOrderCost?.ExecuteAffrows();
            });
        }

        /// <summary>
        /// 关联外部订单
        /// </summary>
        /// <param name="relationPurchaseOrderRequestV2"></param>
        public void RelationPurchaseOrderV2(RelationPurchaseOrderRequestV2 relationPurchaseOrderRequestV2)
        {
            var dbOrder = fsql.Select<Order>(relationPurchaseOrderRequestV2.OrderDropShippingList[0].OrderId).ToOne();
            if (dbOrder == null)
                throw new BusinessException($"订单号{relationPurchaseOrderRequestV2.OrderDropShippingList[0].OrderId}不存在");

            if (relationPurchaseOrderRequestV2.PlatformCommissionRatio == 0M)
                relationPurchaseOrderRequestV2.PlatformCommissionRatio = 0.05M;

            List<OrderDropShipping> insertOrderDropShippingList = new List<OrderDropShipping>();
            List<IUpdate<OrderDropShipping>> updateOrderDropShippingList = new List<IUpdate<OrderDropShipping>>();
            IInsert<OrderCost> insertOrderCost = null;
            IUpdate<OrderCost> updateOrderCost = null;
            IDelete<PurchaseOrder> deletePurchaseOrder = null;
            IDelete<OrderCostDetail> deleteOrderCostDetail = null;
            List<IUpdate<OrderSku>> updateOrderSkuList = new List<IUpdate<OrderSku>>();
            List<PurchaseOrder> insertPurchaseOrderList = new List<PurchaseOrder>();
            List<OrderCostDetail> insertOrderCostDetailList = new List<OrderCostDetail>();

            var dbOrderSkuList = fsql.Select<OrderSku>().Where(osku => osku.Price != 0 && osku.OrderId == dbOrder.Id).ToList();
            var oldPourchaseIdList = fsql.Select<OrderCostDetail>().Where(ocd => ocd.OrderId == dbOrder.Id)
                                                                   .ToList(ocd => ocd.PurchaseOrderPKId);

            deletePurchaseOrder = fsql.Delete<PurchaseOrder>().Where(po => oldPourchaseIdList.Contains(po.Id));
            deleteOrderCostDetail = fsql.Delete<OrderCostDetail>().Where(ocd => ocd.OrderId == dbOrder.Id);
            var avgPreferential = dbOrder.PreferentialAmount / dbOrderSkuList.Count();

            foreach (var odsRequest in relationPurchaseOrderRequestV2.OrderDropShippingList)
            {
                #region 代发信息表
                var orderDropShipping = odsRequest.Map<OrderDropShipping>();
                if (orderDropShipping.Id == 0)
                {
                    orderDropShipping.Id = idGenerator.NewLong();
                    orderDropShipping.CreateTime = DateTime.Now;
                    orderDropShipping.ShopId = dbOrder.ShopId;
                    insertOrderDropShippingList.Add(orderDropShipping);
                }
                else
                {
                    updateOrderDropShippingList.Add(fsql.Update<OrderDropShipping>().SetSource(orderDropShipping).IgnoreColumns(ods => new { ods.CreateTime, ods.ShopId, ods.IsHistory }));
                }
                #endregion

                foreach (var relationOrderSku in odsRequest.RelationPurchaseOrderSkuList)
                {
                    #region OrderSku
                    var updateOrderSku = fsql.Update<OrderSku>().Set(osku => osku.OrderDropShippingId, orderDropShipping.Id)
                                                                .Where(osku => osku.SkuId == relationOrderSku.SkuId && osku.OrderId == dbOrder.Id);
                    updateOrderSkuList.Add(updateOrderSku);
                    #endregion

                    #region 采购单
                    var purchaseOrder = new PurchaseOrder()
                    {
                        Id = idGenerator.NewLong(),
                        CreateTime = DateTime.Now,
                        ProductId = relationOrderSku.ProductId,
                        PurchaseMethod = Enums.PurchaseMethod.线下采购,
                        StorageType = Enums.StorageType.代发,
                        PurchaseOrderId = odsRequest.PurchaseOrderId,
                        PurchasePlatform = odsRequest.PurchasePlatform,
                        PurchaseQuantity = relationOrderSku.Quantity,
                        RemainingQuantity = 0,
                        ShopId = dbOrder.ShopId,
                        SkuId = relationOrderSku.SkuId,
                        SingleConsumableAmount = 0,
                        SingleFirstFreight = 0,
                        SingleFreight = odsRequest.PurchaseFreight / odsRequest.RelationPurchaseOrderSkuList.Count() / relationOrderSku.Quantity,
                        //SingleOperationAmount = 0,
                        SingleInStorageAmount = 0,
                        SingleOutStorageAmount = 0,
                        SingleStorageAmount = 0,
                        SingleSkuAmount = relationOrderSku.SingleSkuAmount,
                        SingleDeliveryFreight = 0
                    };
                    insertPurchaseOrderList.Add(purchaseOrder);
                    #endregion

                    #region 明细
                    var orderCostDetail = new OrderCostDetail()
                    {
                        Id = idGenerator.NewLong(),
                        ConsumableAmount = 0,
                        CreateTime = DateTime.Now,
                        DeductionQuantity = relationOrderSku.Quantity,
                        DeliveryExpressFreight = 0,
                        FirstFreight = 0,
                        //OperationAmount = 0,
                        InStorageAmount = 0,
                        OutStorageAmount = 0,
                        OrderId = dbOrder.Id,
                        ProductId = relationOrderSku.ProductId,
                        PurchaseFreight = odsRequest.PurchaseFreight / odsRequest.RelationPurchaseOrderSkuList.Count(),
                        SkuAmount = relationOrderSku.SingleSkuAmount * relationOrderSku.Quantity,
                        SkuId = relationOrderSku.SkuId,
                        StorageAmount = 0,
                        //TotalCost = relationOrderSku.SingleSkuAmount * relationOrderSku.Quantity + odsRequest.PurchaseFreight / odsRequest.RelationPurchaseOrderSkuList.Count(),
                        //UnitCost = purchaseOrder.UnitCost,
                        PurchaseOrderPKId = purchaseOrder.Id
                    };
                    insertOrderCostDetailList.Add(orderCostDetail);

                    var dbOrderSku = dbOrderSkuList.FirstOrDefault(dbosku => dbosku.SkuId == relationOrderSku.SkuId);
                    if (dbOrderSku != null)
                    {
                        orderCostDetail.SkuGrossProfit = dbOrderSku.Price.Value * orderCostDetail.DeductionQuantity - avgPreferential -
                                                         (orderCostDetail.TotalCost + orderCostDetail.DeliveryExpressFreight) -
                                                         dbOrderSku.Price.Value * orderCostDetail.DeductionQuantity * relationPurchaseOrderRequestV2.PlatformCommissionRatio;
                    }
                    #endregion
                }

                #region 订单成本
                var totalDeliveryFreight = relationPurchaseOrderRequestV2.OrderDropShippingList.Sum(ods => ods.DeliveryFreight);
                var totalPurchaseAmount = relationPurchaseOrderRequestV2.OrderDropShippingList.Sum(ods => ods.PurchaseAmount);
                var orderCost = fsql.Select<OrderCost>(dbOrder.Id).ToOne();
                if (orderCost != null)
                {
                    orderCost.PlatformCommissionRatio = relationPurchaseOrderRequestV2.PlatformCommissionRatio;
                    orderCost.PlatformCommissionAmount = dbOrder.OrderSellerPrice * relationPurchaseOrderRequestV2.PlatformCommissionRatio;
                    orderCost.DeliveryExpressFreight = totalDeliveryFreight;
                    orderCost.PurchaseAmount = totalPurchaseAmount;
                    orderCost.Profit = dbOrder.OrderSellerPrice +
                                       dbOrder.FreightPrice -
                                       orderCost.PurchaseAmount -
                                       orderCost.DeliveryExpressFreight -
                                       orderCost.PlatformCommissionAmount;
                    updateOrderCost = fsql.Update<OrderCost>().SetSource(orderCost).IgnoreColumns(oc => new
                    {
                        oc.CreateTime,
                        oc.SDCommissionAmount,
                        oc.SDOrderAmount,
                        oc.PlatformCommissionAmount,
                        oc.PlatformCommissionRatio
                    });
                }
                else
                {
                    var preferentialAmount = fsql.Select<OrderCoupon>().Where(oc => oc.OrderId == dbOrder.Id)
                                                                       .ToAggregate(g => g.Sum(g.Key.CouponPrice));
                    orderCost = new OrderCost()
                    {
                        OrderId = dbOrder.Id,
                        CreateTime = DateTime.Now,
                        DeliveryExpressFreight = totalDeliveryFreight,
                        PlatformCommissionRatio = relationPurchaseOrderRequestV2.PlatformCommissionRatio,
                        SDCommissionAmount = 0,
                        SDOrderAmount = 0,
                        PurchaseAmount = totalPurchaseAmount,
                        PlatformCommissionAmount = dbOrder.OrderSellerPrice * relationPurchaseOrderRequestV2.PlatformCommissionRatio,
                        PreferentialAmount = preferentialAmount,
                        IsManualEdited = true
                    };

                    orderCost.Profit = dbOrder.OrderSellerPrice +
                                       dbOrder.FreightPrice -
                                       orderCost.PurchaseAmount -
                                       orderCost.DeliveryExpressFreight -
                                       orderCost.PlatformCommissionAmount;
                    insertOrderCost = fsql.Insert(orderCost);
                }
                #endregion
            }

            fsql.Transaction(() =>
                {
                    deletePurchaseOrder.ExecuteAffrows();
                    deleteOrderCostDetail.ExecuteAffrows();
                    foreach (var update in updateOrderSkuList)
                        update.ExecuteAffrows();
                    fsql.Insert(insertPurchaseOrderList).ExecuteAffrows();
                    fsql.Insert(insertOrderCostDetailList).ExecuteAffrows();
                    insertOrderCost?.ExecuteAffrows();
                    updateOrderCost?.ExecuteAffrows();
                    if (insertOrderDropShippingList.Count() > 0)
                        fsql.Insert(insertOrderDropShippingList).ExecuteAffrows();
                    if (updateOrderDropShippingList.Count() > 0)
                    {
                        foreach (var update in updateOrderDropShippingList)
                            update.ExecuteAffrows();
                    }
                    if (dbOrder.StorageType != Enums.StorageType.代发)
                    {
                        fsql.Update<Order>(dbOrder.Id)
                            .Set(o => o.StorageType, Enums.StorageType.代发)
                            .SetIf(dbOrder.OrderState == Enums.OrderState.等待采购, o => o.OrderState, Enums.OrderState.待出库)
                            .ExecuteAffrows();
                    }
                });
        }

        /// <summary>
        /// 出库
        /// </summary>
        /// <param name="outStockRequest"></param>
        /// <exception cref="BusinessException"></exception>
        public void OutStock(OutStockRequest outStockRequest)
        {
            var dbOrder = fsql.Select<Order>(outStockRequest.OrderId).ToOne();
            if (dbOrder == null)
                throw new BusinessException($"订单{outStockRequest.OrderId}不存在");
            if (dbOrder.OrderState != Enums.OrderState.待出库)
                throw new BusinessException($"订单{outStockRequest.OrderId} 只有在待出库时才允许出库");

            var relayAPIHost = GetPlatformRelayAPIHost(outStockRequest.Platform);
            var sendResult = restApiService.SendRequest(relayAPIHost, "api/PlatformSDK/OutStock", outStockRequest, GetYunDingRequestHeader(), HttpMethod.Post);
            if (sendResult.StatusCode != System.Net.HttpStatusCode.OK)
                throw new BusinessException(sendResult.Content) { Code = (int)sendResult.StatusCode };
            var response = JsonConvert.DeserializeObject<ApiResponse<ConsigneeSimpleResponse>>(sendResult.Content);
            if (!response.Success)
                throw new BusinessException(response.Msg) { Code = response.Code };

            fsql.Update<Order>(outStockRequest.OrderId).Set(o => o.OrderState, Enums.OrderState.待收货)
                                                       .Set(o => o.WaybillNo, outStockRequest.WayBillNo)
                                                       .ExecuteAffrows();
        }

        /// <summary>
        /// 修改商家备注
        /// </summary>
        /// <param name="editVenderRemarkRequest"></param>
        public void EditVenderRemark(EditVenderRemarkRequest editVenderRemarkRequest)
        {
            //修改平台订单备注
            var relayAPIHost = GetPlatformRelayAPIHost(editVenderRemarkRequest.Platform);

            if (editVenderRemarkRequest.Platform == Enums.Platform.京东)
            {
                var editApiResult = restApiService.SendRequest(relayAPIHost, "/Api/PlatformSDK/EditVenderRemark", editVenderRemarkRequest, GetYunDingRequestHeader(), HttpMethod.Post);
                if (editApiResult.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new BusinessException($"修改商家备注失败 {editApiResult.Content}") { Code = (int)editApiResult.StatusCode };
                var editResponse = JsonConvert.DeserializeObject<ApiResponse>(editApiResult.Content);
                if (!editResponse.Success)
                    throw new BusinessException(editResponse.Msg);
            }
            else
            {
                throw new NotImplementedException();
            }

            fsql.Update<Order>(editVenderRemarkRequest.OrderId).Set(o => o.Flag, editVenderRemarkRequest.Flag)
                                                               .Set(o => o.VenderRemark, editVenderRemarkRequest.VenderRemark)
                                                               .ExecuteAffrows();
        }

        public OrderResponse SDGroupPullOrder(SDGroupPullOrderRequest request)
        {
            OrderResponse orderResponse = null;
            try
            {
                orderResponse = GetOrderById(request.OrderId);
            }
            catch
            {

            }

            if (orderResponse == null)
            {
                var relayAPIHost = GetPlatformRelayAPIHost(request.Platform);
                var orderApiResult = restApiService.SendRequest(relayAPIHost, "api/PlatformSDK/GetNoPayOrder", new SearchPlatformOrderRequest()
                {
                    OrderId = request.OrderId,
                    AppKey = request.AppKey,
                    AppSecret = request.AppSecret,
                    AppToken = request.AppToken,
                    Platform = request.Platform,
                }, GetYunDingRequestHeader(), HttpMethod.Post);
                if (orderApiResult.StatusCode != System.Net.HttpStatusCode.OK)
                    throw new BusinessException($"获取未付款订单失败 {orderApiResult.Content}");

                var orderJToken = JToken.Parse(orderApiResult.Content);
                var orderInfoJToken = orderJToken["Data"]["jingdong_pop_order_notPayOrderById_responce"]["orderDataNotPayInfo"];
                if (orderInfoJToken == null || !orderInfoJToken.HasValues)
                    throw new BusinessException("未查询到待付款订单");

                orderResponse = new OrderResponse()
                {
                    Id = orderInfoJToken["orderId"].ToString(),
                    ShopId = request.ShopId.ToString(),
                    OrderStartTime = DateTime.Parse(orderInfoJToken["orderCreated"].ToString()),
                    ItemList = new List<OrderSkuResponse>(),
                    Platform = request.Platform,
                    OrderCost = new OrderCostResponse()
                    {
                        OrderId = orderInfoJToken["orderId"].ToString(),
                        IsManualEdited = false
                    }
                };

                var orderSkuIds = string.Join(",", orderInfoJToken["itemList"].Children().Select(j => j.Value<string>("skuId")));
                var skuList = productBusiness.GetProductSkuList(new SearchProductSkuRequest()
                {
                    AppKey = request.AppKey,
                    AppSecret = request.AppSecret,
                    AppToken = request.AppToken,
                    Platform = request.Platform,
                    Sku = orderSkuIds
                });

                foreach (var sku in skuList)
                {
                    if (sku.Price != 0)
                    {
                        var num = orderInfoJToken["itemList"].Children().FirstOrDefault(j => j.Value<string>("skuId") == sku.Id)?.Value<int>("num") ?? 1;
                        orderResponse.ItemList.Add(new OrderSkuResponse()
                        {
                            Logo = sku.Logo,
                            OrderId = request.OrderId,
                            Price = sku.Price,
                            Title = sku.Title,
                            ProductId = sku.ProductId,
                            Id = sku.Id,
                            ItemTotal = num
                        });
                    }
                }
            }
            return orderResponse;
        }


        private ISelect<OrderSku, Order, OrderCostDetail, PurchaseOrder, Product> GetQueryOrderSkuListConditions(ExportOrderSkuRequest request)
        {
            var select = fsql.Select<OrderSku, Order, OrderCostDetail, PurchaseOrder, Product>()
                              .InnerJoin((osku, o, ocd, po, p) => osku.OrderId == o.Id)
                              .LeftJoin((osku, o, ocd, po, p) => osku.OrderId == ocd.OrderId && osku.SkuId == ocd.SkuId)
                              .LeftJoin((osku, o, ocd, po, p) => ocd.PurchaseOrderPKId == po.Id)
                              .LeftJoin((osku, o, ocd, po, p) => osku.ProductId == p.Id)
                              .WhereIf(request.ShopIds != null && request.ShopIds.Count() > 0, (osku, o, ocd, po, p) => request.ShopIds.Contains(o.ShopId))
                              .WhereIf(request.PurchasePlatform != null, (osku, o, ocd, po, p) => po.PurchasePlatform == request.PurchasePlatform)
                              .Where((osku, o, ocd, po, p) => o.StartTime >= request.StartTime &&
                                                              o.StartTime <= request.EndTime &&
                                                              o.OrderState != Enums.OrderState.已取消 &&
                                                              o.IsGift == false &&
                                                              osku.Price > 0)
                              .OrderByDescending((osku, o, ocd, po, p) => o.StartTime);
            return select;
        }

        private Expression<Func<OrderSku, Order, OrderCostDetail, PurchaseOrder, Product, ExportOrderSkuResponse>> GetQueryOrderSkuListField()
        {
            return (osku, o, ocd, po, p) => new ExportOrderSkuResponse()
            {
                ItemTotal = osku.ItemTotal,
                OrderId = osku.OrderId,
                PurchaseFreight = ocd.PurchaseFreight,
                PurchaseSkuAmount = ocd.SkuAmount,
                ShopId = o.ShopId,
                Sku = osku.SkuId,
                SkuPrice = osku.Price,
                Spu = osku.ProductId,
                SpuName = p.Title,
                StartTime = o.StartTime,
                StorageType = o.StorageType,
                OrderState = o.OrderState,
                PreferentialAmount = o.PreferentialAmount,
                SellerPreferentialAmount = o.SellerPreferentialAmount
            };
        }

        public ExportOrderSkuListResponse QueryOrderSkuList(QueryOrderSkuRequest request)
        {
            request.EndTime = request.EndTime.Date.AddDays(1).AddSeconds(-1);
            var select = GetQueryOrderSkuListConditions(request);
            var list = select.Count(out long count).Page(request.PageIndex, request.PageSize).ToList(GetQueryOrderSkuListField());

            if (list.Count() > 0)
            {
                var shops = venderBusiness.GetShopList();
                foreach (var item in list)
                {
                    var shopId = item.ShopId.ToString();
                    item.ShopName = shops.Where(s => s.ShopId == shopId).FirstOrDefault()?.ShopName;
                }
            }

            return new ExportOrderSkuListResponse()
            {
                Count = count,
                ItemList = list
            };
        }

        public IList<ExportOrderSkuResponse> ExportOrderSkuList(ExportOrderSkuRequest request)
        {
            request.EndTime = request.EndTime.Date.AddDays(1).AddSeconds(-1);
            var select = GetQueryOrderSkuListConditions(request);
            var list = select.ToList(GetQueryOrderSkuListField());

            if (list.Count() > 0)
            {
                var shops = venderBusiness.GetShopList();
                foreach (var item in list)
                {
                    var shopId = item.ShopId.ToString();
                    item.ShopName = shops.Where(s => s.ShopId == shopId).FirstOrDefault()?.ShopName;
                }
            }
            return list;
        }

        public OrderCouponDetailResponse GetOrderCouponDetail(QueryOrderCouponDetailRequest request)
        {
            var relayAPIHost = GetPlatformRelayAPIHost(request.Platform);
            var sendResult = restApiService.SendRequest(relayAPIHost, "api/PlatformSDK/GetOrderCouponDetail", request, GetYunDingRequestHeader(), HttpMethod.Post);
            if (sendResult.StatusCode != System.Net.HttpStatusCode.OK)
                throw new BusinessException(sendResult.Content) { Code = (int)sendResult.StatusCode };
            var response = JsonConvert.DeserializeObject<ApiResponse<JToken>>(sendResult.Content);
            if (!response.Success)
                throw new BusinessException(response.Msg) { Code = response.Code };

            var jtoken = response.Data;

            var itemList = new List<OrderCouponDetailGroupItemResponse>();
            var couponDetailVoJToken = jtoken["jingdong_pop_order_coupondetail_responce"]["couponDetailExternal"]["couponDetailVo"];
            var promotionTaskJArray = couponDetailVoJToken["promotionList"] as JArray;
            itemList.AddRange(promotionTaskJArray.Select(j => new OrderCouponDetailGroupItemResponse()
            {
                Initiator = string.IsNullOrEmpty(j.Value<string>("promotionName")) ? "平台" : "商家",
                CouponOrPromotionType = j.Value<string>("saleTypeDesc"),
                PreferentialAmount = j.Value<decimal>("salePrice"),
                UndertakenByMerchantAmount = j.Value<decimal>("salePrice"),
                UndertakenByPlatformAmount = 0
            }));

            var couponJArray = couponDetailVoJToken["couponList"] as JArray;
            itemList.AddRange(couponJArray.Select(j => new OrderCouponDetailGroupItemResponse()
            {
                Initiator = string.IsNullOrEmpty(j.Value<string>("couponName")) ? "平台" : "商家",
                CouponOrPromotionType = j.Value<string>("couponTypeDesc"),
                PreferentialAmount = j.Value<decimal>("couponPrice"),
                UndertakenByMerchantAmount = j.Value<bool>("priceDivide") == true ?
                                             j.Value<decimal>("venderDivideMoney") :
                                             j.Value<decimal>("couponPrice"),
                UndertakenByPlatformAmount = j.Value<decimal>("jdDivideMoney")
            }));

            var groups = itemList.GroupBy(x => x.Initiator);


            return new OrderCouponDetailResponse()
            {
                GroupList = groups.Select(g => new OrderCouponDetailGroupResponse()
                {
                    Initiator = g.Key,
                    ItemList = g.ToList()
                }).ToList(),
                TotalPreferentialAmount = itemList.Sum(x => x.PreferentialAmount ?? 0),
                TotalUndertakenByMerchantAmount = itemList.Sum(x => x.UndertakenByMerchantAmount ?? 0),
                TotalUndertakenByPlatformAmount = itemList.Sum(x => x.UndertakenByPlatformAmount ?? 0),
                TotalBalance = couponDetailVoJToken.Value<decimal?>("totalBalance"),
                TotalBaseDiscount = couponDetailVoJToken.Value<decimal?>("totalBaseDiscount"),
                TotalBaseFee = couponDetailVoJToken.Value<decimal?>("totalBaseFee"),
                TotalCoupon = couponDetailVoJToken.Value<decimal?>("totalCoupon"),
                TotalDongQuan = couponDetailVoJToken.Value<decimal?>("totalDongQuan"),
                TotalExpiryGiftDiscount = couponDetailVoJToken.Value<decimal?>("totalExpiryGiftDiscount"),
                TotalGlobalGeneralIncludeTax = couponDetailVoJToken.Value<decimal?>("totalGlobalGeneralIncludeTax"),
                TotalGlobalGeneralTax = couponDetailVoJToken.Value<decimal?>("totalGlobalGeneralTax"),
                TotalItemPrice = couponDetailVoJToken.Value<decimal?>("totalItemPrice"),
                TotalJdZhiFuYouHui = couponDetailVoJToken.Value<decimal?>("totalJdZhiFuYouHui"),
                TotalJingDou = couponDetailVoJToken.Value<decimal?>("totalJingDou"),
                TotalJingQuan = couponDetailVoJToken.Value<decimal?>("totalJingQuan"),
                TotalJingXiangLiJin = couponDetailVoJToken.Value<decimal?>("totalJingXiangLiJin"),
                TotalLiJinYouHui = couponDetailVoJToken.Value<decimal?>("totalLiJinYouHui"),
                TotalLuoDiPeiService = couponDetailVoJToken.Value<decimal?>("totalLuoDiPeiService"),
                TotalManJian = couponDetailVoJToken.Value<decimal?>("totalManJian"),
                TotalPingTaiChengDanYouHuiQuan = couponDetailVoJToken.Value<decimal?>("totalPingTaiChengDanYouHuiQuan"),
                TotalPlus95 = couponDetailVoJToken.Value<decimal?>("totalPlus95"),
                TotalPromotionDiscount = couponDetailVoJToken.Value<decimal?>("totalPromotionDiscount"),
                TotalRemoteFee = couponDetailVoJToken.Value<decimal?>("totalRemoteFee"),
                TotalShouldPay = couponDetailVoJToken.Value<decimal?>("totalShouldPay"),
                TotalSuperRedEnvelope = couponDetailVoJToken.Value<decimal?>("totalSuperRedEnvelope"),
                TotalTaxFee = couponDetailVoJToken.Value<decimal?>("totalTaxFee"),
                TotalTuiHuanHuoWuYou = couponDetailVoJToken.Value<decimal?>("totalTuiHuanHuoWuYou"),
                TotalVenderFee = couponDetailVoJToken.Value<decimal?>("totalVenderFee"),
                TotalXianPinLeiDongQuan = couponDetailVoJToken.Value<decimal?>("totalXianPinLeiDongQuan"),
                TotalXianPinLeiJingQuan = couponDetailVoJToken.Value<decimal?>("totalXianPinLeiJingQuan"),
                TotalZhiFuYingXiaoYouHui = couponDetailVoJToken.Value<decimal?>("totalZhiFuYingXiaoYouHui")
            };
        }
    }
}