Beispiel #1
0
        public HttpResponseMessage GetAppSettings()
        {
            AppSetting s = _appSettingService.Get();

            // _appSettingService.Save(s);
            AppSettingsViewModel appSettingsViewModel = Mapper.Map <AppSetting, AppSettingsViewModel>(s);
            HttpResponseMessage  response             = Request.CreateResponse(HttpStatusCode.OK, appSettingsViewModel);

            return(response);
        }
        public async Task <string> GetMediaUrl(string fileName)
        {
            var options = await _appSettingService.Get <StorageGitHubOptions>();

            if (options == null || string.IsNullOrWhiteSpace(fileName))
            {
                return(string.Empty);
            }
            var res        = options.RepositoryName.Trim().Trim('/');
            var bra        = options.BranchName.Trim().Trim('/');
            var path       = options.SavePath.Trim().Trim('/');
            var pathInName = $"{fileName.Substring(0, 2)}/{fileName.Substring(2, 2)}/{fileName.Substring(4, 2)}";

            //https://raw.githubusercontent.com/trueai-org/data/master/images/44/b7/96/44b796c968f4703a871b0f6f06fe85b1636844361657344457.jpg
            return($"{ContentHost.TrimEnd('/')}/{res}/{bra}/{path}/{pathInName}/{fileName}");
        }
Beispiel #3
0
        public async Task <PaymentOrderBaseResponse> GeneratePaymentOrder(PaymentOrderRequest request)
        {
            var apiHost = await _appSettingService.Get(ShopKeys.ApiHost);

            var wxRequest = new WeChatPayUnifiedOrderRequest
            {
                Body           = request.Subject,
                OutTradeNo     = request.OrderNo,
                TotalFee       = Convert.ToInt32(request.TotalAmount * 100),
                OpenId         = request.OpenId,
                TradeType      = "JSAPI",
                SpbillCreateIp = "127.0.0.1",
                NotifyUrl      = $"{apiHost.Trim('/')}/api/mp/pay/notify/{request.OrderNo}",
            };
            var response = await _client.ExecuteAsync(wxRequest);

            if (response?.ReturnCode == "SUCCESS" && response?.ResultCode == "SUCCESS")
            {
                var req = new WeChatPayLiteAppCallPaymentRequest
                {
                    Package = "prepay_id=" + response.PrepayId
                };

                // https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
                // 将参数(parameter)给 小程序前端 让他调起支付API
                var parameter = await _client.ExecuteAsync(req);

                var json = JsonConvert.SerializeObject(parameter);
                return(JsonConvert.DeserializeObject <PaymentOrderResponse>(json));
            }
            throw new Exception(response?.ReturnMsg);
        }
Beispiel #4
0
 public LocalStorageService(
     IRepository <Media> mediaRepository,
     IAppSettingService appSettingService)
 {
     host             = appSettingService.Get(ShopKeys.ApiHost).Result;
     _mediaRepository = mediaRepository;
 }
        public async Task <PaymentOrderBaseResponse> GeneratePaymentOrder(PaymentOrderRequest request)
        {
            var ip = Dns.GetHostEntry(Dns.GetHostName())
                     .AddressList.FirstOrDefault(address => address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)?.ToString()
                     ?? "127.0.0.1";

            var apiHost = await _appSettingService.Get(ShopKeys.ApiHost);

            var wxRequest = new WeChatPayUnifiedOrderRequest
            {
                Body       = request.Subject,
                OutTradeNo = request.OrderNo,
                TotalFee   = Convert.ToInt32(request.TotalAmount * 100),
                OpenId     = request.OpenId,
                TradeType  = "JSAPI",
                //SpbillCreateIp = "127.0.0.1",
                SpBillCreateIp = ip,
                NotifyUrl      = $"{apiHost.Trim('/')}/api/mp/pay/notify/{request.OrderNo}",
            };

            var config = await _appSettingService.Get <MiniProgramOptions>();

            var opt = new WeChatPayOptions()
            {
                AppId  = config.AppId,
                MchId  = config.MchId,
                Secret = config.AppSecret,
                Key    = config.Key
            };
            var response = await _client.ExecuteAsync(wxRequest, opt);

            if (response?.ReturnCode == WeChatPayCode.Success && response?.ResultCode == WeChatPayCode.Success)
            {
                var req = new WeChatPayLiteAppSdkRequest
                {
                    Package = $"prepay_id={response.PrepayId}"
                };

                // https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
                // 将参数(parameter)给 小程序前端 让他调起支付API
                var parameter = await _client.ExecuteAsync(req, opt);

                var json = JsonConvert.SerializeObject(parameter);
                return(JsonConvert.DeserializeObject <PaymentOrderResponse>(json));
            }
            throw new Exception(response?.ReturnMsg);
        }
