using Furion;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.Entity;
using Myshipping.Application.Enum;
using Myshipping.Application.Service.TaskManagePlat;
using Myshipping.Core;
using Myshipping.Core.Entity;
using Myshipping.Core.Service;
using MySqlX.XDevAPI.Common;
using NPOI.XWPF.UserModel;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Myshipping.Application
{
///
/// 预甩货通知
///
[ApiDescriptionSettings("Application", Name = "TaskManageRollingNomination", Order = 10)]
public class TaskManageRollingNominationService : ITaskManageRollingNominationService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger _logger;
private readonly SqlSugarRepository _taskBaseRepository;
private readonly SqlSugarRepository _taskRollingNominationInfoRepository;
private readonly SqlSugarRepository _taskRollingNominationShipInfoRepository;
private readonly SqlSugarRepository _taskRollingNominationDetailInfoRepository;
private readonly SqlSugarRepository _taskRollingNominationDispatchInfoRepository;
private readonly SqlSugarRepository _taskShareLinkInfoRepository;
private readonly SqlSugarRepository _bookingOrderRepository;
private readonly SqlSugarRepository _bookingCtnRepository;
private readonly SqlSugarRepository _repPrintTemplate;
private readonly SqlSugarRepository _sysUserRepository;
private readonly INamedServiceProvider _namedServiceProvider;
public TaskManageRollingNominationService(SqlSugarRepository taskBaseRepository,
SqlSugarRepository taskRollingNominationInfoRepository,
SqlSugarRepository taskRollingNominationDetailInfoRepository,
SqlSugarRepository taskRollingNominationDispatchInfoRepository,
SqlSugarRepository taskRollingNominationShipInfoRepository,
SqlSugarRepository taskShareLinkInfoRepository,
SqlSugarRepository bookingOrderRepository,
SqlSugarRepository repPrintTemplate,
SqlSugarRepository sysUserRepository,
INamedServiceProvider namedServiceProvider,
SqlSugarRepository bookingCtnRepository, ISysCacheService cache, ILogger logger)
{
_taskBaseRepository = taskBaseRepository;
_taskRollingNominationInfoRepository = taskRollingNominationInfoRepository;
_taskRollingNominationDetailInfoRepository = taskRollingNominationDetailInfoRepository;
_taskRollingNominationDispatchInfoRepository = taskRollingNominationDispatchInfoRepository;
_taskRollingNominationShipInfoRepository = taskRollingNominationShipInfoRepository;
_taskShareLinkInfoRepository = taskShareLinkInfoRepository;
_bookingOrderRepository = bookingOrderRepository;
_bookingCtnRepository = bookingCtnRepository;
_repPrintTemplate = repPrintTemplate;
_sysUserRepository = sysUserRepository;
_namedServiceProvider = namedServiceProvider;
_cache = cache;
_logger = logger;
}
#region 获取预甩详情
///
/// 获取预甩详情
///
/// 预甩主键
/// 返回回执
[HttpGet("/TaskManageRollingNomination/GetInfo")]
public async Task GetInfo(string pkId)
{
TaskRollingNominationShowDto model = null;
try
{
var rollModel = _taskRollingNominationInfoRepository.AsQueryable()
.First(a => a.PK_ID == pkId && !a.IsDeleted);
if (rollModel == null)
throw Oops.Oh($"预甩货主键{pkId}无法获取业务信息");
model = await InnerGetInfo(rollModel);
}
catch (Exception ex)
{
_logger.LogError($"获取预甩详情异常,原因:{ex.Message}");
throw ex;
}
return model;
}
#endregion
#region 通过任务主键获取预甩详情
///
/// 通过任务主键获取预甩详情
///
/// 预甩任务主键
/// 返回回执
[HttpGet("/TaskManageRollingNomination/GetInfoByTaskId")]
public async Task GetInfoByTaskId(string taskPkId)
{
TaskRollingNominationShowDto model = null;
try
{
var taskBase = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskPkId && !a.IsDeleted);
if (taskBase == null)
throw Oops.Oh($"预甩货任务主键{taskPkId}无法获取任务信息");
var rollModel = _taskRollingNominationInfoRepository.AsQueryable()
.First(a => a.TASK_ID == taskBase.PK_ID && !a.IsDeleted);
if (rollModel == null)
throw Oops.Oh($"预甩货任务主键{taskBase.PK_ID}无法获取业务信息");
model = await InnerGetInfo(rollModel);
}
catch(Exception ex)
{
_logger.LogError($"获取预甩详情异常,原因:{ex.Message}");
throw ex;
}
return model;
}
#endregion
#region 获取预甩详情
///
/// 获取预甩详情
///
/// 预甩货详情实体类
/// 返回详情
private async Task InnerGetInfo(TaskRollingNominationInfo rollModel)
{
TaskRollingNominationShowDto model = null;
try
{
List rollingPlanList = new List();
if (!string.IsNullOrWhiteSpace(rollModel.PLAN_TXT))
{
rollingPlanList = rollModel.PLAN_TXT.Split("\\n").ToList();
}
model = new TaskRollingNominationShowDto
{
PlanType = rollModel.PLAN_TYPE,
CarrierId = rollModel.CARRIERID,
Carrier = rollModel.CARRIER,
ConfirmDeadLine = rollModel.CONFIRM_DEAD_LINE,
CreateTime = rollModel.READ_CREATE_TIME,
RollingTouchDoubleRollRemark = rollModel.ROLL_DOUBLE_REMARK,
LoadDetailList = new List(),
RollingPlanList = rollingPlanList,
PreBillList = new List(),
NominationId = rollModel.PK_ID
};
var shipList = _taskRollingNominationShipInfoRepository.AsQueryable()
.Where(a => a.NOM_ID == rollModel.PK_ID && a.IsDeleted == false).ToList();
var fromEntity = shipList.Where(a =>
a.SHIP_TYPE.Equals("From", StringComparison.OrdinalIgnoreCase)).ToList();
if (fromEntity.Count > 0)
model.From = fromEntity.Select(p=>p.Adapt()).ToList();
var toEntity = shipList.Where(a => Regex.IsMatch(a.SHIP_TYPE,"To(\\s+[0-9]+)?"
, RegexOptions.IgnoreCase)).ToList();
if (toEntity.Count > 0)
model.To = toEntity.Select(p => p.Adapt()).ToList();
//优先PORT关联FROM和TO,也有PORT为空的情况,这种就需要用Terminal来关联
if (model.From.Any(t => string.IsNullOrWhiteSpace(t.Port)))
{
//这里为了前端原船和换船做了根据Terminal对应
model.FromToList = model.From.GroupJoin(model.To, l => l.Terminal?.Trim(), r => r.Terminal?.Trim(), (l, r) =>
{
TaskRollingNominationShipFromToDto dto = new TaskRollingNominationShipFromToDto();
dto.FromShip = l;
var currArg = r.ToList();
if (currArg.Count > 0)
{
dto.ToShipList = currArg.Select((p, idx) =>
{
if (Regex.IsMatch(p.ShipType, "[0-9]+"))
return new { SortNo = int.Parse(Regex.Match(p.ShipType, "[0-9]+").Value), Obj = p };
return new { SortNo = idx + 1, Obj = p };
}).OrderBy(p => p.SortNo).Select(p => p.Obj).ToList();
}
return dto;
}).ToList();
}
else
{
//这里为了前端原船和换船做了根据PORT对应
model.FromToList = model.From.GroupJoin(model.To, l => l.Port?.Trim(), r => r.Port?.Trim(), (l, r) =>
{
TaskRollingNominationShipFromToDto dto = new TaskRollingNominationShipFromToDto();
dto.FromShip = l;
var currArg = r.ToList();
if (currArg.Count > 0)
{
dto.ToShipList = currArg.Select((p, idx) =>
{
if (Regex.IsMatch(p.ShipType, "[0-9]+"))
return new { SortNo = int.Parse(Regex.Match(p.ShipType, "[0-9]+").Value), Obj = p };
return new { SortNo = idx + 1, Obj = p };
}).OrderBy(p => p.SortNo).Select(p => p.Obj).ToList();
}
return dto;
}).ToList();
}
List> tuples = new List>();
var withDispatchList = _taskRollingNominationDetailInfoRepository.AsQueryable().Filter(null, true)
.LeftJoin((detail, dispatch) => detail.PK_ID == dispatch.DETAIL_ID)
.Where((detail, dispatch) => detail.NOM_ID == rollModel.PK_ID && detail.IsDeleted == false
&& (string.IsNullOrWhiteSpace(dispatch.PK_ID) || (!string.IsNullOrWhiteSpace(dispatch.PK_ID) && dispatch.IsDeleted == false)))
.Select((detail, dispatch) => new { Detail = detail, Dispatch = dispatch }).ToList();
if (withDispatchList.Count > 0)
{
model.PreBillList = withDispatchList.Where(a => !a.Detail.NOM_STATUS_NOTE.Equals("Load",StringComparison.OrdinalIgnoreCase))
.Select((a, idx) => {
TaskRollingNominationShipPreBillShowDto preBillInfo = new TaskRollingNominationShipPreBillShowDto
{
Bookedby = a.Detail.BOOKED_BY,
ConfirmDate = a.Dispatch?.CONFIRM_DATE,
ConfirmDeadLine = a.Dispatch?.CONFIRM_DEAD_LINE,
CtnStat = $"{a.Detail.CTNALL}*{a.Detail.CTNNUM}",
CustomerId = a.Detail.CUSTOMERID,
CustomerName = a.Detail.CUSTOMERNAME,
ContractualName = a.Detail.CONTRACTUAL_NAME,
CreateShareLinkDate = a.Dispatch?.CREATE_SHARE_LINK_DATE,
DischargePortName = a.Detail.DISCHARGEPORT_NAME,
IsSend = a.Dispatch != null ? a.Dispatch.IS_SEND : false,
IsUserManual = a.Dispatch != null ? a.Dispatch.IS_USER_MANUAL : false,
LoadPortName = a.Detail.LOADPORT_NAME,
PlaceOfDelivery = a.Detail.PLACEOF_DELIVERY,
PlaceOfReceipt = a.Detail.PLACEOF_RECEIPT,
Shipment = a.Detail.SHIPMENT,
Status = a.Dispatch?.STATUS,
ShareLinkKey = a.Dispatch?.SHARE_LINK_KEY,
UserOpinion = a.Dispatch?.USER_OPINION,
UserOpinionTxt = a.Dispatch?.USER_OPINION_TXT,
BatchId = a.Dispatch?.BATCH_ID,
BookingId = a.Detail.BOOKING_ID,
GroupName = a.Detail.CUSTOMERID.HasValue ? $"CUST_{idx + 1}" : "",
CtnNote = !string.IsNullOrWhiteSpace(a.Detail.CTNNOTE) ? a.Detail.CTNNOTE : ""
};
return preBillInfo;
}).ToList();
tuples = withDispatchList.Where(a => !a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase))
.GroupBy(t => t.Detail.CTNALL)
.Select(t => new
{
Key = t.Key,
Num = t.ToList().Sum(x => x.Detail.CTNNUM)
}).Select(x => new Tuple(x.Key, x.Num)).ToList();
}
if (withDispatchList.Any(a =>
a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase)))
{
model.LoadDetailList.AddRange(withDispatchList.Where(a =>
a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase))
.Select((a, idx) =>
{
return a.Detail.Adapt();
}).ToList());
}
model.TotalPreBillCtnStat = string.Join(",", tuples.GroupBy(x => x.Item1)
.Select(x =>
$"{x.Key}*{x.Sum(t => t.Item2)}").ToArray());
if (model.LoadDetailList.Count > 0)
{
model.TotalLoadCtnStat = string.Join(",", model.LoadDetailList.GroupBy(x => x.CtnAll)
.Select(x =>
$"{x.Key}*{x.Sum(t => t.CtnNum)}").ToArray());
}
}
catch (Exception ex)
{
_logger.LogError($"获取预甩详情异常,原因:{ex.Message}");
throw ex;
}
return model;
}
#endregion
#region 推送预甩货客户访问链接
///
/// 推送预甩货客户访问链接
///
/// 预甩货任务主键组
/// 返回回执
[HttpPost("/TaskManageRollingNomination/PushShareLink")]
public async Task PushShareLink([FromBody] string[] nominationDispatchId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"推送预甩货客户访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 生成预甩货调度
///
/// 生成预甩货调度
///
/// 生成预甩货调度请求
/// 返回回执
[HttpPost("/TaskManageRollingNomination/DispatchRollingNomination")]
public async Task DispatchRollingNomination([FromBody] RollingNominationDispatchRequestDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
/*
1、如果调度ID不为空,标识选择新的明细替换原有的调度。
(1)首先匹配所选的箱型箱量是否一致,装货港、卸货港必需一致,不满足不能进行生成调度。
(2)删除原调度,生成新调度。
2、如果调度ID为空,标识是新增调度。
3、没有订舱ID或委托单位ID的数据不能生成调度。
*/
DateTime nowDate = DateTime.Now;
if (!model.isAdd)
{
if(string.IsNullOrWhiteSpace(model.nominationBatchId))
{
throw Oops.Oh($"改配调度需要提供预甩货调度批次ID");
}
if (model.loadDetailIds == null || model.loadDetailIds.Length == 0)
{
throw Oops.Oh($"预甩货可Load明细信息不能为空");
}
var detailList = _taskRollingNominationDetailInfoRepository.AsQueryable()
.Where(a => model.loadDetailIds.Contains(a.PK_ID) && a.IsDeleted == false).ToList();
if (detailList.Count != model.loadDetailIds.Length)
{
throw Oops.Oh($"预甩货明细部分获取失败,请重新获取预甩货明细");
}
if (detailList.Any(a => !a.BOOKING_ID.HasValue || !a.CUSTOMERID.HasValue))
{
throw Oops.Oh($"预甩货明细存在未对应订舱的记录,不能生成调度");
}
var nomId = detailList.FirstOrDefault().NOM_ID;
var nomModel = _taskRollingNominationInfoRepository.AsQueryable()
.First(a => a.PK_ID == nomId);
var shipmentList = detailList.Select(a => a.SHIPMENT).Distinct().ToList();
Dictionary batchDict = shipmentList.Select(a => new { Key = a, BatchId = IDGen.NextID().ToString() })
.ToDictionary(a => a.Key, b => b.BatchId);
List dispatchList = new List();
List withDispatchDetailList = new List();
var withDispatchList = _taskRollingNominationDetailInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((detail, dispatch) => detail.PK_ID == dispatch.DETAIL_ID)
.Where((detail, dispatch) => detail.PK_ID == dispatch.DETAIL_ID && detail.IsDeleted == false
&& dispatch.IsDeleted == false && dispatch.BATCH_ID == model.nominationBatchId)
.Select((detail, dispatch) => new { Detail = detail, Dispatch = dispatch }).ToList();
if (withDispatchList.Count > 0)
{
withDispatchDetailList = withDispatchList.Select(a => a.Detail)
.ToList();
}
if (dispatchList.Count == 0)
{
throw Oops.Oh($"预甩货调度获取失败,无法改配");
}
//如果原调度对应的明细含有本次提交的明细,不允许改配调度
if (withDispatchDetailList.Any(a =>
model.loadDetailIds.Any(b => b == a.PK_ID)))
{
throw Oops.Oh($"预甩货调度获取失败,提交明细已生成调度,无法改配");
}
//需要匹配箱型箱量
var origCtnStat = string.Join(",", withDispatchDetailList
.GroupBy(a => a.CTNALL).OrderBy(a => a.Key)
.Select(a => $"{a.Key}*{a.Sum(b => b.CTNNUM)}").ToArray());
detailList = _taskRollingNominationDetailInfoRepository.AsQueryable()
.Where(a => shipmentList.Contains(a.SHIPMENT) && a.IsDeleted == false && a.NOM_ID == nomId).ToList();
var targetCtnStat = string.Join(",", detailList
.GroupBy(a => a.CTNALL).OrderBy(a => a.Key)
.Select(a => $"{a.Key}*{a.Sum(b => b.CTNNUM)}").ToArray());
//如果箱型箱量不一致不能改配
if (!origCtnStat.Equals(targetCtnStat))
{
throw Oops.Oh($"预甩货调度获取失败,提交明细箱型箱量于被改配调度不一致,无法改配");
}
var origShip = withDispatchDetailList.FirstOrDefault();
var targetShip = detailList.FirstOrDefault();
var origKey = $"{origShip.PLACEOF_RECEIPT}_{origShip.LOADPORT_NAME}_{origShip.DISCHARGEPORT_NAME}_{origShip.PLACEOF_DELIVERY}";
var targeKey = $"{targetShip.PLACEOF_RECEIPT}_{targetShip.LOADPORT_NAME}_{targetShip.DISCHARGEPORT_NAME}_{targetShip.PLACEOF_DELIVERY}";
//收货地、装货港、卸货港、交货地必需一致
if (!origKey.Equals(targeKey))
{
throw Oops.Oh($"预甩货调度获取失败,提交明细收货地、装货港、卸货港、交货地被改配调度不一致,无法改配");
}
//删除原调度
withDispatchList.ForEach(async a =>
{
a.Dispatch.IsDeleted = true;
a.Dispatch.UpdatedTime = nowDate;
a.Dispatch.UpdatedUserId = UserManager.UserId;
a.Dispatch.UpdatedUserName = UserManager.Name;
await _taskRollingNominationDispatchInfoRepository.AsUpdateable(a.Dispatch)
.UpdateColumns(it => new
{
it.IsDeleted,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
});
//写入新调度
detailList.ForEach(a =>
{
TaskRollingNominationDispatchInfo dispatchInfo = new TaskRollingNominationDispatchInfo
{
PK_ID = IDGen.NextID().ToString(),
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name,
DETAIL_ID = a.PK_ID,
NOM_ID = a.NOM_ID,
NOM_SHIP_ID = a.NOM_SHIP_ID,
IsDeleted = false,
STATUS = "WAIT",
TASK_ID = nomModel.TASK_ID,
TenantId = UserManager.TENANT_ID,
TenantName = UserManager.TENANT_NAME,
BATCH_ID = batchDict[a.SHIPMENT],
};
_taskRollingNominationDispatchInfoRepository.Insert(dispatchInfo);
});
}
else
{
var withDispatchList =
_taskRollingNominationInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((nom, detail) => nom.PK_ID == detail.NOM_ID)
.LeftJoin((nom, detail, dispatch) =>
detail.PK_ID == dispatch.DETAIL_ID && dispatch.IsDeleted == false)
.Where((nom, detail, dispatch) =>
detail.IsDeleted == false
&& detail.NOM_ID == model.nominationId)
.Select((nom, detail, dispatch) =>
new { Nom = nom, Detail = detail, Dispatch = dispatch }).ToList();
if (withDispatchList.Any(p => p.Dispatch != null
&& !string.IsNullOrWhiteSpace(p.Dispatch.PK_ID)))
{
throw Oops.Oh($"预甩货明细已生成调度不能重复");
}
var nomiInfo = withDispatchList.FirstOrDefault().Nom;
var shipmentList = withDispatchList
.Select(a => a.Detail.SHIPMENT)
.Distinct().ToList();
Dictionary batchDict = shipmentList.Select(a => new { Key = a, BatchId = IDGen.NextID().ToString() })
.ToDictionary(a => a.Key, b => b.BatchId);
DateTime deadLine = nomiInfo.CONFIRM_DEAD_LINE.Value.AddHours(2);
//开始写入调度
withDispatchList.ForEach(info =>
{
var a = info.Detail;
if (!a.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase))
{
TaskRollingNominationDispatchInfo dispatchInfo = new TaskRollingNominationDispatchInfo
{
PK_ID = IDGen.NextID().ToString(),
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name,
DETAIL_ID = a.PK_ID,
NOM_ID = a.NOM_ID,
NOM_SHIP_ID = a.NOM_SHIP_ID,
IsDeleted = false,
STATUS = RollingNominationDispatchStatusEnum.WAIT.ToString(),
TASK_ID = nomiInfo.TASK_ID,
TenantId = UserManager.TENANT_ID,
TenantName = UserManager.TENANT_NAME,
BATCH_ID = batchDict[a.SHIPMENT],
CONFIRM_DEAD_LINE = deadLine
};
_taskRollingNominationDispatchInfoRepository.Insert(dispatchInfo);
}
});
}
result.succ = true;
result.msg = "成功";
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"生成预甩货调度异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 刷新预甩货对应订舱
///
/// 刷新预甩货对应订舱
///
/// 预甩货主键
/// 返回回执
[HttpGet("/TaskManageRollingNomination/RefreshBookingOrder")]
public async Task RefreshBookingOrder(string nominationId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
/*
获取所有当票预甩的所有没有BOOKING_ID的明细记录,并用SHIPMENT(提单号),检索订舱数据,能匹配的更新
*/
var list = _taskRollingNominationInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((nom, detail) => nom.PK_ID == detail.NOM_ID)
.Where((nom, detail) => nom.PK_ID == nominationId
&& detail.IsDeleted == false && !detail.BOOKING_ID.HasValue)
.Select((nom, detail) => detail).ToList();
if (list.Count > 0)
{
var mblNoArg = list.Select(a=>a.SHIPMENT).Distinct().ToList();
var orderList = _bookingOrderRepository.AsQueryable()
.Where(a => mblNoArg.Contains(a.MBLNO) && !a.ParentId.HasValue && a.IsDeleted == false).ToList();
DateTime nowDate = DateTime.Now;
if (orderList.Count > 0)
{
orderList.ForEach(ord =>
{
var dlist = list.Where(b => b.SHIPMENT.Equals(ord.MBLNO)).ToList();
if (dlist.Count > 0)
{
dlist.ForEach(dt =>
{
dt.BOOKING_ID = ord.Id;
dt.UpdatedTime = nowDate;
dt.UpdatedUserId = UserManager.UserId;
dt.UpdatedUserName = UserManager.Name;
_taskRollingNominationDetailInfoRepository.AsUpdateable(dt)
.UpdateColumns(it => new
{
it.BOOKING_ID,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommand();
});
}
});
}
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"刷新预甩货对应订舱异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 查看分享链接
///
/// 查看分享链接
///
/// 预甩调度批次号
/// 返回回执
[HttpGet("/TaskManageRollingNomination/GetUrl")]
public async Task GetUrl(string dispatchBatchId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
/*
用预甩调度的dispatchBatchId关联分享表的BUSI_ID获取分享KEY
*/
if (string.IsNullOrWhiteSpace(dispatchBatchId))
throw Oops.Oh($"预甩调度批次号不能为空");
var dispatchInfo = _taskRollingNominationDispatchInfoRepository.AsQueryable()
.First(a => a.BATCH_ID == dispatchBatchId);
if (dispatchInfo == null)
{
throw Oops.Oh($"获取预甩调度信息失败,不存在或已作废");
}
if(string.IsNullOrWhiteSpace(dispatchInfo.SHARE_LINK_KEY))
throw Oops.Oh($"链接访问KEY不存在,请生成分享链接");
string[] statusArg = new string[] { RollingNominationDispatchStatusEnum.CANCEL.ToString(),
RollingNominationDispatchStatusEnum.EXPIRE.ToString() };
if (statusArg.Any(a => a.Equals(dispatchInfo.STATUS, StringComparison.OrdinalIgnoreCase)))
throw Oops.Oh($"链接访问KEY状态不可用");
result.succ = true;
result.ext = dispatchInfo.SHARE_LINK_KEY;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"推送预甩货客户访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 获取Status是load的可配载的列表
///
/// 获取Status是load的可配载的列表
///
/// 预甩货任务主键
/// 返回回执
[HttpGet("/TaskManageRollingNomination/GetLoadStatusDetailList")]
public async Task GetLoadStatusDetailList(string taskPkId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
var withDispatchList =
_taskRollingNominationInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((nom,detail)=> nom.PK_ID == detail.NOM_ID)
.LeftJoin((nom,detail, dispatch) =>
detail.PK_ID == dispatch.DETAIL_ID && dispatch.IsDeleted == false)
.Where((nom,detail, dispatch) =>
nom.TASK_ID == taskPkId && detail.IsDeleted == false && string.IsNullOrWhiteSpace(dispatch.TASK_ID))
.Select((nom, detail, dispatch) => new { Detail = detail}).ToList();
if (withDispatchList.Count > 0)
{
result.ext = withDispatchList.Select(a => a.Detail.Adapt()).ToList();
}
result.succ = true;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"推送预甩货客户访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 获取提单号下预甩货的单票明细
///
/// 获取提单号下预甩货的单票明细
///
/// 预甩货主键
/// 提单号
/// 返回回执
[HttpGet("/TaskManageRollingNomination/GetPreBillDetailList")]
public async Task GetPreBillDetailList([FromQuery] string nominationId, [FromQuery] string shipmentNo)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
var withDispatchList =
_taskRollingNominationInfoRepository.AsQueryable()
.InnerJoin((nom, detail) => nom.PK_ID == detail.NOM_ID)
.Where((nom, detail) =>
nom.PK_ID == nominationId && detail.IsDeleted == false && detail.SHIPMENT == shipmentNo)
.Select((nom, detail) => new { Detail = detail }).ToList();
if (withDispatchList.Count > 0)
{
result.ext = withDispatchList.Select(a => a.Detail.Adapt()).ToList();
}
result.succ = true;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"获取提单号下预甩货的单票明细异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 保存预甩货明细箱型信息
///
/// 保存预甩货明细箱型信息(处理没有给箱型高度或者未能翻译的箱型,进行人工修正)
///
/// 保存预甩货明细箱型请求
/// 返回回执
[HttpPost("/TaskManageRollingNomination/SaveDetailContainer")]
public async Task SaveDetailContainer(SaveDetailContainerDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
if (string.IsNullOrWhiteSpace(model.ctnCode))
{
throw Oops.Oh($"请求的箱型代码不能为空");
}
var detailInfo = _taskRollingNominationDetailInfoRepository.AsQueryable()
.First(a => a.PK_ID == model.detailPKId && a.IsDeleted == false);
if (detailInfo == null)
throw Oops.Oh($"预甩货明细主键{model.detailPKId}无法获取业务信息");
var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList();
var ctnCodeModel = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.Name) &&
a.Code.Equals(model.ctnCode, StringComparison.OrdinalIgnoreCase));
if (ctnCodeModel == null)
throw Oops.Oh($"请求的箱型代码基础数据不存在,请修改");
detailInfo.CTNCODE = ctnCodeModel.Code;
detailInfo.CTNALL = ctnCodeModel.Name;
detailInfo.UpdatedTime = DateTime.Now;
detailInfo.UpdatedUserId = UserManager.UserId;
detailInfo.UpdatedUserName = UserManager.Name;
await _taskRollingNominationDetailInfoRepository.AsUpdateable(detailInfo).UpdateColumns(it => new
{
it.CTNCODE,
it.CTNALL,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
result.succ = true;
result.msg = "成功";
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"保存预甩货明细箱型信息异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 生成访问链接
///
/// 生成访问链接
///
/// 创建分享链接请求
/// 返回回执
[HttpPost("/TaskManageRollingNomination/GenShareLink")]
public async Task GenShareLink(RollingNominationGenShareLinkDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
if (string.IsNullOrWhiteSpace(model.dispatchBatchId))
{
throw Oops.Oh($"预甩调度批次ID不能为空");
}
var list = _taskRollingNominationDispatchInfoRepository.AsQueryable()
.Where(a => a.BATCH_ID == model.dispatchBatchId).ToList();
if(list.Count == 0)
throw Oops.Oh($"预甩调度批次ID无法获取业务信息");
var taskInfo = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == list.FirstOrDefault().TASK_ID);
ShareLinkRequestDto reqDto = new ShareLinkRequestDto {
businessId = model.dispatchBatchId,
businessType = "NOMI_DISPATCH",
expireDate = list.FirstOrDefault().CONFIRM_DEAD_LINE.Value.ToString("yyyy-MM-dd HH:mm:ss"),
isUserFeedBack = true,
taskType = taskInfo.TASK_BASE_TYPE,
isRenew = model.isRenew
};
var service = _namedServiceProvider.GetService(nameof(TaskManageShareLinkService));
result = await service.CreateShareLink(reqDto);
if(result.succ)
{
DateTime nowDate = DateTime.Now;
string shareKey = result.ext.ToString();
list.ForEach(p => {
p.SHARE_LINK_KEY = shareKey;
p.CREATE_SHARE_LINK_DATE = nowDate;
p.UpdatedTime = nowDate;
p.UpdatedUserId = UserManager.UserId;
p.UpdatedUserName = UserManager.Name;
_taskRollingNominationDispatchInfoRepository.AsUpdateable(p)
.UpdateColumns(it => new
{
it.SHARE_LINK_KEY,
it.CREATE_SHARE_LINK_DATE,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
});
}
}
catch(Exception ex)
{
result.succ = false;
result.msg = $"生成访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 取消访问链接
///
/// 取消访问链接
///
/// 预甩调度批次ID
/// 返回回执
[HttpPost("/TaskManageRollingNomination/CancelShareLink")]
public async Task CancelShareLink(string dispatchBatchId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
if (string.IsNullOrWhiteSpace(dispatchBatchId))
{
throw Oops.Oh($"预甩调度批次ID不能为空");
}
var list = _taskRollingNominationDispatchInfoRepository.AsQueryable()
.Where(a => a.BATCH_ID == dispatchBatchId).ToList();
if (list.Count == 0)
throw Oops.Oh($"预甩调度批次ID无法获取业务信息");
var service = _namedServiceProvider.GetService(nameof(TaskManageShareLinkService));
result = await service.CancelShareLink(dispatchBatchId);
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"取消访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 获取用户反馈信息
///
/// 获取用户反馈信息
///
/// 预甩调度批次ID
/// 返回回执
[HttpPost("/TaskManageRollingNomination/GetUserFeedBack")]
public async Task GetUserFeedBack(string dispatchBatchId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
if (string.IsNullOrWhiteSpace(dispatchBatchId))
{
throw Oops.Oh($"预甩调度批次ID不能为空");
}
var list = _taskRollingNominationDispatchInfoRepository.AsQueryable()
.Where(a => a.BATCH_ID == dispatchBatchId).ToList();
if (list.Count == 0)
throw Oops.Oh($"预甩调度批次ID无法获取业务信息");
result.succ = true;
result.ext = new
{
userOpinion = list.FirstOrDefault().USER_OPINION,
userOpinionTxt = list.FirstOrDefault().USER_OPINION_TXT
};
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"获取用户反馈信息异常,原因:{ex.Message}";
}
return result;
}
#endregion
///
/// 发送预甩的通知
///
/// 请求详情
///
[HttpPost("/TaskManageRollingNomination/SendRollingNominationNotice")]
public async Task SendRollingNominationNotice(RollingNominationNoticeDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"取消访问链接异常,原因:{ex.Message}";
}
return result;
}
#region 获取预甩的通知预览
///
/// 获取预甩的通知预览
///
/// 请求详情
///
[HttpPost("/TaskManageRollingNomination/GetRollingNominationNoticeReview")]
public async Task GetRollingNominationNoticeReview(RollingNominationNoticeDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
if (string.IsNullOrWhiteSpace(model.taskId))
{
throw Oops.Oh($"预甩任务ID不能为空");
}
var printTemplate = await _repPrintTemplate.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == model.templateId);
if (printTemplate == null)
{
throw Oops.Bah(BookingErrorCode.BOOK115);
}
if(string.IsNullOrWhiteSpace(printTemplate.CateCode) || !printTemplate.CateCode.Contains("rolling_nomination_notice_template"))
{
throw Oops.Bah("模板类型分类错误,当前只支持预甩邮件通知");
}
string html = string.Empty;
var list = _taskRollingNominationDetailInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((detail, norm) => detail.NOM_ID == norm.PK_ID)
.Where((detail, norm) => norm.TASK_ID == model.taskId && detail.IsDeleted == false && norm.IsDeleted == false)
.Select((detail, dispatch) => detail).ToList();
//填写预甩详情到模板,并返回HTML
//读取订舱数据
var bookingOrderEntity = _bookingOrderRepository.AsQueryable().Filter(null, true)
.First(a => a.Id == list.FirstOrDefault().BOOKING_ID.Value);
SysUser opUserInfo = null;
if (!string.IsNullOrWhiteSpace(bookingOrderEntity.OPID) && Regex.IsMatch(bookingOrderEntity.OPID, "[0-9]+"))
opUserInfo = _sysUserRepository.AsQueryable().Filter(null, true).First(u => u.Id == long.Parse(bookingOrderEntity.OPID));
html = GenerateTemplateHtml(printTemplate.FilePath, opUserInfo, UserManager.TENANT_NAME);
result.succ = true;
result.ext = html;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"取消获取预甩的通知预览异常,原因:{ex.Message}";
}
return result;
}
#endregion
///
/// 获取换船选择列表
///
/// 任务ID
///
[HttpGet("/TaskManageRollingNomination/GetToShipSelect")]
public async Task GetToShipSelect(string taskPkId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
List fromToList = new List();
try
{
var list = _taskRollingNominationDetailInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin((detail, norm) => detail.NOM_ID == norm.PK_ID)
.Where((detail, norm) => norm.TASK_ID == taskPkId && detail.IsDeleted == false && norm.IsDeleted == false)
.Select((detail, norm) => detail).ToList();
if (list.Count == 0)
throw Oops.Oh($"预甩货任务主键{taskPkId}无法获取业务信息");
TaskRollingNominationShowDto model = new TaskRollingNominationShowDto();
var shipList = _taskRollingNominationShipInfoRepository.AsQueryable()
.Where(a => a.NOM_ID == list.FirstOrDefault().NOM_ID && a.IsDeleted == false).ToList();
var fromEntity = shipList.Where(a =>
a.SHIP_TYPE.Equals("From", StringComparison.OrdinalIgnoreCase)).ToList();
if (fromEntity.Count > 0)
model.From = fromEntity.Select(p => p.Adapt()).ToList();
model.LoadDetailList = list.Select(a => a.Adapt()).ToList();
if (model.From != null && model.From.Count > 0)
{
var firstLoadDetail = model.LoadDetailList.FirstOrDefault();
if (model.From.Any(t => string.IsNullOrWhiteSpace(t.Port)))
{
model.From = model.From.Where(a => a.Terminal.Contains(firstLoadDetail.LoadPortName?.Trim())).ToList();
}
else
{
model.From = model.From.Where(a => a.Port.Equals(firstLoadDetail.LoadPortName?.Trim(),StringComparison.OrdinalIgnoreCase)).ToList();
}
}
var toEntity = shipList.Where(a => Regex.IsMatch(a.SHIP_TYPE, "To(\\s+[0-9]+)?"
, RegexOptions.IgnoreCase)).ToList();
if (toEntity.Count > 0)
model.To = toEntity.Select(p => p.Adapt()).ToList();
//优先PORT关联FROM和TO,也有PORT为空的情况,这种就需要用Terminal来关联
if (model.From.Any(t => string.IsNullOrWhiteSpace(t.Port)))
{
//这里为了前端原船和换船做了根据Terminal对应
fromToList = model.From.GroupJoin(model.To, l => l.Terminal?.Trim(), r => r.Terminal?.Trim(), (l, r) =>
{
TaskRollingNominationShipFromToDto dto = new TaskRollingNominationShipFromToDto();
dto.FromShip = l;
var currArg = r.ToList();
if (currArg.Count > 0)
{
dto.ToShipList = currArg.Select((p, idx) =>
{
if (Regex.IsMatch(p.ShipType, "[0-9]+"))
return new { SortNo = int.Parse(Regex.Match(p.ShipType, "[0-9]+").Value), Obj = p };
return new { SortNo = idx + 1, Obj = p };
}).OrderBy(p => p.SortNo).Select(p => p.Obj).ToList();
}
return dto;
}).ToList();
}
else
{
//这里为了前端原船和换船做了根据PORT对应
fromToList = model.From.GroupJoin(model.To, l => l.Port?.Trim(), r => r.Port?.Trim(), (l, r) =>
{
TaskRollingNominationShipFromToDto dto = new TaskRollingNominationShipFromToDto();
dto.FromShip = l;
var currArg = r.ToList();
if (currArg.Count > 0)
{
dto.ToShipList = currArg.Select((p, idx) =>
{
if (Regex.IsMatch(p.ShipType, "[0-9]+"))
return new { SortNo = int.Parse(Regex.Match(p.ShipType, "[0-9]+").Value), Obj = p };
return new { SortNo = idx + 1, Obj = p };
}).OrderBy(p => p.SortNo).Select(p => p.Obj).ToList();
}
return dto;
}).ToList();
}
List> tuples = new List>();
model.FromToList = new List();
if (model.LoadDetailList.Count > 0)
{
model.TotalLoadCtnStat = string.Join(",", model.LoadDetailList.GroupBy(x => x.CtnAll)
.Select(x =>
$"{x.Key}*{x.Sum(t => t.CtnNum)}").ToArray());
string rollRegex = "Roll\\s+to\\s+\\w+\\s+\\w{3,}\\/\\w+,\\s?if\\s+cannot\\s+catch\\s?,\\s+roll\\s+to\\s+\\w{3,}\\s+next\\s+sailing";
string rollontoRegex = "Roll\\s+onto\\s+\\w{3,}\\s+\\w+,\\s+[0-9]+\\s+days\\s+delay\\.";
bool isSelectRoll = false;
bool isRoll = false;
bool isRollOnto = false;
model.LoadDetailList.ForEach(p =>
{
string vslCode = string.Empty;
string voyNo = string.Empty;
string strCode = string.Empty;
string strCode2 = string.Empty;
if (Regex.IsMatch(p.Status, rollRegex, RegexOptions.IgnoreCase))
{
string currS = Regex.Match(p.Status, "(?<=Roll\\sto\\s\\w+\\s)\\w{3,}\\/\\w+(?=,)").Value;
vslCode = Regex.Split(currS, "\\/")[0]?.Trim();
voyNo = Regex.Split(currS, "\\/")[1]?.Trim();
strCode = Regex.Match(p.Status, "(?<=if\\scannot\\scatch\\s?,\\sroll\\sto\\s)\\w{3,}(?=\\s+next\\s+sailing)").Value?.Trim();
isSelectRoll = true;
}
else if (p.Status.Trim().Equals("roll", StringComparison.OrdinalIgnoreCase))
{
isRoll = true;
}
else if (Regex.IsMatch(p.Status, rollontoRegex, RegexOptions.IgnoreCase))
{
vslCode = Regex.Match(p.Status, "(?<=Roll\\sonto\\s)\\w{3,}(?=\\s+\\w+,)").Value?.Trim();
isRollOnto = true;
}
for (int i = 0; i < fromToList.Count; i++)
{
if (!string.IsNullOrWhiteSpace(fromToList[i].FromShip.Port))
{
if (fromToList[i].FromShip.Port.Equals(p.PlaceOfReceipt, StringComparison.OrdinalIgnoreCase))
{
var fromInfo = fromToList[i].FromShip.Adapt();
List toShipList = new List();
if (isSelectRoll)
{
for (int j = 0; j < fromToList[i].ToShipList.Count; j++)
{
if (fromToList[i].ToShipList[j].VslCode.Equals(vslCode, StringComparison.OrdinalIgnoreCase))
{
toShipList.Add(fromToList[i].ToShipList[j].Adapt());
}
else if (fromToList[i].ToShipList[j].ShipString.Equals(strCode, StringComparison.OrdinalIgnoreCase))
{
toShipList.Add(fromToList[i].ToShipList[j].Adapt());
}
}
}
else if (isRoll)
{
for (int j = 0; j < fromToList[i].ToShipList.Count; j++)
{
if (fromToList[i].ToShipList[j].Port.Equals(p.PlaceOfDelivery?.Trim(), StringComparison.OrdinalIgnoreCase))
{
toShipList.Add(fromToList[i].ToShipList[j].Adapt());
}
}
}
if (toShipList.Count == 0)
{
if (fromToList[i].ToShipList.Count == 1)
{
toShipList.Add(fromToList[i].ToShipList.FirstOrDefault().Adapt());
}
}
model.FromToList.Add(new TaskRollingNominationShipFromToDto
{
FromShip = fromInfo,
ToShipList = toShipList
});
}
}
else
{
if (fromToList[i].FromShip.Terminal.Contains(p.PlaceOfReceipt, StringComparison.OrdinalIgnoreCase))
{
var fromInfo = fromToList[i].FromShip.Adapt();
List toShipList = new List();
if (isRollOnto)
{
for (int j = 0; j < fromToList[i].ToShipList.Count; j++)
{
if (fromToList[i].ToShipList[j].VslCode.Equals(vslCode, StringComparison.OrdinalIgnoreCase))
{
toShipList.Add(fromToList[i].ToShipList[j].Adapt());
}
}
}
model.FromToList.Add(new TaskRollingNominationShipFromToDto
{
FromShip = fromInfo,
ToShipList = toShipList
});
}
}
}
});
}
result.succ = true;
result.ext = fromToList;
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"获取换船选择列表异常,原因:{ex.Message}";
}
return result;
}
private string GenerateTemplateHtml(string filePath, SysUser opUserInfo, string tenantName)
{
string result = string.Empty;
var opt = App.GetOptions();
var dirAbs = opt.basePath;
if (string.IsNullOrEmpty(dirAbs))
{
dirAbs = App.WebHostEnvironment.WebRootPath;
}
var fileAbsPath = Path.Combine(dirAbs, filePath);
_logger.LogInformation($"查找模板文件:{fileAbsPath}");
if (!File.Exists(fileAbsPath))
{
throw Oops.Bah(BookingErrorCode.BOOK115);
}
string baseHtml = File.ReadAllText(fileAbsPath);
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Name))
{
baseHtml = baseHtml.Replace("#opname#", opUserInfo.Name);
}
else
{
baseHtml = baseHtml.Replace("#opname#", "操作");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Email))
{
baseHtml = baseHtml.Replace("#opemail#", opUserInfo.Email);
}
else
{
baseHtml = baseHtml.Replace("#opemail#", "");
}
if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Phone))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Phone);
}
else if (opUserInfo != null && !string.IsNullOrWhiteSpace(opUserInfo.Tel))
{
baseHtml = baseHtml.Replace("#optel#", opUserInfo.Tel);
}
else
{
baseHtml = baseHtml.Replace("#optel#", "");
}
return result;
}
}
}