using Ant.Core.Utils; using Ant.Core.WebApi.Enum; using Ant.Core.WebApi.Model; using Aop.Api.Util; using Central.Control.WebApi.Config; using Central.Control.WebApi.DbEntity; using Central.Control.WebApi.EFDbContext; using Central.Control.WebApi.Enum; using Central.Control.WebApi.Log4net; using Central.Control.WebApi.Models.Request; using Central.Control.WebApi.Models.Response; using Central.Control.WebApi.Service.Interface; using Com.Alipay; using Com.Alipay.Business; using Com.Alipay.Domain; using Com.Alipay.Model; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.IO; using System.Linq; using System.Web; namespace Central.Control.WebApi.Service { /// /// /// public class OrderService: IOrderService { IAlipayTradeService serviceClient = F2FBiz.CreateClientInstance(AliPayConfig.serverUrl, AliPayConfig.appId, AliPayConfig.merchant_private_key, AliPayConfig.version, AliPayConfig.sign_type, AliPayConfig.alipay_public_key, AliPayConfig.charset); /// /// 支付宝回写地址 /// public readonly static string aliNotifyUrl = ConfigurationManager.AppSettings["aliNotifyUrl"].ToString(); private readonly IDbContext _dbContent; private readonly IUserService _userService; private readonly ILog4NetHelper _log4NetHelper; /// /// /// /// /// /// public OrderService( IDbContext dbContent, IUserService userService, ILog4NetHelper log4NetHelper) { _dbContent = dbContent; _userService = userService; _log4NetHelper = log4NetHelper; } /// /// 下单 /// /// /// public ApiResult Order(OrderRequestDto req) { #region 1、验证参数 if (req == null || req.OrderInfo == null || req.OrderInfo.Count() == 0) { return new ApiResult(ApiStatusCode.InvalidParameter, "请求参数不正确"); } #endregion #region 2、验证相应数据和库存 var productIds = req.OrderInfo.Select(p => p.ProductId).ToList(); var products = _dbContent.Set().Where(p => p.IsDelete == 0 && p.Sale == Enum.SaleEnum.On && productIds.Contains(p.Id)).ToList(); if (products.Count() <= 0) { return new ApiResult(ApiStatusCode.RecordNotFound, "未找到下单的商品"); } #endregion #region 3、包装盒库存验证 var session = _userService.GetLoginSession(); // 修改 var devicePackings = _dbContent.Set().Where(p => p.IsDelete == 0 && p.DeviceId == session.UserId).ToList(); if (devicePackings == null || devicePackings.Count() == 0) { return new ApiResult(ApiStatusCode.Forbidden, "包装盒库存不足,请联系工作人员添加包装盒"); } int orderCount = req.OrderInfo.Sum(p => p.Count); int packingCount = devicePackings.Sum(p => p.Stock * p.Capacity); if (packingCount < orderCount) { return new ApiResult(ApiStatusCode.Forbidden, "包装盒库存不足,请联系工作人员添加包装盒"); } // 计算使用的包装盒数量(减包装盒库存) var orderCountIndex = orderCount; foreach (var devicePacking in devicePackings) { if (orderCountIndex <= 0) { break;// 数量为0了,则直接跳出循环 } int currentPackingStock = devicePacking.Stock; for (int i = 0; i < currentPackingStock; i++) { // 循环库存 if (orderCountIndex <= 0) { break;// 数量为0了,则直接跳出循环 } orderCountIndex = orderCountIndex - devicePacking.Capacity; devicePacking.Stock--;// 减库存 } } #endregion #region 4、商品库存验证 var orderId = IdGenerator.NewId(); List orderDetailAdds = new List(); List orderProcessAdds = new List(); foreach (var o in req.OrderInfo) { var currentProduct = products.FirstOrDefault(p => p.Id == o.ProductId); if (currentProduct == null) { return new ApiResult(ApiStatusCode.RecordNotFound, $"{o.ProductId}商品不存在"); } if (currentProduct.Stock < o.Count) { return new ApiResult(ApiStatusCode.Forbidden, $"{currentProduct.Name}商品库存不足,请修改后重新下单"); } // 扣库存 currentProduct.Stock = currentProduct.Stock - o.Count; // orderDetails orderDetailAdds.Add(new YW_OrderDetails() { Id = IdGenerator.NewId(), OrderId = orderId, ProductId = currentProduct.Id, Name = currentProduct.Name, Code = currentProduct.Code, Img = currentProduct.Img, Info = currentProduct.Info, Price = currentProduct.Price, BuyingPrice = currentProduct.BuyingPrice, Count = o.Count, CreateBY = session.UserId }); } #endregion #region 5、下单 YW_Order order = new YW_Order() { Id = orderId, DeviceId = session.UserId, Price = orderDetailAdds.Sum(p => p.Price * p.Count), PayStatus = PayStatusEnum.UnPay, OrderStatus = OrderStatusEnum.UnPay, // PaySerialId = Snowflake.Instance().GetId().ToString(), // 支付流水号,支付完成会回写 CreateBY = session.UserId }; YW_OrderProcess orderProcess = new YW_OrderProcess() { Id = IdGenerator.NewId(), OrderId = order.Id, DeviceId = session.UserId, CurrentOrderStatus = OrderStatusEnum.UnPay, Message = "下单成功", CreateBY = session.Id }; #endregion #region 6、存库 _dbContent.Set().Add(order); _dbContent.Set().Add(orderProcess); _dbContent.Set().AddRange(orderDetailAdds); // 数据库执行 库存已经改过了,会自动保存 _dbContent.SaveChanges(); #endregion #region 5、支付宝支付--目前直接入支付宝支付测试,后期需要替换成中间页面 #endregion return new ApiResult(new OrderResponseDto() { OrderId = order.Id, Price = order.Price }); } /// /// 获取待烧烤的商品列表 /// /// public ApiResult> GetQueueOrders() { var orders = _dbContent.Set() .Where(p => p.IsDelete == 0 && p.PayStatus == PayStatusEnum.Paid && p.OrderStatus == OrderStatusEnum.Paid) .OrderBy(p => p.CreateDT).ToList(); var orderIds = orders.Select(p => p.Id).ToList(); var orderDetails = _dbContent.Set().Where(p => p.IsDelete == 0 && orderIds.Contains(p.OrderId)).ToList(); List result = new List(); orders.ForEach(item => { QueueOrderResponseDto resultItem = new QueueOrderResponseDto() { OrderId = item.Id, Price = item.Price, OrderDetails = orderDetails .Where(p => p.OrderId == item.Id) .Select(p => SafeClone.Trans(p)) .ToList() }; resultItem.OrderDetails?.ForEach(p => p.Img = $"{ProductService.ImagePrefix}{p.Img}"); result.Add(resultItem); }); return new ApiResult>(result); } /// /// 回写流程状态 /// /// /// public ApiResult OrderProcess(OrderProcessRequestDto req) { if (req == null) { return new ApiResult(ApiStatusCode.InvalidParameter, "请求参数不正确"); } var order = _dbContent.Set().FirstOrDefault(p => p.Id == req.OrderId); if (order == null) { return new ApiResult(ApiStatusCode.InvalidParameter, "未找到相应订单"); } if (order.PayStatus != PayStatusEnum.Paid) { return new ApiResult(ApiStatusCode.InvalidParameter, "未支付订单不能回写流程"); } if (order.OrderStatus == OrderStatusEnum.UnPay || order.OrderStatus == OrderStatusEnum.Cancel) { return new ApiResult(ApiStatusCode.InvalidParameter, "未支付或已取消订单不能回写流程"); } var seesion = _userService.GetLoginSession(); // 修改订单状态 order.OrderStatus = req.OrderStatus; // 记录订单流程 YW_OrderProcess orderProcess = new YW_OrderProcess() { Id = IdGenerator.NewId(), OrderId = req.OrderId, DeviceId = seesion.UserId, CurrentOrderStatus = req.OrderStatus, Message = req.Message, CreateBY = seesion.UserId }; _dbContent.Set().Add(orderProcess); _dbContent.SaveChanges(); return new ApiResult(); } /// /// 支付宝回写 /// /// public string AliPayNotify() { _log4NetHelper.Info("[AliPayNotify]-start"); SortedDictionary sPara = GetRequestPost(); _log4NetHelper.Info("[AliPayNotify]-[原始请求参数]-" + JsonConvert.SerializeObject(sPara)); Notify aliNotify = new Notify(AliPayConfig.charset, AliPayConfig.sign_type, AliPayConfig.pid, AliPayConfig.mapiUrl, AliPayConfig.alipay_public_key); string notifyId = HttpContext.Current.Request.Form["notify_id"]; string sign = HttpContext.Current.Request.Form["sign"]; _log4NetHelper.Info($"[AliPayNotify]-[基础参数]-notify_id:{notifyId};sign{sign}"); //对异步通知进行验签 bool verifyResult = aliNotify.Verify(sPara, notifyId, sign); if (verifyResult && CheckParams()) //验签成功 && 关键业务参数校验成功 { _log4NetHelper.Info("[AliPayNotify]-验签成功"); PayStatusEnum payStatus = PayStatusEnum.Fail; if (HttpContext.Current.Request.Form["trade_status"] == "TRADE_SUCCESS") { payStatus = PayStatusEnum.Paid; } PayWriteBackRequestDto payWriteBack = new PayWriteBackRequestDto() { PaySerialId = HttpContext.Current.Request.Form["trade_no"] ?? string.Empty, OrderId = HttpContext.Current.Request.Form["out_trade_no"] ?? string.Empty, PayStatus = payStatus, PayWay = PayWayEnum.AliPay, BuyerId = HttpContext.Current.Request.Form["buyer_id"] ?? string.Empty, BuyAccount = HttpContext.Current.Request.Form["buyer_logon_id"] ?? string.Empty, SellerId = HttpContext.Current.Request.Form["seller_id"] ?? string.Empty, SellAccount = HttpContext.Current.Request.Form["seller_email"] ?? string.Empty, TotalAmount = ConvertHelper.ToDecimal(HttpContext.Current.Request.Form["total_amount"]), PayAmount = ConvertHelper.ToDecimal(HttpContext.Current.Request.Form["buyer_pay_amount"]), PayTime = ConvertHelper.ToDateTime(HttpContext.Current.Request.Form["gmt_payment"]), PayResponse = JsonConvert.SerializeObject(sPara) }; // 回写到实际表中 var result = PayWriteBack(payWriteBack); if (!result.IsSuccess) { // 失败了 _log4NetHelper.Info($"[AliPayNotify]-[支付回写验证失败]-{result.Message}"); return "false"; } return "sucess"; } else { _log4NetHelper.Info("[AliPayNotify]-验签失败!!!"); return "false"; } } /// /// 支付回写(雏形,需要根据实际需要接入支付宝或微信) /// /// /// private ApiResult PayWriteBack(PayWriteBackRequestDto req) { if (req == null || string.IsNullOrWhiteSpace(req.PaySerialId)) { return new ApiResult(ApiStatusCode.InvalidParameter, "请求参数不正确"); } var order = _dbContent.Set().FirstOrDefault(p => p.Id == req.OrderId); if (order == null) { return new ApiResult(ApiStatusCode.InvalidParameter, "未找到相应订单"); } if (order.Price != req.TotalAmount) { // 需要写入订单日志------------------------ return new ApiResult(ApiStatusCode.InvalidParameter, $"回写总金额与订单金额不匹配,订单号{order.Id};订单价格{order.Price};支付流水号{req.PaySerialId};支付订单总金额{req.TotalAmount}"); } if (order.Price != req.PayAmount) { // 需要写入订单日志------------------------ return new ApiResult(ApiStatusCode.InvalidParameter, $"回写支付金额与订单金额不匹配,订单号{order.Id};订单价格{order.Price};支付流水号{req.PaySerialId};支付订单已付金额{req.PayAmount}"); } var status = GetStatusByPayWriteBack(req.PayStatus); // 修改订单状态 order.PayStatus = status.Item1; order.OrderStatus = status.Item2; order.PaySerialId = req.PaySerialId; // 记录订单流程 YW_PayCall payCall = new YW_PayCall() { Id = IdGenerator.NewId(), OrderId = req.OrderId, PayStatus = status.Item1, PaySerialId = req.PaySerialId, PayWay = req.PayWay, BuyerId = req.BuyerId, BuyAccount = req.BuyAccount, SellerId = req.SellerId, SellAccount = req.SellAccount, PayAmount = req.PayAmount, PayTime = req.PayTime, PayResponse = req.PayResponse, CreateBY = req.BuyAccount }; _dbContent.Set().Add(payCall); _dbContent.SaveChanges(); return new ApiResult(); } /// /// 支付测试 /// /// public ApiResult PayTest() { AlipayTradePrecreateContentBuilder builder = BuildPrecreateContent(); string out_trade_no = builder.out_trade_no; //如果需要接收扫码支付异步通知,那么请把下面两行注释代替本行。 //推荐使用轮询撤销机制,不推荐使用异步通知,避免单边账问题发生。 // AlipayF2FPrecreateResult precreateResult = serviceClient.tradePrecreate(builder); string notify_url = aliNotifyUrl; //商户接收异步通知的地址 AlipayF2FPrecreateResult precreateResult = serviceClient.tradePrecreate(builder, notify_url); //以下返回结果的处理供参考。 //payResponse.QrCode即二维码对于的链接 //将链接用二维码工具生成二维码打印出来,顾客可以用支付宝钱包扫码支付。 string result = ""; return new ApiResult(precreateResult); //switch (precreateResult.Status) //{ // case ResultEnum.SUCCESS: // DoWaitProcess(precreateResult); // txtRCCode.Text = precreateResult.response.QrCode; // break; // case ResultEnum.FAILED: // result = precreateResult.response.Body; // Response.Redirect("result.aspx?Text=" + result); // break; // case ResultEnum.UNKNOWN: // if (precreateResult.response == null) // { // result = "配置或网络异常,请检查后重试"; // } // else // { // result = "系统异常,请更新外部订单后重新发起请求"; // } // Response.Redirect("result.aspx?Text=" + result); // break; //} } /// /// 构造支付请求数据 /// /// 请求数据集 private AlipayTradePrecreateContentBuilder BuildPrecreateContent() { AlipayTradePrecreateContentBuilder builder = new AlipayTradePrecreateContentBuilder(); //收款账号 builder.seller_id = AliPayConfig.pid; //订单编号----------------------- builder.out_trade_no = DateTime.Now.ToString("yyyyMMddHHmmss") + "0000" + (new Random()).Next(1, 10000).ToString(); //订单总金额----------------------------- builder.total_amount = "0.02"; //参与优惠计算的金额 //builder.discountable_amount = ""; //不参与优惠计算的金额 //builder.undiscountable_amount = ""; //订单名称------------------------------- builder.subject = "smj_webapi测试订单"; //自定义超时时间 builder.timeout_express = "5m"; //订单描述 builder.body = ""; //门店编号,很重要的参数,可以用作之后的营销-------------------- builder.store_id = "test store id"; //操作员编号,很重要的参数,可以用作之后的营销--------------------- builder.operator_id = "test"; //传入商品信息详情 List gList = new List(); GoodsInfo goods = new GoodsInfo(); goods.goods_id = "goods id"; goods.goods_name = "goods name"; goods.price = "0.02"; goods.quantity = "1"; gList.Add(goods); builder.goods_detail = gList; //系统商接入可以填此参数用作返佣 //ExtendParams exParam = new ExtendParams(); //exParam.sysServiceProviderId = "20880000000000"; //builder.extendParams = exParam; return builder; } /// /// /// /// /// private Tuple GetStatusByPayWriteBack(PayStatusEnum payStatus) { // 临时:payStatus 0失败,1成功 OrderStatusEnum orderStatus = OrderStatusEnum.UnPay; switch (payStatus) { case PayStatusEnum.UnPay:// 成功 orderStatus = OrderStatusEnum.Paid; break; default:// 失败 break; } return new Tuple(payStatus, orderStatus); } /// /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组 /// /// request回来的信息组成的数组 private SortedDictionary GetRequestPost() { int i = 0; SortedDictionary sArray = new SortedDictionary(); NameValueCollection coll; //Load Form variables into NameValueCollection variable. coll = HttpContext.Current.Request.Form; // Get names of all forms into a string array. String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], HttpContext.Current.Request.Form[requestItem[i]]); } return sArray; } /// /// 对支付宝异步通知的关键参数进行校验 /// /// private bool CheckParams() { bool ret = true; //获得调用方的appid; //如果是非授权模式,appid是商户的appid;如果是授权模式(token调用),appid是系统商的appid string app_id = HttpContext.Current.Request.Form["app_id"]; if (app_id != AliPayConfig.appId) { ret = false; _log4NetHelper.Info($"[支付回写][appid认证失败]:request_appid:{app_id};sys_appid:{AliPayConfig.appId}"); } return ret; } } }