using DS.Module.Core; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Op.Interface; using DS.WMS.Core.Sys.Entity; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using NLog; using SqlSugar; using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Threading.Tasks; using DS.Module.Core.Extensions; using LogicExtensions; using DS.Module.Core.Helpers; using Newtonsoft.Json.Linq; using DS.Module.Core.Data; using DS.WMS.Core.Sys.Interface; using DS.WMS.Core.Code.Method; using DS.WMS.Core.Code.Interface; namespace DS.WMS.Core.Op.Method { public class DJYChargeFeeService: IDJYChargeFeeService { private readonly IServiceProvider _serviceProvider; private readonly ISqlSugarClient db; private readonly IUser user; private readonly ISaasDbService saasService; private readonly IConfigService _configService; private readonly ICodeThirdPartyService _codeThirdPartyService; private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger(); public DJYChargeFeeService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; _configService = serviceProvider.GetRequiredService(); _codeThirdPartyService = serviceProvider.GetRequiredService(); } #region 扣费 /// /// 扣费 /// /// 扣费请求 /// 返回回执 public async Task> ChargeFee(DJYChargeFeeRequestDto model) { /* 1、先获取扣费URL 2、根据业务主键取所有订单信息 3、获取扣费KEY和密钥(通过接口账户维护) 4、提取订单操作相关的账户,如果绑定了大简云用户ID,默认用大简云用户ID,否则就用系统参数设置的大简云用户ID 5、组织扣费报文,并发送 6、接收回执,写入记录表 */ Logger.Log(NLog.LogLevel.Info, $"收到订舱扣费请求,{JsonConvert.SerializeObject(model)}"); var batchId = DateTime.Now.Ticks.ToString(); var tenantDb = saasService.GetBizDbScopeById(user.TenantId); tenantDb.QueryFilter.Clear(); //提取扣费URL var feeUrl = db.Queryable().Filter(null, true) .Where(x => x.Code == "djyFeeApiUrl" && x.TenantId == 1288018625843826688).Select(x => x.Value).First(); if(string.IsNullOrWhiteSpace(feeUrl)) { Logger.Log(NLog.LogLevel.Info, $"未配置大简云扣费接口地址,请联系管理员"); return DataResult.Failed("未配置大简云扣费接口地址,请联系管理员"); } var orderList = tenantDb.Queryable().Filter(null, true).Where(a => model.BusinessIdList.Contains(a.Id)).ToList(); DateTime nowDate = DateTime.Now; DJYChargeFeeResultDto resultDto = new DJYChargeFeeResultDto { ExcuteDate = nowDate, ExcuteDetail = new List() }; foreach (var id in model.BusinessIdList) { DJYChargeFeeResultDetailDto detail = new DJYChargeFeeResultDetailDto { BillId = id, }; var orderInfo = orderList.FirstOrDefault(a => a.Id == id); var userInfo = db.Queryable().Filter(null, true).First(x => x.Id == orderInfo.OperatorId && x.TenantId == long.Parse(user.TenantId)); string djyUserId = userInfo?.DjyUserId; if (string.IsNullOrWhiteSpace(djyUserId)) { var defaultDJYUserId = _configService.GetConfig("DJY_CHARGE_FEE_DEFAULT_USERID", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; djyUserId = defaultDJYUserId; Logger.Log(NLog.LogLevel.Info, $"批次号={batchId}-调用扣费,当前操作OP={userInfo?.UserName}没有绑定大简云用户ID,试用系统默认的大简云用户ID={defaultDJYUserId}"); } if (string.IsNullOrWhiteSpace(djyUserId)) { detail.Status = "FAILURE"; detail.Message = $"当前操作OP={userInfo?.UserName}没有绑定大简云用户ID,请联系管理员"; continue; } var webAccountConfig = _codeThirdPartyService.GetCodeThirdPartyInfoWithCompany("DJYChargeFeeAuth").GetAwaiter().GetResult()?.Data; //未配置公司或个人的第三方账户维护-(MSK API合约),请联系管理员 if (webAccountConfig == null) { detail.Status = "FAILURE"; detail.Message = $"未配置大简云扣费授权,请在接口账户维护"; continue; } string feeUserId = webAccountConfig.AppKey; string feeUserKey = webAccountConfig.AppSecret; var runId = Guid.NewGuid().ToString(); var seconds = DateTime.Now.ToTimestamp(); var srcBeforMD5 = $"{runId}{feeUserId}expend{(int)model.BSType}{(int)model.SendType}{id}{orderInfo.MBLNO}{seconds}{feeUserKey}"; var md5 = MD5Helper.Encrypt(srcBeforMD5); var reqModel = new DJYChargeFeeBaseDto { runId = runId, userId = feeUserId, module = "expend",//固定 bsType = ((int)model.BSType).ToString(), sendType = ((int)model.SendType).ToString(), timestamp = seconds,//秒级时间戳 md5 = md5,// 加密字符串小写 RunId + UserId + Module + BsType + SendType+Timestamp+ Key Data = new DJYChargeFeeDataDto { BSNO = orderInfo.Id.ToString(), MBLNO = orderInfo.MBLNO, HBLNO = orderInfo.HBLNO, CtnrInfo = "", CtnrCount = 1, IsCredit = 1,//是否是信用支付 1 信用支付 0不允许信用支付默认值为0, LURURENID = djyUserId, SENDUSERID = djyUserId, VESSEL = orderInfo.Vessel, VOYNO = orderInfo.InnerVoyno, ETD = orderInfo.ATD, CARRIER = orderInfo.Carrier } }; Logger.Log(NLog.LogLevel.Info, $"批次号={batchId}-调用扣费,请求报文:{JsonConvert.SerializeObject(reqModel)}"); var record = new DJYChargeFee { BillId = id, BatchNo = batchId, BSType = model.BSType.ToString(), SendType = model.SendType.ToString(), FeeType = $"{(int)model.BSType}_{(int)model.SendType}", MBLNO = orderInfo.MBLNO, }; try { var jsonBody = JsonConvert.SerializeObject(reqModel); var res = RequestHelper.Post(jsonBody, feeUrl); Logger.Log(NLog.LogLevel.Info, $"批次号={batchId}-调用扣费,返回结果:{res}"); var jobjApiRtn = JObject.Parse(res); var code = jobjApiRtn.GetIntValue("code"); var jobjApiRtnData = jobjApiRtn.GetValue("data") as JObject; if (code == 200 || code == 450) { var jobjApiRtnDataPayInfo = jobjApiRtnData.GetValue("payInfo") as JObject; var price = Convert.ToDecimal(jobjApiRtnDataPayInfo.GetValue("price").ToString()); var total = Convert.ToDecimal(jobjApiRtnDataPayInfo.GetValue("total").ToString()); var msg = jobjApiRtn.GetValue("message").ToString(); record.Amount = total; record.Price = price; record.ResultNote = msg; record.Status = "SUCC"; detail.Status = "SUCC"; tenantDb.Insertable(record).ExecuteCommand(); } else { var msg = jobjApiRtn.GetValue("message").ToString(); record.ResultNote = msg; record.Status = "FAILURE"; detail.Status = "FAILURE"; detail.Message = msg; tenantDb.Insertable(record).ExecuteCommand(); Logger.Log(NLog.LogLevel.Info, $"批次号={batchId}-扣费失败,原因:{msg}"); //DingTalkGroupHelper.SendDingTalkGroupMessage("bookingFeeNotify", "扣费失败提醒", errMsg); } } catch (Exception ex) { Logger.Log(NLog.LogLevel.Info, $"批次号={batchId}-扣费异常,原因:{ex.Message}"); record.ResultNote = ex.Message.Length > 200? ex.Message.Substring(0,200): ex.Message; record.Status = "EXCEPTION"; detail.Status = "EXCEPTION"; detail.Message = ex.Message; } resultDto.ExcuteDetail.Add(detail); } return DataResult.Success(resultDto); } #endregion /// /// 扣费前校验 /// /// 扣费请求 /// 返回回执 public async Task> CheckChargeFee(DJYChargeFeeRequestDto model) { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); tenantDb.QueryFilter.Clear(); //提取扣费URL var feeUrl = db.Queryable().Filter(null, true) .Where(x => x.Code == "djyFeeApiUrl" && x.TenantId == 1288018625843826688).Select(x => x.Value).First(); if (string.IsNullOrWhiteSpace(feeUrl)) { Logger.Log(NLog.LogLevel.Info, $"未配置大简云扣费接口地址,请联系管理员"); return DataResult.Failed("未配置大简云扣费接口地址,请联系管理员"); } var orderList = tenantDb.Queryable().Filter(null,true).Where(a => model.BusinessIdList.Contains(a.Id)).ToList(); List opUserIdList = orderList.Select(a => a.OperatorId).Distinct().ToList(); var userList = db.Queryable().Filter(null, true).Where(x => opUserIdList.Contains(x.Id) && x.TenantId == long.Parse(user.TenantId)).ToList(); var defaultDJYUserId = _configService.GetConfig("DJY_CHARGE_FEE_DEFAULT_USERID", long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value; //校验是否有大简云账户 if (userList.Any(a=> string.IsNullOrWhiteSpace(a.DjyUserId)) && string.IsNullOrWhiteSpace(defaultDJYUserId)) { return DataResult.Failed($"操作={string.Join(",", userList.Where(a => string.IsNullOrWhiteSpace(a.DjyUserId)).Select(a => a.UserName).ToArray())},未绑定大简云账户ID,请联系管理员"); } Dictionary> dict = new Dictionary>(); //校验是否已有扣费记录 foreach (var order in orderList) { var record = tenantDb.Queryable().Filter(null, true) .First(a => a.BillId == order.Id && a.FeeType == $"{(int)model.BSType}_{(int)model.SendType}" && a.Deleted == false); if (record != null) { dict.Add(order.Id, new Tuple(!string.IsNullOrWhiteSpace(order.MBLNO) ? $"提单号:{order.MBLNO}" : $"委托编号:{order.CustomerNo}", "已有扣费记录")); } } if (dict.Count > 0) { return DataResult.Failed($"{string.Join(",", dict.Select(a => a.Value.Item1).ToArray())} 已有扣费记录"); } return DataResult.Success(string.Empty); } } }