You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BookingHeChuan/Myshipping.Application/Service/BookingCustomerOrder/BookingCustomerOrderService.cs

2970 lines
128 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Furion;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Furion.LinqBuilder;
using Furion.RemoteRequest.Extensions;
using Mapster;
using MathNet.Numerics.LinearAlgebra.Factorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MiniExcelLibs;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.EDI;
using Myshipping.Application.Entity;
using Myshipping.Application.Enum;
using Myshipping.Application.Service.BookingOrder.Dto;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Extension;
using Myshipping.Core.Helper;
using Myshipping.Core.Service;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.PTG;
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Yitter.IdGenerator;
namespace Myshipping.Application
{
/// <summary>
/// 客户订舱
/// </summary>
[ApiDescriptionSettings("Application", Name = "BookingCustomerOrder", Order = 1)]
public class BookingCustomerOrderService : IDynamicApiController, ITransient
{
private const string StaLogCateAudit = "cust_audit";
private readonly SqlSugarRepository<BookingCustomerOrder> _rep;
private readonly SqlSugarRepository<BookingCtn> _repCtn;
private readonly ILogger<BookingOrderService> _logger;
private readonly ISysCacheService _cache;
private readonly SqlSugarRepository<BookingFile> _repFile;
private readonly SqlSugarRepository<BookingStatusLog> _repStatuslog;
private readonly SqlSugarRepository<BookingStatusLogDetail> _repStatuslogDetail;
private readonly SqlSugarRepository<BookingServiceItem> _repServiceItem;
private readonly SqlSugarRepository<BookingOrder> _repOrder;
private readonly SqlSugarRepository<BookingCustomerOrderTemplate> _repOrderTempl;
private readonly SqlSugarRepository<BookingEDIExt> _repEdiExt;
private readonly SqlSugarRepository<BookingGoodsStatus> _goodsStatus;
private readonly SqlSugarRepository<BookingGoodsStatusConfig> _goodsStatusConfig;
private readonly IEventPublisher _publisher;
private readonly SqlSugarRepository<DjyApiAuth> _repApiAuth;
private readonly SqlSugarRepository<DjyMessage> _repMessage;
private readonly IBookingOrderService bookingOrderService;
private readonly SqlSugarRepository<DjyCustomer> _repCustomer;
private readonly SqlSugarRepository<DjyCustomerParamValue> _repCustomerParamValue;
private readonly SqlSugarRepository<DjyCustomerContact> _repCustomerContact;
private readonly SqlSugarRepository<BookingFeeRecord> _repFeeRecord;
private readonly IDjyWebsiteAccountConfigService _webAccountConfig;
public BookingCustomerOrderService(SqlSugarRepository<BookingCustomerOrder> rep, SqlSugarRepository<BookingCtn> repCtn,
ILogger<BookingOrderService> logger, ISysCacheService cache, SqlSugarRepository<BookingFile> repFile,
SqlSugarRepository<BookingStatusLog> statuslog, SqlSugarRepository<BookingServiceItem> repServiceItem,
SqlSugarRepository<BookingOrder> repOrder, SqlSugarRepository<BookingStatusLogDetail> repStatuslogDetail,
SqlSugarRepository<BookingCustomerOrderTemplate> repOrderTempl,
SqlSugarRepository<BookingEDIExt> repEdiExt, SqlSugarRepository<BookingGoodsStatus> goodsStatus, SqlSugarRepository<BookingGoodsStatusConfig> goodsStatusConfig,
IEventPublisher publisher, SqlSugarRepository<DjyApiAuth> repApiAuth, SqlSugarRepository<DjyMessage> repMessage, IBookingOrderService bookingOrderService,
SqlSugarRepository<DjyCustomer> repCustomer, SqlSugarRepository<DjyCustomerParamValue> repCustomerParamValue, SqlSugarRepository<DjyCustomerContact> repCustomerContact,
SqlSugarRepository<BookingFeeRecord> repFeeRecord, IDjyWebsiteAccountConfigService webAccountConfig)
{
this._logger = logger;
this._rep = rep;
this._repCtn = repCtn;
this._cache = cache;
this._repFile = repFile;
this._repStatuslog = statuslog;
this._repServiceItem = repServiceItem;
this._repOrder = repOrder;
this._repStatuslogDetail = repStatuslogDetail;
this._repOrderTempl = repOrderTempl;
this._repEdiExt = repEdiExt;
this._goodsStatus = goodsStatus;
this._goodsStatusConfig = goodsStatusConfig;
this._publisher = publisher;
this._repApiAuth = repApiAuth;
this._repMessage = repMessage;
this.bookingOrderService = bookingOrderService;
this._repCustomer = repCustomer;
this._repCustomerParamValue = repCustomerParamValue;
this._repCustomerContact = repCustomerContact;
this._repFeeRecord = repFeeRecord;
_webAccountConfig = webAccountConfig;
}
#region 订舱草稿及附件
/// <summary>
/// 订舱草稿台账
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/PageData")]
public async Task<SqlSugarPagedList<BookingCustomerOrderListOutput>> PageData(BookingCustomerOrderQueryInput input)
{
var query = _rep.AsQueryable().Filter(null, true).Where(x => x.TenantId == UserManager.TENANT_ID)
.Where(x => !x.IsDeleted)
.WhereIF(input.Id > 0, x => x.Id == input.Id)
.WhereIF(!string.IsNullOrEmpty(input.BOOKINGNO), x => x.BOOKINGNO.Contains(input.BOOKINGNO))
.WhereIF(!string.IsNullOrEmpty(input.VESSEL), x => x.VESSEL.Contains(input.VESSEL))
.WhereIF(!string.IsNullOrEmpty(input.VOYNO), x => x.VOYNO.Contains(input.VOYNO))
.WhereIF(!string.IsNullOrEmpty(input.YARDID), x => x.YARDID == input.YARDID)
.WhereIF(!string.IsNullOrEmpty(input.YARD), x => x.YARD.Contains(input.YARD))
.WhereIF(!string.IsNullOrEmpty(input.PORTDISCHARGEID), x => x.PORTDISCHARGEID == input.PORTDISCHARGEID)
.WhereIF(!string.IsNullOrEmpty(input.PORTDISCHARGE), x => x.PORTDISCHARGE.Contains(input.PORTDISCHARGE))
.WhereIF(!string.IsNullOrEmpty(input.CARRIERID), x => x.CARRIERID == input.CARRIERID)
.WhereIF(!string.IsNullOrEmpty(input.CARRIER), x => x.CARRIER.Contains(input.CARRIER))
.WhereIF(!string.IsNullOrEmpty(input.ShipperName), x => x.ShipperName.Contains(input.ShipperName))
.WhereIF(!string.IsNullOrEmpty(input.ConsigneeName), x => x.ConsigneeName.Contains(input.ConsigneeName))
.WhereIF(!string.IsNullOrEmpty(input.NotifypartName), x => x.NotifypartName.Contains(input.NotifypartName))
.WhereIF(!string.IsNullOrEmpty(input.BookingName), x => x.BookingName.Contains(input.BookingName))
.WhereIF(!string.IsNullOrEmpty(input.BookingTenantName), x => x.BookingTenantName.Contains(input.BookingTenantName))
.WhereIF(input.ETDStart.HasValue, x => x.ETD >= input.ETDStart)
.WhereIF(input.ETDEnd.HasValue, x => x.ETD < input.ETDEnd.Value.Date.AddDays(1))
.WhereIF(input.CreatedTimeStart.HasValue, x => x.CreatedTime >= input.CreatedTimeStart)
.WhereIF(input.CreatedTimeEnd.HasValue, x => x.CreatedTime < input.CreatedTimeEnd.Value.Date.AddDays(1))
.WhereIF(input.UpdateTimeStart.HasValue, x => x.UpdatedTime >= input.UpdateTimeStart)
.WhereIF(input.UpdateTimeEnd.HasValue, x => x.UpdatedTime < input.UpdateTimeEnd.Value.Date.AddDays(1))
.WhereIF(input.BSStatusList != null && input.BSStatusList.Count > 0, x => input.BSStatusList.Contains(x.BSSTATUS))
;
if (!string.IsNullOrEmpty(input.SortField) || input.MultiSort == null || input.MultiSort.Count == 0)
{
query = query.OrderBy(PageInputOrder.OrderBuilder(input.SortField, input.DescSort));
}
else
{
query = query.OrderBy(PageInputOrder.MultiOrderBuilder(input.MultiSort));
}
var entities = await query.ToPagedListAsync(input.PageNo, input.PageSize);
var list = entities.Adapt<SqlSugarPagedList<BookingCustomerOrderListOutput>>();
//动态日志
var bkIdList = list.Items.Select(x => x.Id).ToList();
var staLogList = _repStatuslog.Where(x => bkIdList.Contains(x.BookingId.Value) && x.Category == StaLogCateAudit).ToList();
foreach (var item in list.Items)
{
item.LogList = staLogList.Where(x => x.BookingId == item.Id).OrderByDescending(x => x.OpTime).Adapt<List<BookingCustomerLogDto>>();
}
return list;
}
/// <summary>
/// 保存草稿数据
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Save")]
public async Task<BookingCustomerOrderSaveOutput> Save(BookingCustomerOrderSaveInput input)
{
if (input == null)
{
throw Oops.Bah("请传入正常数据!");
}
var ms = JsonUtil.TrimFields(input);
if (!string.IsNullOrEmpty(ms))
{
throw Oops.Bah(ms);
}
BookingCustomerOrder entity = null;
List<BookingCtn> ctnList = new List<BookingCtn>();
if (input.Id == 0)
{
entity = input.Adapt<BookingCustomerOrder>();
if (string.IsNullOrEmpty(entity.VOYNO))
{
entity.VOYNO = entity.VOYNOINNER;
}
entity.BSSTATUS = "已录入";
entity.BOOKINGNO = $"BK{YitIdHelper.NextId()}";
//EMC需要把收发通拼接起来
if (input.CARRIERID == "EMC")
{
ContactSFT(entity);
}
await _rep.InsertAsync(entity);
}
else
{
entity = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == input.Id);
if (entity.BSSTATUS == "已提交")
{
throw Oops.Bah("请先撤销提交后再修改");
}
if (entity.BSSTATUS == "已审核")
{
throw Oops.Bah("已审核的数据不允许修改");
}
entity = input.Adapt(entity);
//EMC需要把收发通拼接起来
if (input.CARRIERID == "EMC")
{
ContactSFT(entity);
}
await _rep.UpdateAsync(entity);
await _repCtn.DeleteAsync(x => x.BILLID == input.Id);
}
//箱信息保存
if (input.CtnList != null)
{
foreach (var item in input.CtnList)
{
var ctnentity = item.Adapt<BookingCtn>();
ctnentity.BILLID = entity.Id;
await _repCtn.InsertAsync(ctnentity);
ctnList.Add(ctnentity);
}
var groupList = input.CtnList.Where(x => x.CTNNUM > 0).GroupBy(c => c.CTNALL).Select(g => $"{g.Key}*{g.Sum(gg => gg.CTNNUM)}");
entity.CNTRTOTAL = string.Join(" / ", groupList);
}
else
{
entity.CNTRTOTAL = "";
}
await _rep.UpdateAsync(entity);
//服务项目
_repServiceItem.Delete(x => x.BookingId == entity.Id);
foreach (var item in input.ServiceItemList)
{
var bsi = item.Adapt<BookingServiceItem>();
bsi.Id = YitIdHelper.NextId();
bsi.BookingId = entity.Id;
await _repServiceItem.InsertAsync(bsi);
}
//文件
var dbFiles = _repFile.AsQueryable().Where(x => x.BookingId == entity.Id).ToList();
var opt = App.GetOptions<BookingAttachOptions>();
var dirAbs = string.Empty;
if (string.IsNullOrEmpty(opt.basePath))
{
dirAbs = Path.Combine(App.WebHostEnvironment.WebRootPath, opt.relativePath);
}
else
{
dirAbs = Path.Combine(opt.basePath, opt.relativePath);
}
if (!Directory.Exists(dirAbs))
Directory.CreateDirectory(dirAbs);
//清除前端已删除的文件
if (input.Files != null && input.Files.Count() > 0)
{
var delIds = dbFiles.Where(x => !input.Files.Contains(x.Id)).Select(x => x.Id);
await _repFile.DeleteAsync(x => delIds.Contains(x.Id));
}
else
{
await _repFile.DeleteAsync(x => x.BookingId == entity.Id);
}
//临时文件转为正式文件
if (input.TempFileNames != null && input.TempFileNames.Count() > 0)
{
var optTempFile = App.GetOptions<TempFileOptions>().Path;
foreach (var tmpFile in input.TempFileNames)
{
var tempPath = Path.Combine(optTempFile, tmpFile);
if (File.Exists(tempPath))
{
var saveFileName = $"{DateTime.Now.Ticks}{Path.GetExtension(tmpFile)}";
var fileRelaPath = Path.Combine(opt.relativePath, saveFileName).ToLower();
var fileAbsPath = Path.Combine(dirAbs, saveFileName).ToLower();
File.Copy(tempPath, fileAbsPath, true);
var newFile = new BookingFile
{
Id = YitIdHelper.NextId(),
FileName = Path.GetFileName(tmpFile),
FilePath = fileRelaPath,
TypeCode = "tuodan",
TypeName = "托单文件",
BookingId = entity.Id,
};
await _repFile.InsertAsync(newFile);
}
}
}
//日志动态
SaveAuditLog(input.Id == 0 ? "已录入" : "已修改", entity.Id);
//EMC需要保存船期原始数据
if (input.CARRIERID == "EMC" && input.ShipData != null)
{
_logger.LogInformation($"保存船期数据EMC{input.ShipData}");
JObject jobjExt = new JObject();
if (!string.IsNullOrEmpty(entity.ExtendData))
{
jobjExt = JObject.Parse(entity.ExtendData);
}
jobjExt["shipInfo"] = input.ShipData;
entity.ExtendData = jobjExt.ToString();
await _rep.AsUpdateable(entity).UpdateColumns(x => new { x.ExtendData }).ExecuteCommandAsync();
}
//返回给前端数据
var outModel = entity.Adapt<BookingCustomerOrderSaveOutput>();
outModel.CtnList = ctnList.Adapt<List<BookingCustomerCtnDto>>();
var dicFile = new Dictionary<long, string>();
_repFile.AsQueryable().Where(x => x.BookingId == entity.Id).ForEach(x => dicFile.Add(x.Id, x.FileName));
outModel.Files = dicFile;
outModel.LogList = _repStatuslog.AsQueryable().Where(x => x.BookingId == entity.Id && x.Category == StaLogCateAudit).OrderByDescending(x => x.OpTime).ToList().Adapt<List<BookingCustomerLogDto>>();
outModel.ServiceItemList = _repServiceItem.AsQueryable().Where(x => x.BookingId == entity.Id).ToList().Adapt<List<BookingServiceItemCustomerDto>>();
return outModel;
}
private async Task SaveData(BookingCustomerOrder entity, List<BookingCtn> ctns, List<BookingServiceItem> servList, bool ins)
{
if (ins)
{
if (string.IsNullOrEmpty(entity.VOYNO))
{
entity.VOYNO = entity.VOYNOINNER;
}
entity.Id = YitIdHelper.NextId();
entity.BSSTATUS = "已录入";
entity.BOOKINGNO = $"BK{YitIdHelper.NextId()}";
await _rep.InsertAsync(entity);
}
else
{
if (entity.BSSTATUS != "已录入" && entity.BSSTATUS != "已驳回")
{
throw Oops.Bah("当前状态不允许修改");
}
if (string.IsNullOrEmpty(entity.VOYNO))
{
entity.VOYNO = entity.VOYNOINNER;
}
await _rep.UpdateAsync(entity);
await _repCtn.DeleteAsync(x => x.BILLID == entity.Id);
}
//箱信息保存
if (ctns != null)
{
foreach (var ctn in ctns)
{
ctn.Id = YitIdHelper.NextId();
ctn.BILLID = entity.Id;
await _repCtn.InsertAsync(ctn);
}
var groupList = ctns.Where(x => x.CTNNUM > 0).GroupBy(c => c.CTNALL).Select(g => $"{g.Key}*{g.Sum(gg => gg.CTNNUM)}");
entity.CNTRTOTAL = string.Join(" / ", groupList);
}
else
{
entity.CNTRTOTAL = "";
}
await _rep.UpdateAsync(entity);
if (servList == null || servList.Count == 0)
{
throw Oops.Bah("必须选择服务项目");
}
//服务项目
_repServiceItem.Delete(x => x.BookingId == entity.Id);
foreach (var srv in servList)
{
srv.Id = YitIdHelper.NextId();
srv.BookingId = entity.Id;
await _repServiceItem.InsertAsync(srv);
}
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Get")]
public async Task<BookingCustomerOrderSaveOutput> Get(long id)
{
var entity = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == id);
var outModel = entity.Adapt<BookingCustomerOrderSaveOutput>();
outModel.CtnList = _repCtn.Where(x => x.BILLID == id).ToList().Adapt<List<BookingCustomerCtnDto>>();
var dicFile = new Dictionary<long, string>();
_repFile.AsQueryable().Where(x => x.BookingId == entity.Id).ForEach(x => dicFile.Add(x.Id, x.FileName));
outModel.Files = dicFile;
outModel.LogList = _repStatuslog.AsQueryable().Where(x => x.BookingId == entity.Id && x.Category == StaLogCateAudit).OrderByDescending(x => x.OpTime).ToList().Adapt<List<BookingCustomerLogDto>>();
outModel.ServiceItemList = _repServiceItem.AsQueryable().Where(x => x.BookingId == entity.Id).ToList().Adapt<List<BookingServiceItemCustomerDto>>();
return outModel;
}
/// <summary>
/// 上传临时文件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/UploadTempFile")]
public async Task<string> UploadTempFile(IFormFile file)
{
//未上传文件
if (file == null || file.Length == 0)
{
throw Oops.Bah("未上传任何文件");
}
var optTempFile = App.GetOptions<TempFileOptions>().Path;
var tempFilePath = $"{DateTime.Now.Ticks}"; //临时存放目录
var tempSavePath = Path.Combine(optTempFile, tempFilePath);
Directory.CreateDirectory(tempSavePath);
var fileFullPath = Path.Combine(tempSavePath, file.FileName);//服务器路径
using (var stream = File.Create(fileFullPath))
{
await file.CopyToAsync(stream);
}
return Path.Combine(tempFilePath, file.FileName);
}
/// <summary>
/// 下载查看上传的文件
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetFile"), AllowAnonymous]
public async Task<IActionResult> GetFile(long id)
{
var savedFile = await _repFile.AsQueryable().Filter(null, true).FirstAsync(u => u.Id == id);
if (savedFile == null)
{
throw Oops.Oh("文件不存在");
}
var opt = App.GetOptions<BookingAttachOptions>();
var dirAbs = opt.basePath;
if (string.IsNullOrEmpty(dirAbs))
{
dirAbs = App.WebHostEnvironment.WebRootPath;
}
var fileFullPath = Path.Combine(dirAbs, savedFile.FilePath);
if (!File.Exists(fileFullPath))
{
throw Oops.Oh("文件不存在");
}
//var fileName = HttpUtility.UrlEncode(savedFile.FileName, Encoding.GetEncoding("UTF-8"));
var result = new FileStreamResult(new FileStream(fileFullPath, FileMode.Open), "application/octet-stream") { FileDownloadName = savedFile.FileName };
return result;
}
/// <summary>
/// 根据文件名称下载查看上传的文件
/// </summary>
/// <param name="fn">文件路径名称</param>
/// <param name="isTemp">是否为临时文件</param>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetFileByName"), AllowAnonymous]
public async Task<IActionResult> GetFileByName(string fn, bool isTemp = true)
{
var fileFullPath = "";
if (isTemp)
{
var optTempFile = App.GetOptions<TempFileOptions>().Path;
fileFullPath = Path.Combine(optTempFile, fn);//服务器路径
}
else
{
var opt = App.GetOptions<BookingAttachOptions>();
if (string.IsNullOrEmpty(opt.basePath))
{
fileFullPath = Path.Combine(App.WebHostEnvironment.WebRootPath, fn);//服务器路径
}
else
{
fileFullPath = Path.Combine(opt.basePath, fn);//服务器路径
}
}
if (!File.Exists(fileFullPath))
{
_logger.LogError($"未能找到文件:{fileFullPath}");
throw Oops.Oh("文件不存在");
}
//var fileName = HttpUtility.UrlEncode(savedFile.FileName, Encoding.GetEncoding("UTF-8"));
var result = new FileStreamResult(new FileStream(fileFullPath, FileMode.Open), "application/octet-stream") { FileDownloadName = Path.GetFileName(fn) };
return result;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Delete")]
public async Task Delete(List<long> ids)
{
var list = await _rep.AsQueryable().Filter(null, true).Where(x => ids.Contains(x.Id)).ToListAsync();
var canNotDelList = list.Where(x => x.BSSTATUS != "已录入" && x.BSSTATUS != "已驳回");
if (canNotDelList.Any())
{
var errMsg = string.Join("\r\n", canNotDelList.Select(x => $"{x.BOOKINGNO}的数据当前状态不能删除").ToList());
throw Oops.Bah(errMsg);
}
list.ForEach(x =>
{
x.IsDeleted = true;
_rep.Update(x);
});
}
#endregion
#region 客户端操作与接口
/// <summary>
/// 提交订舱
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Submit")]
public async Task<string> Submit(List<long> ids)
{
var allSysConfig = await _cache.GetAllSysConfig();
var recUrl = allSysConfig.FirstOrDefault(x => x.Code == "DjyBookingRequestReceiveUrl");
if (recUrl == null || string.IsNullOrEmpty(recUrl.Value))
{
throw Oops.Bah("大简云接收订舱URL地址未配置请联系管理员");
}
var userId = allSysConfig.FirstOrDefault(x => x.Code == "DjyBookingReceiveUserId");
var userSecret = allSysConfig.FirstOrDefault(x => x.Code == "DjyBookingReceiveUserSecret");
if (userId == null || string.IsNullOrEmpty(userId.Value) || userSecret == null || string.IsNullOrEmpty(userSecret.Value))
{
throw Oops.Bah("大简云接收订舱用户key和秘钥未配置请联系管理员");
}
//构建数据并发送
var orderList = _rep.AsQueryable().Filter(null, true).Where(x => ids.Contains(x.Id)).ToList();
//2023-9-1衣国豪点击发送订舱时最少得填写船公司船期目的地品名箱型箱量重量如果以上信息没填允许保存但是发送订舱时给出提示 XXX不能为空请补充后重新发送
var emptyCarrList = orderList.Where(x => string.IsNullOrEmpty(x.CARRIERID)).Select(x => x.BOOKINGNO).ToList();
if (emptyCarrList.Any())
{
throw Oops.Bah($"船公司不能为空:\r\n{string.Join("\r\n ", emptyCarrList)}\r\n请补充后重新发送");
}
var emptyETD = orderList.Where(x => !x.ETD.HasValue).Select(x => x.BOOKINGNO).ToList();
if (emptyETD.Any())
{
throw Oops.Bah($"船期不能为空:\r\n{string.Join("\r\n ", emptyETD)}\r\n请补充后重新发送");
}
var emptyDischarge = orderList.Where(x => string.IsNullOrEmpty(x.PORTDISCHARGEID)).Select(x => x.BOOKINGNO).ToList();
if (emptyDischarge.Any())
{
throw Oops.Bah($"目的地不能为空:\r\n{string.Join("\r\n ", emptyDischarge)}\r\n请补充后重新发送");
}
var emptyDescrip = orderList.Where(x => string.IsNullOrEmpty(x.DESCRIPTION)).Select(x => x.BOOKINGNO).ToList();
if (emptyDescrip.Any())
{
throw Oops.Bah($"品名不能为空:\r\n{string.Join("\r\n ", emptyDescrip)}\r\n请补充后重新发送");
}
var emptyKgs = orderList.Where(x => !x.KGS.HasValue).Select(x => x.BOOKINGNO).ToList();
if (emptyKgs.Any())
{
throw Oops.Bah($"重量不能为空:\r\n{string.Join("\r\n ", emptyKgs)}\r\n请补充后重新发送");
}
var ordIdList = orderList.Select(o => o.Id).ToList();
var ctnList = _repCtn.AsQueryable().Filter(null, true).Where(x => ordIdList.Contains(x.BILLID.Value)).ToList();
//2023-9-1衣国豪点击发送订舱时最少得填写船公司船期目的地品名箱型箱量重量如果以上信息没填允许保存但是发送订舱时给出提示 XXX不能为空请补充后重新发送
var emptyCtn = ctnList.Where(x => string.IsNullOrEmpty(x.CTNALL) || !x.CTNNUM.HasValue).Select(x => x.BILLID).Distinct().ToList();
if (emptyCtn.Any())
{
var emptyCtnOrd = orderList.Where(x => emptyCtn.Contains(x.Id)).Select(x => x.BOOKINGNO).ToList();
throw Oops.Bah($"箱型箱量不能为空:\r\n{string.Join("\r\n", emptyCtnOrd)}\r\n请补充后重新发送");
}
var distinctCarr = orderList.Select(x => x.CARRIERID).Distinct().ToList();
if (distinctCarr.Count > 1)
{
throw Oops.Bah($"批量发送时,只能选择同一船司的数据");
}
var fileList = _repFile.AsQueryable().Filter(null, true).Where(x => ordIdList.Contains(x.BookingId)).ToList();
var serviceItemList = _repServiceItem.AsQueryable().Filter(null, true).Where(x => ordIdList.Contains(x.BookingId.Value)).ToList();
var sendList = new List<BookingCustomerSubmitDto>();
var opt = App.GetOptions<BookingAttachOptions>();
var dirAbs = opt.basePath;
if (string.IsNullOrEmpty(dirAbs))
{
dirAbs = App.WebHostEnvironment.WebRootPath;
}
//当前系统的url
var sysUrlCfg = allSysConfig.FirstOrDefault(x => x.Code == "SystemUrl");
var sysUrl = sysUrlCfg.Value;
if (!sysUrl.EndsWith("/"))
{
sysUrl += "/";
}
//接收回推数据的接口key和秘钥 RecBookingFeedback
var apiAuth = _repApiAuth.AsQueryable().Filter(null, true).First(x => x.ApiCode == "RecBookingFeedback" && x.TenantId == UserManager.TENANT_ID);
if (apiAuth == null)
{
throw Oops.Bah("回推数据接收接口授权未配置");
}
foreach (var order in orderList)
{
if (order.BSSTATUS == "已审核")
{
throw Oops.Bah($"{order.BOOKINGNO} 当前状态为{order.BSSTATUS},不能提交");
}
var dto = order.Adapt<BookingCustomerSubmitDto>();
dto.BookingTenantId = UserManager.TENANT_ID;
dto.BookingTenantName = UserManager.TENANT_NAME;
dto.BookingCompanyId = UserManager.DjyCompanyId;
dto.BookingUserId = UserManager.UserId;
dto.BookingUserName = UserManager.Name;
dto.BookingDjyUserId = UserManager.DjyUserId;
dto.FeedbackUrl = $"{sysUrl}BookingCustomerOrder/RecBookingFeedback";
dto.FeedbackKey = apiAuth.ApiKey;
dto.FeedbackSecret = apiAuth.ApiSecret;
dto.CtnList = ctnList.Where(x => x.BILLID == order.Id).ToList().Adapt<List<BookingCustomerCtnDto>>();
dto.ServiceItemList = serviceItemList.Where(x => x.BookingId == order.Id).ToList().Adapt<List<BookingServiceItemCustomerDto>>();
dto.Files = fileList.Where(x => x.BookingId == order.Id).ToList().Adapt<List<BookingFileSyncCustomerDto>>();
sendList.Add(dto);
}
//构建完整url
var submitUrl = recUrl.Value;
// 如果当前环境为开发环境,则请求本机运营端程序的接口地址,来进行调试
if (App.HostEnvironment.IsDevelopment())
{
submitUrl = "http://localhost:5130";
// 更改回推接收地址
sendList.ForEach(x => x.FeedbackUrl = $"{App.Configuration["Url"]}/BookingCustomerOrder/RecBookingFeedback");
}
if (!submitUrl.EndsWith("/"))
{
submitUrl += "/";
}
submitUrl += "BookingCustomerOrder/ReceiveBooking";
_logger.LogInformation($"提交订舱数据({submitUrl}{userId.Value}{userSecret.Value}{JsonConvert.SerializeObject(sendList)}");
var rtn = await submitUrl
.SetHeaders(new Dictionary<string, object> {
{ CommonConst.API_USER_HEADER_KEY, userId.Value},
{ CommonConst.API_USER_HEADER_SECRET, userSecret.Value}
})
.SetBody(sendList)
.PostAsStringAsync();
_logger.LogInformation($"返回数据:{rtn}");
var resultText = new StringBuilder();
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") != 200)
{
throw Oops.Bah(jobjRtn.GetStringValue("message"));
}
else
{
var arrData = jobjRtn.GetJArrayValue("data");
foreach (JObject item in arrData)
{
var id = item.GetLongValue("id");
var bookingno = item.GetStringValue("bookingno");
var message = item.GetStringValue("message");
var succ = item.GetBooleanValue("success");
if (succ)
{
var model = _rep.AsQueryable().Filter(null, true).First(x => x.Id == id);
model.BSSTATUS = "已提交";
await _rep.AsUpdateable(model).UpdateColumns(x => new { x.BSSTATUS }).ExecuteCommandAsync();
//日志动态
SaveAuditLog("已提交", id);
}
else
{
//日志动态
SaveAuditLog($"提交失败", id, remark: item.GetStringValue("message"));
}
resultText.AppendLine($"{bookingno}{message}");
}
return resultText.ToString();
}
}
/// <summary>
/// 取消提交订舱
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/CancelSubmit")]
public async Task<string> CancelSubmit(List<long> ids)
{
var recUrl = _cache.GetAllSysConfig().Result.FirstOrDefault(x => x.Code == "DjyBookingRequestReceiveUrl");
if (recUrl == null || string.IsNullOrEmpty(recUrl.Value))
{
throw Oops.Bah("大简云接收订舱URL地址未配置请联系管理员");
}
var userId = _cache.GetAllSysConfig().Result.FirstOrDefault(x => x.Code == "DjyBookingReceiveUserId");
var userSecret = _cache.GetAllSysConfig().Result.FirstOrDefault(x => x.Code == "DjyBookingReceiveUserSecret");
if (userId == null || string.IsNullOrEmpty(userId.Value) || userSecret == null || string.IsNullOrEmpty(userSecret.Value))
{
throw Oops.Bah("大简云接收订舱用户key和秘钥未配置请联系管理员");
}
var orderList = _rep.AsQueryable().Filter(null, true).Where(x => ids.Contains(x.Id)).ToList();
var noSubmitList = orderList.Where(x => x.BSSTATUS != "已提交").Select(x => x.BOOKINGNO).ToList();
if (noSubmitList.Count > 0)
{
throw Oops.Bah($"编号为 {string.Join(",", noSubmitList)} 的状态不能取消订舱");
}
var sendList = orderList.Select(x => new BookingCustomerCancelSubmitDto()
{
Id = x.Id.ToString(),
BOOKINGNO = x.BOOKINGNO
}).ToList();
//构建完整url
var submitUrl = recUrl.Value;
if (!submitUrl.EndsWith("/"))
{
submitUrl += "/";
}
submitUrl += "BookingCustomerOrder/CancelBooking";
_logger.LogInformation($"取消提交订舱数据({submitUrl}{userId.Value}{userSecret.Value}{JsonConvert.SerializeObject(sendList)}");
var rtn = await submitUrl
.SetHeaders(new Dictionary<string, object> {
{ CommonConst.API_USER_HEADER_KEY, userId.Value},
{ CommonConst.API_USER_HEADER_SECRET, userSecret.Value}
})
.SetBody(sendList)
.PostAsStringAsync();
_logger.LogInformation($"返回数据:{rtn}");
var resultText = new StringBuilder();
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") != 200)
{
throw Oops.Bah(jobjRtn.GetStringValue("message"));
}
else
{
var arrData = jobjRtn.GetJArrayValue("data");
foreach (JObject item in arrData)
{
var id = item.GetLongValue("id");
var bookingno = item.GetStringValue("bookingno");
var message = item.GetStringValue("message");
var succ = item.GetBooleanValue("success");
if (succ)
{
var model = _rep.AsQueryable().Filter(null, true).First(x => x.Id == id);
model.BSSTATUS = "已录入";
await _rep.UpdateAsync(model);
//日志动态
SaveAuditLog($"取消提交", id);
}
else
{
//日志动态
SaveAuditLog($"取消提交失败", id, remark: item.GetStringValue("message"));
}
resultText.AppendLine($"{bookingno}{message}");
}
return resultText.ToString();
}
}
/// <summary>
/// 查询船期数据EMC
/// </summary>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/QueryShipInfoEMC")]
public async Task<dynamic> QueryShipInfoEMC(long custOrdId)
{
var allSysConfig = await _cache.GetAllSysConfig();
var sCfgSpiderUrl = allSysConfig.FirstOrDefault(x => x.Code == "BookingPostApiServerAddr" && x.GroupCode == "DJY_CONST");
if (sCfgSpiderUrl == null)
{
throw Oops.Bah("订舱API的爬虫URL地址未配置请联系管理员");
}
var sCfgUserKey = allSysConfig.FirstOrDefault(x => x.Code == "BookingPostApiKey" && x.GroupCode == "DJY_CONST");
var sCfgUserSecret = allSysConfig.FirstOrDefault(x => x.Code == "BookingPostApiSecret" && x.GroupCode == "DJY_CONST");
if (sCfgUserKey == null || sCfgUserSecret == null)
{
throw Oops.Bah("订舱API的KEY和密钥未配置请联系管理员");
}
var apiUrl = sCfgSpiderUrl.Value;
if (!apiUrl.EndsWith("/"))
{
apiUrl += "/";
}
apiUrl += "v1/emc/ship/query";
var custOrder = await _rep.AsQueryable().FirstAsync(x => x.Id == custOrdId);
var ctns = await _repCtn.AsQueryable().Where(x => x.BILLID == custOrdId).ToListAsync();
var mappingCtn = await _cache.GetAllMappingCtn();
var mappingPortLoad = await _cache.GetAllMappingPortLoad();
var mappingPort = await _cache.GetAllMappingPort();
//收货地
var mapPlaceReceipt = mappingPortLoad.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.PLACERECEIPTCODE);
if (mapPlaceReceipt == null)
{
throw Oops.Bah($"未找到收货地映射信息:{custOrder.PLACERECEIPTCODE}");
}
//起运港
var mapPortLoad = mappingPortLoad.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.PORTLOADCODE);
if (mapPortLoad == null)
{
throw Oops.Bah($"未找到起运港映射信息:{custOrder.PORTLOADCODE}");
}
//卸货港
var mapPort = mappingPort.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.PORTDISCHARGECODE);
if (mapPort == null)
{
throw Oops.Bah($"未找到卸货港映射信息:{custOrder.PORTDISCHARGECODE}");
}
//目的地
var mapDestination = mappingPort.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == custOrder.DESTINATIONCODE);
if (mapDestination == null)
{
throw Oops.Bah($"未找到目的地映射信息:{custOrder.DESTINATIONCODE}");
}
//箱型转换
var disCtnCode = ctns.Select(x => x.CTNCODE).Distinct().ToList();
var mapCtnCode = new List<string>();
foreach (var ctnall in disCtnCode)
{
var mapCtn = mappingCtn.FirstOrDefault(x => x.Module == "DjyCustBooking" && x.CarrierCode == "EMC" && x.Code == ctnall);
if (mapCtn == null)
{
throw Oops.Bah($"未找到箱型映射信息:{ctnall}");
}
mapCtnCode.Add(mapCtn.MapName);
}
var postModel = new
{
userKey = sCfgUserKey.Value,
userSecret = sCfgUserSecret.Value,
webAccount = custOrder.BookingAccount,
webPassword = custOrder.BookingPassword,
searchConditionDate = custOrder.ETD.Value.AddDays(-7).ToString("yyyy-MM-dd"),
originName = mapPlaceReceipt.MapName,
destinationName = mapDestination.MapName,
polPortName = mapPortLoad.MapName,
podPortName = mapPort.MapName,
serviceType = custOrder.ServiceType,
serviceMode = custOrder.ServiceMode,
bookingOffice = custOrder.BookingAddr,
isReefer = "N",
contractType = custOrder.ContractType,
contractNo = custOrder.CONTRACTNO,
containerTypeList = mapCtnCode
};
_logger.LogInformation($"发送查询API数据给爬虫{apiUrl}{postModel.ToJsonString()}");
var rtnQuery = await apiUrl.SetBody(postModel)
.PostAsStringAsync();
_logger.LogInformation($"爬虫返回:{rtnQuery}");
var jobjRtnQuery = JObject.Parse(rtnQuery);
if (jobjRtnQuery.GetIntValue("code") != 200)
{
throw Oops.Bah($"查询船期数据出错:{jobjRtnQuery.GetStringValue("msg")}");
}
else
{
var jarrVessel = jobjRtnQuery.GetJArrayValue("data");
return jarrVessel;
}
}
/// <summary>
/// 保存船期数据EMC
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/SaveShipInfoEMC")]
public async Task SaveShipInfoEMC(SaveShipInfoEMCDto dto)
{
_logger.LogInformation($"保存船期数据EMC{dto.ToJsonString()}");
var custOrder = await _rep.AsQueryable().FirstAsync(x => x.Id == dto.Id);
JObject jobjExt = new JObject();
if (!string.IsNullOrEmpty(custOrder.ExtendData))
{
jobjExt = JObject.Parse(custOrder.ExtendData);
}
jobjExt["shipInfo"] = dto.ShipData;
custOrder.ExtendData = jobjExt.ToString();
await _rep.AsUpdateable(custOrder).UpdateColumns(x => new { x.ExtendData }).ExecuteCommandAsync();
}
#region 客户订舱模板
/// <summary>
/// 客户订舱模板列表
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateList")]
public async Task<SqlSugarPagedList<BookingCustomerTemplateQueryOutput>> OrderTemplateList(BookingCustomerTemplateQueryInput input)
{
var query = _repOrderTempl.AsQueryable()
.Where(t => t.CreatedUserId == UserManager.UserId)
.WhereIF(!string.IsNullOrEmpty(input.Title), t => t.Title.Contains(input.Title))
.Select(t => new BookingCustomerTemplateQueryOutput()
{
Id = t.Id,
Title = t.Title,
});
if (!string.IsNullOrEmpty(input.SortField) || input.MultiSort == null || input.MultiSort.Count == 0)
{
query = query.OrderBy(PageInputOrder.OrderBuilder(input.SortField, input.DescSort));
}
else
{
query = query.OrderBy(PageInputOrder.MultiOrderBuilder(input.MultiSort));
}
return await query.ToPagedListAsync(input.PageNo, input.PageSize);
}
/// <summary>
/// 客户订舱模板删除
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateDel")]
public async Task OrderTemplateDel(long id)
{
await _repOrderTempl.DeleteAsync(id);
}
/// <summary>
/// 客户订舱模板保存
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateSave")]
public async Task OrderTemplateSave(BookingCustomerTemplateSaveInput model)
{
if (string.IsNullOrEmpty(model.Title))
{
throw Oops.Bah("请输入模板名称");
}
var template = model.Adapt<BookingCustomerOrderTemplate>();
await _repOrderTempl.InsertAsync(template);
}
/// <summary>
/// 客户订舱模板内容
/// </summary>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetOrderTemplate")]
public async Task<string> GetOrderTemplate(long id)
{
var objTemp = await _repOrderTempl.FirstOrDefaultAsync(x => x.Id == id);
if (objTemp == null)
{
throw Oops.Bah("模板未找到");
}
return objTemp.JsonContent;
}
#endregion
//[HttpPost("/BookingCustomerOrder/FeedbackTest"), AllowAnonymous]
//public async Task FeedbackTest(string json)
//{
//}
/// <summary>
/// 接收订舱回推统一接口
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/RecBookingFeedback"), AllowAnonymous, ApiUser(ApiCode = "RecBookingFeedback")]
public async Task<dynamic> RecBookingFeedback(string feedbackType, string jsonContent, string syncType)
{
_logger.LogInformation($"收到订舱回推数据feedbackType{feedbackType}jsonContent{jsonContent}syncType{syncType}");
if (string.IsNullOrEmpty(feedbackType) || string.IsNullOrEmpty(jsonContent))
{
throw Oops.Bah("参数有误");
}
#region 审核反馈
if (feedbackType == BookingFeedbackType.Audit.ToString())
{
var recModel = JsonConvert.DeserializeObject<BookingCustomerRecAduitFeedbackDto>(jsonContent);
var id = Convert.ToInt64(recModel.Id);
var model = _rep.AsQueryable().Filter(null, true).First(x => x.Id == id);
if (model == null)
{
throw Oops.Bah("未找到数据");
}
//if (model.BSSTATUS != "已提交")
//{
// throw Oops.Bah("当前状态不能接受审核回推");
//}
if (recModel.Accept)
{
model.BSSTATUS = "已审核";
}
else
{
model.BSSTATUS = "已驳回";
}
await _rep.UpdateAsync(model);
//日志动态
SaveAuditLog($"{model.BSSTATUS}", id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: $"审核意见:{recModel.Comment}");
long bookingId = 0;
//进入客户订舱系统的订舱台账
if (recModel.Accept)
{
var bkOrder = model.Adapt<BookingOrder>();
bkOrder.Id = YitIdHelper.NextId();
bkOrder.BSSTATUS = "已录入";
bkOrder.ParentId = 0;
bkOrder.LANENAME = bkOrder.LANECODE;
await _repOrder.InsertAsync(bkOrder);
model.BookingId = bkOrder.Id; //客户订舱数据与订舱台账数据关联
bookingId = bkOrder.Id;
await _rep.UpdateAsync(model);
var bkEdiExt = new BookingEDIExt();
bkEdiExt.Id = YitIdHelper.NextId();
bkEdiExt.BookingId = bkOrder.Id;
bkEdiExt.SalerCode = model.SaleCode;
await _repEdiExt.InsertAsync(bkEdiExt);
var ctnList = await _repCtn.AsQueryable().Filter(null, true).Where(x => x.BILLID == model.Id).ToListAsync();
foreach (var ctn in ctnList)
{
ctn.Id = YitIdHelper.NextId();
ctn.BILLID = bkOrder.Id;
await _repCtn.InsertAsync(ctn);
}
//服务项目
var servList = await _repServiceItem.Where(x => x.BookingId == model.Id).ToListAsync();
foreach (var serv in servList)
{
serv.Id = YitIdHelper.NextId();
serv.BookingId = bkOrder.Id;
await _repServiceItem.InsertAsync(serv);
}
//附件
var files = await _repFile.AsQueryable().Filter(null, true).Where(x => x.BookingId == model.Id && x.IsDeleted == false).ToListAsync();
foreach (var file in files)
{
file.Id = YitIdHelper.NextId();
file.BookingId = bkOrder.Id;
await _repFile.InsertAsync(file);
}
}
// 接收到订舱需求审核后推送东胜
_ = Task.Run(() =>
{
try
{
string json = null;
if (recModel.Accept)
{
var body = new
{
Type = "CustOrderStatusAccept",
Data = new
{
model.BSNO,
BSSTATUS = "已审核",
BookingOrderId = bookingId
}
};
json = body.ToJsonString();
}
else
{
var body = new
{
Type = "CustOrderStatusReject",
Data = new
{
model.BSNO,
BSSTATUS = "已驳回",
COMMENT = recModel.Comment
}
};
json = body.ToJsonString();
}
var mqUrl = _cache.GetAllSysConfig().Result.FirstOrDefault(x => x.Code == "AuditBookingMqUrl")?.Value ?? throw new Exception("需配置接收订舱需求审核后推送东胜MQ连接串[AuditBookingMqUrl]");
const string MqActionExchangeName = "amq.direct";
const string MqActionQueueName = "auditbooking.output.ds";
ConnectionFactory factory = new ConnectionFactory();
factory.Uri = new Uri(mqUrl);
using (IConnection conn = factory.CreateConnection())
using (IModel mqModel = conn.CreateModel())
{
mqModel.ExchangeDeclare(MqActionExchangeName, ExchangeType.Direct, true);
var queueName = $"{MqActionQueueName}.{model.TenantId}";
mqModel.QueueDeclare(queueName, false, false, false, null);
mqModel.QueueBind(queueName, MqActionExchangeName, queueName, null);
IBasicProperties props = mqModel.CreateBasicProperties();
props.DeliveryMode = 2;
byte[] messageBodyBytes = Encoding.UTF8.GetBytes(SharpZipLib.Compress(json));
mqModel.BasicPublish(MqActionExchangeName, queueName, props, messageBodyBytes);
conn.Close();
_logger.LogInformation($"接收到订舱需求审核后推送东胜,已发送数据到消息队列【{mqUrl}】,队列名称:【{queueName}】,数据内容:【{json}】");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "接收到订舱需求审核后推送东胜时发生异常");
}
});
if (recModel.Accept)
{
return bookingId;
}
else
{
return 0;
}
}
#endregion
#region 订舱完整数据
else if (feedbackType == BookingFeedbackType.BookingAll.ToString())
{
var recModel = JsonConvert.DeserializeObject<BookingCustomerRecDataFeedbackDto>(jsonContent);
var dbOrder = await _repOrder.AsQueryable().Filter(null, true).FirstAsync(x => !x.IsDeleted && x.Id == recModel.Order.Id);
if (dbOrder == null)
{
throw Oops.Bah($"未找到id为{recModel.Order.Id}的数据");
}
if (!string.IsNullOrEmpty(dbOrder.MBLNO)) //提单号不覆盖
{
recModel.Order.MBLNO = dbOrder.MBLNO;
}
//保存主表
recModel.Order.Adapt(dbOrder);
await _repOrder.UpdateAsync(dbOrder);
//更新箱信息
await _repCtn.DeleteAsync(x => x.BILLID == recModel.Order.Id);
foreach (var ctn in recModel.Ctns)
{
var saveCtn = ctn.Adapt<BookingCtn>();
saveCtn.BILLID = recModel.Order.Id;
saveCtn.CreatedUserId = dbOrder.CreatedUserId;
saveCtn.CreatedUserName = "系统";
saveCtn.CreatedTime = DateTime.Now;
saveCtn.TenantId = dbOrder.TenantId;
await _repCtn.InsertAsync(saveCtn);
}
//货运动态
foreach (var sta in recModel.StatusLogs)
{
await _repStatuslogDetail.DeleteAsync(x => x.PId == sta.Id);
await _repStatuslog.DeleteAsync(x => x.Id == sta.Id);
var insStaLog = sta.Adapt<BookingStatusLog>();
insStaLog.BookingId = recModel.Order.Id;
await _repStatuslog.InsertAsync(insStaLog);
foreach (var staDetail in sta.Details)
{
var insStaDetail = staDetail.Adapt<BookingStatusLogDetail>();
insStaDetail.PId = insStaLog.Id;
await _repStatuslogDetail.InsertAsync(insStaDetail);
}
}
//文件
//var opt = App.GetOptions<BookingAttachOptions>();
//var dirAbs = string.Empty;
//if (string.IsNullOrEmpty(opt.basePath))
//{
// dirAbs = Path.Combine(App.WebHostEnvironment.WebRootPath, opt.relativePath);
//}
//else
//{
// dirAbs = Path.Combine(opt.basePath, opt.relativePath);
//}
//if (!Directory.Exists(dirAbs))
// Directory.CreateDirectory(dirAbs);
var dbFiles = await _repFile.AsQueryable().Filter(null, true).Where(f => f.BookingId == recModel.Order.Id).ToListAsync();
foreach (var file in recModel.Files)
{
if (dbFiles.Count(ff => ff.Id == file.Id) == 0) //新文件
{
var insFile = file.Adapt<BookingFile>();
insFile.BookingId = recModel.Order.Id;
insFile.CreatedUserId = dbOrder.CreatedUserId;
insFile.CreatedUserName = "系统";
insFile.CreatedTime = DateTime.Now;
insFile.TenantId = dbOrder.TenantId;
//var saveFileName = $"{DateTime.Now.Ticks}{Path.GetExtension(file.FileName)}";
//var fileRelaPath = Path.Combine(opt.relativePath, saveFileName).ToLower();
//var fileAbsPath = Path.Combine(dirAbs, saveFileName).ToLower();
//insFile.FilePath = fileRelaPath;
//File.WriteAllBytes(fileAbsPath, file.FileContent);
await _repFile.InsertAsync(insFile);
}
}
BookingOrderSyncTypeEnum? syncTypeEnum = syncType switch
{
"BC" => BookingOrderSyncTypeEnum.BC,
"CC" => BookingOrderSyncTypeEnum.CC,
//"FILE" => BookingOrderSyncTypeEnum.FILE,
_ => null,
};
await bookingOrderService.SendBookingOrder(new long[] { dbOrder.Id }, syncTypeEnum);
}
#endregion
#region 订舱货物状态回推
else if (feedbackType == BookingFeedbackType.GoodsStatus.ToString())
{
var recModel = JsonConvert.DeserializeObject<GoodsStatusSyncDto>(jsonContent);
var dbOrder = await _repOrder.AsQueryable().Filter(null, true).FirstAsync(x => !x.IsDeleted && x.Id == recModel.Id);
if (dbOrder == null)
{
throw Oops.Bah($"未找到id为{recModel.Id}的数据");
}
var gsCfg = await _goodsStatusConfig.AsQueryable().Filter(null, true)
.FirstAsync(x => x.CreatedUserId == dbOrder.CreatedUserId
&& x.IsDeleted == false
&& x.SystemCode == recModel.Code);
if (gsCfg == null)
{
throw Oops.Bah($"用户{dbOrder.CreatedUserName}的货物状态配置数据未找到:{recModel.Code}");
}
if (recModel.IsCancel) //取消货物状态
{
_logger.LogInformation($"取消货物状态{gsCfg.SystemCode} {dbOrder.Id}");
await _goodsStatus.DeleteAsync(x => x.ConfigId == gsCfg.Id
&& x.bookingId == dbOrder.Id
&& x.CreatedUserId == dbOrder.CreatedUserId);
}
else
{
var gs = await _goodsStatus.AsQueryable().Filter(null, true)
.FirstAsync(x => x.ConfigId == gsCfg.Id
&& x.bookingId == dbOrder.Id
&& x.CreatedUserId == dbOrder.CreatedUserId
&& x.IsDeleted == false);
if (gs == null)
{
gs = new BookingGoodsStatus();
gs.Id = YitIdHelper.NextId();
gs.bookingId = dbOrder.Id;
gs.ConfigId = gsCfg.Id;
gs.TenantId = dbOrder.TenantId;
gs.CreatedUserId = dbOrder.CreatedUserId;
gs.CreatedUserName = dbOrder.CreatedUserName;
gs.FinishUserId = dbOrder.CreatedUserId;
gs.FinishUser = "系统";
gs.FinishTime = string.IsNullOrEmpty(recModel.FinishTime) ? DateTime.Now : Convert.ToDateTime(recModel.FinishTime);
await _goodsStatus.InsertAsync(gs);
}
else
{
gs.FinishUserId = dbOrder.CreatedUserId;
gs.FinishUser = "系统";
gs.FinishTime = string.IsNullOrEmpty(recModel.FinishTime) ? DateTime.Now : Convert.ToDateTime(recModel.FinishTime);
await _goodsStatus.UpdateAsync(gs);
}
await _publisher.PublishAsync(new ChannelEventSource("GoodsStatusSubscribeNotify:Book", new { BookingId = dbOrder.Id, StatusCode = gsCfg.SystemCode, StatusName = gsCfg.StatusName }));
}
}
#endregion
#region 服务项目审核回推
else if (feedbackType == BookingFeedbackType.ServiceItemAudit.ToString())
{
var recModel = JsonConvert.DeserializeObject<ChangeServiceItemResponseDto>(jsonContent);
var ordId = Convert.ToInt64(recModel.Dto.Id);
var order = await _repOrder.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == ordId);
if (recModel.IsReject) //驳回
{
if (recModel.Dto.IsCancel) //申请的是取消,需要恢复服务项目显示
{
var servItm = await _repServiceItem.AsQueryable().Filter(null, true).FirstAsync(x => x.BookingId == ordId && x.Code == recModel.Dto.ServiceCode);
if (servItm == null)
{
servItm = new BookingServiceItem();
servItm.Id = YitIdHelper.NextId();
servItm.BookingId = Convert.ToInt64(recModel.Dto.Id);
servItm.Code = recModel.Dto.ServiceCode;
servItm.Value = recModel.Dto.ServiceName;
await _repServiceItem.InsertAsync(servItm);
}
}
else //申请的是新增,则删掉服务项目
{
await _repServiceItem.DeleteAsync(x => x.BookingId == ordId && x.Code == recModel.Dto.ServiceCode);
}
}
else //通过
{
if (!recModel.Dto.IsCancel) //申请的新增,将未确认状态置为确认
{
var servItm = await _repServiceItem.AsQueryable().Filter(null, true).FirstAsync(x => x.BookingId == ordId && x.Code == recModel.Dto.ServiceCode);
if (servItm != null)
{
servItm.UnConfirm = false;
await _repServiceItem.UpdateAsync(servItm);
}
}
}
var serItm = _cache.GetAllDictData().Result.FirstOrDefault(x => x.TypeCode == "booking_service_item" && x.Code == recModel.Dto.ServiceCode);
var mess = new DjyMessage();
mess.Module = MessageModule.Booking.ToString();
mess.TypeCode = MessageType.ChangeServiceItem.ToString();
mess.TypeName = EnumHelper.GetDescription(typeof(MessageType), mess.TypeCode);
mess.RelativeId = ordId;
mess.RelativeCode = order.BOOKINGNO;
if (recModel.IsReject)
{
mess.Content = $"{recModel.AuditName} 退回了您{(recModel.Dto.IsCancel ? "" : "")}服务项目 {serItm.Value},原因是:{recModel.ProcResult}";
}
else
{
mess.Content = $"{recModel.AuditName} 同意了您{(recModel.Dto.IsCancel ? "" : "")}服务项目 {serItm.Value}";
}
mess.FromName = "大简云";
mess.ProcStatus = MessageProcessStatus.UnProcess.ToString();
await this._repMessage.InsertAsync(mess);
await _publisher.PublishAsync(new ChannelEventSource("Message:NotifyReceiveNew"));
}
#endregion
#region 服务项目手工修改通知回推
else if (feedbackType == BookingFeedbackType.ServiceItemChange.ToString())
{
var recModel = JsonConvert.DeserializeObject<DjyChangeServiceItemDto>(jsonContent);
var ordId = Convert.ToInt64(recModel.Id);
var order = await _repOrder.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == ordId);
var serItm = _cache.GetAllDictData().Result.FirstOrDefault(x => x.TypeCode == "booking_service_item" && x.Code == recModel.ServiceCode);
if (recModel.IsCancel)
{
await _repServiceItem.DeleteAsync(x => x.BookingId == ordId && x.Code == recModel.ServiceCode);
}
else
{
var servItm = await _repServiceItem.AsQueryable().Filter(null, true).FirstAsync(x => x.BookingId == ordId && x.Code == recModel.ServiceCode);
if (servItm != null)
{
servItm.UnConfirm = false;
await _repServiceItem.UpdateAsync(servItm);
}
else
{
servItm = new BookingServiceItem();
servItm.Id = YitIdHelper.NextId();
servItm.BookingId = ordId;
servItm.Code = recModel.ServiceCode;
servItm.Value = serItm.Value;
await _repServiceItem.InsertAsync(servItm);
}
}
var mess = new DjyMessage();
mess.Module = MessageModule.Booking.ToString();
mess.TypeCode = MessageType.ChangeServiceItem.ToString();
mess.TypeName = EnumHelper.GetDescription(typeof(MessageType), mess.TypeCode);
mess.RelativeId = ordId;
mess.RelativeCode = order.BOOKINGNO;
mess.Content = $"{recModel.UserName} {(recModel.IsCancel ? "" : "")}服务项目 {serItm.Value},原因是:{recModel.Remark}";
mess.FromName = "大简云";
mess.ProcStatus = MessageProcessStatus.UnProcess.ToString();
await this._repMessage.InsertAsync(mess);
await _publisher.PublishAsync(new ChannelEventSource("Message:NotifyReceiveNew"));
}
#endregion
#region 单证补料审核通知回推
else if (feedbackType == BookingFeedbackType.DocSupplementAudit.ToString())
{
var recModel = JsonConvert.DeserializeObject<DocSupplementResponseDto>(jsonContent);
var ordId = Convert.ToInt64(recModel.Dto.Id);
var order = await _repOrder.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == ordId);
if (!recModel.IsReject) //审核通过,挂载附件
{
//进入订舱附件
foreach (var ff in recModel.Dto.FileList)
{
var fileSuffix = Path.GetFileName(ff.FileName);
var newFile = new BookingFile
{
Id = ff.Id,
FileName = ff.FileName,
FilePath = ff.FilePath,
TypeCode = ff.TypeCode,
TypeName = ff.TypeName,
BookingId = ordId,
TenantId = order.TenantId,
TenantName = order.TenantName,
};
await _repFile.InsertAsync(newFile);
}
}
var mess = new DjyMessage();
mess.Module = MessageModule.Booking.ToString();
mess.TypeCode = MessageType.DocSupplement.ToString();
mess.TypeName = EnumHelper.GetDescription(typeof(MessageType), mess.TypeCode);
mess.RelativeId = ordId;
mess.RelativeCode = order.BOOKINGNO;
if (recModel.IsReject)
{
mess.Content = $"{recModel.AuditName} 退回了提交的 {recModel.Dto.DocTypeName},原因是:{recModel.ProcResult}";
}
else
{
mess.Content = $"{recModel.AuditName} 通过了提交的 {recModel.Dto.DocTypeName}";
}
mess.FromName = "大简云";
mess.ProcStatus = MessageProcessStatus.UnProcess.ToString();
await this._repMessage.InsertAsync(mess);
await _publisher.PublishAsync(new ChannelEventSource("Message:NotifyReceiveNew"));
}
#endregion
return null;
}
/// <summary>
/// 导入
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ImportBooking")]
public async Task ImportBooking(IFormFile file, [FromForm] string carrierId)
{
//未上传文件
if (file == null || file.Length == 0)
{
throw Oops.Bah("未上传任何文件");
}
var ms = new MemoryStream();
await file.CopyToAsync(ms);
ms.Position = 0;
var dicIns = new Dictionary<BookingCustomerOrder, List<BookingCtn>>();
if (carrierId == "COSCO")
{
var data = MiniExcel.QueryAsDataTable(ms);
var colNames = new string[] { "COSCO账号", "密码", "约号", "船名", "航次", "航线", "ETD", "运输条款", "付费方式", "品名", "起运港", "卸货港", "目的地", "货物类型", "箱型箱量", "单箱重量", "订舱备注", "放舱通知邮箱", "航管" };
//DataRow drHead = data.Rows[0];
foreach (var cn in colNames)
{
if (!data.Columns.Contains(cn))
{
throw Oops.Bah($"文件格式有误,未找到列:{cn}");
}
}
var carrList = await _cache.GetAllCodeCarrier();
var portLoadList = await _cache.GetAllCodePortLoad();
var portDestList = await _cache.GetAllCodePort();
var serviceList = await _cache.GetAllCodeService();
var frtList = await _cache.GetAllCodeFrt();
var ctnList = await _cache.GetAllCodeCtn();
var errList = new List<string>();
for (var idx = 0; idx < data.Rows.Count; idx++)
{
var custOrder = new BookingCustomerOrder();
custOrder.CARRIERID = carrierId;
custOrder.CARRIER = carrierId;
custOrder.CONTRACTNO = data.Rows[idx]["约号"].ToString();
custOrder.VESSEL = data.Rows[idx]["船名"].ToString();
custOrder.VOYNO = data.Rows[idx]["航次"].ToString();
custOrder.LANECODE = data.Rows[idx]["航线"].ToString();
var strETD = data.Rows[idx]["ETD"].ToString();
if (DateTime.TryParse(strETD, out DateTime etd))
{
custOrder.ETD = etd;
}
else
{
errList.Add($"第{idx + 1}行未能识别ETD{strETD}");
}
var serCode = data.Rows[idx]["运输条款"].ToString();
var service = serviceList.FirstOrDefault(x => x.Code == serCode);
if (service == null)
{
errList.Add($"第{idx + 1}行,未找到运输条款:{serCode}");
}
else
{
custOrder.SERVICECODE = service.Code;
custOrder.SERVICE = service.Name;
}
var frtCode = data.Rows[idx]["付费方式"].ToString();
var frt = frtList.FirstOrDefault(x => x.Code == frtCode);
if (frt == null)
{
errList.Add($"第{idx + 1}行,未找到付费方式:{frtCode}");
}
else
{
custOrder.FRTCODE = frt.Code;
custOrder.BLFRT = frt.EnName;
}
custOrder.DESCRIPTION = data.Rows[idx]["品名"].ToString();
var portLoadCode = data.Rows[idx]["起运港"].ToString();
var portLoad = portLoadList.FirstOrDefault(x => x.Code == portLoadCode);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到起运港:{portLoadCode}");
}
else
{
custOrder.PORTLOADID = portLoad.EdiCode;
custOrder.PORTLOAD = portLoad.EnName;
custOrder.PORTLOADCODE = portLoad.Code;
}
var portCode = data.Rows[idx]["卸货港"].ToString();
var portDest = portDestList.FirstOrDefault(x => x.Code == portCode);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到卸货港:{portCode}");
}
else
{
custOrder.PORTDISCHARGEID = portLoad.EdiCode;
custOrder.PORTDISCHARGE = portLoad.EnName;
custOrder.PORTDISCHARGECODE = portLoad.Code;
}
var destina = data.Rows[idx]["目的地"].ToString();
var destinaFind = portDestList.FirstOrDefault(x => x.Code == destina);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到卸货港:{portCode}");
}
else
{
custOrder.DESTINATIONID = portLoad.EdiCode;
custOrder.DESTINATION = portLoad.EnName;
custOrder.DESTINATIONCODE = portLoad.Code;
}
var cargoId = data.Rows[idx]["货物类型"].ToString();
custOrder.CARGOID = cargoId.Substring(0, 1);
custOrder.SOREMARK = data.Rows[idx]["订舱备注"].ToString();
custOrder.SaleCode = data.Rows[idx]["航管"].ToString();
//订舱账号、密码
var jobj = new JObject();
jobj["Account"] = data.Rows[idx]["COSCO账号"].ToString();
jobj["Password"] = data.Rows[idx]["密码"].ToString();
jobj["OpMail"] = data.Rows[idx]["放舱通知邮箱"].ToString();
custOrder.ExtendData = jobj.ToJsonString();
//箱信息
var ctnStr = data.Rows[idx]["箱型箱量"].ToString();
var arrCtn = ctnStr.Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var ctns = new List<BookingCtn>();
if (arrCtn.Length == 2)
{
var ctn = ctnList.FirstOrDefault(x => x.Code == arrCtn[0]);
if (ctn == null)
{
errList.Add($"第{idx + 1}行,未找到箱型:{arrCtn[0]}");
}
else if (int.TryParse(arrCtn[1], out int num))
{
var ctnAdd = new BookingCtn()
{
CTNALL = ctn.Name,
CTNNUM = num,
CTNCODE = ctn.Code
};
ctns.Add(ctnAdd);
var ctnKGS = data.Rows[idx]["单箱重量"].ToString();
if (decimal.TryParse(ctnKGS, out decimal cw))
{
ctnAdd.KGS = cw;
}
}
}
dicIns.Add(custOrder, ctns);
}
if (errList.Count > 0)
{
throw Oops.Bah(string.Join("\r\n", errList));
}
}
else if (carrierId == "EMC")
{
var data = MiniExcel.QueryAsDataTable(ms);
var colNames = new string[] { "POL", "卸货港", "交货地", "运送方式", "运送型态", "SIZE", "WEIGHT单箱", "description of goods", "合约类型", "合约号", "运费付款方式", "船名", "航次", "航线", "ETD", "订舱确认邮箱", "备注 (其它注意事项)" };
//DataRow drHead = data.Rows[0];
foreach (var cn in colNames)
{
if (!data.Columns.Contains(cn))
{
throw Oops.Bah($"文件格式有误,未找到列:{cn}");
}
}
var carrList = await _cache.GetAllCodeCarrier();
var portLoadList = await _cache.GetAllCodePortLoad();
var portDestList = await _cache.GetAllCodePort();
var serviceList = await _cache.GetAllCodeService();
var frtList = await _cache.GetAllCodeFrt();
var ctnList = await _cache.GetAllCodeCtn();
var errList = new List<string>();
for (var idx = 0; idx < data.Rows.Count; idx++)
{
var custOrder = new BookingCustomerOrder();
custOrder.CARRIERID = carrierId;
custOrder.CARRIER = carrierId;
custOrder.CONTRACTNO = data.Rows[idx]["合约号"].ToString();
custOrder.VESSEL = data.Rows[idx]["船名"].ToString();
custOrder.VOYNO = data.Rows[idx]["航次"].ToString();
custOrder.LANECODE = data.Rows[idx]["航线"].ToString();
var strETD = data.Rows[idx]["ETD"].ToString();
if (Regex.IsMatch(strETD, "^\\d+$"))
{
custOrder.ETD = DateTime.FromOADate(Convert.ToDouble(strETD));
}
else
{
if (DateTime.TryParse(strETD, out DateTime etd))
{
custOrder.ETD = etd;
}
else
{
errList.Add($"第{idx + 1}行未能识别ETD{strETD}");
}
}
var frtCode = data.Rows[idx]["运费付款方式"].ToString();
var frt = frtList.FirstOrDefault(x => x.Code == frtCode);
if (frt == null)
{
errList.Add($"第{idx + 1}行,未找到付费方式:{frtCode}");
}
else
{
custOrder.FRTCODE = frt.Code;
custOrder.BLFRT = frt.EnName;
}
custOrder.DESCRIPTION = data.Rows[idx]["description of goods"].ToString();
var portLoadCode = data.Rows[idx]["POL"].ToString();
var portLoad = portLoadList.FirstOrDefault(x => x.Code == portLoadCode || x.EnName == portLoadCode);
if (portLoad == null)
{
errList.Add($"第{idx + 1}行,未找到起运港:{portLoadCode}");
}
else
{
custOrder.PORTLOADID = portLoad.EdiCode;
custOrder.PORTLOAD = portLoad.EnName;
custOrder.PORTLOADCODE = portLoad.Code;
}
var portCode = data.Rows[idx]["卸货港"].ToString();
var portDest = portDestList.FirstOrDefault(x => x.Code == portCode || x.EnName == portCode);
if (portDest == null)
{
errList.Add($"第{idx + 1}行,未找到卸货港:{portCode}");
}
else
{
custOrder.PORTDISCHARGEID = portDest.EdiCode;
custOrder.PORTDISCHARGE = portDest.EnName;
custOrder.PORTDISCHARGECODE = portDest.Code;
}
var destina = data.Rows[idx]["交货地"].ToString();
var destinaFind = portDestList.FirstOrDefault(x => x.Code == destina || x.EnName == destina);
if (destinaFind == null)
{
errList.Add($"第{idx + 1}行,未找到交货地:{destina}");
}
else
{
custOrder.DESTINATIONID = destinaFind.EdiCode;
custOrder.DESTINATION = destinaFind.EnName;
custOrder.DESTINATIONCODE = destinaFind.Code;
}
custOrder.SOREMARK = data.Rows[idx]["备注 (其它注意事项)"].ToString();
//订舱账号、密码
//custOrder.BookingAccount = data.Rows[idx]["EMC账号"].ToString();
//custOrder.BookingPassword = data.Rows[idx]["EMC密码"].ToString();
//2024年6月17日衣国豪导入时一定会先设置用户的账号密码因此取用户设置中的账密
var webAccountConfig = await _webAccountConfig.GetAccountConfigByTenantId("EmcWeb", UserManager.UserId, UserManager.TENANT_ID);
if (webAccountConfig != null)
{
custOrder.BookingAccount = webAccountConfig.Account;
custOrder.BookingPassword = webAccountConfig.Password;
}
custOrder.OpMail = data.Rows[idx]["订舱确认邮箱"].ToString();
//custOrder.ContactName = data.Rows[idx]["联系人"].ToString();
//custOrder.ContactTel = data.Rows[idx]["联系电话"].ToString();
custOrder.ServiceType = data.Rows[idx]["运送方式"].ToString();
custOrder.ServiceMode = data.Rows[idx]["运送型态"].ToString();
custOrder.ContractType = data.Rows[idx]["合约类型"].ToString();
/*
* 2024年6月17日
* 模板导入后收货地默认同装货港签约方默认forwarder提单数量默认1
* 订舱网点,提单签发地,发货人信息,货物代理人信息,默认调用该用户最近一票订舱业务信息。
*/
custOrder.PLACERECEIPT = custOrder.PORTLOAD;
custOrder.PLACERECEIPTID = custOrder.PORTLOADID;
custOrder.PLACERECEIPTCODE = custOrder.PORTLOADCODE;
custOrder.SignType = "Forwarder";
custOrder.BillCount = 1;
var lastOrder = await _rep.AsQueryable().Where(x => x.CreatedUserId == UserManager.UserId).OrderByDescending(x => x.CreatedTime).FirstAsync();
custOrder.BookingAddr = lastOrder.BookingAddr;
custOrder.BillSignLoc = lastOrder.BillSignLoc;
custOrder.SHIPPER = lastOrder.SHIPPER;
custOrder.ShipperAddress = lastOrder.ShipperAddress;
custOrder.ShipperCity = lastOrder.ShipperCity;
custOrder.ShipperCountry = lastOrder.ShipperCountry;
custOrder.ShipperCounty = lastOrder.ShipperCounty;
custOrder.ShipperEmail = lastOrder.ShipperEmail;
custOrder.ShipperFirstName = lastOrder.ShipperFirstName;
custOrder.ShipperInnerCode = lastOrder.ShipperInnerCode;
custOrder.ShipperLastName = lastOrder.ShipperLastName;
custOrder.ShipperName = lastOrder.ShipperName;
custOrder.ShipperPhone = lastOrder.ShipperPhone;
custOrder.ShipperPhoneCode = lastOrder.ShipperPhoneCode;
custOrder.ShipperPhoneCountryCode = lastOrder.ShipperPhoneCountryCode;
custOrder.ShipperPhoneExtension = lastOrder.ShipperPhoneExtension;
custOrder.ShipperPostCode = lastOrder.ShipperPostCode;
custOrder.ShipperProvince = lastOrder.ShipperProvince;
custOrder.ShipperSex = lastOrder.ShipperSex;
custOrder.BookingAddress = lastOrder.BookingAddress;
custOrder.BookingCity = lastOrder.BookingCity;
custOrder.BookingCountry = lastOrder.BookingCountry;
custOrder.BookingCounty = lastOrder.BookingCounty;
custOrder.BookingEmail = lastOrder.BookingEmail;
custOrder.BookingFirstName = lastOrder.BookingFirstName;
custOrder.BookingInnerCode = lastOrder.BookingInnerCode;
custOrder.BookingLastName = lastOrder.BookingLastName;
custOrder.BookingName = lastOrder.BookingName;
custOrder.BookingPhone = lastOrder.BookingPhone;
custOrder.BookingPhoneCode = lastOrder.BookingPhoneCode;
custOrder.BookingPhoneCountryCode = lastOrder.BookingPhoneCountryCode;
custOrder.BookingPhoneExtension = lastOrder.BookingPhoneExtension;
custOrder.BookingPostCode = lastOrder.BookingPostCode;
custOrder.BookingProvince = lastOrder.BookingProvince;
custOrder.BookingSex = lastOrder.BookingSex;
//箱信息
var ctnStr = data.Rows[idx]["SIZE"].ToString();
var arrCtn = ctnStr.Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var ctns = new List<BookingCtn>();
if (arrCtn.Length == 2)
{
var ctn = ctnList.FirstOrDefault(x => x.Code == arrCtn[0] || x.Name == arrCtn[0]);
if (ctn == null)
{
errList.Add($"第{idx + 1}行,未找到箱型:{arrCtn[0]}");
}
else if (int.TryParse(arrCtn[1], out int num))
{
var ctnAdd = new BookingCtn()
{
CTNALL = ctn.Name,
CTNNUM = num,
CTNCODE = ctn.Code
};
ctns.Add(ctnAdd);
var ctnKGS = data.Rows[idx]["WEIGHT单箱"].ToString();
if (decimal.TryParse(ctnKGS, out decimal cw))
{
ctnAdd.KGS = cw;
}
}
}
dicIns.Add(custOrder, ctns);
}
if (errList.Count > 0)
{
throw Oops.Bah(string.Join("\r\n", errList));
}
}
else
{
throw Oops.Bah("当前不支持的该船司");
}
foreach (var k in dicIns)
{
await SaveData(k.Key, k.Value, new List<BookingServiceItem>() { new BookingServiceItem() { Code = "dingcang", Value = "订舱" } }, true);
}
}
#endregion
#region 运营端操作与接口
/// <summary>
/// 接收客户订舱系统提交的数据
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ReceiveBooking"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task<List<BookingSubmitResultModel>> ReceiveBooking(List<BookingCustomerSubmitDto> list)
{
_logger.LogInformation($"收到提交的订舱数据:{JsonConvert.SerializeObject(list)}");
var rtnList = new List<BookingSubmitResultModel>();
var ordOkList = new List<BookingCustomerOrder>();
foreach (var item in list)
{
var strId = item.Id.ToString();
var order = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.TenantId == UserManager.TENANT_ID && x.BSNO == strId);
if (order == null)
{
order = item.Adapt<BookingCustomerOrder>();
order.BSNO = order.Id.ToString(); //客户订舱系统中的id
order.Id = YitIdHelper.NextId();
order.BSSTATUS = "待审核";
await _rep.InsertAsync(order);
}
else
{
if (order.BSSTATUS == "已审核")
{
rtnList.Add(new BookingSubmitResultModel()
{
Id = item.Id,
Success = false,
BOOKINGNO = item.BOOKINGNO,
Message = $"数据已审核,不能重复提交"
}); ;
continue;
}
var idBackup = order.Id; //防止覆盖
var bsnoBackup = order.BSNO; //防止覆盖
order = item.Adapt(order);
order.Id = idBackup;
order.BSNO = bsnoBackup;
order.BSSTATUS = "待审核";
order.IsDeleted = false;
await _rep.UpdateAsync(order);
}
ordOkList.Add(order);
//箱信息
await _repCtn.DeleteAsync(x => x.BILLID == order.Id);
foreach (var ctn in item.CtnList)
{
var bkCtn = ctn.Adapt<BookingCtn>();
bkCtn.Id = YitIdHelper.NextId();
bkCtn.BILLID = order.Id;
await _repCtn.InsertAsync(bkCtn);
}
//服务项目
await _repServiceItem.DeleteAsync(x => x.BookingId == order.Id);
foreach (var serv in item.ServiceItemList)
{
var bkServ = serv.Adapt<BookingServiceItem>();
bkServ.Id = YitIdHelper.NextId();
bkServ.BookingId = order.Id;
await _repServiceItem.InsertAsync(bkServ);
}
//文件
await _repFile.DeleteAsync(x => x.BookingId == order.Id);
foreach (var file in item.Files)
{
var bkFile = file.Adapt<BookingFile>();
bkFile.Id = YitIdHelper.NextId();
bkFile.BookingId = order.Id;
await _repFile.InsertAsync(bkFile);
}
rtnList.Add(new BookingSubmitResultModel()
{
Id = item.Id,
Success = true,
BOOKINGNO = item.BOOKINGNO,
Message = $"提交成功"
});
//日志动态
SaveAuditLog($"待审核", order.Id);
}
_logger.LogInformation($"rtnList:{rtnList.ToJsonString()}");
//全部成功后,才能自动订舱和审核
if (rtnList.Count(x => x.Success == false) == 0)
{
var tCustId = list.First().BookingTenantId;
_logger.LogInformation($"提交成功,准备自动订舱和审核");
//自动订舱和自动审核
var cust = await _repCustomer.AsQueryable().Filter(null, true).FirstAsync(x => x.CustSysId == tCustId);
if (cust != null)
{
_logger.LogInformation($"找到客户端租户对应客户:{cust.FullName}");
var paraCallApiAuditAuto = await _repCustomerParamValue.AsQueryable().FirstAsync(x => x.CustomerId == cust.Id && x.ParaCode == "BookingCallApiAndAuditAuto");
if (paraCallApiAuditAuto != null && !string.IsNullOrEmpty(paraCallApiAuditAuto.ItemCode))
{
foreach (var ord in ordOkList)
{
if (!paraCallApiAuditAuto.ItemCode.Contains(ord.CARRIERID))
{
continue;
}
//异步执行自动订舱和审核,并带有延时
Task.Run(async () =>
{
Task.Delay(2000);
var succ = false;
try
{
_logger.LogInformation($"自动订舱:{ord}");
await PostApiSO(ord.Id);
succ = true;
}
catch (Exception ex)
{
_logger.LogWarning($"自动订舱失败:{ord},错误信息:{ex.Message}");
await AuditBooking(ord.Id, false, ex.Message);
}
if (succ)
{
_logger.LogInformation($"自动审核:{ord}");
await AuditBooking(ord.Id, true, "系统自动审核");
}
});
}
}
}
else
{
_logger.LogWarning($"未找到客户CustSysId{tCustId}");
}
}
return rtnList;
}
/// <summary>
/// 审核订舱请求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/AuditBooking")]
public async Task AuditBooking(long id, bool accept, string comment)
{
var model = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == id);
if (model == null)
{
throw Oops.Bah("未找到业务信息");
}
if (model.BSSTATUS != "待审核")
{
throw Oops.Bah("当前状态不能审核");
}
if (accept)
{
model.BSSTATUS = "已审核";
}
else
{
model.BSSTATUS = "已驳回";
}
//回推回执
var feedbackData = new BookingCustomerRecAduitFeedbackDto()
{
Id = model.BSNO,
Accept = accept,
Comment = comment
};
var feedbackObj = new BookingFeedbackDto(BookingFeedbackType.Audit.ToString());
feedbackObj.JsonContent = feedbackData.ToJsonString();
_logger.LogInformation($"回推审核数据:{JsonConvert.SerializeObject(feedbackObj)}URL{model.FeedbackUrl}");
var rtn = await model.FeedbackUrl
.SetHeaders(new Dictionary<string, object> {
{ CommonConst.API_USER_HEADER_KEY, model.FeedbackKey},
{ CommonConst.API_USER_HEADER_SECRET, model.FeedbackSecret}
})
.SetBody(feedbackObj, "application/x-www-form-urlencoded")
.PostAsStringAsync();
_logger.LogInformation($"回推审核返回:{rtn}");
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") != 200)
{
throw Oops.Bah(jobjRtn.GetStringValue("message"));
}
await _rep.UpdateAsync(model); //回推成功后,存库
//日志动态
SaveAuditLog($"{(accept ? "" : "")}", id, remark: $"审核意见:{comment}");
//进入订舱台账
if (accept)
{
var custBookId = jobjRtn.GetStringValue("data"); //返回的客户订舱系统的订舱数据id
var bkOrder = model.Adapt<BookingOrder>();
bkOrder.Id = YitIdHelper.NextId();
bkOrder.BSNO = custBookId;
bkOrder.BSSTATUS = "已录入";
bkOrder.CUSTOMERNAME = model.BookingTenantName;
bkOrder.ParentId = 0;
bkOrder.LANENAME = bkOrder.LANECODE;
bkOrder.OPID = UserManager.UserId.ToString();
bkOrder.OP = UserManager.Name;
await _repOrder.InsertAsync(bkOrder);
var bkEdiExt = new BookingEDIExt();
bkEdiExt.Id = YitIdHelper.NextId();
bkEdiExt.BookingId = bkOrder.Id;
bkEdiExt.SalerCode = model.SaleCode;
await _repEdiExt.InsertAsync(bkEdiExt);
model.BookingId = bkOrder.Id; //客户订舱数据与订舱台账数据关联
await _rep.UpdateAsync(model);
var ctnList = await _repCtn.AsQueryable().Filter(null, true).Where(x => x.BILLID == model.Id).ToListAsync();
foreach (var ctn in ctnList)
{
ctn.Id = YitIdHelper.NextId();
ctn.BILLID = bkOrder.Id;
await _repCtn.InsertAsync(ctn);
}
//服务项目
var servList = await _repServiceItem.Where(x => x.BookingId == model.Id).ToListAsync();
foreach (var serv in servList)
{
serv.Id = YitIdHelper.NextId();
serv.BookingId = bkOrder.Id;
await _repServiceItem.InsertAsync(serv);
}
//附件
var files = await _repFile.AsQueryable().Filter(null, true).Where(x => x.BookingId == model.Id && x.IsDeleted == false).ToListAsync();
foreach (var file in files)
{
file.Id = YitIdHelper.NextId();
file.BookingId = bkOrder.Id;
await _repFile.InsertAsync(file);
}
}
//扣费
if (accept)
{
await FeeSo(model.Id);
}
}
/// <summary>
/// 接收客户订舱系统取消提交的数据
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/CancelBooking"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task<List<BookingSubmitResultModel>> CancelBooking(List<BookingCustomerCancelSubmitDto> list)
{
_logger.LogInformation($"收到提交的订舱数据:{JsonConvert.SerializeObject(list)}");
var rtnList = new List<BookingSubmitResultModel>();
foreach (var item in list)
{
var strId = item.Id.ToString();
var order = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.TenantId == UserManager.TENANT_ID && !x.IsDeleted && x.BSNO == strId);
if (order == null)
{
rtnList.Add(new BookingSubmitResultModel()
{
Id = item.Id,
Success = false,
BOOKINGNO = item.BOOKINGNO,
Message = $"未找到订舱数据"
});
}
else
{
if (order.BSSTATUS != "待审核")
{
rtnList.Add(new BookingSubmitResultModel()
{
Id = item.Id,
Success = false,
BOOKINGNO = item.BOOKINGNO,
Message = $"当前状态不能取消"
});
continue;
}
order.IsDeleted = true;
await _rep.UpdateAsync(order);
rtnList.Add(new BookingSubmitResultModel()
{
Id = item.Id,
Success = true,
BOOKINGNO = item.BOOKINGNO,
Message = $"已成功取消"
});
//日志动态
SaveAuditLog($"取消提交", order.Id);
}
}
return rtnList;
}
/// <summary>
/// 接收客户端修改服务项目
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ChangeServiceItem"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task ChangeServiceItem(ChangeServiceItemDto dto)
{
var model = await _rep.AsQueryable().Filter(null, true)
.InnerJoin(_repOrder.AsQueryable().Filter(null, true), (custOrd, ord) => custOrd.BookingId == ord.Id)
.Where((custOrd, ord) => custOrd.BookingTenantName == dto.CompanyName && ord.BSNO == dto.Id)
.Select((custOrd, ord) => new { ord, custOrd })
.FirstAsync();
if (model == null)
{
throw Oops.Bah("未找到业务数据");
}
var serItm = _cache.GetAllDictData().Result.FirstOrDefault(x => x.TypeCode == "booking_service_item" && x.Code == dto.ServiceCode);
var mess = new DjyMessage();
mess.Module = MessageModule.Booking.ToString();
mess.TypeCode = MessageType.ChangeServiceItem.ToString();
mess.TypeName = EnumHelper.GetDescription(typeof(MessageType), mess.TypeCode);
mess.RelativeId = model.ord.Id;
mess.RelativeCode = model.ord.BOOKINGNO;
mess.Content = $"{dto.UserName} {(dto.IsCancel ? "" : "")}了服务项目:{serItm.Value}";
mess.ExtData = new ChangeServiceItemExtModel() { Dto = dto, OrderId = model.ord.Id, CustomerOrderId = model.custOrd.Id }.ToJsonString();
mess.FromName = dto.CompanyName;
mess.ProcStatus = MessageProcessStatus.UnProcess.ToString();
await this._repMessage.InsertAsync(mess);
await _publisher.PublishAsync(new ChannelEventSource("Message:NotifyReceiveNew"));
}
/// <summary>
/// 接收客户端提交的单证补料
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/RecDocSupplement"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task RecDocSupplement(DocSupplementSubmitDto dto)
{
var model = await _rep.AsQueryable().Filter(null, true)
.InnerJoin(_repOrder.AsQueryable().Filter(null, true), (custOrd, ord) => custOrd.BookingId == ord.Id)
.Where((custOrd, ord) => custOrd.BookingTenantName == dto.CompanyName && ord.BSNO == dto.Id)
.Select((custOrd, ord) => new { ord, custOrd })
.FirstAsync();
if (model == null)
{
throw Oops.Bah("未找到业务数据");
}
var mess = new DjyMessage();
mess.Module = MessageModule.Booking.ToString();
mess.TypeCode = MessageType.DocSupplement.ToString();
mess.TypeName = EnumHelper.GetDescription(typeof(MessageType), mess.TypeCode);
mess.RelativeId = model.ord.Id;
mess.RelativeCode = model.ord.BOOKINGNO;
mess.Content = $"{dto.UserName} 增加了 {dto.DocTypeName}";
mess.ExtData = new DocSupplementExtModel() { Dto = dto, OrderId = model.ord.Id, CustomerOrderId = model.custOrd.Id }.ToJsonString();
mess.FromName = dto.CompanyName;
mess.ProcStatus = MessageProcessStatus.UnProcess.ToString();
await this._repMessage.InsertAsync(mess);
await _publisher.PublishAsync(new ChannelEventSource("Message:NotifyReceiveNew"));
}
/// <summary>
/// 扣费
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/DoFee")]
public async Task DoFee(long custOrdId)
{
await FeeSo(custOrdId);
}
#endregion
#region 私有方法
/// <summary>
/// 保存审核的日志动态(使用当前登录人信息)
/// </summary>
private void SaveAuditLog(string status, long bookId, string remark = null)
{
var staLog = new BookingStatusLog();
staLog.Status = status;
staLog.CreatedUserId = UserManager.UserId;
staLog.CreatedUserName = UserManager.Name;
staLog.CreatedTime = DateTime.Now;
staLog.OpTime = DateTime.Now;
staLog.BookingId = bookId;
staLog.Category = StaLogCateAudit;
staLog.Remark = remark;
_repStatuslog.Insert(staLog);
}
/// <summary>
/// 保存审核的日志动态
/// </summary>
private void SaveAuditLog(string status, long bookId, long userId, long tenantId, string userName, string remark = null)
{
var staLog = new BookingStatusLog();
staLog.Status = status;
staLog.CreatedUserId = userId;
staLog.CreatedUserName = userName;
staLog.CreatedTime = DateTime.Now;
staLog.OpTime = DateTime.Now;
staLog.BookingId = bookId;
staLog.Category = StaLogCateAudit;
staLog.TenantId = tenantId;
staLog.Remark = remark;
_repStatuslog.Insert(staLog);
}
/// <summary>
/// 订舱审核后自动扣费
/// </summary>
/// <returns></returns>
private async Task FeeSo(long id)
{
var model = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == id);
var cust = await _repCustomer.AsQueryable().Filter(null, true).FirstAsync(x => x.CustSysId == model.BookingTenantId);
var custParaList = await _repCustomerParamValue.AsQueryable().Filter(null, true).Where(x => x.CustomerId == cust.Id && (x.ParaCode == "DjyFeeApiUserId" || x.ParaCode == "DjyFeeApiUserSecret")).ToListAsync();
var bsType = 32;
var sendType = 0;
var typeStr = $"{bsType}_{sendType}";
var sysCfg = await _cache.GetAllSysConfig();
var feeUrl = sysCfg.FirstOrDefault(x => x.Code == "djyFeeApiUrl");
if (feeUrl == null || string.IsNullOrEmpty(feeUrl.Value))
{
var errMsg = "大简云扣费URL未配置";
_logger.LogError(errMsg);
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: errMsg);
return;
}
//扣费接口用户id和key
var feeUserId = custParaList.FirstOrDefault(x => x.ParaCode == "DjyFeeApiUserId")?.ItemCode;
var feeUserKey = custParaList.FirstOrDefault(x => x.ParaCode == "DjyFeeApiUserSecret")?.ItemCode;
if (string.IsNullOrEmpty(feeUserId) || string.IsNullOrEmpty(feeUserKey))
{
var errMsg = $"未找到{model.BOOKINGNO}({model.Id})所在客户的授权userid和key无法调用扣费";
_logger.LogError(errMsg);
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: "未找到扣费接口授权信息");
return;
}
//判断重复扣费
var c = _repFeeRecord.AsQueryable().Filter(null, true).Count(x => x.TenantId == model.BookingTenantId && x.MBLNO == model.BOOKINGNO);
if (c > 0)
{
_logger.LogInformation($"已存在扣费记录id{model.Id},订舱号:{model.BOOKINGNO},租户:{model.BookingTenantId}");
return;
}
//客户联系人
var contact = await _repCustomerContact.AsQueryable().Filter(null, true).FirstAsync(x => x.CustSysId == model.BookingUserId);
if (contact == null)
{
var errMsg = $"未找到{model.BOOKINGNO}({model.Id})的客户联系人";
_logger.LogError(errMsg);
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: "未找到客户联系人");
return;
}
//扣费dto
var seconds = DateTime.Now.ToTimeStamp();
var runId = Guid.NewGuid().ToString();
var srcBeforMD5 = $"{runId}{feeUserId}expend{bsType}{sendType}{model.Id}{model.BOOKINGNO}{seconds}{feeUserKey}";
var postObj = new
{
runId,
userId = feeUserId,
module = "expend",//固定
bsType = $"{bsType}",
sendType = $"{sendType}",
timestamp = seconds,//秒级时间戳
md5 = srcBeforMD5.ToMd5(),// 加密字符串小写 RunId + UserId + Module + BsType + SendType+Timestamp+ Key
Data = new
{
BSNO = model.Id.ToString(),
MBLNO = model.BOOKINGNO,
CtnrInfo = "",
CtnrCount = 1,
IsCredit = 0,//是否是信用支付 1 信用支付 0不允许信用支付默认值为0,
LURURENID = contact.DjyGid,
SENDUSERID = contact.DjyGid,
VESSEL = model.VESSEL,
VOYNO = model.VOYNO,
ETD = model.ETD,
CARRIER = model.CARRIER
}
};
_logger.LogInformation($"调用扣费:{postObj.ToJsonString()}");
var apiRtn = await feeUrl.Value
.SetHttpMethod(HttpMethod.Post)
.SetBody(postObj)
.SetRetryPolicy(3, 5000)
.OnException((c, m, errMsg) =>
{
_logger.LogError($"扣费失败:{errMsg}");
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: errMsg);
})
.SendAsStringAsync();
_logger.LogInformation($"调用扣费返回:{apiRtn}");
var jobjApiRtn = JObject.Parse(apiRtn);
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 fr = new BookingFeeRecord();
fr.Id = YitIdHelper.NextId();
fr.BillId = model.Id;
fr.MBLNO = model.BOOKINGNO;
fr.TenantId = model.BookingTenantId;
fr.Type = typeStr;
fr.Amount = total;
await _repFeeRecord.InsertAsync(fr);
SaveAuditLog($"扣费成功", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: "");
}
else
{
var errMsg = jobjApiRtn.GetValue("message").ToString();
_logger.LogError($"扣费失败:{errMsg}");
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: errMsg);
}
}
#endregion
#region 外部开放接口
/// <summary>
/// 接收外部调用生成客户订舱需求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ReceiveCustomerOrder"), AllowAnonymous, ApiUser]
public async Task ReceiveCustomerOrder([FromForm] BookingCustomerApiSaveInput input, IFormFile[] files)
{
var carrList = await _cache.GetAllCodeCarrier();
var portLoadList = await _cache.GetAllCodePortLoad();
var portDestList = await _cache.GetAllCodePort();
var serviceList = await _cache.GetAllCodeService();
var frtList = await _cache.GetAllCodeFrt();
var ctnList = await _cache.GetAllCodeCtn();
#region 校验
/*
1.必填字段船公司开船日期起运港目的港箱型箱量服务项目运输条款付费方式件数毛重包装货物标识品名HSCODE。
2.条件字段1若货物标识为冻柜温度通风湿度必填。
3.条件字段2若货物标识为危险品危险品编号危险品等级联系人电话HSCODE必填。
*/
/*
必填字段:去掉 件数、包装、HSCODE增加合约号订舱账号订舱密码
*/
if (string.IsNullOrEmpty(input.BSNO))
{
throw Oops.Bah("未提供业务ID");
}
if (string.IsNullOrEmpty(input.CONTRACTNO))
{
throw Oops.Bah("合约号不能为空");
}
//if (string.IsNullOrEmpty(input.BOOKINGACCOUNT))
//{
// throw Oops.Bah("订舱账号不能为空");
//}
//if (string.IsNullOrEmpty(input.BOOKINGPASSWORD))
//{
// throw Oops.Bah("订舱密码不能为空");
//}
//2024-4-2为保证后面自动化订舱需要船司、港口、箱型等信息改为传公共库中的唯一代码
if (string.IsNullOrEmpty(input.CARRIERID))
{
throw Oops.Bah("船司代码不能为空");
}
var carr = carrList.FirstOrDefault(x => x.Code == input.CARRIERID);
if (carr == null)
{
throw Oops.Bah($"未找到匹配的船司代码:{input.CARRIERID}");
}
// 2024-4-9中远约号最长8位
if (input.CARRIERID == "COSCO" && input.CONTRACTNO.Length > 8)
{
throw Oops.Bah($"约号超长【中远】约号最长8位请检查");
}
if (!input.ETD.HasValue)
{
throw Oops.Bah("开船日期不能为空");
}
//2024-4-2为保证后面自动化订舱需要船司、港口、箱型等信息改为传公共库中的唯一代码名称和五字码根据唯一代码匹配写入无需传递
//if (string.IsNullOrEmpty(input.PORTLOADID) || string.IsNullOrEmpty(input.PORTLOAD))
//{
// throw Oops.Bah("起运港代码和名称不能为空");
//}
//if (string.IsNullOrEmpty(input.PORTDISCHARGEID) || string.IsNullOrEmpty(input.PORTDISCHARGE))
//{
// throw Oops.Bah("目的港代码和名称不能为空");
//}
//起运港校验
if (string.IsNullOrEmpty(input.PORTLOADCODE))
{
throw Oops.Bah("起运港代码不能为空");
}
var portLoad = portLoadList.FirstOrDefault(x => x.Code == input.PORTLOADCODE);
if (portLoad == null)
{
throw Oops.Bah($"未找到匹配的起运港:{input.PORTLOADCODE}");
}
//目的港校验
if (string.IsNullOrEmpty(input.PORTDISCHARGECODE))
{
throw Oops.Bah("目的港代码不能为空");
}
var portDest = portDestList.FirstOrDefault(x => x.Code == input.PORTDISCHARGECODE);
if (portDest == null)
{
throw Oops.Bah($"未找到匹配的目的港:{input.PORTDISCHARGECODE}");
}
////收货地校验
//if (string.IsNullOrEmpty(input.PLACERECEIPTCODE))
//{
// throw Oops.Bah("收货地代码不能为空");
//}
var placereceipt = portLoadList.FirstOrDefault(x => x.Code == input.PLACERECEIPTCODE);
//if (placereceipt == null)
//{
// throw Oops.Bah($"未找到匹配的收货地:{input.PLACERECEIPTCODE}");
//}
//目的地校验
if (string.IsNullOrEmpty(input.DESTINATIONCODE))
{
throw Oops.Bah("目的地代码不能为空");
}
var destination = portDestList.FirstOrDefault(x => x.Code == input.DESTINATIONCODE);
if (destination == null)
{
throw Oops.Bah($"未找到匹配的目的地:{input.DESTINATIONCODE}");
}
if (string.IsNullOrEmpty(input.SERVICECODE))
{
throw Oops.Bah("运输条款代码不能为空");
}
var service = serviceList.FirstOrDefault(x => x.Code == input.SERVICECODE);
if (service == null)
{
throw Oops.Bah($"未找到匹配的运输条款:{input.SERVICECODE}");
}
if (string.IsNullOrEmpty(input.FRTCODE))
{
throw Oops.Bah("付费方式代码不能为空");
}
var frt = frtList.FirstOrDefault(x => x.Code == input.FRTCODE);
if (frt == null)
{
throw Oops.Bah($"未找到匹配的付费方式:{input.FRTCODE}");
}
if (!input.KGS.HasValue)
{
throw Oops.Bah("重量不能为空");
}
if (string.IsNullOrEmpty(input.CARGOID))
{
throw Oops.Bah("货物标识不能为空");
}
if (input.CARGOID == "R")
{
if (string.IsNullOrEmpty(input.TEMPSET))
{
throw Oops.Bah("货物标识为冻柜的情况下,温度不能为空");
}
if (string.IsNullOrEmpty(input.REEFERF))
{
throw Oops.Bah("货物标识为冻柜的情况下,通风度不能为空");
}
if (string.IsNullOrEmpty(input.HUMIDITY))
{
throw Oops.Bah("货物标识为冻柜的情况下,湿度不能为空");
}
}
else if (input.CARGOID == "D")
{
if (string.IsNullOrEmpty(input.DUNNO))
{
throw Oops.Bah("货物标识为危险品的情况下,危险品编号不能为空");
}
if (string.IsNullOrEmpty(input.DCLASS))
{
throw Oops.Bah("货物标识为危险品的情况下,危险品等级不能为空");
}
if (string.IsNullOrEmpty(input.LINKMAN))
{
throw Oops.Bah("货物标识为危险品的情况下,危险品联系人不能为空");
}
if (string.IsNullOrEmpty(input.DTEL))
{
throw Oops.Bah("货物标识为危险品的情况下,危险品联系电话不能为空");
}
}
if (string.IsNullOrEmpty(input.DESCRIPTION))
{
throw Oops.Bah("品名不能为空");
}
if (input.CtnList == null || input.CtnList.Count == 0)
{
throw Oops.Bah("箱信息不能为空");
}
var notExistCode = input.CtnList.Where(x => ctnList.Count(y => y.Code == x.CTNCODE) == 0).Select(x => x.CTNCODE).ToList();
if (notExistCode.Any())
{
throw Oops.Bah($"未找到箱型:{string.Join(",", notExistCode)}");
}
if (input.ServiceItemList == null || input.ServiceItemList.Count == 0)
{
throw Oops.Bah("服务项目不能为空");
}
if (input.CARRIERID == "EMC" && string.IsNullOrEmpty(input.ShipInfoJson))
{
throw Oops.Bah($"长荣订舱需提供船期数据");
}
#endregion
var custOrder = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.TenantId == UserManager.TENANT_ID && x.BSNO == input.BSNO);
var ins = false;
if (custOrder != null)
{
if (custOrder.BSSTATUS == "已审核")
{
throw Oops.Bah("已审核的数据不能修改");
}
if (custOrder.BSSTATUS == "已提交")
{
await CancelSubmit(new List<long>() { custOrder.Id });
custOrder = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == custOrder.Id); //取消后重新拉取一遍数据
}
input.Id = custOrder.Id;
input.Adapt(custOrder);
}
else
{
custOrder = input.Adapt<BookingCustomerOrder>();
ins = true;
}
//订舱船期数据
JObject jobjExt = new JObject();
if (!string.IsNullOrEmpty(custOrder.ExtendData))
{
jobjExt = JObject.Parse(custOrder.ExtendData);
}
if (custOrder.CARRIERID == "EMC")
{
jobjExt["shipInfo"] = JObject.Parse(input.ShipInfoJson);
}
custOrder.ExtendData = jobjExt.ToString();
//赋值根据唯一代码匹配后的代码、名称等信息
custOrder.CARRIER = carr.EnName;
custOrder.PORTLOAD = portLoad.EnName;
custOrder.PORTLOADID = portLoad.EdiCode;
custOrder.PORTDISCHARGE = portDest.EnName;
custOrder.PORTDISCHARGEID = portDest.EdiCode;
custOrder.SERVICE = service.Name;
custOrder.PLACERECEIPT = placereceipt?.EnName;
custOrder.PLACERECEIPTID = placereceipt?.EdiCode;
custOrder.DESTINATION = destination.EnName;
custOrder.DESTINATIONID = destination.EdiCode;
custOrder.BLFRT = frt.EnName;
//2024年4月19日将分拆的收发通拼接到大文本的收发通中
ContactSFT(custOrder);
var ctns = input.CtnList.Adapt<List<BookingCtn>>();
foreach (var ctn in ctns)
{
ctn.CTNALL = ctnList.First(x => x.Code == ctn.CTNCODE).Name;
}
var servList = input.ServiceItemList.Adapt<List<BookingServiceItem>>();
await SaveData(custOrder, ctns, servList, ins);
#region 处理附件
var dbFiles = _repFile.AsQueryable().Where(x => x.BookingId == custOrder.Id).ToList();
var opt = App.GetOptions<BookingAttachOptions>();
var dirAbs = string.Empty;
if (string.IsNullOrEmpty(opt.basePath))
{
dirAbs = Path.Combine(App.WebHostEnvironment.WebRootPath, opt.relativePath);
}
else
{
dirAbs = Path.Combine(opt.basePath, opt.relativePath);
}
if (!Directory.Exists(dirAbs))
Directory.CreateDirectory(dirAbs);
foreach (var upFile in files)
{
var extName = Path.GetExtension(upFile.FileName);
if (opt.fileType.Contains(extName.ToLower()))
{
throw Oops.Bah($"不允许的文件类型:{extName}");
}
var dbFile = dbFiles.FirstOrDefault(x => x.BookingId == custOrder.Id && x.FileName == upFile.FileName);
if (dbFile == null)
{
var saveFileName = $"{DateTime.Now.Ticks}{extName}";
var fileRelaPath = Path.Combine(opt.relativePath, saveFileName).ToLower();
var fileAbsPath = Path.Combine(dirAbs, saveFileName).ToLower();
using (var stream = File.Create(fileAbsPath))
{
await upFile.CopyToAsync(stream);
}
var newFile = new BookingFile
{
Id = YitIdHelper.NextId(),
FileName = Path.GetFileName(upFile.FileName),
FilePath = fileRelaPath,
TypeCode = "tuodan",
TypeName = "托单文件",
BookingId = custOrder.Id,
};
await _repFile.InsertAsync(newFile);
}
else
{
var fileFullPath = Path.Combine(dirAbs, dbFile.FilePath);
using (var stream = File.Create(fileFullPath))
{
await upFile.CopyToAsync(stream);
}
await _repFile.UpdateAsync(dbFile);
}
}
#endregion
await Submit(new List<long> { custOrder.Id });
}
/// <summary>
/// 拼接收发通
/// </summary>
/// <param name="custOrder"></param>
private void ContactSFT(BookingCustomerOrder custOrder)
{
if (string.IsNullOrEmpty(custOrder.SHIPPER) && !string.IsNullOrEmpty(custOrder.ShipperName))
{
custOrder.SHIPPER = @$"{custOrder.ShipperName}
{custOrder.ShipperAddress}
{custOrder.ShipperCountry} {custOrder.ShipperProvince} {custOrder.ShipperCity} {custOrder.ShipperCounty} {custOrder.ShipperPostCode}
{custOrder.ShipperLastName} {custOrder.ShipperFirstName} {custOrder.ShipperPhoneCountryCode} {custOrder.ShipperPhoneCode} {custOrder.ShipperPhone}".ToUpper();
}
if (string.IsNullOrEmpty(custOrder.CONSIGNEE) && !string.IsNullOrEmpty(custOrder.ConsigneeName))
{
custOrder.CONSIGNEE = @$"{custOrder.ConsigneeName}
{custOrder.ConsigneeAddress}
{custOrder.ConsigneeCountry} {custOrder.ConsigneeProvince} {custOrder.ConsigneeCity} {custOrder.ConsigneeCounty} {custOrder.ConsigneePostCode}
{custOrder.ConsigneeLastName} {custOrder.ConsigneeFirstName} {custOrder.ConsigneePhoneCountryCode} {custOrder.ConsigneePhoneCode} {custOrder.ConsigneePhone}".ToUpper();
}
if (string.IsNullOrEmpty(custOrder.NOTIFYPARTY) && !string.IsNullOrEmpty(custOrder.NotifypartName))
{
custOrder.NOTIFYPARTY = @$"{custOrder.NotifypartName}
{custOrder.NotifypartAddress}
{custOrder.NotifypartCountry} {custOrder.NotifypartProvince} {custOrder.NotifypartCity} {custOrder.NotifypartCounty} {custOrder.NotifypartPostCode}
{custOrder.NotifypartLastName} {custOrder.NotifypartFirstName} {custOrder.NotifypartPhoneCountryCode} {custOrder.NotifypartPhoneCode} {custOrder.NotifypartPhone}".ToUpper();
}
}
#endregion
#region 发送订舱
/// <summary>
/// 发送Api订舱
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/PostApiSO")]
public async Task PostApiSO(long id)
{
var order = await _rep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == id);
KeyValuePair<bool, string> rtn = new KeyValuePair<bool, string>(false, "不支持的船司");
if (order.CARRIERID == "COSCO")
{
rtn = await ZhongYuanSoApiHelper.DoPost(id);
}
else if (order.CARRIERID == "EMC")
{
rtn = await EMCSoApiHelper.DoPost(id);
}
if (!rtn.Key)
{
SaveAuditLog("发送订舱", id, remark: rtn.Value);
throw Oops.Bah(rtn.Value);
}
SaveAuditLog("发送订舱", id, remark: rtn.Value);
}
#endregion
}
}