Beispiel #6
0
        public async Task <Result> Get()
        {
            var version = await _appSettingService.Get("Global.AssetVersion");

            var result = new SystemInfoResult()
            {
                Version         = version,
                ServerTimeZone  = TimeZoneInfo.Local.StandardName,
                ServerLocalTime = DateTime.Now,
                UtcTime         = DateTime.UtcNow,
                HttpHost        = _httpContextAccessor.HttpContext.Request.Headers[HeaderNames.Host],
            };

            //ensure no exception is thrown
            try
            {
                result.OperatingSystem = Environment.OSVersion.VersionString;
                result.AspNetInfo      = RuntimeEnvironment.GetSystemVersion();
                result.IsFullTrust     = AppDomain.CurrentDomain.IsFullyTrusted.ToString();
            }
            catch { }

            //foreach (var header in _httpContextAccessor.HttpContext.Request.Headers)
            //{
            //    result.Headers.Add(new SystemInfoResult.HeaderModel
            //    {
            //        Name = header.Key,
            //        Value = header.Value
            //    });
            //}

            //foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            //{
            //    var loadedAssemblyModel = new SystemInfoResult.LoadedAssembly
            //    {
            //        FullName = assembly.FullName
            //    };

            //    //ensure no exception is thrown
            //    try
            //    {
            //        loadedAssemblyModel.Location = assembly.IsDynamic ? null : assembly.Location;
            //        loadedAssemblyModel.IsDebug = assembly.GetCustomAttributes(typeof(DebuggableAttribute), false)
            //            .FirstOrDefault() is DebuggableAttribute attribute && attribute.IsJITOptimizerDisabled;

            //        //https://stackoverflow.com/questions/2050396/getting-the-date-of-a-net-assembly
            //        //we use a simple method because the more Jeff Atwood's solution doesn't work anymore
            //        //more info at https://blog.codinghorror.com/determining-build-date-the-hard-way/
            //        loadedAssemblyModel.BuildDate = assembly.IsDynamic ? null : (DateTime?)TimeZoneInfo.ConvertTimeFromUtc(System.IO.File.GetLastWriteTimeUtc(assembly.Location), TimeZoneInfo.Local);

            //    }
            //    catch { }
            //    result.LoadedAssemblies.Add(loadedAssemblyModel);
            //}

            return(Result.Ok(result));
        }
Beispiel #7
0
 public EmailSender(
     IConfiguration config,
     IRepository <EmailSend> emilSendRepository,
     ILogger <EmailSender> logger,
     IAppSettingService appSettingService)
 {
     _emailConfig        = appSettingService.Get <EmailSenderSmtpOptions>().Result;
     _emilSendRepository = emilSendRepository;
     _logger             = logger;
 }
Beispiel #8
0
        public MQService(IAppSettingService appSettingService)
        {
            var options = appSettingService.Get <RabbitMQOptions>().Result;

            if (string.IsNullOrWhiteSpace(options?.ConnectionString))
            {
                throw new ArgumentNullException(nameof(RabbitMQOptions));
            }

            _bus = RabbitHutch.CreateBus(options.ConnectionString);
        }
