using Myshipping.Core; using Furion.DependencyInjection; using Furion.DynamicApiController; using Mapster; using Microsoft.AspNetCore.Mvc; using SqlSugar; using System.Linq; using System.Threading.Tasks; using Myshipping.Application.Entity; using Microsoft.AspNetCore.Authorization; using Furion; using Microsoft.AspNetCore.Http; using Furion.DataEncryption; using System.Collections.Generic; using System.Security.Claims; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Furion.FriendlyException; using Furion.Logging; using System; using Microsoft.Extensions.Logging; using System.Reflection; using System.ComponentModel; using Myshipping.Application.ConfigOption; using System.IO; using Yitter.IdGenerator; using Myshipping.Core.Entity; using Furion.RemoteRequest.Extensions; using System.Net.Http; using Myshipping.Core.Service; using System.Reflection.Emit; using Myshipping.Application.Service.BookingOrderSeaeEdi.Dto; using Myshipping.Application.Enum; using Myshipping.Application.Service.BookingOrder.Dto; using Newtonsoft.Json.Linq; using System.Text; using System.Web; using Furion.UnifyResult; namespace Myshipping.Application { /// /// 舱单服务 /// [ApiDescriptionSettings("Application", Name = "BookingOrderSeaeEdi", Order = 1)] public class BookingOrderSeaeEdiService : IBookingOrderSeaeEdiService, IDynamicApiController, ITransient { private readonly ILogger _logger; private readonly SqlSugarRepository _seaeedi; private readonly SqlSugarRepository _seaeedictn; private readonly ISysCacheService _cache; private readonly IBookingOrderService _rep; private readonly SqlSugarRepository _repStatuslog; private readonly SqlSugarRepository _repTemplate; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; private readonly SqlSugarRepository _repBookingOrder; private readonly SqlSugarRepository _repBookingCtn; public BookingOrderSeaeEdiService(ILogger logger, SqlSugarRepository seaeedi, SqlSugarRepository seaeedictn, ISysCacheService cache, SqlSugarRepository repStatuslog, SqlSugarRepository repTemplate, IBookingOrderService rep, IDjyWebsiteAccountConfigService webAccountConfig, SqlSugarRepository repBookingORder, SqlSugarRepository repBookingCtn) { this._logger = logger; this._seaeedi = seaeedi; this._seaeedictn = seaeedictn; this._cache = cache; this._repStatuslog = repStatuslog; this._webAccountConfig = webAccountConfig; this._repTemplate = repTemplate; this._rep = rep; this._repBookingOrder = repBookingORder; this._repBookingCtn = repBookingCtn; } /// /// 获取数据 /// /// /// [HttpGet("/BookingOrderSeaeEdi/PageESeaeEdi")] public async Task> PageESeaeEdi(long bookingId) { var entities = await _seaeedi.AsQueryable().Filter(null, true).Where(x => x.BookingId == bookingId && x.IsDeleted == false).ToListAsync(); var list = entities.Adapt>(); foreach (var item in list) { var ctn = await _seaeedictn.AsQueryable().Filter(null, true).Where(x => x.PId == item.Id && x.IsDeleted == false).ToListAsync(); item.EdiCtn = ctn.Adapt>(); } return list; } /// /// 立即返回保存信息 /// /// /// [HttpPost("/BookingOrderSeaeEdi/Save")] public async Task Save(BookingOrderSeaeEdiServiceDto input) { if (input == null) { throw Oops.Bah("请传入正常数据!"); } if (!string.IsNullOrWhiteSpace(input.MBLNO)) { var et = await _seaeedi.Where(x => x.MBLNO == input.MBLNO && x.TenantId == UserManager.TENANT_ID && x.HBLNO == input.HBLNO && x.Id != input.Id).FirstAsync(); if (et != null) { throw Oops.Bah("当前提单号已存在,请勿重复录入!"); } } BookingOrderSeaeEdi entity = null; if (input.Id == 0) { entity = input.Adapt(); entity.State = "已录入"; if (!string.IsNullOrEmpty(entity.CARRIERID)) { entity.CARRIER = _cache.GetAllCodeCarrier().Result.Where(x => x.Code == entity.CARRIERID).Select(x => x.EdiCode).FirstOrDefault(); } if (entity.CARGOID != "D") { entity.DCLASS = string.Empty; entity.DUNNO = string.Empty; } await _seaeedi.InsertAsync(entity); if (input.EdiCtn != null) { foreach (var item in input.EdiCtn) { var ctn = item.Adapt(); ctn.PId = entity.Id; if (ctn.CTNALL.Length == 4) { ctn.SIZE = ctn.CTNALL != null ? ctn.CTNALL.Substring(0, 2) : ""; ctn.CTN = ctn.CTNALL != null ? ctn.CTNALL.Substring(2, 2) : ""; } if (ctn.CTNALL.Contains("'")) { ctn.SIZE = ctn.CTNALL.Split("'")[0].ToString(); ctn.CTN = ctn.CTNALL.Split("'")[1].ToString(); } await _seaeedictn.InsertAsync(ctn); } } } else { entity = _seaeedi.AsQueryable().First(x => x.Id == input.Id); if (entity == null) { throw Oops.Bah("未找到业务数据"); } if (entity.State != "已录入") { if (input.State != entity.State) { input.State = entity.State; //防止前端数据覆盖状态 } if (input.HBLNO != entity.HBLNO) { throw Oops.Bah("已直发状态不能修改分单号"); } } //校验数据可修改后,赋值前端数据 input.Adapt(entity); if (!string.IsNullOrEmpty(entity.CARRIERID)) { entity.CARRIER = _cache.GetAllCodeCarrier().Result.Where(x => x.Code == entity.CARRIERID).Select(x => x.EdiCode).FirstOrDefault(); } if (entity.CARGOID != "D") { entity.DCLASS = string.Empty; entity.DUNNO = string.Empty; } await _seaeedi.AsUpdateable(entity).IgnoreColumns(it => new { it.MBLNO, //it.HBLNO, //2023年9月4日,原有直接忽略的逻辑有问题,应该是直发之后不能改,而不是录入状态就不能改分单号 it.BookingId, it.TenantId, it.CreatedTime, it.CreatedUserId, it.CreatedUserName, it.IsDeleted }).ExecuteCommandAsync(); await _seaeedictn.DeleteAsync(x => x.PId == input.Id); if (input.EdiCtn != null) { foreach (var item in input.EdiCtn) { var ctn = item.Adapt(); ctn.PId = entity.Id; if (ctn.CTNALL.Length == 4) { ctn.SIZE = ctn.CTNALL != null ? ctn.CTNALL.Substring(0, 2) : ""; ctn.CTN = ctn.CTNALL != null ? ctn.CTNALL.Substring(2, 2) : ""; } if (ctn.CTNALL.Contains("'")) { ctn.SIZE = ctn.CTNALL.Split("'")[0].ToString(); ctn.CTN = ctn.CTNALL.Split("'")[1].ToString(); } await _seaeedictn.InsertAsync(ctn); } } } var entities = await _seaeedi.AsQueryable().Filter(null, true).Where(x => x.Id == entity.Id).ToListAsync(); var list = entities.Adapt>(); foreach (var item in list) { var ctn = await _seaeedictn.AsQueryable().Filter(null, true).Where(x => x.PId == item.Id).ToListAsync(); item.EdiCtn = ctn.Adapt>(); } return list; } /// /// 删除舱单 /// /// /// [SqlSugarUnitOfWork] [HttpPost("/BookingOrderSeaeEdi/Delete")] public async Task Delete(string Ids) { var arr = Ids.Split(","); if (arr.Count() > 0) { foreach (var ar in arr) { long Id = Convert.ToInt64(ar); await _seaeedi.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdi { IsDeleted = true }); await _seaeedictn.UpdateAsync(x => x.PId == Id, x => new BookingOrderSeaeEdiCtn { IsDeleted = true }); _logger.LogInformation(Id + "删除成功!"); } } } #region 舱单 /// /// 舱单 /// /// [HttpPost("/BookingOrderSeaeEdi/CustEDI")] public async Task CustEDI(string Ids, string type, string SENDREMARK, bool? isCheck) { var arr = Ids.Split(","); if (arr.Count() > 0) { List custEDIDtos = new List(); var key = _webAccountConfig.GetAccountConfig("DjyCangDan", UserManager.UserId).Result; if (key == null) { throw Oops.Bah("当前用户未配置key,请联系管理员"); } var dicUrl = _cache.GetAllDictData().Result.First(x => x.TypeCode == "url_set" && x.Code == "request_emf"); long bookingId = 0; foreach (var ar in arr) { long Id = Convert.ToInt64(ar); var order = await _seaeedi.AsQueryable().Filter(null, true).Where(x => x.Id == Id).FirstAsync(); var ctns = await _seaeedictn.AsQueryable().Filter(null, true).Where(x => x.PId == order.Id).ToListAsync(); bookingId = order.BookingId; //船公司 if (string.IsNullOrEmpty(order.CARRIER)) { throw Oops.Bah(BookingErrorCode.BOOK118); } //提单号不能为空 if (string.IsNullOrEmpty(order.MBLNO)) { throw Oops.Bah(BookingErrorCode.BOOK127); } MDATA mDATA = new MDATA(); List CTNDATA = new List(); mDATA = order.Adapt(); if (string.IsNullOrEmpty(mDATA.FORWARDER)) { throw Oops.Bah("船代不能为空"); } if (string.IsNullOrEmpty(mDATA.YARDID)) { throw Oops.Bah("场站不能为空"); } mDATA.SENDREMARK = SENDREMARK; var FORWARDER = mDATA.FORWARDER; var YardCode = mDATA.YARDID; if (_cache.GetAllMappingForwarder().Result.Where(x => x.Code == FORWARDER && x.Module == "cangdan").Select(x => x.MapCode).FirstOrDefault() == null) { throw Oops.Bah("暂不支持此船代"); } mDATA.FORWARDER = _cache.GetAllMappingForwarder().Result.Where(x => x.Code == FORWARDER && x.Module == "cangdan").Select(x => x.MapCode).FirstOrDefault(); mDATA.YARDID = _cache.GetAllMappingYard().Result.Where(x => x.Code == YardCode && x.Module == "cangdan").Select(x => x.MapCode).FirstOrDefault(); CTNDATA = ctns.Adapt>(); foreach (var item in CTNDATA) { item.KINDPKGS = _cache.GetAllCodePackage().Result.Where(x => x.Name == item.KINDPKGS).Select(x => x.EdiCode).FirstOrDefault(); } custEDIDtos.Add(new CustEDIDto { MDATA = mDATA, CTNDATA = CTNDATA }); } #region 舱单发送前,校验 if (isCheck == true && (type is "1" or "0") && custEDIDtos.Count > 0) { // 需要在舱单发送前增加以下字段的比对,由舱单字段与订舱数据字段做比对,比对存在异常提醒客户是否确认发送,对比字段如下: // 主单提单号:主单主单提单号与订舱主提单号不一致时提醒 // 船名航次,唛头,货描 ,起运港,卸货港:主单与订舱 或 分单与主单不一致时提醒 // 件数,重量,尺码(按箱子判断):分单之和>主单 或 主单 != 订舱 时提醒 // 箱封号、箱型:主单的箱封号+箱型与订舱不一致时提醒、分单中出现主单中不存在的箱封号+箱型时提醒 var seaeList = await _seaeedi.AsQueryable() .Filter(null, true) .Where(x => x.BookingId == bookingId && x.IsDeleted == false) .ToListAsync(); var seaeCtnList = await _seaeedictn.AsQueryable() .Filter(null, true) .Where(x => seaeList.Select(x => x.Id).Contains(x.PId) && x.IsDeleted == false) .ToListAsync(); var bkOrder = await _repBookingOrder.AsQueryable() .Filter(null, true) .Where(x => x.Id == bookingId && x.IsDeleted == false) .FirstAsync(); var bkOrderCtnList = await _repBookingCtn.AsQueryable() .Filter(null, true) .Where(x => x.BILLID == bookingId && x.IsDeleted == false) .ToListAsync(); if (bkOrder == null) { throw Oops.Bah("未找到订舱数据"); } var checkResult = new List(); // 舱单主单 var mainSeaOrder = seaeList.FirstOrDefault(x => string.IsNullOrWhiteSpace(x.HBLNO)); // 舱单分单 var subSeaOrderList = seaeList.Where(x => !string.IsNullOrWhiteSpace(x.HBLNO)).ToList(); // 校验规则1:船名航次,唛头,货描 ,起运港,卸货港,主单提单号 if (bkOrder.MBLNO != mainSeaOrder.MBLNO) checkResult.Add("舱单主单与订舱【提单号】不一致"); if (bkOrder.VESSEL != mainSeaOrder.VESSEL) checkResult.Add("舱单主单与订舱【船名】不一致"); if (bkOrder.VOYNO != mainSeaOrder.VOYNO) checkResult.Add("舱单主单与订舱【航次】不一致"); if (bkOrder.MARKS != mainSeaOrder.MARKS) checkResult.Add("舱单主单与订舱【唛头】不一致"); if (bkOrder.DESCRIPTION != mainSeaOrder.DESCRIPTION) checkResult.Add("舱单主单与订舱【货描】不一致"); if (bkOrder.PORTLOADID != mainSeaOrder.PORTLOADID || bkOrder.PORTLOAD != mainSeaOrder.PORTLOAD) checkResult.Add("舱单主单与订舱【起运港】不一致"); if (bkOrder.PORTDISCHARGEID != mainSeaOrder.PORTDISCHARGEID || bkOrder.PORTDISCHARGE != mainSeaOrder.PORTDISCHARGE) checkResult.Add("舱单主单与订舱【卸货港】不一致"); subSeaOrderList.ForEach(x => { if (bkOrder.VESSEL != x.VESSEL) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【船名】不一致"); if (bkOrder.VOYNO != x.VOYNO) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【航次】不一致"); if (bkOrder.MARKS != x.MARKS) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【唛头】不一致"); if (bkOrder.DESCRIPTION != x.DESCRIPTION) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【货描】不一致"); if (bkOrder.PORTLOADID != x.PORTLOADID || bkOrder.PORTLOAD != x.PORTLOAD) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【起运港】不一致"); if (bkOrder.PORTDISCHARGEID != x.PORTDISCHARGEID || bkOrder.PORTDISCHARGE != x.PORTDISCHARGE) checkResult.Add($"舱单分单【{x.HBLNO}】与订舱【卸货港】不一致"); }); // 校验规则2:件重尺 // 先进行件重尺总数的比较 var 主单箱子列表 = seaeCtnList.Where(x => x.PId == mainSeaOrder.Id).ToList(); var 分单箱子列表 = seaeCtnList.Where(x => x.PId != mainSeaOrder.Id).ToList(); if (主单箱子列表.Sum(x => x.PKGS) != bkOrderCtnList.Sum(x => x.PKGS)) { checkResult.Add($"舱单主单中箱子的【总件数】与订舱中箱子的【总件数】不一致"); } if (主单箱子列表.Sum(x => x.KGS) != bkOrderCtnList.Sum(x => x.KGS)) { checkResult.Add($"舱单主单中箱子的【总重量】与订舱中箱子的【总重量】不一致"); } if (主单箱子列表.Sum(x => x.CBM) != bkOrderCtnList.Sum(x => x.CBM)) { checkResult.Add($"舱单主单中箱子的【总尺码】与订舱中箱子的【总尺码】不一致"); } if (分单箱子列表.Sum(x => x.PKGS) != bkOrderCtnList.Sum(x => x.PKGS)) { checkResult.Add($"舱单分单中箱子的【总件数】与订舱中箱子的【总件数】不一致"); } if (分单箱子列表.Sum(x => x.KGS) != bkOrderCtnList.Sum(x => x.KGS)) { checkResult.Add($"舱单分单中箱子的【总重量】与订舱中箱子的【总重量】不一致"); } if (分单箱子列表.Sum(x => x.CBM) != bkOrderCtnList.Sum(x => x.CBM)) { checkResult.Add($"舱单分单中箱子的【总尺码】与订舱中箱子的【总尺码】不一致"); } // 再按箱号比较 foreach (var item in 主单箱子列表.GroupBy(x => x.CNTRNO)) { if (item.Sum(x => x.PKGS) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.PKGS)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单主单中的【件数】与订舱中同箱号箱子的【件数】不一致"); } if (item.Sum(x => x.KGS) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.KGS)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单主单中的【重量】与订舱中同箱号箱子的【重量】不一致"); } if (item.Sum(x => x.CBM) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.CBM)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单主单中的【尺码】与订舱中同箱号箱子的【尺码】不一致"); } } foreach (var item in 分单箱子列表.GroupBy(x => x.CNTRNO)) { if (item.Sum(x => x.PKGS) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.PKGS)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单各分单中的【总件数】与订舱中同箱号箱子的【件数】不一致"); } if (item.Sum(x => x.KGS) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.KGS)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单各分单中的【总重量】与订舱中同箱号箱子的【重量】不一致"); } if (item.Sum(x => x.CBM) != bkOrderCtnList.Where(x => x.CNTRNO == item.Key).Sum(x => x.CBM)) { checkResult.Add($"箱号为【{item.Key}】的箱子,在舱单各分单中的【总尺码】与订舱中同箱号箱子的【尺码】不一致"); } } // 校验规则3:箱号+封号+箱型 var 订舱箱封号箱型列表 = bkOrderCtnList.Select(x => $"箱号[{x.CNTRNO}] 封号[{x.SEALNO}] 箱型[{x.CTNALL.Replace("'", "")}]").ToList(); var 主单箱封号箱型列表 = 主单箱子列表.Select(x => $"箱号[{x.CNTRNO}] 封号[{x.SEALNO}] 箱型[{x.CTNALL.Replace("'", "")}]").ToList(); var 分单箱封号箱型列表 = 分单箱子列表.Select(x => $"箱号[{x.CNTRNO}] 封号[{x.SEALNO}] 箱型[{x.CTNALL.Replace("'", "")}]").Distinct().ToList(); var list1 = 订舱箱封号箱型列表.Except(主单箱封号箱型列表); if (list1.Any()) { checkResult.Add($"订舱中的下列箱信息在舱单主单中不存在:{string.Join(",", list1)}"); } else { var list2 = 主单箱封号箱型列表.Except(订舱箱封号箱型列表); if (list2.Any()) { checkResult.Add($"舱单主单中的下列箱信息在订舱中不存在:{string.Join(",", list2)}"); } } var list3 = 分单箱封号箱型列表.Except(订舱箱封号箱型列表); if (list3.Any()) { checkResult.Add($"舱单分单中存在未知的箱信息:{string.Join(",", list3)}"); } if (checkResult.Count > 0) { UnifyContext.Fill(new { checkResult }); throw new Exception("校验不通过"); } } #endregion string strPostObj = custEDIDtos.ToJsonString(); var sendObj = new { ac = "emf", uid = UserManager.DjyUserId, skey = key.Password, optype = type, data = strPostObj }; _logger.LogInformation($"调用舱单接口 {dicUrl.Value} 传递数据:{strPostObj}"); var strResp = await dicUrl.Value.SetContentType("multipart/form-data").SetBody(sendObj).PostAsStringAsync(); _logger.LogInformation($"调用舱单接口返回:{strResp}"); var jobjResp = JObject.Parse(strResp); bool respCode = jobjResp.GetBooleanValue("Success"); if (respCode == false) { throw Oops.Bah(jobjResp.GetStringValue("Message").Replace("
", "\r\n").Replace("
", "")); } foreach (var ar in arr) { long Id = Convert.ToInt64(ar); var order = await _seaeedi.AsQueryable().Filter(null, true).Where(x => x.Id == Id).FirstAsync(); //货运动态 var bsl = new BookingStatusLog(); bsl.BookingId = order.BookingId; if (type == "3") { bsl.Status = $"保存舱单"; } if (type == "0") { bsl.Status = $"直发舱单"; } if (type == "1") { bsl.Status = $"修改舱单"; } if (type == "2") { bsl.Status = $"删除舱单"; } if (type == "4") { bsl.Status = $"作废舱单"; } bsl.OpTime = DateTime.Now; bsl.Category = "ship"; bsl.MBLNO = order.MBLNO; await _repStatuslog.InsertAsync(bsl); if (type == "3") { await _seaeedi.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdi { State = "已发送", SENDREMARK = SENDREMARK }); } if (type == "0" || type == "1") { await _seaeedi.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdi { State = "已直发", SENDREMARK = SENDREMARK }); if (string.IsNullOrEmpty(order.HBLNO)) { await _rep.SetGoodsStatus("YFCD", order.BookingId); await _rep.SendBookingOrder(new long[] { order.BookingId }); } } if (type == "2") { await _seaeedi.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdi { State = "已删除", SENDREMARK = SENDREMARK }); } if (type == "4") { await _seaeedi.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdi { State = "已作废", SENDREMARK = SENDREMARK }); } } } } #endregion #region 模板 /// /// 获取模板数据 /// /// [HttpGet("/BookingOrderSeaeEdi/GetBookingOrderSeaeEdiTemplateList")] public async Task> GetBookingOrderSeaeEdiTemplateList(string type, string templatename = null) { var entities = await _repTemplate.AsQueryable().Where(x => x.Type == type). WhereIF(!string.IsNullOrEmpty(templatename), x => x.TemplateName.Contains(templatename)). ToListAsync(); var list = entities.Adapt>(); return list; } /// /// 保存信息 /// /// /// [HttpPost("/BookingOrderSeaeEdi/SaveBookingOrderSeaeEdiTemplate")] public async Task SaveBookingOrderSeaeEdiTemplate(BookingOrderSeaeEdiTemplateDto input) { if (input == null) { throw Oops.Bah("请传入正常数据!"); } if (!string.IsNullOrWhiteSpace(input.TemplateNAME)) { var et = await _repTemplate.Where(x => x.TemplateName == input.TemplateNAME && x.Id != input.Id).FirstAsync(); if (et != null) { throw Oops.Bah("当前模板名称已存在,请勿重复录入!"); } } var entity = input.Adapt(); if (input.Id == 0) { await _repTemplate.InsertAsync(entity); } else { await _repTemplate.AsUpdateable(entity).IgnoreColumns(it => new { it.TenantId, it.CreatedTime, it.CreatedUserId, it.CreatedUserName, it.IsDeleted }).ExecuteCommandAsync(); } } /// /// 删除舱单 /// /// /// [SqlSugarUnitOfWork] [HttpPost("/BookingOrderSeaeEdi/DeleteBookingOrderSeaeEdiTemplate")] public async Task DeleteBookingOrderSeaeEdiTemplate(string Ids) { var arr = Ids.Split(","); if (arr.Count() > 0) { foreach (var ar in arr) { long Id = Convert.ToInt64(ar); await _repTemplate.UpdateAsync(x => x.Id == Id, x => new BookingOrderSeaeEdiTemplate { IsDeleted = true }); } } } #endregion } }