123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- 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
- {
- /// <summary>
- ///
- /// </summary>
- 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);
- /// <summary>
- /// 支付宝回写地址
- /// </summary>
- public readonly static string aliNotifyUrl = ConfigurationManager.AppSettings["aliNotifyUrl"].ToString();
- private readonly IDbContext _dbContent;
- private readonly IUserService _userService;
- private readonly ILog4NetHelper _log4NetHelper;
- /// <summary>
- ///
- /// </summary>
- /// <param name="dbContent"></param>
- /// <param name="userService"></param>
- /// <param name="log4NetHelper"></param>
- public OrderService(
- IDbContext dbContent,
- IUserService userService,
- ILog4NetHelper log4NetHelper)
- {
- _dbContent = dbContent;
- _userService = userService;
- _log4NetHelper = log4NetHelper;
- }
- /// <summary>
- /// 下单
- /// </summary>
- /// <param name="req"></param>
- /// <returns></returns>
- public ApiResult<OrderResponseDto> Order(OrderRequestDto req)
- {
- #region 1、验证参数
- if (req == null
- || req.OrderInfo == null
- || req.OrderInfo.Count() == 0)
- {
- return new ApiResult<OrderResponseDto>(ApiStatusCode.InvalidParameter, "请求参数不正确");
- }
- #endregion
- #region 2、验证相应数据和库存
- var productIds = req.OrderInfo.Select(p => p.ProductId).ToList();
- var products = _dbContent.Set<YW_Product>().Where(p => p.IsDelete == 0 && p.Sale == Enum.SaleEnum.On && productIds.Contains(p.Id)).ToList();
- if (products.Count() <= 0)
- {
- return new ApiResult<OrderResponseDto>(ApiStatusCode.RecordNotFound, "未找到下单的商品");
- }
- #endregion
- #region 3、包装盒库存验证
- var session = _userService.GetLoginSession();
- // 修改
- var devicePackings = _dbContent.Set<YW_DevicePacking>().Where(p => p.IsDelete == 0 && p.DeviceId == session.UserId).ToList();
- if (devicePackings == null || devicePackings.Count() == 0)
- {
- return new ApiResult<OrderResponseDto>(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<OrderResponseDto>(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<YW_OrderDetails> orderDetailAdds = new List<YW_OrderDetails>();
- List<YW_OrderProcess> orderProcessAdds = new List<YW_OrderProcess>();
- foreach (var o in req.OrderInfo)
- {
- var currentProduct = products.FirstOrDefault(p => p.Id == o.ProductId);
- if (currentProduct == null)
- {
- return new ApiResult<OrderResponseDto>(ApiStatusCode.RecordNotFound, $"{o.ProductId}商品不存在");
- }
- if (currentProduct.Stock < o.Count)
- {
- return new ApiResult<OrderResponseDto>(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<YW_Order>().Add(order);
- _dbContent.Set<YW_OrderProcess>().Add(orderProcess);
- _dbContent.Set<YW_OrderDetails>().AddRange(orderDetailAdds);
- // 数据库执行 库存已经改过了,会自动保存
- _dbContent.SaveChanges();
- #endregion
- #region 5、支付宝支付--目前直接入支付宝支付测试,后期需要替换成中间页面
- #endregion
- return new ApiResult<OrderResponseDto>(new OrderResponseDto()
- {
- OrderId = order.Id,
- Price = order.Price
- });
- }
- /// <summary>
- /// 获取待烧烤的商品列表
- /// <summary>
- /// <returns></returns>
- public ApiResult<List<QueueOrderResponseDto>> GetQueueOrders()
- {
- var orders = _dbContent.Set<YW_Order>()
- .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<YW_OrderDetails>().Where(p => p.IsDelete == 0 && orderIds.Contains(p.OrderId)).ToList();
- List<QueueOrderResponseDto> result = new List<QueueOrderResponseDto>();
- orders.ForEach(item => {
- QueueOrderResponseDto resultItem = new QueueOrderResponseDto()
- {
- OrderId = item.Id,
- Price = item.Price,
- OrderDetails = orderDetails
- .Where(p => p.OrderId == item.Id)
- .Select(p => SafeClone<YW_OrderDetails, QueueOrderDetailsDto>.Trans(p))
- .ToList()
- };
- resultItem.OrderDetails?.ForEach(p => p.Img = $"{ProductService.ImagePrefix}{p.Img}");
- result.Add(resultItem);
- });
- return new ApiResult<List<QueueOrderResponseDto>>(result);
- }
- /// <summary>
- /// 回写流程状态
- /// </summary>
- /// <param name="req"></param>
- /// <returns></returns>
- public ApiResult OrderProcess(OrderProcessRequestDto req)
- {
- if (req == null)
- {
- return new ApiResult(ApiStatusCode.InvalidParameter, "请求参数不正确");
- }
- var order = _dbContent.Set<YW_Order>().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<YW_OrderProcess>().Add(orderProcess);
- _dbContent.SaveChanges();
- return new ApiResult();
- }
- /// <summary>
- /// 支付宝回写
- /// </summary>
- /// <returns></returns>
- public string AliPayNotify()
- {
- _log4NetHelper.Info("[AliPayNotify]-start");
- SortedDictionary<string, string> 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";
- }
- }
- /// <summary>
- /// 支付回写(雏形,需要根据实际需要接入支付宝或微信)
- /// </summary>
- /// <param name="req"></param>
- /// <returns></returns>
- private ApiResult PayWriteBack(PayWriteBackRequestDto req)
- {
- if (req == null
- || string.IsNullOrWhiteSpace(req.PaySerialId))
- {
- return new ApiResult(ApiStatusCode.InvalidParameter, "请求参数不正确");
- }
- var order = _dbContent.Set<YW_Order>().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<YW_PayCall>().Add(payCall);
- _dbContent.SaveChanges();
- return new ApiResult();
- }
- /// <summary>
- /// 支付测试
- /// </summary>
- /// <returns></returns>
- public ApiResult<AlipayF2FPrecreateResult> 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<AlipayF2FPrecreateResult>(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;
- //}
- }
- /// <summary>
- /// 构造支付请求数据
- /// </summary>
- /// <returns>请求数据集</returns>
- 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<GoodsInfo> gList = new List<GoodsInfo>();
- 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;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="payStatus"></param>
- /// <returns></returns>
- private Tuple<PayStatusEnum, OrderStatusEnum> GetStatusByPayWriteBack(PayStatusEnum payStatus)
- {
- // 临时:payStatus 0失败,1成功
- OrderStatusEnum orderStatus = OrderStatusEnum.UnPay;
- switch (payStatus)
- {
- case PayStatusEnum.UnPay:// 成功
- orderStatus = OrderStatusEnum.Paid;
- break;
- default:// 失败
- break;
- }
- return new Tuple<PayStatusEnum, OrderStatusEnum>(payStatus, orderStatus);
- }
- /// <summary>
- /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
- /// </summary>
- /// <returns>request回来的信息组成的数组</returns>
- private SortedDictionary<string, string> GetRequestPost()
- {
- int i = 0;
- SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
- 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;
- }
- /// <summary>
- /// 对支付宝异步通知的关键参数进行校验
- /// </summary>
- /// <returns></returns>
- 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;
- }
- }
- }
|