Beispiel #9
0
        public async Task <Result> CinfirmReceipt(int id)
        {
            var user = await _workContext.GetCurrentOrThrowAsync();

            var order = await _orderRepository.Query()
                        .FirstOrDefaultAsync(c => c.CustomerId == user.Id && c.Id == id);

            if (order == null)
            {
                return(Result.Fail("订单不存在"));
            }
            else if (order.OrderStatus == OrderStatus.Canceled)
            {
                return(Result.Fail("订单已取消"));
            }
            var orderSs = new OrderStatus[] { OrderStatus.PaymentReceived, OrderStatus.Shipping, OrderStatus.Shipped };

            if (!orderSs.Contains(order.OrderStatus))
            {
                return(Result.Fail("当前订单无法确认收货"));;
            }

            order.OrderStatus    = OrderStatus.Complete;
            order.ShippingStatus = ShippingStatus.Delivered;
            order.DeliveredOn    = DateTime.Now;
            order.UpdatedOn      = DateTime.Now;
            order.UpdatedById    = user.Id;
            await _orderRepository.SaveChangesAsync();

            // 自动好评
            var min = await _appSettingService.Get <int>(OrderKeys.OrderCompleteAutoReviewTimeForMinute);

            foreach (var item in order.OrderItems)
            {
                await _jobService.Schedule(() =>
                                           _reviewService.ReviewAutoGood(item.ProductId, EntityTypeWithId.Product, order.Id, ReviewSourceType.Order)
                                           , TimeSpan.FromMinutes(min));
            }

            return(Result.Ok());
        }
Beispiel #10
0
        public ActionResult AppSettingDialog(int id = 0)
        {
            CategoryItems      item       = new CategoryItems();
            IAppSettingService appService = IocMvcFactoryHelper.GetInterface <IAppSettingService>();

            if (id > 0)
            { //查询带编辑的数据
                item = appService.Get(id);
            }
            ViewData[ParamNameTemplate.AppSettingParentNode] =
                (item.Id > 0 && item.ParentCode != InitAppSetting.DefaultAppsettingRootCode) ?
                appService.QueryNodes(item.ParentCode)
                :QueryAppSettingList(InitAppSetting.DefaultAppsettingRootCode);
            return(View(item));
        }
Beispiel #11
0
 public MPApiController(
     IAppSettingService appSettingService,
     IAccountService accountService,
     IRepository <UserLogin> userLoginRepository,
     UserManager <User> userManager,
     SignInManager <User> signInManager,
     ILoggerFactory loggerFactory,
     IConfiguration configuration,
     IRepository <User> userRepository,
     ITokenService tokenService)
 {
     _option = appSettingService.Get <MiniProgramOptions>().Result;
     _userLoginRepository = userLoginRepository;
     _userManager         = userManager;
     _signInManager       = signInManager;
     _userRepository      = userRepository;
     _tokenService        = tokenService;
 }
Beispiel #12
0
        public AliyunSmsSenderService(
            ILoggerFactory loggerFactory,
            //IOptionsMonitor<AliyunSmsOptions> options,
            IRepository <SmsSend> smsSendRepository,
            IStaticCacheManager cacheManager,
            IAppSettingService appSettingService)
        {
            _logger            = loggerFactory.CreateLogger <AliyunSmsSenderService>();
            _smsSendRepository = smsSendRepository;
            _cacheManager      = cacheManager;
            _appSettingService = appSettingService;

            var options = _appSettingService.Get <SmsSenderAliyunOptions>().Result;

            regionId        = options.RegionId;
            accessKeyId     = options.AccessKeyId;
            accessKeySecret = options.AccessKeySecret;
            isTest          = options.IsTest;
        }
Beispiel #13
0
        public async Task <IActionResult> NotifyByOrderNo(string no)
        {
            try
            {
                var config = await _appSettingService.Get <MiniProgramOptions>();

                var opt = new WeChatPayOptions()
                {
                    AppId  = config.AppId,
                    MchId  = config.MchId,
                    Secret = config.AppSecret,
                    Key    = config.Key
                };

                var notify = await _client.ExecuteAsync <WeChatPayUnifiedOrderNotify>(Request, opt);

                if (notify.ReturnCode == "SUCCESS")
                {
                    if (notify.ResultCode == "SUCCESS")
                    {
                        await _mqService.Send(QueueKeys.PaymentReceived, new PaymentReceived()
                        {
                            Note             = "微信支付成功结果通知",
                            OrderNo          = no,
                            PaymentFeeAmount = notify.TotalFee / 100M,
                            PaymentMethod    = PaymentMethod.WeChat,
                            PaymentOn        = DateTime.ParseExact(notify.TimeEnd, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture)
                        });

                        return(WeChatPayNotifyResult.Success);
                    }
                }
                return(NoContent());
            }
            catch
            {
                return(NoContent());
            }
            finally
            {
                _logger.LogInformation("参数:{@no}", no);
            }
        }
Beispiel #14
0
        public async Task <Result> Post([FromBody] ReplyAddParam param)
        {
            var user = await _workContext.GetCurrentOrThrowAsync();

            var reply = new Reply
            {
                ReviewId    = param.ReviewId,
                Comment     = param.Comment,
                IsAnonymous = param.IsAnonymous,
                ParentId    = null,
                UserId      = user.Id,
                ReplierName = param.IsAnonymous ? $"{user.FullName.First()}***{user.FullName.Last()}" : user.FullName,
            };

            if (param.ToReplyId != null)
            {
                var toReply = await _replyRepository.FirstOrDefaultAsync(param.ToReplyId.Value);

                if (toReply == null)
                {
                    throw new Exception("回复信息不存在");
                }
                reply.ToUserId   = toReply.UserId;
                reply.ToUserName = toReply.ReplierName;
                reply.ParentId   = toReply.ParentId ?? toReply.Id;
            }
            _replyRepository.Add(reply);
            await _replyRepository.SaveChangesAsync();

            var isAuto = await _appSettingService.Get <bool>(ReviewKeys.IsReplyAutoApproved);

            if (isAuto)
            {
                await _mqService.Send(QueueKeys.ReplyAutoApproved, new ReplyAutoApprovedEvent()
                {
                    ReplyId = reply.Id
                });
            }
            return(Result.Ok());
        }
Beispiel #15
0
        public async Task <Media> SaveMediaAsync(Stream mediaBinaryStream, string fileName, string mimeType = null)
        {
            var bytes = new byte[mediaBinaryStream.Length];

            using (mediaBinaryStream)
            {
                mediaBinaryStream.Read(bytes, 0, bytes.Length);
            }
            var hsMd5 = Md5Helper.Encrypt(bytes);
            var media = await _mediaRepository.Query(c => c.Md5 == hsMd5).FirstOrDefaultAsync();

            if (media != null)
            {
                return(media);
            }

            var result = await Task.Run(() =>
            {
                return(Upload(bytes, hsMd5, fileName));
            });

            if (result?.Data == null)
            {
                return(null);
            }
            var cusDomain = await _appSettingService.Get <StorageSmOptions>();

            var url = result.Data.Url;

            if (!string.IsNullOrWhiteSpace(cusDomain?.CustomDomain))
            {
                url = $"{cusDomain.CustomDomain.Trim('/')}/{result.Data.Path.Trim('/')}";
            }
            media = new Media()
            {
                MediaType = MediaType.File,
                FileName  = result.Data.Filename,
                FileSize  = result.Data.Size,
                Hash      = result.Data.Hash,
                Url       = url,
                Path      = result.Data.Path,
                Host      = StorageSmKeys.Host,
                Md5       = hsMd5
            };
            if (!string.IsNullOrWhiteSpace(mimeType))
            {
                mimeType = mimeType.Trim().ToLower();
                if (mimeType.StartsWith("video"))
                {
                    media.MediaType = MediaType.Video;
                }
                else if (mimeType.StartsWith("image"))
                {
                    media.MediaType = MediaType.Image;
                }
                else
                {
                    media.MediaType = MediaType.File;
                }
            }
            _mediaRepository.Add(media);
            await _mediaRepository.SaveChangesAsync();

            return(media);
        }
        public PartialViewResult Edit(int id)
        {
            AppSetting ObjAppSetting = _appSettingService.Get(id);

            return(PartialView(ObjAppSetting));
        }
Beispiel #17
0
        public async Task <Result> Post(int id, [FromBody] OrderShipmentParam param)
        {
            var currentUser = await _workContext.GetCurrentUserAsync();

            var order = await _orderRepository.Query()
                        .Include(c => c.OrderItems).ThenInclude(c => c.Product)
                        .FirstOrDefaultAsync(c => c.Id == id);

            if (order == null)
            {
                return(Result.Fail("订单不存在"));
            }
            if (order.OrderStatus != OrderStatus.Shipping && order.OrderStatus != OrderStatus.PaymentReceived)
            {
                return(Result.Fail($"订单状态处于[{order.OrderStatus}],不允许发货"));
            }

            switch (order.ShippingStatus)
            {
            case ShippingStatus.NoShipping:
            {
                //无物流
                order.OrderStatus = OrderStatus.Shipped;
                await _orderRepository.SaveChangesAsync();

                return(Result.Ok());
            }

            case null:
            case ShippingStatus.NotYetShipped:
            case ShippingStatus.PartiallyShipped:
                order.ShippingStatus = ShippingStatus.PartiallyShipped;
                break;

            case ShippingStatus.Shipped:
                return(Result.Fail($"订单已发货"));

            case ShippingStatus.Delivered:
                return(Result.Fail($"订单已收货"));

            default:
                return(Result.Fail($"配送状态异常"));
            }
            if (order.OrderStatus == OrderStatus.PaymentReceived)
            {
                order.OrderStatus = OrderStatus.Shipping;
            }

            var shipment = new Shipment
            {
                TrackingNumber = param.TrackingNumber,
                AdminComment   = param.AdminComment,
                TotalWeight    = param.TotalWeight,
                OrderId        = id,
                UpdatedById    = currentUser.Id,
                CreatedById    = currentUser.Id,
                ShippedOn      = DateTime.Now
            };

            foreach (var item in param.Items)
            {
                if (item.QuantityToShip <= 0 ||
                    shipment.Items.Any(c => c.OrderItemId == item.OrderItemId) ||
                    !order.OrderItems.Any(c => c.Id == item.OrderItemId))
                {
                    continue;
                }

                var orderItem = order.OrderItems.First(c => c.Id == item.OrderItemId);
                if (orderItem.ShippedQuantity >= orderItem.Quantity)
                {
                    throw new Exception($"订单商品[{orderItem.Product.Name}],已全部发货");
                }
                if (orderItem.ShippedQuantity + item.QuantityToShip > orderItem.Quantity)
                {
                    throw new Exception($"订单商品[{orderItem.Product.Name}],发货数量不能>下单数量");
                }

                var shipmentItem = new ShipmentItem
                {
                    Shipment    = shipment,
                    Quantity    = item.QuantityToShip,
                    ProductId   = orderItem.ProductId,
                    OrderItemId = item.OrderItemId,
                    CreatedById = currentUser.Id,
                    UpdatedById = currentUser.Id
                };
                shipment.Items.Add(shipmentItem);
                orderItem.ShippedQuantity += item.QuantityToShip;
            }

            if (!order.OrderItems.Any(c => c.ShippedQuantity < c.Quantity))
            {
                var timeFromMin = await _appSettingService.Get <int>(OrderKeys.OrderAutoCompleteTimeForMinute);

                //全部发货
                order.ShippingStatus = ShippingStatus.Shipped;
                order.OrderStatus    = OrderStatus.Shipped;
                order.ShippedOn      = DateTime.Now;
                order.DeliveredEndOn = order.ShippedOn.Value.AddMinutes(timeFromMin);
                order.UpdatedOn      = DateTime.Now;
            }

            _shipmentRepository.Add(shipment);

            using (var transaction = _orderRepository.BeginTransaction())
            {
                await _orderRepository.SaveChangesAsync();

                await _shipmentRepository.SaveChangesAsync();

                transaction.Commit();
            }
            return(Result.Ok());
        }
Beispiel #18
0
        public async Task <Result> AddReview([FromBody] ReviewAddParam param)
        {
            var user = await _workContext.GetCurrentOrThrowAsync();

            var anyType = entityTypeIds.Any(c => c == param.EntityTypeId);

            if (!anyType)
            {
                throw new Exception("参数异常");
            }

            if (param.SourceType == null && param.SourceId != null)
            {
                throw new Exception("评论来源类型异常");
            }
            else if (param.SourceType != null && param.SourceId != null)
            {
                if (param.SourceType == ReviewSourceType.Order && param.EntityTypeId == EntityTypeWithId.Product)
                {
                    var anyProduct = _orderRepository.Query().Any(c => c.Id == param.SourceId.Value && c.OrderItems.Any(x => x.ProductId == param.EntityId));
                    if (!anyProduct)
                    {
                        throw new Exception("评论商品不存在");
                    }
                    var order = await _orderRepository.Query().FirstOrDefaultAsync(c => c.Id == param.SourceId);

                    if (order == null)
                    {
                        throw new Exception("订单不存在");
                    }
                    if (order.OrderStatus != OrderStatus.Complete)
                    {
                        throw new Exception("订单未完成,无法进行评价");
                    }
                }
            }

            // 一个用户
            // 评论 某订单 某商品只能一次
            // 评论 无订单关联 评论商品只能一次
            var any = await _reviewRepository.Query()
                      .AnyAsync(c => c.UserId == user.Id && c.EntityTypeId == (int)param.EntityTypeId && c.EntityId == param.EntityId && c.SourceId == param.SourceId && c.SourceType == param.SourceType);

            if (any)
            {
                throw new Exception("您已评论");
            }

            var review = new Review
            {
                Rating       = param.Rating,
                Title        = param.Title,
                Comment      = param.Comment,
                EntityId     = param.EntityId,
                EntityTypeId = (int)param.EntityTypeId,
                IsAnonymous  = param.IsAnonymous,
                UserId       = user.Id,
                ReviewerName = param.IsAnonymous ? $"{user.FullName.First()}***{user.FullName.Last()}" : user.FullName,
                SourceId     = param.SourceId,
                SourceType   = param.SourceType
            };

            if (param?.MediaIds.Count > 0)
            {
                var mediaIds = param.MediaIds.Distinct();
                int i        = 0;
                foreach (var mediaId in mediaIds)
                {
                    review.Medias.Add(new ReviewMedia()
                    {
                        DisplayOrder = i,
                        MediaId      = mediaId,
                        Review       = review
                    });
                    i++;
                }
            }
            _reviewRepository.Add(review);
            _reviewRepository.SaveChanges();

            var isAuto = await _appSettingService.Get <bool>(ReviewKeys.IsReviewAutoApproved);

            if (isAuto)
            {
                await _mqService.DirectSend(QueueKeys.ReviewAutoApproved, new ReviewAutoApprovedEvent()
                {
                    ReviewId = review.Id
                });
            }
            return(Result.Ok());
        }
Beispiel #19
0
        public async Task <Order> OrderCreate(int userId, OrderCreateBaseParam param, string adminNote = null)
        {
            if (param == null)
            {
                throw new Exception("参数异常");
            }
            if (param.Items == null || param.Items.Count <= 0)
            {
                throw new Exception("购买商品不存在或已下架");
            }
            if (param.Items.Any(c => c.Quantity <= 0))
            {
                throw new Exception("购买商品数量必须>0");
            }

            param.Items = param.Items.GroupBy(c => c.ProductId).Select(c => new OrderCreateBaseItemParam()
            {
                ProductId = c.Key,
                Quantity  = c.Sum(x => x.Quantity)
            }).ToList();

            var customerId       = param.CustomerId;
            var payEndTimeForMin = await _appSettingService.Get <int>(OrderKeys.OrderAutoCanceledTimeForMinute);

            var productIds = param.Items.Select(c => c.ProductId).Distinct();
            var products   = await _productRepository.Query()
                             .Where(c => productIds.Contains(c.Id) && c.IsPublished && c.IsAllowToOrder)
                             .Include(c => c.ThumbnailImage)
                             .ToListAsync();

            if (products == null || products.Count <= 0)
            {
                throw new Exception("购买商品不存在或已下架");
            }

            var stocks = await _stockRepository.Query().Where(c => productIds.Contains(c.ProductId)).ToListAsync();

            var order = new Order()
            {
                OrderStatus       = OrderStatus.PendingPayment, // 默认创建订单,待付款
                CreatedById       = userId,
                UpdatedById       = userId,
                CustomerId        = customerId,
                AdminNote         = adminNote,
                OrderNote         = param.OrderNote,
                ShippingMethod    = param.ShippingMethod,
                PaymentType       = param.PaymentType,
                ShippingFeeAmount = param.ShippingFeeAmount,
                DiscountAmount    = param.DiscountAmount,
                PaymentEndOn      = DateTime.Now.AddMinutes(payEndTimeForMin)
            };

            var orderShipping = await UserAddressToOrderAddress(param.ShippingUserAddressId, customerId, AddressType.Shipping, order);

            OrderAddress orderBilling = null;

            if (param.BillingUserAddressId.HasValue && param.BillingUserAddressId.Value > 0)
            {
                orderBilling = await this.UserAddressToOrderAddress(param.BillingUserAddressId.Value, customerId, AddressType.Billing, order);
            }

            var addStockHistories = new List <StockHistory>();

            foreach (var item in param.Items)
            {
                var product = products.FirstOrDefault(c => c.Id == item.ProductId);
                if (product == null)
                {
                    continue;
                }

                OrderStockDoWorker(stocks, addStockHistories, product, userId, -item.Quantity, order, "创建订单");

                var orderItem = new OrderItem()
                {
                    Order           = order,
                    Product         = product,
                    ItemWeight      = 0,
                    ItemAmount      = item.Quantity * product.Price,
                    Quantity        = item.Quantity,
                    ProductPrice    = product.Price,
                    DiscountAmount  = 0,
                    CreatedById     = userId,
                    UpdatedById     = userId,
                    ProductName     = product.Name,
                    ProductMediaUrl = product.ThumbnailImage?.Url
                };
                order.OrderItems.Add(orderItem);
            }

            order.SubTotal             = order.OrderItems.Sum(c => c.Quantity * c.ProductPrice);
            order.SubTotalWithDiscount = order.OrderItems.Sum(c => c.DiscountAmount);
            order.OrderTotal           = order.OrderItems.Sum(c => c.Product.Price * c.Quantity) + order.ShippingFeeAmount - order.SubTotalWithDiscount - order.DiscountAmount;
            _orderRepository.Add(order);

            // Unable to save changes because a circular dependency was detected in the data to be saved
            // https://github.com/aspnet/EntityFrameworkCore/issues/11888
            // https://docs.microsoft.com/zh-cn/ef/core/saving/transactions
            // https://stackoverflow.com/questions/40073149/entity-framework-circular-dependency-for-last-entity
            using (var transaction = _orderRepository.BeginTransaction())
            {
                await _orderRepository.SaveChangesAsync();

                order.ShippingAddress = orderShipping;
                order.BillingAddress  = orderBilling;
                await _orderRepository.SaveChangesAsync();

                var orderCreated = new OrderCreated
                {
                    OrderId = order.Id,
                    Order   = order,
                    UserId  = order.CreatedById,
                    Note    = order.OrderNote
                };
                await _mediator.Publish(orderCreated);

                await _stockRepository.SaveChangesAsync();

                if (addStockHistories.Count > 0)
                {
                    _stockHistoryRepository.AddRange(addStockHistories);
                    await _stockHistoryRepository.SaveChangesAsync();
                }

                // 订单取消任务 如果n分钟内用户支付或主动取消订单时,则自动取消此任务
                var min = await _appSettingService.Get <int>(OrderKeys.OrderAutoCanceledTimeForMinute);

                await _jobService.Schedule(() => Cancel(order.Id, (int)UserWithId.System, "超时自动取消"), TimeSpan.FromMinutes(min));

                transaction.Commit();
            }

            //TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }
            //using (var ts = new TransactionScope())
            //{
            //    ts.Complete();
            //}

            return(order);
        }
        public IActionResult GetAppSetting(int id)
        {
            var appSetting = appSettingService.Get(id);

            return(Json(appSetting));
        }