|
|
using Amazon.Runtime.Internal.Util;
|
|
|
using DS.Module.Core;
|
|
|
using DS.Module.Core.Log;
|
|
|
using DS.Module.SqlSugar;
|
|
|
using DS.Module.UserModule;
|
|
|
using DS.WMS.Core.Op.Dtos;
|
|
|
using DS.WMS.Core.Op.Entity;
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using SqlSugar;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using Mapster;
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
using DS.WMS.Core.Op.Interface;
|
|
|
using SqlSugar.IOC;
|
|
|
using Newtonsoft.Json;
|
|
|
using NLog;
|
|
|
using DS.WMS.Core.Sys.Interface;
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
using LanguageExt.Common;
|
|
|
using DS.Module.Core.Helpers;
|
|
|
using NPOI.SS.Formula.Functions;
|
|
|
using System.Text.RegularExpressions;
|
|
|
using DS.WMS.Core.Sys.Method;
|
|
|
using DS.WMS.Core.Map.Dtos;
|
|
|
using Org.BouncyCastle.Ocsp;
|
|
|
using DS.WMS.Core.Code.Entity;
|
|
|
using DS.WMS.Core.Map.Entity;
|
|
|
using DS.WMS.Core.Code.Dtos;
|
|
|
using System.Net.Http.Headers;
|
|
|
using DS.Module.DjyServiceStatus;
|
|
|
using NPOI.SS.UserModel;
|
|
|
using DS.WMS.Core.Info.Interface;
|
|
|
using Microsoft.Extensions.FileSystemGlobbing;
|
|
|
using DS.WMS.Core.Info.Entity;
|
|
|
using DS.WMS.Core.Info.Dtos;
|
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
using AngleSharp.Dom.Events;
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
using DS.WMS.Core.Map.Interface;
|
|
|
using DS.WMS.Core.Code.Interface;
|
|
|
using DS.WMS.Core.Code.Method;
|
|
|
using DS.WMS.Core.Map.Method;
|
|
|
|
|
|
namespace DS.WMS.Core.Op.Method
|
|
|
{
|
|
|
public class BookingSlotService : IBookingSlotService
|
|
|
{
|
|
|
private readonly IServiceProvider _serviceProvider;
|
|
|
private readonly ISqlSugarClient db;
|
|
|
private readonly IUser user;
|
|
|
private readonly ISaasDbService saasService;
|
|
|
private readonly ISeaExportService _seaExportService;
|
|
|
private readonly IBookingLabelService _bookingLabelService;
|
|
|
private readonly ILogAuditService _logAuditService;
|
|
|
private readonly ISysCacheService _sysCacheService;
|
|
|
private readonly ISysFileService _sysFileService;
|
|
|
private readonly IBookingSlotStockService _bookingSlotStockService;
|
|
|
private readonly IOpFileService _opFileService;
|
|
|
private readonly IConfigService _configService;
|
|
|
private readonly IClientContactService _clientContactService;
|
|
|
private readonly IClientInfoService _clientInfoService;
|
|
|
private readonly IDjyServiceStatusService _djyServiceStatusService;
|
|
|
private readonly IWebHostEnvironment _environment;
|
|
|
private readonly IMappingCarrierService _mappingCarrierService;
|
|
|
private readonly ICodeCtnService _codeCtnService;
|
|
|
private readonly ICodePortService _codePortService;
|
|
|
private readonly IMappingPortService _mappingPortService;
|
|
|
private readonly ICodeCountryService _codeCountryService;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly string bcCompareUrl;
|
|
|
|
|
|
private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
|
|
const string CONST_BC_FILE_CODE = "bc";
|
|
|
const string CONST_BC_FILE_NAME = "Booking Confirmation";
|
|
|
|
|
|
const string CONST_BC_NOTICE_FILE_CODE = "bc_notice";
|
|
|
const string CONST_BC_NOTICE_FILE_NAME = "Booking Confirmation Notice";
|
|
|
|
|
|
const string CONST_BC_MODIFY_FILE_CODE = "bc_modify";
|
|
|
const string CONST_BC_MODIFY_FILE_NAME = "Booking Amendment";
|
|
|
|
|
|
const string CONST_BC_MODIFY_NOTICE_FILE_CODE = "bc_modifynotice";
|
|
|
const string CONST_BC_MODIFY_NOTICE_FILE_NAME = "Booking Amendment Notice";
|
|
|
|
|
|
//收货地名称解析装货港港口
|
|
|
const string RECEIPT_TO_PORTLOAD = "ReceiptToPortLoad";
|
|
|
|
|
|
//交货地名称解析卸货港港口
|
|
|
const string DELIVERY_TO_PORT = "DeliveryToPort";
|
|
|
|
|
|
//BC任务或舱位生成订舱订单时客户联系人必填
|
|
|
const string CONST_CREATE_BOOKING_NEED_CONTACT = "BC_TASK_OR_SLOT_BOOKING_NEED_CONTACT";
|
|
|
|
|
|
//船公司基础映射模块
|
|
|
const string CONST_MAPPING_CARRIER_MODULE = "CarrierBaseMapping";
|
|
|
|
|
|
|
|
|
public BookingSlotService(IServiceProvider serviceProvider)
|
|
|
{
|
|
|
_serviceProvider = serviceProvider;
|
|
|
db = _serviceProvider.GetRequiredService<ISqlSugarClient>();
|
|
|
user = _serviceProvider.GetRequiredService<IUser>();
|
|
|
saasService = _serviceProvider.GetRequiredService<ISaasDbService>();
|
|
|
_seaExportService = _serviceProvider.GetRequiredService<ISeaExportService>();
|
|
|
_bookingLabelService = _serviceProvider.GetRequiredService<IBookingLabelService>();
|
|
|
_logAuditService = _serviceProvider.GetRequiredService<ILogAuditService>();
|
|
|
_sysCacheService = _serviceProvider.GetRequiredService<ISysCacheService>();
|
|
|
_sysFileService = _serviceProvider.GetRequiredService<ISysFileService>();
|
|
|
_bookingSlotStockService = _serviceProvider.GetRequiredService<IBookingSlotStockService>();
|
|
|
_opFileService = _serviceProvider.GetRequiredService<IOpFileService>();
|
|
|
_configService = _serviceProvider.GetRequiredService<IConfigService>();
|
|
|
_djyServiceStatusService = _serviceProvider.GetRequiredService<IDjyServiceStatusService>();
|
|
|
_environment = _serviceProvider.GetRequiredService<IWebHostEnvironment>();
|
|
|
_codeCtnService = _serviceProvider.GetRequiredService<ICodeCtnService>();
|
|
|
_codePortService = _serviceProvider.GetRequiredService<ICodePortService>();
|
|
|
_mappingPortService = _serviceProvider.GetRequiredService<IMappingPortService>();
|
|
|
_codeCountryService = _serviceProvider.GetRequiredService<ICodeCountryService>();
|
|
|
|
|
|
bcCompareUrl = AppSetting.app(new string[] { "BCCompare", "Url" });
|
|
|
}
|
|
|
|
|
|
#region 保存舱位
|
|
|
/// <summary>
|
|
|
/// 保存舱位
|
|
|
/// </summary>
|
|
|
/// <param name="input">舱位详情</param>
|
|
|
/// <returns>返回输出</returns>
|
|
|
public async Task<DataResult<BookingSlotBaseSaveOutput>> Save(BookingSlotBaseSaveInput input)
|
|
|
{
|
|
|
BookingSlotBase model = null;
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
if (input.Id > 0) //修改
|
|
|
{
|
|
|
var c = tenantDb.Queryable<BookingSlotBase>().Where(x => x.SlotBookingNo == input.SlotBookingNo
|
|
|
&& input.Id != input.Id).Count();
|
|
|
|
|
|
if (c > 0)
|
|
|
{
|
|
|
//订舱提单号已存在
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSlotBookingNoExists)));
|
|
|
}
|
|
|
|
|
|
model = tenantDb.Queryable<BookingSlotBase>().First(x => x.Id == input.Id);
|
|
|
var oldObj = model.Adapt<BookingSlotBaseSaveInput>();
|
|
|
|
|
|
input.Adapt(model);
|
|
|
|
|
|
// 1.判断新的舱位信息的7个库存统计维度是否发生变化
|
|
|
// 2.如果有变化,则需要更新旧的库存信息
|
|
|
bool isNeedUpdateOldStock = false;
|
|
|
if (oldObj.Vessel != model.Vessel
|
|
|
|| oldObj.Voyno != model.Voyno
|
|
|
|| oldObj.BookingSlotType != model.BookingSlotType
|
|
|
|| oldObj.CarrierCode != model.CarrierCode
|
|
|
|| oldObj.PortLoadId != model.PortLoadCode
|
|
|
|| oldObj.PortDischargeId != model.PortDischargeCode)
|
|
|
{
|
|
|
isNeedUpdateOldStock = true;
|
|
|
}
|
|
|
await tenantDb.Updateable<BookingSlotBase>(model).ExecuteCommandAsync();
|
|
|
|
|
|
if (isNeedUpdateOldStock)
|
|
|
{
|
|
|
//更新库存
|
|
|
//await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel
|
|
|
//{
|
|
|
// BOOKING_SLOT_TYPE = oldObj.BOOKING_SLOT_TYPE,
|
|
|
// CARRIERID = oldObj.CARRIERID,
|
|
|
// CONTRACT_NO = oldObj.CONTRACT_NO,
|
|
|
// VESSEL = oldObj.VESSEL,
|
|
|
// VOYNO = oldObj.VOYNO,
|
|
|
// PORTLOADID = oldObj.PORTLOADID,
|
|
|
// PORTDISCHARGEID = oldObj.PORTDISCHARGEID,
|
|
|
// TenantId = model.TenantId
|
|
|
//}));
|
|
|
}
|
|
|
|
|
|
var delCtnList = tenantDb.Queryable<BookingSlotCtn>().Where(x => x.SlotId == model.Id).ToList();
|
|
|
|
|
|
if(delCtnList.Count > 0)
|
|
|
await tenantDb.Deleteable<BookingSlotCtn>(delCtnList).ExecuteCommandAsync();
|
|
|
|
|
|
if (input.CtnList != null)
|
|
|
{
|
|
|
foreach (var ctn in input.CtnList)
|
|
|
{
|
|
|
var newCtn = ctn.Adapt<BookingSlotCtn>();
|
|
|
newCtn.SlotId = model.Id;
|
|
|
await tenantDb.Insertable<BookingSlotCtn>(newCtn).ExecuteCommandAsync();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#region 关联订舱信息修改
|
|
|
if (input.BookingSlotSaleInfoList != null)
|
|
|
{
|
|
|
foreach (var item in input.BookingSlotSaleInfoList)
|
|
|
{
|
|
|
if (!item.UpdateFlag)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
var allocation = await tenantDb.Queryable<BookingSlotAllocation>().FirstAsync(x => x.Id == item.Id);
|
|
|
if (allocation == null)
|
|
|
{
|
|
|
//保存失败,原因:更新关联订舱时未查询到订舱(关联表Id:{item.Id})
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSaveFailAllocRecordNull)), item.Id));
|
|
|
}
|
|
|
|
|
|
// 更新关联表
|
|
|
item.Adapt(allocation);
|
|
|
|
|
|
|
|
|
await tenantDb.Ado.BeginTranAsync();
|
|
|
try
|
|
|
{
|
|
|
await tenantDb.Updateable<BookingSlotAllocation>(allocation).UpdateColumns(x => new
|
|
|
{
|
|
|
x.CustomerId,
|
|
|
x.CustomerName,
|
|
|
x.CustServiceId,
|
|
|
x.CustService,
|
|
|
x.Sale,
|
|
|
x.SaleId,
|
|
|
x.Op,
|
|
|
x.OpId,
|
|
|
x.Doc,
|
|
|
x.DocId,
|
|
|
x.BusinessId,
|
|
|
x.Business,
|
|
|
x.Shipper,
|
|
|
x.SaleTime,
|
|
|
x.GoodsName,
|
|
|
x.SellingPrice,
|
|
|
x.UpdateBy,
|
|
|
//x.UpdatedUserName,
|
|
|
x.UpdateTime,
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
// 更新订舱表
|
|
|
//var bookingOrder = await _repBookingOrder.FirstOrDefaultAsync(x => x.Id == allocation.BOOKING_ID);
|
|
|
|
|
|
var bookingOrder = _seaExportService.GetSeaExportInfo(allocation.BookingId.ToString()).Data;
|
|
|
|
|
|
/*
|
|
|
var oldBookingOrder = bookingOrder.Adapt<BookingOrder>();
|
|
|
if (bookingOrder != null)
|
|
|
{
|
|
|
bookingOrder.CUSTOMERID = allocation.CUSTOMERID;
|
|
|
bookingOrder.CUSTOMERNAME = allocation.CUSTOMERNAME;
|
|
|
bookingOrder.CUSTSERVICE = allocation.CUSTSERVICE;
|
|
|
bookingOrder.CUSTSERVICEID = allocation.CUSTSERVICEID;
|
|
|
bookingOrder.SALE = allocation.SALE;
|
|
|
bookingOrder.SALEID = allocation.SALEID;
|
|
|
bookingOrder.OP = allocation.OP;
|
|
|
bookingOrder.OPID = allocation.OPID;
|
|
|
bookingOrder.DOC = allocation.DOC;
|
|
|
bookingOrder.DOCID = allocation.DOCID;
|
|
|
bookingOrder.BUSINESS = allocation.BUSINESS;
|
|
|
bookingOrder.BUSINESSID = allocation.BUSINESSID;
|
|
|
|
|
|
await _repBookingOrder.AsUpdateable(bookingOrder).UpdateColumns(x => new
|
|
|
{
|
|
|
x.CUSTOMERID,
|
|
|
x.CUSTOMERNAME,
|
|
|
x.CUSTSERVICE,
|
|
|
x.CUSTSERVICEID,
|
|
|
x.SALE,
|
|
|
x.SALEID,
|
|
|
x.OP,
|
|
|
x.OPID,
|
|
|
x.DOC,
|
|
|
x.DOCID,
|
|
|
x.UpdatedUserId,
|
|
|
x.UpdatedUserName,
|
|
|
x.UpdatedTime,
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
|
Parallel.For(0, 1, (n) =>
|
|
|
{
|
|
|
//bookingOrderService.SaveLog(bookingOrder, oldBookingOrder, "舱位关联更新");
|
|
|
|
|
|
// 推送东胜
|
|
|
//bookingOrderService.SendBookingOrder(new long[] { allocation.BOOKING_ID });
|
|
|
});
|
|
|
}
|
|
|
*/
|
|
|
await tenantDb.Ado.CommitTranAsync();
|
|
|
}
|
|
|
catch (Exception)
|
|
|
{
|
|
|
await tenantDb.Ado.RollbackTranAsync();
|
|
|
//await ex.LogAsync(Db);
|
|
|
//return DataResult.Failed(MultiLanguageConst.Operation_Failed);
|
|
|
|
|
|
//_repAllocation.CurrentRollbackTran();
|
|
|
throw;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
//Parallel.For(0, 1, (n) =>
|
|
|
//{
|
|
|
// _ = InsLog("Update", model.Id, typeof(BookingSlotBaseSaveInput), oldObj, input,
|
|
|
// nameof(BookingSlotBaseApiSaveDto.CtnList),
|
|
|
// nameof(BookingSlotBaseApiSaveDto.BookingSlotSaleInfoList));
|
|
|
//});
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var c = tenantDb.Queryable<BookingSlotBase>().Where(x => x.SlotBookingNo == input.SlotBookingNo).Count();
|
|
|
if (c > 0)
|
|
|
{
|
|
|
//订舱提单号已存在
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSlotBookingNoExists)));
|
|
|
}
|
|
|
|
|
|
model = input.Adapt<BookingSlotBase>();
|
|
|
await tenantDb.Insertable<BookingSlotBase>(model).ExecuteReturnEntityAsync();
|
|
|
|
|
|
foreach (var ctn in input.CtnList)
|
|
|
{
|
|
|
var newCtn = ctn.Adapt<BookingSlotCtn>();
|
|
|
newCtn.SlotId = model.Id;
|
|
|
await tenantDb.Insertable<BookingSlotCtn>(newCtn).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
//await InsLog("Add", model.Id, "新增舱位");
|
|
|
}
|
|
|
|
|
|
//更新库存
|
|
|
//await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel
|
|
|
//{
|
|
|
// BOOKING_SLOT_TYPE = model.BOOKING_SLOT_TYPE,
|
|
|
// CARRIERID = model.CARRIERID,
|
|
|
// CONTRACT_NO = model.CONTRACT_NO,
|
|
|
// VESSEL = model.VESSEL,
|
|
|
// VOYNO = model.VOYNO,
|
|
|
// PORTLOADID = model.PORTLOADID,
|
|
|
// PORTDISCHARGEID = model.PORTDISCHARGEID,
|
|
|
// TenantId = model.TenantId
|
|
|
//}));
|
|
|
|
|
|
var inputDto = new BookingSlotBaseApiDto
|
|
|
{
|
|
|
DataObj = new BookingSlotBaseApiSaveDto
|
|
|
{
|
|
|
PortDischargeId = model.PortDischargeCode,
|
|
|
PortDischarge = model.PortDischarge,
|
|
|
PortLoadId = model.PortLoadCode,
|
|
|
PortLoad = model.PortLoad,
|
|
|
PlaceDelivery = model.PlaceDelivery,
|
|
|
PlaceDeliveryId = model.PlaceDeliveryCode,
|
|
|
PlaceReceipt = model.PlaceReceipt,
|
|
|
PlaceReceiptId = model.PlaceReceiptCode,
|
|
|
}
|
|
|
};
|
|
|
|
|
|
//这里自动匹配标签
|
|
|
await GenerateSlotLabel(inputDto, model.Id);
|
|
|
|
|
|
return await Detail(model.Id);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 自动生成舱位标签
|
|
|
/// <summary>
|
|
|
/// 自动生成舱位标签
|
|
|
/// </summary>
|
|
|
/// <param name="dto">舱位详情</param>
|
|
|
/// <param name="id">舱位ID</param>
|
|
|
/// <returns></returns>
|
|
|
private async Task<DataResult<string>> GenerateSlotLabel(BookingSlotBaseApiDto dto, long id)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
/*
|
|
|
1、获取所有的可用标签
|
|
|
2、只执行REGEX_PATTERN_TXT有值的标签记录。
|
|
|
3、根据提取的标签JSON执行验证,符合条件的自动标记本标签
|
|
|
*/
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var labelList = _bookingLabelService.List(1).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
List<BookingLabelBaseDto> ruleList = new List<BookingLabelBaseDto>();
|
|
|
|
|
|
if (labelList.Count > 0)
|
|
|
{
|
|
|
for (int i = 0; i < labelList.Count; i++)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(labelList[i].RegexPatternTxt))
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
var regList = JsonConvert.DeserializeObject<List<BookingLabelRegexDto>>(labelList[i].RegexPatternTxt);
|
|
|
|
|
|
if (regList != null && regList.Count > 0)
|
|
|
{
|
|
|
bool isSucc = true;
|
|
|
|
|
|
for (int j = 0; j < regList.Count; j++)
|
|
|
{
|
|
|
var operEnum = (LabelRegexOperEnum)System.Enum.Parse(typeof(LabelRegexOperEnum), regList[j].oper);
|
|
|
|
|
|
if (regList[j].name.Equals("PORTLOADID", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PORTLOADID", dto.DataObj.PortLoadId, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else if (regList[j].name.Equals("PLACERECEIPT", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PLACERECEIPT", dto.DataObj.PlaceReceipt, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else if (regList[j].name.Equals("PORTLOAD", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PORTLOAD", dto.DataObj.PortLoad, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else if (regList[j].name.Equals("PORTDISCHARGEID", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PORTDISCHARGEID", dto.DataObj.PortDischargeId, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else if (regList[j].name.Equals("PORTDISCHARGE", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PORTDISCHARGE", dto.DataObj.PortDischarge, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
else if (regList[j].name.Equals("PLACEDELIVERY", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
isSucc = CheckLabel("PLACEDELIVERY", dto.DataObj.PlaceDelivery, regList[j].val, regList[j].master, operEnum);
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
ruleList.Add(labelList[i]);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (regList[j].master)
|
|
|
break;
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (isSucc)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"标签对应到有效规则,{labelList[i].Name}");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception innEx)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"标签对应失败,{labelList[i].Name},原因:{innEx.Message}");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (ruleList.Count > 0)
|
|
|
{
|
|
|
var bindModel = new BindLabelDto
|
|
|
{
|
|
|
BusinessIdArray = new[] { id },
|
|
|
LabelIdArray = ruleList.Select(a => a.Id.Value).ToArray()
|
|
|
};
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"标签绑定请求,{JsonConvert.SerializeObject(bindModel)}");
|
|
|
|
|
|
await _bookingLabelService.SetLabel(bindModel);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"标签绑定请求完成");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Error, $"自动生成舱位标签失败,原因:{e.Message}");
|
|
|
|
|
|
return DataResult<string>.Failed(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSlotBookingNoExists)),e.Message));
|
|
|
}
|
|
|
|
|
|
return DataResult<string>.Success(string.Empty);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 判断标签识别
|
|
|
/// <summary>
|
|
|
/// 判断标签识别
|
|
|
/// </summary>
|
|
|
/// <param name="name">字段名称</param>
|
|
|
/// <param name="val">字段值</param>
|
|
|
/// <param name="checkVal">判断值</param>
|
|
|
/// <param name="isMaster">是否必校验</param>
|
|
|
/// <param name="operEnum">操作符枚举</param>
|
|
|
/// <returns>true-满足识别 false-不满足识别</returns>
|
|
|
private bool CheckLabel(string name, string val, string checkVal, bool isMaster, LabelRegexOperEnum operEnum)
|
|
|
{
|
|
|
if (operEnum == LabelRegexOperEnum.equal)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val) && val.Equals(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
else if (operEnum == LabelRegexOperEnum.startwith)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val) && val.StartsWith(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
else if (operEnum == LabelRegexOperEnum.like)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val) && val.Contains(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
else if (operEnum == LabelRegexOperEnum.notequal)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
{
|
|
|
if (!val.Equals(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (isMaster)
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else if (operEnum == LabelRegexOperEnum.notexists)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
{
|
|
|
if (!val.Contains(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (isMaster)
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else if (operEnum == LabelRegexOperEnum.notstartwith)
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(val))
|
|
|
{
|
|
|
if (!val.StartsWith(checkVal, StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (isMaster)
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 获取舱位详情
|
|
|
/// <summary>
|
|
|
/// 获取舱位详情
|
|
|
/// </summary>
|
|
|
/// <param name="id">舱位主键</param>
|
|
|
/// <returns>返回舱位详情</returns>
|
|
|
public async Task<DataResult<BookingSlotBaseSaveOutput>> Detail(long id)
|
|
|
{
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var slotBase = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(u => u.Id == id);
|
|
|
if (slotBase == null)
|
|
|
{
|
|
|
//未查询到此舱位信息,已删除或不存在
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotBaseInfoNull)));
|
|
|
}
|
|
|
var ctns = await tenantDb.Queryable<BookingSlotCtn>().Where(x => x.SlotId == id).ToListAsync();
|
|
|
|
|
|
var rtn = slotBase.Adapt<BookingSlotBaseSaveOutput>();
|
|
|
rtn.CtnList = ctns.Adapt<List<BookingSlotCtnSaveInput>>();
|
|
|
|
|
|
rtn.LogList = _logAuditService.GetAuditLogBookingList(slotBase.Id).GetAwaiter().GetResult()?.Data;
|
|
|
|
|
|
// 赋值关联的订舱列表
|
|
|
// 查询舱位绑定的销售信息,赋值到舱位对象中
|
|
|
List<BookingSlotSaleInfoDto> saleInfoList = await tenantDb.Queryable<BookingSlotAllocation>()
|
|
|
.Where(x => x.BookingSlotId == id)
|
|
|
.Select(x => new BookingSlotSaleInfoDto
|
|
|
{
|
|
|
Id = x.Id,
|
|
|
BookingId = x.BookingId,
|
|
|
BookingSlotId = x.BookingSlotId,
|
|
|
CustomerId = x.CustomerId,
|
|
|
CustomerName = x.CustomerName,
|
|
|
CustServiceId = x.CustServiceId,
|
|
|
CustService = x.CustService,
|
|
|
SaleId = x.SaleId,
|
|
|
Sale = x.Sale,
|
|
|
OpId = x.OpId,
|
|
|
Op = x.Op,
|
|
|
DocId = x.DocId,
|
|
|
Doc = x.Doc,
|
|
|
BusinessId = x.BusinessId,
|
|
|
Business = x.Business,
|
|
|
SaleTime = x.SaleTime,
|
|
|
Shipper = x.Shipper,
|
|
|
GoodsName = x.GoodsName,
|
|
|
SellingPrice = x.SellingPrice,
|
|
|
CreatedUserId = x.CreateBy
|
|
|
}).ToListAsync();
|
|
|
|
|
|
/*
|
|
|
if (saleInfoList.Any())
|
|
|
{
|
|
|
// 判断是否启用了委托单位查看控制权限
|
|
|
var tenantParamList = await _cache.GetAllTenantParam();
|
|
|
var isEnableCustomerAuthority = tenantParamList.FirstOrDefault(x => x.TenantId == UserManager.TENANT_ID
|
|
|
&& x.ParaCode == TenantParamCode.IS_ENABLE_CUSTOMER_AUTHORITY)?.ItemCode == "YES";
|
|
|
List<long> userList = null;
|
|
|
List<string> userListStr = null;
|
|
|
if (isEnableCustomerAuthority)
|
|
|
{
|
|
|
userList = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuDjyCustomer);
|
|
|
if (userList != null && userList.Count > 0)
|
|
|
{
|
|
|
userListStr = userList.Select(x => x.ToString()).ToList();
|
|
|
|
|
|
// 遍历销售信息,如果销售信息中的“销售、操作、单证、客服、创建人”中不在当前登陆人的权限范围,则隐藏客户信息
|
|
|
foreach (BookingSlotSaleInfoDto saleInfoItem in saleInfoList)
|
|
|
{
|
|
|
if (!userList.Contains(saleInfoItem.CreatedUserId ?? 0)
|
|
|
&& !userListStr.Contains(saleInfoItem.OPID)
|
|
|
&& !userListStr.Contains(saleInfoItem.DOCID)
|
|
|
&& !userListStr.Contains(saleInfoItem.SALEID)
|
|
|
&& !userListStr.Contains(saleInfoItem.CUSTSERVICEID))
|
|
|
{
|
|
|
saleInfoItem.CUSTOMERID = 0;
|
|
|
saleInfoItem.CUSTOMERNAME = "--";
|
|
|
saleInfoItem.OPID = "";
|
|
|
saleInfoItem.OP = "--";
|
|
|
saleInfoItem.DOCID = "";
|
|
|
saleInfoItem.DOC = "--";
|
|
|
saleInfoItem.SALEID = "";
|
|
|
saleInfoItem.SALE = "--";
|
|
|
saleInfoItem.SHIPPER = "--";
|
|
|
saleInfoItem.GOODSNAME = "--";
|
|
|
saleInfoItem.CUSTSERVICEID = "";
|
|
|
saleInfoItem.CUSTSERVICE = "--";
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
rtn.BookingSlotSaleInfoList = saleInfoList;
|
|
|
|
|
|
return DataResult<BookingSlotBaseSaveOutput>.Success(rtn);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 舱位接收保存、取消接口
|
|
|
/// <summary>
|
|
|
/// 舱位接收保存、取消接口
|
|
|
/// </summary>
|
|
|
/// <param name="jsonData">请求详情(JSON)</param>
|
|
|
/// <param name="file">BC附件</param>
|
|
|
/// <param name="modifyFile">BC修改附件</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<long>> ApiReceive(string jsonData, IFormFile file = null, IFormFile modifyFile = null)
|
|
|
{
|
|
|
long id = 0;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"jsonData={jsonData} 接收请求舱位报文");
|
|
|
|
|
|
BookingSlotBaseApiDto dto = JsonConvert.DeserializeObject<BookingSlotBaseApiDto>(jsonData);
|
|
|
|
|
|
DynameFileInfo bcFile = null;
|
|
|
DynameFileInfo bcNoticeFile = null;
|
|
|
|
|
|
if (file != null)
|
|
|
{
|
|
|
bcFile = new DynameFileInfo
|
|
|
{
|
|
|
FileBytes = file.ToByteArray(),
|
|
|
FileName = file.FileName
|
|
|
};
|
|
|
}
|
|
|
|
|
|
if (modifyFile != null)
|
|
|
{
|
|
|
bcNoticeFile = new DynameFileInfo
|
|
|
{
|
|
|
FileBytes = modifyFile.ToByteArray(),
|
|
|
FileName = modifyFile.FileName
|
|
|
};
|
|
|
}
|
|
|
|
|
|
var rlt = await InnerApiReceive(dto, bcFile, bcNoticeFile);
|
|
|
|
|
|
id = rlt.Data;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Error, $"执行舱位失败,原因:{ex.Message}");
|
|
|
|
|
|
return DataResult<long>.FailedData(id, string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotApiReceiveError)), ex.Message));
|
|
|
}
|
|
|
|
|
|
if (id == 0)
|
|
|
return DataResult<long>.FailedData(id);
|
|
|
|
|
|
return DataResult<long>.Success(id);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 舱位接收保存、取消接口(内部接口)
|
|
|
/// <summary>
|
|
|
/// 舱位接收保存、取消接口(内部接口)
|
|
|
/// </summary>
|
|
|
/// <param name="dto">舱位详情</param>
|
|
|
/// <param name="file">原文件</param>
|
|
|
/// <param name="modifyFile">修改文件</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<long>> InnerApiReceive(BookingSlotBaseApiDto dto, DynameFileInfo file = null, DynameFileInfo modifyFile = null)
|
|
|
{
|
|
|
long id = 0;
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
//接口方法直接调用save、delete等方法会报错,可能因为非token授权登录导致,故重写一遍保存、删除代码
|
|
|
if (dto.OpType == "add" || dto.OpType == "update" || dto.OpType == "del" || dto.OpType == "cancellation")
|
|
|
{
|
|
|
//翻译船公司
|
|
|
if (!string.IsNullOrWhiteSpace(dto.DataObj.CarrierCode) && string.IsNullOrWhiteSpace(dto.DataObj.CarrierCode))
|
|
|
{
|
|
|
var allCarrierList = await _mappingCarrierService.GetAllList();
|
|
|
|
|
|
if (allCarrierList.Succeeded)
|
|
|
{
|
|
|
var carrierInfo = allCarrierList.Data.Where(t => t.Code.Equals(dto.DataObj.CarrierCode, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
|
|
|
|
|
if (carrierInfo != null)
|
|
|
{
|
|
|
dto.DataObj.Carrier = carrierInfo.MapName?.Trim();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//翻译箱型代码
|
|
|
if (dto.DataObj.CtnList != null && dto.DataObj.CtnList.Count > 0 &&
|
|
|
dto.DataObj.CtnList.Any(t => string.IsNullOrWhiteSpace(t.CtnCode)))
|
|
|
{
|
|
|
List<CodeCtnRes> ctnCodeList = new List<CodeCtnRes>();
|
|
|
|
|
|
var allCtnCodeList = await _codeCtnService.GetAllList();
|
|
|
|
|
|
if (allCtnCodeList.Succeeded)
|
|
|
{
|
|
|
ctnCodeList = allCtnCodeList.Data;
|
|
|
}
|
|
|
|
|
|
dto.DataObj.CtnList.ForEach(t =>
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(t.CtnAll) && string.IsNullOrWhiteSpace(t.CtnCode))
|
|
|
{
|
|
|
var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) &&
|
|
|
a.CtnName.Equals(t.CtnAll, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (ctnCode != null)
|
|
|
t.CtnCode = $"{ctnCode.CtnSize}{ctnCode.CtnType}";
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
List<CodePortRes> portCodeList = new List<CodePortRes>();
|
|
|
|
|
|
// 解析收货地,得到装货港名称及五字码
|
|
|
if (!string.IsNullOrWhiteSpace(dto.DataObj.PlaceReceipt))
|
|
|
{
|
|
|
var portEnName = dto.DataObj.PlaceReceipt.Split(',')[0]?.Trim();
|
|
|
|
|
|
//这里CMA的收货地全称放在了括号里面
|
|
|
if (dto.DataObj.CarrierCode.Equals("CMA", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(dto.DataObj.PlaceReceipt))
|
|
|
dto.DataObj.PlaceReceipt = dto.DataObj.PlaceReceipt.Replace("(", "(").Replace(")", ")");
|
|
|
|
|
|
if (dto.DataObj.PlaceReceipt.IndexOf("(") >= 0)
|
|
|
{
|
|
|
string currStr = Regex.Match(dto.DataObj.PlaceReceipt, "(?<=\\().*(?=\\))").Value?.Trim();
|
|
|
|
|
|
portEnName = currStr.Split(',')[0]?.Trim();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(portEnName))
|
|
|
{
|
|
|
var allPortCodeList = await _codePortService.GetAllList();
|
|
|
|
|
|
if (allPortCodeList.Succeeded)
|
|
|
{
|
|
|
portCodeList = allPortCodeList.Data;
|
|
|
}
|
|
|
|
|
|
//var cachePortLoad = await _cache.GetAllCodePortLoad();
|
|
|
var portInfo = await PlaceReceiptToPortload(portEnName, portCodeList, () => _mappingPortService.GetAllList());
|
|
|
|
|
|
if (!portInfo.Succeeded)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"通过收货地城市名称未匹配到港口信息,订舱编号:{dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
dto.DataObj.PortLoad = portInfo.Data.PortName;
|
|
|
dto.DataObj.PortLoadId = portInfo.Data.EdiCode;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"收货地分割后得到的城市名称为空,订舱编号:{dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"收货地为空,订舱编号:{dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
|
|
|
|
|
|
// 解析交货地,得到为卸货港名称及五字码, 以及国家信息
|
|
|
if (!string.IsNullOrWhiteSpace(dto.DataObj.PlaceDelivery))
|
|
|
{
|
|
|
var portEnName = dto.DataObj.PlaceDelivery.Split(',')[0]?.Trim();
|
|
|
|
|
|
//这里CMA的收货地全称放在了括号里面
|
|
|
if (dto.DataObj.CarrierCode.Equals("CMA", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
if (!string.IsNullOrWhiteSpace(dto.DataObj.PlaceDelivery))
|
|
|
dto.DataObj.PlaceDelivery = dto.DataObj.PlaceDelivery.Replace("(", "(").Replace(")", ")");
|
|
|
|
|
|
if (dto.DataObj.PlaceDelivery.IndexOf("(") >= 0)
|
|
|
{
|
|
|
string currStr = Regex.Match(dto.DataObj.PlaceDelivery, "(?<=\\().*(?=\\))").Value?.Trim();
|
|
|
|
|
|
portEnName = currStr.Split(',')[0]?.Trim();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(portEnName))
|
|
|
{
|
|
|
if (portCodeList.Count == 0)
|
|
|
{
|
|
|
var allPortCodeList = await _codePortService.GetAllList();
|
|
|
|
|
|
if (allPortCodeList.Succeeded)
|
|
|
{
|
|
|
portCodeList = allPortCodeList.Data;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var portInfo = await PlaceDeliveryToPort(portEnName, portCodeList, () => _mappingPortService.GetAllList());
|
|
|
|
|
|
if (portInfo.Succeeded)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"通过交货地城市名称未匹配到港口信息,订舱编号:{dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var allCountryCodeList = await _codeCountryService.GetAllList();
|
|
|
|
|
|
if(allCountryCodeList.Succeeded)
|
|
|
{
|
|
|
var countryInfo = allCountryCodeList.Data.FirstOrDefault(p => p.Id == portInfo.Data.CountryId);
|
|
|
|
|
|
|
|
|
dto.DataObj.PortDischargeCountry = countryInfo?.CountryEnName;
|
|
|
dto.DataObj.PortDischargeCountryCode = countryInfo?.CountryCode;
|
|
|
}
|
|
|
|
|
|
dto.DataObj.PortDischarge = portInfo.Data.PortName;
|
|
|
dto.DataObj.PortDischargeId = portInfo.Data.EdiCode;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"交货地分割后得到的城市名称为空,订舱编号:{ dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"交货地为空,订舱编号:{dto.DataObj.SlotBookingNo}");
|
|
|
}
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(dto.DataObj.CtnStat))
|
|
|
{
|
|
|
if (dto.DataObj.CtnList != null && dto.DataObj.CtnList.Count > 0)
|
|
|
{
|
|
|
dto.DataObj.CtnStat = string.Join(",", dto.DataObj.CtnList.GroupBy(a => a.CtnAll).Select(a =>
|
|
|
$"{a.Key}*{a.Select(b => b.CtnNum).Sum()}").ToArray());
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//自动转换对应标签
|
|
|
|
|
|
BookingSlotBase model = null;
|
|
|
if (dto.OpType == "add")
|
|
|
{
|
|
|
var c = tenantDb.Queryable<BookingSlotBase>().Where(x => x.SlotBookingNo == dto.DataObj.SlotBookingNo).Count();
|
|
|
if (c > 0)
|
|
|
{
|
|
|
//订舱提单号已存在
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSlotBookingNoExists)));
|
|
|
}
|
|
|
|
|
|
model = dto.DataObj.Adapt<BookingSlotBase>();
|
|
|
await tenantDb.Insertable<BookingSlotBase>(model).ExecuteReturnEntityAsync();
|
|
|
|
|
|
id = model.Id;
|
|
|
|
|
|
foreach (var ctn in dto.DataObj.CtnList)
|
|
|
{
|
|
|
var newCtn = ctn.Adapt<BookingSlotCtn>();
|
|
|
newCtn.SlotId = model.Id;
|
|
|
await tenantDb.Insertable<BookingSlotCtn>(newCtn).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
//await InsLog("Add", model.Id, "新增舱位");
|
|
|
|
|
|
string batchNo = GuidHelper.GetSnowflakeId();
|
|
|
|
|
|
//处理附件
|
|
|
if (file != null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"请求文件名:{file.FileName}");
|
|
|
|
|
|
var fileRlt = await _sysFileService.SaveFileDirect(model.Id.ToString(), file.FileBytes, batchNo, file.FileName, "bcfiles");
|
|
|
|
|
|
var fileFullPath = fileRlt.Data;
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"保存文件路径:{fileFullPath}");
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileFullPath))
|
|
|
{
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, fileFullPath, file.FileName, long.Parse(user.TenantId),
|
|
|
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (modifyFile != null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"请求文件名(变更文件):{modifyFile.FileName}");
|
|
|
|
|
|
var fileRlt = await _sysFileService.SaveFileDirect(model.Id.ToString(), modifyFile.FileBytes, batchNo, modifyFile.FileName, "bcnoticefiles");
|
|
|
|
|
|
var fileFullPath = fileRlt.Data;
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"保存文件路径(变更文件):{fileFullPath}");
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileFullPath))
|
|
|
{
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, fileFullPath, modifyFile.FileName, long.Parse(user.TenantId),
|
|
|
CONST_BC_NOTICE_FILE_CODE, CONST_BC_NOTICE_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//触发标签自动绑定
|
|
|
await GenerateSlotLabel(dto, id);
|
|
|
}
|
|
|
else if (dto.OpType == "update")
|
|
|
{
|
|
|
model = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(x => x.SlotBookingNo == dto.DataObj.SlotBookingNo);
|
|
|
if (model == null)
|
|
|
{
|
|
|
//throw Oops.Bah($"未找到订舱编号为 {dto.DataObj.SlotBookingNo} 的数据");
|
|
|
}
|
|
|
|
|
|
id = model.Id;
|
|
|
|
|
|
//生成待比对详情
|
|
|
ParserBCInfoDto bcSrcDto = new ParserBCInfoDto();
|
|
|
|
|
|
try
|
|
|
{
|
|
|
bcSrcDto = model.Adapt<ParserBCInfoDto>();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"slotId={model.Id} 映射数据库对象请求对应异常,原因:{ex.Message}");
|
|
|
|
|
|
//throw Oops.Bah($"slotId={model.Id} 映射数据库对象请求对应异常,原因:{ex.Message}");
|
|
|
}
|
|
|
|
|
|
ParserBCInfoDto bcTargetDto = new ParserBCInfoDto();
|
|
|
|
|
|
try
|
|
|
{
|
|
|
bcTargetDto = dto.DataObj.Adapt<ParserBCInfoDto>();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"slotId={model.Id} 映射推送的舱位请求对应异常,原因:{ex.Message}");
|
|
|
|
|
|
//throw Oops.Bah($"slotId={model.Id} 映射推送的舱位请求对应异常,原因:{ex.Message}");
|
|
|
}
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"slotId={model.Id} 开始处理重要提醒");
|
|
|
//执行差异重要提醒
|
|
|
//await MeasureDiffCautionTask(bcSrcDto, bcTargetDto, model.Id);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"slotId={model.Id} 处理重要提醒结束");
|
|
|
|
|
|
//提取箱信息
|
|
|
var ctnList = tenantDb.Queryable<BookingSlotCtn>()
|
|
|
.Where(x => x.SlotId == model.Id).ToList();
|
|
|
|
|
|
if (ctnList != null)
|
|
|
{
|
|
|
bcSrcDto.CtnList = ctnList.GroupBy(x => x.CtnAll)
|
|
|
.Select(x =>
|
|
|
{
|
|
|
return new ParserBCCTNInfoDto
|
|
|
{
|
|
|
CtnALL = x.Key,
|
|
|
CtnNum = x.ToList()
|
|
|
.Sum(a => a.CtnNum)
|
|
|
};
|
|
|
}).ToList();
|
|
|
}
|
|
|
|
|
|
if (dto.DataObj.CtnList != null && dto.DataObj.CtnList.Count > 0)
|
|
|
{
|
|
|
bcTargetDto.CtnList = dto.DataObj.CtnList.GroupBy(x => x.CtnAll)
|
|
|
.Select(x =>
|
|
|
{
|
|
|
return new ParserBCCTNInfoDto
|
|
|
{
|
|
|
CtnALL = x.Key,
|
|
|
CtnNum = x.ToList()
|
|
|
.Sum(a => a.CtnNum)
|
|
|
};
|
|
|
}).ToList();
|
|
|
}
|
|
|
|
|
|
var oldObj = model.Adapt<BookingSlotBaseApiSaveDto>();
|
|
|
|
|
|
dto.DataObj.Adapt(model);
|
|
|
|
|
|
// 1.判断新的舱位信息的7个库存统计维度是否发生变化
|
|
|
// 2.如果有变化,则需要更新旧的库存信息
|
|
|
bool isNeedUpdateOldStock = false;
|
|
|
if (oldObj.Vessel != model.Vessel
|
|
|
|| oldObj.Voyno != model.Voyno
|
|
|
|| oldObj.BookingSlotType != model.BookingSlotType
|
|
|
|| oldObj.CarrierId != model.CarrierId
|
|
|
|| oldObj.PortLoadId != model.PortLoadCode
|
|
|
|| oldObj.PortDischargeId != model.PortDischargeCode)
|
|
|
{
|
|
|
isNeedUpdateOldStock = true;
|
|
|
}
|
|
|
await tenantDb.Updateable<BookingSlotBase>(model).ExecuteCommandAsync();
|
|
|
|
|
|
if (isNeedUpdateOldStock)
|
|
|
{
|
|
|
//BookingSlotStock:Update
|
|
|
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
|
|
|
{
|
|
|
BookingSlotType = oldObj.BookingSlotType,
|
|
|
CarrierCode = oldObj.CarrierCode,
|
|
|
ContractNo = oldObj.ContractNo,
|
|
|
Vessel = oldObj.Vessel,
|
|
|
Voyno = oldObj.Voyno,
|
|
|
PortLoadId = oldObj.PortLoadId,
|
|
|
PortDischargeId = oldObj.PortDischargeId,
|
|
|
TenantId = long.Parse(user.TenantId)
|
|
|
});
|
|
|
}
|
|
|
|
|
|
var currCtnList = await tenantDb.Queryable<BookingSlotCtn>().Where(p => p.SlotId == model.Id).ToListAsync();
|
|
|
|
|
|
if (currCtnList.Count > 0)
|
|
|
{
|
|
|
currCtnList.ForEach(async p =>
|
|
|
{
|
|
|
await tenantDb.Deleteable<BookingSlotCtn>(p).ExecuteCommandAsync();
|
|
|
});
|
|
|
}
|
|
|
|
|
|
foreach (var ctn in dto.DataObj.CtnList)
|
|
|
{
|
|
|
var newCtn = ctn.Adapt<BookingSlotCtn>();
|
|
|
newCtn.SlotId = model.Id;
|
|
|
await tenantDb.Insertable<BookingSlotCtn>(newCtn).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
//await InsLog("Update", model.Id, typeof(BookingSlotBaseApiSaveDto), oldObj, dto.DataObj, nameof(BookingSlotBaseApiSaveDto.CtnList), nameof(BookingSlotBaseApiSaveDto.BookingSlotSaleInfoList));
|
|
|
|
|
|
string batchNo = GuidHelper.GetSnowflakeId();
|
|
|
|
|
|
//处理附件
|
|
|
if (file != null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"请求文件名:{file.FileName}");
|
|
|
|
|
|
var fileRlt = await _sysFileService.SaveFileDirect(model.Id.ToString(), file.FileBytes, batchNo, file.FileName, "bcmoidfyfiles");
|
|
|
|
|
|
var fileFullPath = fileRlt.Data;
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"保存文件路径:{fileFullPath}");
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileFullPath))
|
|
|
{
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, fileFullPath, file.FileName, long.Parse(user.TenantId),
|
|
|
CONST_BC_MODIFY_FILE_CODE, CONST_BC_MODIFY_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (modifyFile != null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"请求文件名(变更文件):{modifyFile.FileName}");
|
|
|
|
|
|
var fileRlt = await _sysFileService.SaveFileDirect(model.Id.ToString(), modifyFile.FileBytes, batchNo, modifyFile.FileName, "bcmodifynoticefiles");
|
|
|
|
|
|
var fileFullPath = fileRlt.Data;
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"保存文件路径(变更文件):{fileFullPath}");
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(fileFullPath))
|
|
|
{
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, fileFullPath, modifyFile.FileName, long.Parse(user.TenantId),
|
|
|
CONST_BC_MODIFY_NOTICE_FILE_CODE, CONST_BC_MODIFY_NOTICE_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//一般更新数据指的是Booking Amendment,需要与舱位进行数据比对
|
|
|
await PushCompareBCInfo(bcSrcDto, bcTargetDto, id, dto.BatchNo);
|
|
|
|
|
|
//触发标签自动绑定
|
|
|
await GenerateSlotLabel(dto, id);
|
|
|
}
|
|
|
else if (dto.OpType == "del")
|
|
|
{
|
|
|
var slotNO = dto.DataObj.SlotBookingNo;
|
|
|
model = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(x => x.SlotBookingNo == slotNO);
|
|
|
if (model == null)
|
|
|
{
|
|
|
//throw Oops.Bah($"未找到订舱编号为 {slotNO} 的数据");
|
|
|
}
|
|
|
|
|
|
id = model.Id;
|
|
|
|
|
|
model.Deleted = true;
|
|
|
await tenantDb.Updateable<BookingSlotBase>(model).ExecuteCommandAsync();
|
|
|
|
|
|
var ctns = await tenantDb.Queryable<BookingSlotCtn>().Where(x => x.SlotId == model.Id).ToListAsync();
|
|
|
foreach (var ctn in ctns)
|
|
|
{
|
|
|
ctn.Deleted = true;
|
|
|
await tenantDb.Updateable<BookingSlotCtn>(ctn).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
//await InsLog("Del", model.Id, "取消舱位");
|
|
|
}
|
|
|
else if (dto.OpType == "cancellation")
|
|
|
{
|
|
|
// 更新标志
|
|
|
var slotNO = dto.DataObj.SlotBookingNo;
|
|
|
model = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(x => x.SlotBookingNo == slotNO);
|
|
|
if (model == null)
|
|
|
{
|
|
|
//throw Oops.Bah($"未找到订舱编号为 {slotNO} 的数据");
|
|
|
}
|
|
|
|
|
|
id = model.Id;
|
|
|
model.IsCancellation = true;
|
|
|
model.CancellationDate = DateTime.Now;
|
|
|
await tenantDb.Updateable<BookingSlotBase>(model).EnableDiffLogEvent().ExecuteCommandAsync();
|
|
|
|
|
|
// 删除该舱位相关的订舱关联关系
|
|
|
var slotList = await tenantDb.Queryable<BookingSlotAllocation>().Where(a => a.BookingSlotId == id).ToListAsync();
|
|
|
var slotIdList = slotList.Select(s => s.Id);
|
|
|
|
|
|
await tenantDb.Updateable<BookingSlotAllocation>()
|
|
|
.SetColumns(a => a.Deleted == true)
|
|
|
.SetColumns(a => a.UpdateTime == DateTime.Now)
|
|
|
.SetColumns(a => a.UpdateBy == long.Parse(user.UserId))
|
|
|
//.SetColumns(a => a.UpdatedUserName == UserManager.Name)
|
|
|
.Where(a => slotIdList.Contains(a.Id))
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
await tenantDb.Updateable<BookingSlotAllocationCtn>()
|
|
|
.SetColumns(a => a.Deleted == true)
|
|
|
.SetColumns(a => a.UpdateTime == DateTime.Now)
|
|
|
.SetColumns(a => a.UpdateBy == long.Parse(user.UserId))
|
|
|
//.SetColumns(a => a.UpdatedUserName == UserManager.Name)
|
|
|
.Where(a => slotIdList.Contains(a.SlotAllocId))
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
//await InsLog("Cancellation", model.Id, "取消舱位");
|
|
|
}
|
|
|
|
|
|
//更新库存
|
|
|
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
|
|
|
{
|
|
|
BookingSlotType = model.BookingSlotType,
|
|
|
CarrierCode = model.CarrierCode,
|
|
|
ContractNo = model.ContractNo,
|
|
|
Vessel = model.Vessel,
|
|
|
Voyno = model.Voyno,
|
|
|
PortLoadId = model.PortLoadCode,
|
|
|
PortDischargeId = model.PortDischargeCode,
|
|
|
TenantId = long.Parse(user.TenantId)
|
|
|
});
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//throw Oops.Bah("操作类型参数有误");
|
|
|
}
|
|
|
|
|
|
|
|
|
if(id == 0)
|
|
|
return DataResult<long>.FailedData(id);
|
|
|
|
|
|
return DataResult<long>.Success(id);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 异步写入附件表
|
|
|
/// <summary>
|
|
|
/// 异步写入附件表
|
|
|
/// </summary>
|
|
|
/// <param name="boookId">订舱ID</param>
|
|
|
/// <param name="FilePath">文件路径</param>
|
|
|
/// <param name="fileName">文件名</param>
|
|
|
/// <param name="tenantId">租户ID</param>
|
|
|
/// <param name="fileTypeCode">附件类型代码</param>
|
|
|
/// <param name="fileTypeName">附件类型名称</param>
|
|
|
/// <param name="moudle">附件模块代码</param>
|
|
|
/// <returns></returns>
|
|
|
private async Task SaveEDIFile(long boookId, string FilePath, string fileName, long tenantId,
|
|
|
string fileTypeCode = "bc", string fileTypeName = "Booking Confirmation", string moudle = "BookingSlot")
|
|
|
{
|
|
|
/*
|
|
|
直接将附件信息写入附件表
|
|
|
*/
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var newFile = new OpFile
|
|
|
{
|
|
|
Id = SnowFlakeSingle.Instance.NextId(),
|
|
|
FileName = fileName,
|
|
|
FilePath = FilePath,
|
|
|
TypeCode = fileTypeCode,
|
|
|
TypeName = fileTypeName,
|
|
|
LinkId = boookId,
|
|
|
};
|
|
|
|
|
|
await tenantDb.Insertable(newFile).ExecuteCommandAsync();
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 根据收货地港口英文名解析出起始港对象
|
|
|
/// <summary>
|
|
|
/// 根据收货地港口英文名解析出起始港对象
|
|
|
/// </summary>
|
|
|
/// <param name="portEnName">收货地港口英文名</param>
|
|
|
/// <param name="cachePortLoad">起始港缓存</param>
|
|
|
/// <param name="cacheMapPortLoadFunc">起始港缓存映射</param>
|
|
|
/// <returns>起始港对象</returns>
|
|
|
private async Task<DataResult<CodePortRes>> PlaceReceiptToPortload(string portEnName, List<CodePortRes> cachePortLoad, Func<Task<DataResult<List<MappingPortRes>>>> cacheMapPortLoadFunc)
|
|
|
{
|
|
|
CodePortRes portInfo = null;
|
|
|
|
|
|
if (string.IsNullOrEmpty(portEnName))
|
|
|
{
|
|
|
return DataResult<CodePortRes>.FailedData(portInfo);
|
|
|
}
|
|
|
|
|
|
// 匹配方式1:精准匹配
|
|
|
portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式2:起始模糊匹配
|
|
|
portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式3:完整模糊匹配
|
|
|
portInfo = cachePortLoad.FirstOrDefault(x => x.PortName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式4:精准映射匹配
|
|
|
var mapCachePortLoad = await cacheMapPortLoadFunc();
|
|
|
var map = mapCachePortLoad.Data.FirstOrDefault(x => x.Module == RECEIPT_TO_PORTLOAD
|
|
|
&& x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (map != null)
|
|
|
{
|
|
|
portInfo = cachePortLoad.FirstOrDefault(x => x.Id == map.LinkId);
|
|
|
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
}
|
|
|
|
|
|
return DataResult<CodePortRes>.FailedData(portInfo);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 根据交货地港口英文名解析出目的港对象
|
|
|
/// <summary>
|
|
|
/// 根据交货地港口英文名解析出目的港对象
|
|
|
/// </summary>
|
|
|
/// <param name="portEnName">交货地港口英文名</param>
|
|
|
/// <param name="cachePort">目的港缓存</param>
|
|
|
/// <param name="cacheMapPortFunc">目的港缓存映射</param>
|
|
|
/// <returns>目的港对象</returns>
|
|
|
private async Task<DataResult<CodePortRes>> PlaceDeliveryToPort(string portEnName, List<CodePortRes> cachePort, Func<Task<DataResult<List<MappingPortRes>>>> cacheMapPortFunc)
|
|
|
{
|
|
|
CodePortRes portInfo = null;
|
|
|
|
|
|
if (string.IsNullOrEmpty(portEnName))
|
|
|
{
|
|
|
return DataResult<CodePortRes>.FailedData(portInfo);
|
|
|
}
|
|
|
|
|
|
// 匹配方式1:精准匹配
|
|
|
portInfo = cachePort.FirstOrDefault(x => x.PortName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式2:起始模糊匹配
|
|
|
portInfo = cachePort.FirstOrDefault(x => x.PortName.StartsWith(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式3:完整模糊匹配
|
|
|
portInfo = cachePort.FirstOrDefault(x => x.PortName.Contains(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
|
|
|
// 匹配方式4:精准映射匹配
|
|
|
var mapCachePort = await cacheMapPortFunc();
|
|
|
var map = mapCachePort.Data.FirstOrDefault(x => x.Module == DELIVERY_TO_PORT
|
|
|
&& x.MapName.Equals(portEnName, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (map != null)
|
|
|
{
|
|
|
portInfo = cachePort.FirstOrDefault(x => x.Id == map.LinkId);
|
|
|
|
|
|
if (portInfo != null) return DataResult<CodePortRes>.Success(portInfo);
|
|
|
}
|
|
|
|
|
|
return DataResult<CodePortRes>.FailedData(portInfo);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 推送BC变更比对
|
|
|
/// <summary>
|
|
|
/// 推送BC变更比对
|
|
|
/// </summary>
|
|
|
/// <param name="bcSrcDto">原舱位详情</param>
|
|
|
/// <param name="bcTargetDto">变更后舱位详情</param>
|
|
|
/// <param name="slotId">舱位主键</param>
|
|
|
/// <param name="reqBatchNo">请求批次号用来区分对应的哪个批次任务</param>
|
|
|
/// <returns></returns>
|
|
|
[NonAction]
|
|
|
public async Task PushCompareBCInfo(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto, long slotId, string reqBatchNo)
|
|
|
{
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
string batchNo = GuidHelper.GetSnowflakeId();
|
|
|
|
|
|
DateTime bDate = DateTime.Now;
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"批次={batchNo} slotId={slotId} 开始请求比对结果");
|
|
|
|
|
|
var compareResult = await ExcuteCompare(bcSrcDto, bcTargetDto);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"批次={batchNo} slotId={slotId} 请求比对结果完成,结果={JsonConvert.SerializeObject(compareResult)}");
|
|
|
|
|
|
DateTime eDate = DateTime.Now;
|
|
|
TimeSpan ts = eDate.Subtract(bDate);
|
|
|
var timeDiff = ts.TotalMilliseconds;
|
|
|
|
|
|
if (compareResult != null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, "批次={no} 请求完成,耗时:{timeDiff}ms. 结果{msg}", batchNo, timeDiff, compareResult.succ ? "成功" : "失败");
|
|
|
}
|
|
|
|
|
|
if (compareResult != null)
|
|
|
{
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
var hisInfo = tenantDb.Queryable<BookingSlotCompare>().First(a => a.CompareBatchNo == reqBatchNo);
|
|
|
|
|
|
if (hisInfo == null)
|
|
|
{
|
|
|
BookingSlotCompare entity = new BookingSlotCompare
|
|
|
{
|
|
|
SlotId = slotId,
|
|
|
CompareBatchNo = reqBatchNo,
|
|
|
CompareDiffNum = compareResult.extra.IsExistsDiff ? compareResult.extra.ShowDetailList.Count : 0,
|
|
|
CreateTime = nowDate,
|
|
|
UpdateTime = nowDate,
|
|
|
CreateBy = long.Parse(user.UserId),
|
|
|
//CreatedUserName = UserManager.Name,
|
|
|
UpdateBy = long.Parse(user.UserId),
|
|
|
//UpdatedUserName = UserManager.Name,
|
|
|
CompareType = "BC_MODIFY",
|
|
|
CompareRlt = JsonConvert.SerializeObject(compareResult.extra.ShowDetailList),
|
|
|
};
|
|
|
|
|
|
await tenantDb.Insertable<BookingSlotCompare>(entity).ExecuteCommandAsync();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
hisInfo.CompareDiffNum = compareResult.extra.IsExistsDiff ? compareResult.extra.ShowDetailList.Count : 0;
|
|
|
hisInfo.UpdateTime = nowDate;
|
|
|
hisInfo.UpdateBy = long.Parse(user.UserId);
|
|
|
//hisInfo.UpdatedUserName = user.UserName;
|
|
|
|
|
|
hisInfo.CompareRlt = JsonConvert.SerializeObject(compareResult.extra.ShowDetailList);
|
|
|
|
|
|
await tenantDb.Updateable<BookingSlotCompare>(hisInfo).UpdateColumns(it =>
|
|
|
new
|
|
|
{
|
|
|
it.CompareDiffNum,
|
|
|
it.CompareRlt,
|
|
|
it.UpdateTime,
|
|
|
it.UpdateBy,
|
|
|
//it.UpdatedUserName
|
|
|
}).ExecuteCommandAsync();
|
|
|
}
|
|
|
//throw Oops.Oh($"舱位主键{slotId}请求BC比对失败,返回为空");
|
|
|
|
|
|
//if (compareResult.extra.ShowDetailList == null || compareResult.extra.ShowDetailList.Count == 0)
|
|
|
//{
|
|
|
// new EmailNoticeHelper().SendEmailNotice($"MBLNO={bcSrcDto.MBLNo} 与舱位比对差异失败,比对结果为0", $"MBLNO={bcSrcDto.MBLNo} 与舱位比对差异失败,比对结果为0", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList());
|
|
|
//}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//new EmailNoticeHelper().SendEmailNotice($"MBLNO={bcSrcDto.MBLNo} 与舱位比对差异失败,未获取到比对结果", $"MBLNO={bcSrcDto.MBLNo} 与舱位比对差异失败,未获取到比对结果", App.Configuration["EmailNoticeDefaultUser"].GetUserEmailList());
|
|
|
}
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 请求BC比对
|
|
|
/// <summary>
|
|
|
/// 请求BC比对
|
|
|
/// </summary>
|
|
|
/// <param name="bcSrcDto">BC详情</param>
|
|
|
/// <param name="bcTargetDto">BC变更后详情</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
[NonAction]
|
|
|
public async Task<TaskManageExcuteResultDto> ExcuteCompare(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto)
|
|
|
{
|
|
|
TaskManageExcuteResultDto model = null;
|
|
|
/*
|
|
|
1、读取配置文件中的规则引擎URL
|
|
|
2、填充请求的类,并生成JSON报文
|
|
|
3、POST请求接口,并记录回执。
|
|
|
4、返回信息。
|
|
|
*/
|
|
|
|
|
|
var url = bcCompareUrl; //App.Configuration["BCCompareUrl"];
|
|
|
|
|
|
using (var httpClient = new HttpClient())
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
using (var reduceAttach = new MultipartFormDataContent())
|
|
|
{
|
|
|
var dataContent = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(bcSrcDto)));
|
|
|
|
|
|
dataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
|
|
|
{
|
|
|
Name = "srcJson"
|
|
|
};
|
|
|
|
|
|
reduceAttach.Add(dataContent);
|
|
|
|
|
|
var dataContent2 = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(bcTargetDto)));
|
|
|
|
|
|
dataContent2.Headers.ContentDisposition = new ContentDispositionHeaderValue($"form-data")
|
|
|
{
|
|
|
Name = "destJson"
|
|
|
};
|
|
|
|
|
|
reduceAttach.Add(dataContent2);
|
|
|
|
|
|
//请求
|
|
|
var response = httpClient.PostAsync(url, reduceAttach).Result;
|
|
|
|
|
|
var result = response.Content.ReadAsStringAsync().Result;
|
|
|
|
|
|
model = JsonConvert.DeserializeObject<TaskManageExcuteResultDto>(result);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"推送BC比返回结果:{JsonConvert.SerializeObject(model)}");
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Error, "推送BC比对异常,原因:{error}", ex.Message);
|
|
|
|
|
|
// throw Oops.Oh($"推送BC比对异常,原因:{ex.Message}");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return model;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 获取合票详情(生成合票需要先调此方法)
|
|
|
/// <summary>
|
|
|
/// 获取合票详情(生成合票需要先调此方法)
|
|
|
/// </summary>
|
|
|
/// <param name="model"></param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<BookingSlotMergeResultDto> GetMergeList(QueryMergeSlotDto model)
|
|
|
{
|
|
|
BookingSlotMergeResultDto rlt = new BookingSlotMergeResultDto();
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
List<BookingSlotBase> slotList = new List<BookingSlotBase>();
|
|
|
if (model != null)
|
|
|
{
|
|
|
/*
|
|
|
合票时需要校对的内容
|
|
|
*/
|
|
|
//船公司、船名场次、合约号、承运方式(直达、中转)、订舱方式(合约订舱)、装货地、卸货地
|
|
|
slotList = tenantDb.Queryable<BookingSlotBase>().Where(a => model.MergeList.Contains(a.Id) && a.Deleted == false).ToList();
|
|
|
|
|
|
//校验查询结果
|
|
|
if (model.MergeList.Count != slotList.Count)
|
|
|
{
|
|
|
var lostArg = model.MergeList.GroupJoin(slotList, l => l, r => r.Id, (l, r) =>
|
|
|
{
|
|
|
var currList = r.ToList();
|
|
|
|
|
|
if (currList.Count == 0)
|
|
|
return 0;
|
|
|
|
|
|
return l;
|
|
|
}).Where(a => a > 0).ToArray();
|
|
|
|
|
|
//部分舱位信息提取失败,请确认舱位是否存在或已作废
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckPartRecordDeletedOrNoExists)));
|
|
|
}
|
|
|
|
|
|
if (slotList.Any(a => string.IsNullOrWhiteSpace(a.CarrierCode)
|
|
|
|| string.IsNullOrWhiteSpace(a.Vessel) || string.IsNullOrWhiteSpace(a.Voyno) || (!a.BookingSlotType.Equals("SPOT_ORDER") && string.IsNullOrWhiteSpace(a.ContractNo))
|
|
|
|| string.IsNullOrWhiteSpace(a.CarriageType) || string.IsNullOrWhiteSpace(a.BookingSlotType)
|
|
|
|| string.IsNullOrWhiteSpace(a.PortLoadCode) || string.IsNullOrWhiteSpace(a.PortDischargeCode)))
|
|
|
{
|
|
|
//舱位合票校验失败,部分舱位的以下信息船公司、船名场次、合约号、承运方式、订舱方式、装货地、卸货地有空值情况
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckPartRecordNoConsistent)));
|
|
|
}
|
|
|
|
|
|
var checkList = slotList.Select(a => new
|
|
|
{
|
|
|
key = $"{a.CarrierCode}_{a.Vessel}_{a.Voyno}_{a.ContractNo}_{a.CarriageType}_{a.BookingSlotType}_{a.PortLoadCode}_{a.PortDischargeCode}",
|
|
|
obj = a
|
|
|
}).ToList();
|
|
|
|
|
|
//如果汇总去重不惟一,不能进行合票操作
|
|
|
if (checkList.GroupBy(a => a.key).Count() > 1)
|
|
|
{
|
|
|
//舱位合票校验失败,船公司、船名场次、合约号、承运方式、订舱方式、装货地、卸货地不统一不能合票
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckPartRecordNoConsistentFail)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var list = await GetAvailableSlots(null, model.MergeList, null);
|
|
|
|
|
|
//舱位合票失败,校验库存为不可用,请确认正确的库存
|
|
|
if (list.Count == 0)
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckStockEmpty)));
|
|
|
|
|
|
//这里取完库存后,在跟请求的舱位做匹配,如果舱位没有库存了,提示错误终止合票
|
|
|
var stockCheckList = slotList.GroupJoin(list, l => l.Id, r => r.Id, (l, r) =>
|
|
|
{
|
|
|
var currList = r.ToList();
|
|
|
|
|
|
if (currList.Count == 0)
|
|
|
return new { Succ = false, No = l.SlotBookingNo };
|
|
|
|
|
|
return new { Succ = true, No = l.SlotBookingNo };
|
|
|
}).Where(a => !a.Succ).ToList();
|
|
|
|
|
|
if (stockCheckList.Count > 0)
|
|
|
{
|
|
|
//舱位合票失败,舱位提单号:{string.Join(",", stockCheckList.Select(a => a.No).ToArray())} 缺少库存
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckPartRecordNoConsistentFail)), string.Join(",", stockCheckList.Select(a => a.No).ToArray())));
|
|
|
}
|
|
|
|
|
|
rlt.slotDetailList = list;
|
|
|
|
|
|
string ctnStat = string.Empty;
|
|
|
|
|
|
if (list.Count > 0)
|
|
|
{
|
|
|
rlt.ctnStat = string.Join(",", list.SelectMany(a => a.CtnList).OrderBy(a => a.CtnAll).GroupBy(a => a.CtnAll)
|
|
|
.Select(a => $"{a.Key}*{a.Sum(b => b.CtnNum)}").ToArray());
|
|
|
}
|
|
|
|
|
|
if (slotList.Any(a => !string.IsNullOrWhiteSpace(a.LoadGuaranteeFlag)))
|
|
|
{
|
|
|
rlt.importantNotes = string.Join(";", slotList.Where(a => !string.IsNullOrWhiteSpace(a.LoadGuaranteeFlag))
|
|
|
.GroupBy(a => a.LoadGuaranteeFlagName)
|
|
|
.Select(a => string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotMergeCheckPartRecordNoConsistentFail)), string.Join(",", a.Select(b => b.SlotBookingNo).ToArray()), a.Key)).ToArray());
|
|
|
}
|
|
|
|
|
|
|
|
|
// 查询可用舱位及箱子列表
|
|
|
return rlt;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 舱位引入
|
|
|
/// <summary>
|
|
|
/// 分页查询可用的舱位及箱子列表
|
|
|
/// </summary>
|
|
|
/// <param name="input">可选:舱位查询条件</param>
|
|
|
/// <param name="pageInfo">可选:分页信息</param>
|
|
|
public async Task<SqlSugarPagedList<BookingSlotBaseWithCtnDto>> GetAvailableSlots([FromQuery] BookingSlotBaseDto input,
|
|
|
[FromQuery] PageWithTotal pageInfo)
|
|
|
{
|
|
|
var result = await GetAvailableSlots(input, null, pageInfo);
|
|
|
|
|
|
SqlSugarPagedList<BookingSlotBaseWithCtnDto> pageResult = new()
|
|
|
{
|
|
|
PageIndex = pageInfo.PageNo,
|
|
|
PageSize = pageInfo.PageSize,
|
|
|
TotalCount = pageInfo.Total,
|
|
|
Items = result,
|
|
|
};
|
|
|
return pageResult;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 查询可用的舱位及箱子列表
|
|
|
/// <summary>
|
|
|
/// 查询可用的舱位及箱子列表
|
|
|
/// </summary>
|
|
|
/// <param name="slotInput">筛选条件1:舱位信息、箱型</param>
|
|
|
/// <param name="slotIdListInput">筛选条件2:舱位主键列表</param>
|
|
|
/// <param name="pageInfo">筛选条件3:分页</param>
|
|
|
/// <returns>可用的舱位列表(含可用的箱子列表)</returns>
|
|
|
[NonAction]
|
|
|
public async Task<List<BookingSlotBaseWithCtnDto>> GetAvailableSlots(BookingSlotBaseDto slotInput = null,
|
|
|
List<long> slotIdListInput = null,
|
|
|
PageWithTotal pageInfo = null)
|
|
|
{
|
|
|
slotInput ??= new();
|
|
|
slotIdListInput ??= new();
|
|
|
|
|
|
string[] ctnCodeList = null;
|
|
|
if (!string.IsNullOrEmpty(slotInput.CtnStat))
|
|
|
{
|
|
|
ctnCodeList = slotInput.CtnStat.Split(',');
|
|
|
}
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
// 1. 【舱位基础表】与【箱子表】做关联,并根据【舱位主键】、【箱型】做分组,统计出【总的箱量】,作为queryable1
|
|
|
var queryable1 = tenantDb.Queryable<BookingSlotBase, BookingSlotCtn>((bas, ctn) => bas.Id == ctn.SlotId)
|
|
|
.Where(bas => bas.IsCancellation == false)
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.SlotBookingNo), bas => bas.SlotBookingNo == slotInput.SlotBookingNo)
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.PortLoad), bas => bas.PortLoad.Contains(slotInput.PortLoad))
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.PortDischarge), bas => bas.PortDischarge.Contains(slotInput.PortDischarge))
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.Vessel), bas => bas.Vessel.Contains(slotInput.Vessel))
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.Voyno), bas => bas.Voyno.Contains(slotInput.Voyno))
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.CarriageType), bas => bas.CarriageType == slotInput.CarriageType)
|
|
|
.WhereIF(!string.IsNullOrEmpty(slotInput.BookingSlotType), bas => bas.BookingSlotType == slotInput.BookingSlotType)
|
|
|
.WhereIF(ctnCodeList != null, (bas, ctn) => ctnCodeList.Contains(ctn.CtnCode))
|
|
|
.WhereIF(slotIdListInput.Any(), (bas) => slotIdListInput.Contains(bas.Id))
|
|
|
.GroupBy((bas, ctn) => new
|
|
|
{
|
|
|
bas.Id,
|
|
|
ctn.CtnCode
|
|
|
})
|
|
|
.Select((bas, ctn) => new
|
|
|
{
|
|
|
id = bas.Id,
|
|
|
ctnCode = ctn.CtnCode,
|
|
|
numAll = SqlFunc.AggregateSum(ctn.CtnNum)
|
|
|
})
|
|
|
.MergeTable();
|
|
|
|
|
|
// 2. 【已引入舱位表】与【已使用的箱子表】做关联,并根据【舱位主键】、【箱型】做分组,统计出【已使用的箱量】,作为queryable2
|
|
|
var queryable2 = tenantDb.Queryable<BookingSlotAllocation, BookingSlotAllocationCtn>((alc, ctn) => alc.Id == ctn.SlotAllocId)
|
|
|
.WhereIF(slotIdListInput.Any(), (alc, ctn) => slotIdListInput.Contains(alc.BookingSlotId))
|
|
|
.GroupBy((alc, ctn) => new
|
|
|
{
|
|
|
alc.BookingSlotId,
|
|
|
ctn.CtnCode
|
|
|
})
|
|
|
.Select((alc, ctn) => new
|
|
|
{
|
|
|
id = alc.BookingSlotId,
|
|
|
ctnCode = ctn.CtnCode,
|
|
|
numUse = SqlFunc.AggregateSum(ctn.CtnNum)
|
|
|
})
|
|
|
.MergeTable();
|
|
|
|
|
|
// 3. 将queryable1 左连接 queryable2,使用【总的箱量】减去【已使用的箱量】,得到【剩余的箱量】,添加【剩余的箱量】> 0 的条件,作为queryable3
|
|
|
var queryable3 = queryable1.LeftJoin(queryable2, (q1, q2) => q1.id == q2.id && q1.ctnCode == q2.ctnCode)
|
|
|
.Select((q1, q2) => new
|
|
|
{
|
|
|
q1.id,
|
|
|
q1.ctnCode,
|
|
|
q1.numAll,
|
|
|
numResidue = SqlFunc.IsNull(q1.numAll - q2.numUse, q1.numAll)
|
|
|
})
|
|
|
.MergeTable()
|
|
|
.Where(r => r.numResidue > 0);
|
|
|
|
|
|
// 4. 执行ToList(),得到可用的【舱位主键】、【箱型】、【箱量】列表
|
|
|
RefAsync<int> total = 0;
|
|
|
var canUselist = pageInfo == null
|
|
|
? await queryable3.ToListAsync()
|
|
|
: await queryable3.ToPageListAsync(pageInfo.PageNo, pageInfo.PageSize, total);
|
|
|
|
|
|
if (pageInfo != null)
|
|
|
{
|
|
|
pageInfo.Total = total;
|
|
|
}
|
|
|
|
|
|
// 查询舱位列表
|
|
|
var baseIdList = canUselist.Select(c => c.id);
|
|
|
List<BookingSlotBase> baseList = await tenantDb.Queryable<BookingSlotBase>()
|
|
|
.Where(u => baseIdList.Contains(u.Id))
|
|
|
.ToListAsync();
|
|
|
|
|
|
List<CodeCtnRes> ctnCodeCache = new List<CodeCtnRes>();
|
|
|
|
|
|
var allCtnist = await _codeCtnService.GetAllList();
|
|
|
|
|
|
if (allCtnist.Succeeded)
|
|
|
{
|
|
|
ctnCodeCache = allCtnist.Data;
|
|
|
}
|
|
|
|
|
|
// 构建结果
|
|
|
List<BookingSlotBaseWithCtnDto> result = baseList.Adapt<List<BookingSlotBaseWithCtnDto>>();
|
|
|
foreach (var item in result)
|
|
|
{
|
|
|
var ctnList = canUselist.Where(c => c.id == item.Id).ToList();
|
|
|
if (ctnList?.Any() == true)
|
|
|
{
|
|
|
item.CtnList = ctnList.Select(c => new BookingSlotCtnDto()
|
|
|
{
|
|
|
CtnCode = c.ctnCode,
|
|
|
CtnNum = c.numResidue,
|
|
|
TotalNum = c.numAll,
|
|
|
CtnAll = ctnCodeCache.FirstOrDefault(e => $"{e.CtnSize}{e.CtnType}" == c.ctnCode)?.CtnName ?? throw new Exception($"舱位信息中存在未收录的箱型:{c.ctnCode},需要在箱型字典中补充"),
|
|
|
}).ToList();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 获取附件
|
|
|
/// <summary>
|
|
|
/// 获取附件
|
|
|
/// </summary>
|
|
|
/// <param name="id">舱位主键</param>
|
|
|
/// <returns>返回附件列表</returns>
|
|
|
public async Task<DataResult<List<OpFileRes>>> GetFile(long id)
|
|
|
{
|
|
|
return _opFileService.GetOpFileList(id.ToString()) ;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 检查指定订舱记录,是否可以引入舱位列表
|
|
|
/// <summary>
|
|
|
/// 检查指定订舱记录,是否可以引入舱位列表
|
|
|
/// </summary>
|
|
|
/// <param name="slots">待引入的舱位列表</param>
|
|
|
/// <param name="bookingOrderId">待关联的订舱记录</param>
|
|
|
/// <returns>isExists:指定订舱记录是否已经引入过舱位数据,isEnough:现有舱位及箱子是否满足需求,message:提示信息</returns>
|
|
|
public async Task<(bool isExists, bool isEnough, string message)> CheckImportSlots(List<BookingSlotBaseWithCtnDto> slots, long bookingOrderId)
|
|
|
{
|
|
|
slots ??= new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
// 判断是否已存在引用关系
|
|
|
if (bookingOrderId != 0 && await tenantDb.Queryable<BookingSlotAllocation>().AnyAsync(a => a.BookingId == bookingOrderId))
|
|
|
{
|
|
|
//订舱主键{bookingOrderId}已引用舱位
|
|
|
return (true, false, string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateContaNull)), bookingOrderId));
|
|
|
}
|
|
|
var slotIdList = slots.Select(s => s.Id).ToList();
|
|
|
|
|
|
// 查询可用舱位及箱子列表
|
|
|
var latestSlotList = await GetAvailableSlots(null, slotIdList);
|
|
|
|
|
|
// 判断余量是否满足需求
|
|
|
foreach (var inSlotItem in slots)
|
|
|
{
|
|
|
var latestSlot = latestSlotList.FirstOrDefault(b => b.Id == inSlotItem.Id);
|
|
|
if (latestSlot == null)
|
|
|
{
|
|
|
//订舱编号为{inSlotItem.SlotBookingNo}的舱位已被占用或取消,请重新引入
|
|
|
return (false, false, $"订舱编号为{inSlotItem.SlotBookingNo}的舱位已被占用或取消,请重新引入");
|
|
|
}
|
|
|
if (inSlotItem.CtnList?.Any() == false)
|
|
|
{
|
|
|
//每个舱位至少选择一个箱子,订舱编号:{inSlotItem.SlotBookingNo}
|
|
|
return (false, false, $"每个舱位至少选择一个箱子,订舱编号:{inSlotItem.SlotBookingNo}");
|
|
|
}
|
|
|
foreach (var inCtnItem in inSlotItem.CtnList)
|
|
|
{
|
|
|
var latestCtn = latestSlot.CtnList.FirstOrDefault(c => c.CtnCode == inCtnItem.CtnCode);
|
|
|
if (latestCtn == null)
|
|
|
{
|
|
|
//订舱编号为{latestSlot.SlotBookingNo}的舱位中,箱型为{inCtnItem.CtnAll}的箱子已被占用或取消,请重新引入
|
|
|
return (false, false, $"订舱编号为{latestSlot.SlotBookingNo}的舱位中,箱型为{inCtnItem.CtnAll}的箱子已被占用或取消,请重新引入");
|
|
|
}
|
|
|
if (latestCtn.CtnNum < inCtnItem.CtnNum)
|
|
|
{
|
|
|
//订舱编号为{latestSlot.SlotBookingNo}的舱位中,箱型为{inCtnItem.CtnAll}的箱子当前剩余{latestCtn.CtnNum}个,少于所需的{inCtnItem.CtnNum}个,请重新引入
|
|
|
return (false, false, $"订舱编号为{latestSlot.SlotBookingNo}的舱位中,箱型为{inCtnItem.CtnAll}的箱子当前剩余{latestCtn.CtnNum}个,少于所需的{inCtnItem.CtnNum}个,请重新引入");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//可以引入
|
|
|
return (false, true, $"可以引入");
|
|
|
}
|
|
|
public static object ImportLockObj = new object();
|
|
|
#endregion
|
|
|
|
|
|
#region 生成订舱订单
|
|
|
/// <summary>
|
|
|
/// 生成订舱订单
|
|
|
/// </summary>
|
|
|
/// <param name="model">生成订舱订单请求</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<DataResult<long>> CreateBookingOrder(BookingGenerateDto model)
|
|
|
{
|
|
|
if (model.CustomerId == null || string.IsNullOrWhiteSpace(model.CustomerName))
|
|
|
{
|
|
|
//请选择委托单位
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerNull)));
|
|
|
}
|
|
|
|
|
|
if (model.CtnList == null || !model.CtnList.Any())
|
|
|
{
|
|
|
//请选择要使用的箱信息
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateContaNull)));
|
|
|
}
|
|
|
|
|
|
//舱位ID不能为空
|
|
|
if (!model.SlotId.HasValue || model.SlotId.Value < 1)
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateSlotIdNull)));
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var slotInfo = await tenantDb.Queryable<BookingSlotBase>()
|
|
|
.FirstAsync(a => a.Id == model.SlotId.Value);
|
|
|
|
|
|
//舱位信息不存在或已作废
|
|
|
if (slotInfo == null)
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateRecordDeletedOrNoExists)));
|
|
|
|
|
|
// 判断是否已存在引用关系
|
|
|
//if (_repAllocation.IsExists(a => a.BOOKING_SLOT_ID == slotInfo.Id
|
|
|
// && a.BOOKING_ID > 0 && a.IsDeleted == false))
|
|
|
//{
|
|
|
// throw Oops.Oh($"舱位已有对应的订舱订单,不能重复执行");
|
|
|
//}
|
|
|
|
|
|
//var ctnList = _repCtn.AsQueryable().Where(a => a.SLOT_ID == slotInfo.Id && a.IsDeleted == false)
|
|
|
// .ToList();
|
|
|
|
|
|
var fileList = _opFileService.GetOpFileList(slotInfo.Id.ToString()).Data;
|
|
|
|
|
|
var paramConfig = _configService.GetConfig(CONST_CREATE_BOOKING_NEED_CONTACT, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
|
|
|
|
|
|
|
|
|
if (model.CustomerContactList != null && model.CustomerContactList.Count > 0)
|
|
|
{
|
|
|
//取委托客户下面所有的联系人列表
|
|
|
var djyCustomerInfo = _clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = model.CustomerId.Value,IsController = true }).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
if (djyCustomerInfo == null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"委托单位{model.CustomerName} 获取失败,委托单位不存在或已作废 SlotId={model.SlotId.Value}");
|
|
|
|
|
|
//委托单位{0} 获取失败,委托单位不存在或已作废
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateContaNull)), model.CustomerName));
|
|
|
}
|
|
|
|
|
|
if (djyCustomerInfo.ClientContactList == null && djyCustomerInfo.ClientContactList.Count < 1)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"委托单位{model.CustomerName} 获取相关联系人失败,委托单位相关联系人为空 SlotId={model.SlotId.Value}");
|
|
|
|
|
|
//委托单位{0} 获取相关联系人失败,委托单位相关联系人为空
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractInfoNull)), model.CustomerName));
|
|
|
}
|
|
|
|
|
|
model.CustomerContactList.ForEach(contact =>
|
|
|
{
|
|
|
var djyCustomerContactMan = djyCustomerInfo.ClientContactList
|
|
|
.FirstOrDefault(a => a.Id == contact.CustomerContactId);
|
|
|
|
|
|
if (djyCustomerContactMan == null)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"委托单位{model.CustomerName} 联系人 {contact.Name}获取失败,联系人不存在或已作废 SlotId={model.SlotId.Value}");
|
|
|
|
|
|
//委托单位 {0} 联系人 {1} 获取失败,联系人不存在或已作废
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractDeletedOrNoExists)), model.CustomerName, contact.Name));
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (paramConfig != null && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
|
|
|
{
|
|
|
//生成订舱时往来单位联系人必填,请修改
|
|
|
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractNotNull)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var bookingOrderId = await GenerateBookingOrder(slotInfo, fileList, model, null);
|
|
|
|
|
|
return DataResult<long>.Success(bookingOrderId, MultiLanguageConst.DataCreateSuccess);
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region 生成订舱
|
|
|
/// <summary>
|
|
|
/// 生成订舱
|
|
|
/// </summary>
|
|
|
/// <param name="bookingSlotBase">舱位详情</param>
|
|
|
/// <param name="bookingSlotFileList">舱位附件列表</param>
|
|
|
/// <param name="generateModel">订舱请求详情</param>
|
|
|
/// <param name="masterBookingSlotNo">合票的主舱位提单号(合票时必传)</param>
|
|
|
/// <returns>返回订舱ID</returns>
|
|
|
private async Task<long> GenerateBookingOrder(BookingSlotBase bookingSlotBase,
|
|
|
List<OpFileRes> bookingSlotFileList,
|
|
|
BookingGenerateDto generateModel, string masterBookingSlotNo)
|
|
|
{
|
|
|
long id = 0;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
/*
|
|
|
1、新增订舱
|
|
|
2、推送服务项目
|
|
|
3、推送附件
|
|
|
*/
|
|
|
var allMapCarrierList = await _mappingCarrierService.GetAllList();
|
|
|
|
|
|
MappingCarrierRes carrierInfo = null;
|
|
|
|
|
|
if (allMapCarrierList.Succeeded)
|
|
|
{
|
|
|
carrierInfo = allMapCarrierList.Data.FirstOrDefault(t => t.LinkId == bookingSlotBase.CarrierId.Value && t.Module == CONST_MAPPING_CARRIER_MODULE);
|
|
|
}
|
|
|
|
|
|
var custNo = bookingSlotBase.SlotBookingNo.Trim();
|
|
|
|
|
|
SeaExportReq bkModel = new SeaExportReq
|
|
|
{
|
|
|
CustomerId = generateModel.CustomerId.Value,
|
|
|
CustomerName = generateModel.CustomerName,
|
|
|
Carrier = carrierInfo?.MapName?.Trim(),
|
|
|
CarrierId = bookingSlotBase.CarrierId.Value,
|
|
|
BookingNo = custNo,
|
|
|
//MBLNO = bookingSlotBase.SLOT_BOOKING_NO.Trim(),
|
|
|
ContractNo = !string.IsNullOrWhiteSpace(bookingSlotBase.ContractNo) ? bookingSlotBase.ContractNo : "",
|
|
|
Vessel = bookingSlotBase.Vessel?.ToUpper()?.Trim(),
|
|
|
Voyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(),
|
|
|
InnerVoyno = bookingSlotBase.Voyno?.ToUpper()?.Trim(),
|
|
|
ETD = bookingSlotBase.ETD,
|
|
|
ETA = bookingSlotBase.ETA,
|
|
|
SaleId = generateModel.SaleId.HasValue? generateModel.SaleId.Value:0,
|
|
|
Sale = generateModel.SaleName,
|
|
|
OperatorId = generateModel.OpId.HasValue ? generateModel.OpId.Value : 0,
|
|
|
//op = generateModel.OpName,
|
|
|
Doc = generateModel.DocId.HasValue ? generateModel.DocId.Value : 0,
|
|
|
//DOC = generateModel.DocName,
|
|
|
//ROUTEID = generateModel.RouteID?.ToString(),
|
|
|
//ROUTE = generateModel.Route,
|
|
|
//CZRemark = generateModel.CZRemark,
|
|
|
//ShenQingXiangShi = generateModel.ShenQingXiangShi,
|
|
|
//LineManageID = generateModel.LineManageID?.ToString(),
|
|
|
//LineName = generateModel.LineManage,
|
|
|
//CLOSEVGMDATE = bookingSlotBase.VGMSubmissionCutDate,
|
|
|
ClosingDate = bookingSlotBase.CYCutDate,
|
|
|
CloseDocDate = bookingSlotBase.SICutDate,
|
|
|
CustomerService = generateModel.CustServiceId.HasValue ? generateModel.CustServiceId.Value : 0,
|
|
|
//CUSTSERVICE = generateModel.CustServiceName,
|
|
|
|
|
|
LoadPort = bookingSlotBase.PortLoad,
|
|
|
LoadPortId = bookingSlotBase.PortLoadId.HasValue? bookingSlotBase.PortLoadId.Value:0,
|
|
|
DischargePortId = bookingSlotBase.PortDischargeId.HasValue ? bookingSlotBase.PortLoadId.Value : 0,
|
|
|
DischargePort = bookingSlotBase.PortDischarge,
|
|
|
|
|
|
ReceiptPlace = bookingSlotBase.PlaceReceipt,
|
|
|
ReceiptPlaceId = bookingSlotBase.PlaceReceiptId.HasValue ? bookingSlotBase.PlaceReceiptId.Value : 0,
|
|
|
DeliveryPlace = bookingSlotBase.PlaceDelivery,
|
|
|
DeliveryPlaceId = bookingSlotBase.PlaceDeliveryId.HasValue ? bookingSlotBase.PlaceDeliveryId.Value : 0,
|
|
|
|
|
|
CtnInfo = new List<OpCtnReq>()
|
|
|
};
|
|
|
|
|
|
// 判断是否为拆票的舱位,如果为拆票,提单号需要加上ABCD...
|
|
|
var selectNum = generateModel.CtnList.Sum(x => x.CtnNum);
|
|
|
Logger.Log(NLog.LogLevel.Info, "根据舱位生成订舱,selectNum:{selectNum}", selectNum);
|
|
|
|
|
|
var allNum = await tenantDb.Queryable<BookingSlotCtn>().Where(x => x.SlotId == generateModel.SlotId).SumAsync(x => x.CtnNum);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, "根据舱位生成订舱,allNum:{allNum}", allNum);
|
|
|
//bkModel.IsSplit = selectNum != allNum;
|
|
|
bkModel.SplitOrMergeFlag = selectNum != allNum ? 1 : 0;
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(masterBookingSlotNo))
|
|
|
bkModel.SplitOrMergeFlag = 2;
|
|
|
|
|
|
//拆票逻辑
|
|
|
if (bkModel.SplitOrMergeFlag == 1)
|
|
|
{
|
|
|
//var sql = _repBookingOrder.AsQueryable().Where(" MBLNO like @mblno ", new { mblno = custNo + '_' }).OrderByDescending(x => x.Id).Select(x => x.MBLNO).ToSqlString();
|
|
|
//var currentMblno = await _repBookingOrder.AsQueryable().Where(" MBLNO like @mblno ", new { mblno = custNo + '_' })
|
|
|
// .OrderByDescending(x => x.Id)
|
|
|
// .Select(x => x.MBLNO)
|
|
|
// .FirstAsync();
|
|
|
|
|
|
//获取所有订舱编号是舱位提单号,并且是已经拆单的订舱记录
|
|
|
var orderList = tenantDb.Queryable<SeaExport>().Where(a => a.BookingNo == custNo && a.SplitOrMergeFlag == 1 && a.Deleted == false).ToList();
|
|
|
|
|
|
if (orderList.Count == 0)
|
|
|
{
|
|
|
bkModel.MBLNO = $"{custNo}A";
|
|
|
bkModel.BookingNo = custNo;
|
|
|
bkModel.HBLNO = custNo;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var maxChar = orderList.Select(a =>
|
|
|
{
|
|
|
var startIndx = a.BookingNo.Length;
|
|
|
return a.MBLNO.Substring(startIndx);
|
|
|
}).Max();
|
|
|
|
|
|
//获取的历史拆票后缀异常,maxChar={maxChar}
|
|
|
if (maxChar.Length != 1 || !Regex.IsMatch(maxChar, "[A-Z]{1}"))
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateCustomerContractNotNull)), maxChar));
|
|
|
|
|
|
bkModel.MBLNO = $"{custNo}{LetterIndexUtil.GetNextLetter(maxChar[0])}";
|
|
|
bkModel.BookingNo = custNo;
|
|
|
bkModel.HBLNO = custNo;
|
|
|
}
|
|
|
//if (currentMblno == null)
|
|
|
//{
|
|
|
// bkModel.MBLNO = custNo + "A";
|
|
|
|
|
|
|
|
|
//}
|
|
|
//else
|
|
|
//{
|
|
|
// var lastLetter = currentMblno.Substring(currentMblno.Length - 1, 1)[0];
|
|
|
// var newMblno = custNo + LetterIndexUtil.GetNextLetter(lastLetter);
|
|
|
// bkModel.MBLNO = newMblno;
|
|
|
//}
|
|
|
}
|
|
|
else if (bkModel.SplitOrMergeFlag == 2)
|
|
|
{
|
|
|
//合票
|
|
|
var orderList = tenantDb.Queryable<SeaExport>().Where(a => a.BookingNo == custNo && a.SplitOrMergeFlag == 2
|
|
|
&& a.MBLNO == custNo && a.Deleted == false).ToList();
|
|
|
|
|
|
if (orderList.Count == 0)
|
|
|
{
|
|
|
bkModel.MBLNO = custNo;
|
|
|
bkModel.BookingNo = custNo;
|
|
|
bkModel.HBLNO = masterBookingSlotNo;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//舱位提单号:{custNo} 已有订舱记录不能重复操作
|
|
|
throw new Exception(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotSplitMergeHasOrder)), custNo));
|
|
|
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
bkModel.MBLNO = bookingSlotBase.SlotBookingNo.Trim();
|
|
|
}
|
|
|
Logger.Log(NLog.LogLevel.Info, "根据舱位生成订舱,得到MBLNO:{MBLNO}", bkModel.MBLNO);
|
|
|
|
|
|
List<CodeCtnRes> ctnCodeList = new List<CodeCtnRes>();
|
|
|
|
|
|
var ctnCacheRlt = await _codeCtnService.GetAllList();
|
|
|
|
|
|
if (ctnCacheRlt.Succeeded)
|
|
|
{
|
|
|
ctnCodeList = ctnCacheRlt.Data;
|
|
|
}
|
|
|
|
|
|
if (generateModel.CtnList != null && generateModel.CtnList.Count > 0)
|
|
|
{
|
|
|
generateModel.CtnList.ForEach(t =>
|
|
|
{
|
|
|
var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) &&
|
|
|
a.CtnName.Equals(t.CtnAll, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
OpCtnReq ctn = new OpCtnReq
|
|
|
{
|
|
|
CtnCode = $"{ctnCode?.CtnSize}{ctnCode?.CtnType}",
|
|
|
CtnAll = t.CtnAll,
|
|
|
CtnNum = t.CtnNum
|
|
|
};
|
|
|
|
|
|
bkModel.CtnInfo.Add(ctn);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 验证舱位是否可用
|
|
|
var slotInfo = bookingSlotBase.Adapt<BookingSlotBaseWithCtnDto>();
|
|
|
slotInfo.CtnList = generateModel.CtnList;
|
|
|
var importSlots = new List<BookingSlotBaseWithCtnDto>() { slotInfo };
|
|
|
var checkResult = await CheckImportSlots(importSlots, 0);
|
|
|
if (!checkResult.isEnough)
|
|
|
{
|
|
|
throw new Exception(checkResult.message);
|
|
|
}
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, "根据舱位生成订舱,开始调用Save保存订舱");
|
|
|
|
|
|
var bkRlt = await _seaExportService.EditSeaExport(bkModel);
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"根据舱位生成订舱,调用Save保存订舱完成,id:{bkRlt.Data}");
|
|
|
|
|
|
id = long.Parse(bkRlt.Data.ToString());
|
|
|
|
|
|
string batchNo = GuidHelper.GetSnowflakeId();
|
|
|
|
|
|
if (id > 0)
|
|
|
{
|
|
|
////对应订舱和舱位关系
|
|
|
var allocRlt = await ImportSlots(importSlots, id, false, generateModel);
|
|
|
Logger.Log(NLog.LogLevel.Info, "根据舱位生成订舱,引入订舱关系完成");
|
|
|
|
|
|
//更新舱位的拆合单标记
|
|
|
var slotEntity = tenantDb.Queryable<BookingSlotBase>().First(a => a.Id == bookingSlotBase.Id && a.Deleted == false);
|
|
|
|
|
|
if (slotEntity != null)
|
|
|
{
|
|
|
slotEntity.SplitOrMergeFlag = bkModel.SplitOrMergeFlag;
|
|
|
|
|
|
//更新舱位的拆合单标记
|
|
|
await tenantDb.Updateable<BookingSlotBase>(slotEntity).UpdateColumns(a => new { a.SplitOrMergeFlag }).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
//这里如果指定了委托单位的邮件联系人,则推送订舱联系人
|
|
|
if (generateModel.CustomerContactList != null && generateModel.CustomerContactList.Count > 0)
|
|
|
{
|
|
|
var bookingContactList = tenantDb.Queryable<BusinessOrderContact>()
|
|
|
.Where(a => a.BusinessId == id && a.Deleted == false).ToList();
|
|
|
|
|
|
var djyCustomerInfo = _clientInfoService.GetClientInfoWithContact(new Info.Dtos.QueryClientInfo { ClientId = generateModel.CustomerId.Value, IsController = true })
|
|
|
.GetAwaiter().GetResult().Data;
|
|
|
|
|
|
|
|
|
generateModel.CustomerContactList.ForEach(contact =>
|
|
|
{
|
|
|
ClientContactRes djyCustomerContactMan = null;
|
|
|
|
|
|
if (djyCustomerInfo.ClientContactList != null && djyCustomerInfo.ClientContactList.Count > 0)
|
|
|
{
|
|
|
djyCustomerContactMan = djyCustomerInfo.ClientContactList.FirstOrDefault(a =>
|
|
|
a.Id == contact.CustomerContactId);
|
|
|
}
|
|
|
|
|
|
if (djyCustomerContactMan != null)
|
|
|
{
|
|
|
var bookingContact = bookingContactList
|
|
|
.FirstOrDefault(x => x.Email.Equals(djyCustomerContactMan.Email, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
if (bookingContact == null)
|
|
|
{
|
|
|
bookingContact = new BusinessOrderContact
|
|
|
{
|
|
|
Name = djyCustomerContactMan.ShortName,
|
|
|
BusinessId = id,
|
|
|
Email = djyCustomerContactMan.Email,
|
|
|
Note = djyCustomerContactMan.Note,
|
|
|
CreateTime = DateTime.Now,
|
|
|
CreateBy = long.Parse(user.UserId),
|
|
|
//CreatedUserName = UserManager.Name
|
|
|
};
|
|
|
|
|
|
tenantDb.Insertable<BusinessOrderContact>(bookingContact).ExecuteCommand();
|
|
|
//_bookingOrderContactRepository.Insert(bookingContact);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
bookingContact.Name = djyCustomerContactMan.ShortName;
|
|
|
bookingContact.Email = djyCustomerContactMan.Email;
|
|
|
bookingContact.Note = djyCustomerContactMan.Note;
|
|
|
bookingContact.UpdateTime = DateTime.Now;
|
|
|
bookingContact.UpdateBy = long.Parse(user.UserId);
|
|
|
//bookingContact.UpdatedUserName = UserManager.Name;
|
|
|
|
|
|
tenantDb.Updateable<BusinessOrderContact>(bookingContact).UpdateColumns(it => new
|
|
|
{
|
|
|
it.Name,
|
|
|
it.Email,
|
|
|
it.Note,
|
|
|
it.UpdateTime,
|
|
|
it.UpdateBy,
|
|
|
//it.UpdatedUserName
|
|
|
|
|
|
}).ExecuteCommand();
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (generateModel.ProjectList != null && generateModel.ProjectList.Count > 0)
|
|
|
{
|
|
|
//写入服务项目
|
|
|
var prjRlt = _djyServiceStatusService.SaveServiceProject(new EmbedServiceProjectDto
|
|
|
{
|
|
|
BusinessId = id.ToString(),
|
|
|
ProjectCodes = generateModel.ProjectList.Distinct().ToArray(),
|
|
|
});
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"推送订舱的服务项目完成 id={id} rlt={JsonConvert.SerializeObject(prjRlt)}");
|
|
|
}
|
|
|
|
|
|
//var opt = App.GetOptions<BookingAttachOptions>();
|
|
|
//var dirAbs = opt.basePath;
|
|
|
//if (string.IsNullOrEmpty(dirAbs))
|
|
|
//{
|
|
|
// dirAbs = App.WebHostEnvironment.WebRootPath;
|
|
|
//}
|
|
|
|
|
|
var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" });
|
|
|
var relativePath = AppSetting.app(new string[] { "FileSettings", "RelativePath" });
|
|
|
var dirAbs = string.Empty;
|
|
|
var fileRelaPath = string.Empty;
|
|
|
var fileAbsPath = string.Empty;
|
|
|
if (string.IsNullOrEmpty(basePath))
|
|
|
{
|
|
|
dirAbs = Path.Combine(_environment.WebRootPath, relativePath);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
dirAbs = Path.Combine(basePath, relativePath);
|
|
|
}
|
|
|
|
|
|
if (bookingSlotFileList.Any(a => a.TypeCode.Equals("bc", StringComparison.OrdinalIgnoreCase)))
|
|
|
{
|
|
|
var file = bookingSlotFileList.OrderByDescending(a => a.CreateTime)
|
|
|
.FirstOrDefault(a => a.TypeCode.Equals("bc", StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
var fileFullPath = Path.Combine(dirAbs, file.FilePath);
|
|
|
|
|
|
if (File.Exists(fileFullPath))
|
|
|
{
|
|
|
//如果确认文件读取成功
|
|
|
var bookFilePath = _sysFileService.MoveFile(id.ToString(), fileFullPath, batchNo
|
|
|
, false, null, true).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, bookFilePath, new System.IO.FileInfo(bookFilePath).Name, long.Parse(user.TenantId),
|
|
|
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (bookingSlotFileList.Any(a => a.TypeCode.Equals("bc_notice", StringComparison.OrdinalIgnoreCase)))
|
|
|
{
|
|
|
var file = bookingSlotFileList.OrderByDescending(a => a.CreateTime)
|
|
|
.FirstOrDefault(a => a.TypeCode.Equals("bc_notice", StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
var fileFullPath = Path.Combine(dirAbs, file.FilePath);
|
|
|
|
|
|
if (File.Exists(fileFullPath))
|
|
|
{
|
|
|
//如果确认文件读取成功
|
|
|
var bookFilePath = _sysFileService.MoveFile(id.ToString(), fileFullPath, batchNo
|
|
|
, false, "bcnoticefile", true).GetAwaiter().GetResult().Data;
|
|
|
|
|
|
//将格式单附件写入订舱的附件
|
|
|
SaveEDIFile(id, bookFilePath, new System.IO.FileInfo(bookFilePath).Name, long.Parse(user.TenantId),
|
|
|
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME).GetAwaiter();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Logger.Log(NLog.LogLevel.Info, $"MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱订单成功 id={id}");
|
|
|
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Logger.Log(NLog.LogLevel.Info, $"MBLNO:{bookingSlotBase.SlotBookingNo} 生成订舱订单异常,原因:{ex.Message}");
|
|
|
throw;
|
|
|
}
|
|
|
|
|
|
|
|
|
return id;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
|
/// 为指定订舱记录引入舱位信息
|
|
|
/// </summary>
|
|
|
/// <param name="slots">待引入的舱位列表</param>
|
|
|
/// <param name="bookingOrderId">待关联的订舱记录</param>
|
|
|
/// <param name="isCheck">是否进行剩余量检查</param>
|
|
|
/// <param name="generateModel">额外的用于生成管理记录的信息</param>
|
|
|
/// <returns>isSuccess:检查(余量及已引用检查)是否成功通过,message:提示信息</returns>
|
|
|
[NonAction]
|
|
|
public async Task<(bool isSuccess, string message)> ImportSlots(List<BookingSlotBaseWithCtnDto> slots,
|
|
|
long bookingOrderId,
|
|
|
bool isCheck,
|
|
|
BookingGenerateDto generateModel = null)
|
|
|
{
|
|
|
slots ??= new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
Monitor.Enter(ImportLockObj);
|
|
|
try
|
|
|
{
|
|
|
if (isCheck)
|
|
|
{
|
|
|
(bool isExists, bool isEnough, string message) checkResult = await CheckImportSlots(slots, bookingOrderId);
|
|
|
|
|
|
if (checkResult.isExists || !checkResult.isEnough)
|
|
|
return (false, checkResult.message);
|
|
|
}
|
|
|
|
|
|
var slotIdList = slots.Select(s => s.Id).ToList();
|
|
|
List<BookingSlotBase> latestSlotList = await tenantDb.Queryable<BookingSlotBase>().Where(b => slotIdList.Contains(b.Id)).ToListAsync();
|
|
|
foreach (var inSlotItem in slots)
|
|
|
{
|
|
|
var latestSlot = latestSlotList.First(b => b.Id == inSlotItem.Id);
|
|
|
|
|
|
// 保存关联信息
|
|
|
var config = new TypeAdapterConfig();
|
|
|
config.ForType<BookingSlotBase, BookingSlotAllocation>()
|
|
|
.Ignore(dest => dest.CreateTime)
|
|
|
.Ignore(dest => dest.UpdateTime)
|
|
|
.Ignore(dest => dest.CreateBy)
|
|
|
.Ignore(dest => dest.UpdateBy);
|
|
|
//.Ignore(dest => dest.CreatedUserName)
|
|
|
//.Ignore(dest => dest.UpdatedUserName)
|
|
|
//.Ignore(dest => dest.TenantId)
|
|
|
//.Ignore(dest => dest.TenantName);
|
|
|
|
|
|
var newSlotAllocation = latestSlot.Adapt<BookingSlotAllocation>(config);
|
|
|
newSlotAllocation.Id = 0;
|
|
|
newSlotAllocation.BookingSlotId = latestSlot.Id;
|
|
|
newSlotAllocation.BookingId = bookingOrderId;
|
|
|
newSlotAllocation.AlloBillNo = latestSlot.SlotBookingNo;
|
|
|
newSlotAllocation.FinalBillNo = latestSlot.SlotBookingNo;
|
|
|
|
|
|
if (generateModel != null)
|
|
|
{
|
|
|
newSlotAllocation.CustomerId = generateModel.CustomerId;
|
|
|
newSlotAllocation.CustomerName = generateModel.CustomerName;
|
|
|
newSlotAllocation.CustServiceId = generateModel.CustServiceId?.ToString();
|
|
|
newSlotAllocation.CustService = generateModel.CustServiceName;
|
|
|
newSlotAllocation.SaleId = generateModel.SaleId?.ToString();
|
|
|
newSlotAllocation.Sale = generateModel.SaleName;
|
|
|
newSlotAllocation.DocId = generateModel.DocId?.ToString();
|
|
|
newSlotAllocation.Doc = generateModel.DocName;
|
|
|
newSlotAllocation.OpId = generateModel.OpId?.ToString();
|
|
|
newSlotAllocation.Op = generateModel.OpName;
|
|
|
newSlotAllocation.Business = generateModel.BUSINESS;
|
|
|
newSlotAllocation.BusinessId = generateModel.BUSINESSID;
|
|
|
newSlotAllocation.SaleTime = generateModel.SALE_TIME;
|
|
|
newSlotAllocation.Shipper = generateModel.SHIPPER;
|
|
|
newSlotAllocation.GoodsName = generateModel.GOODSNAME;
|
|
|
newSlotAllocation.SellingPrice = generateModel.SELLING_PRICE;
|
|
|
newSlotAllocation.SplitOrMergeFlag = generateModel.SplitOrMerge;
|
|
|
|
|
|
if (generateModel.SplitOrMerge == 1 || generateModel.SplitOrMerge == 2)
|
|
|
{
|
|
|
newSlotAllocation.AlloBillNo = generateModel.NewMBlNo;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
await tenantDb.Insertable<BookingSlotAllocation>(newSlotAllocation).ExecuteReturnEntityAsync();
|
|
|
|
|
|
// 保存关联的箱信息
|
|
|
var insertCtnList = inSlotItem.CtnList.Select(c => new BookingSlotAllocationCtn()
|
|
|
{
|
|
|
SlotAllocId = newSlotAllocation.Id,
|
|
|
CtnCode = c.CtnCode,
|
|
|
CtnAll = c.CtnAll,
|
|
|
CtnNum = c.CtnNum
|
|
|
});
|
|
|
await tenantDb.Insertable<BookingSlotAllocationCtn>(insertCtnList).ExecuteCommandAsync();
|
|
|
|
|
|
// 为订舱保存附件信息
|
|
|
var lastestBcFile = await tenantDb.Queryable<OpFile>().Where(x => (x.TypeCode == "bc" || x.TypeCode == "bc_notice") && x.LinkId == latestSlot.Id)
|
|
|
.OrderByDescending(x => x.Id)
|
|
|
.FirstAsync();
|
|
|
if (lastestBcFile != null)
|
|
|
{
|
|
|
var file = lastestBcFile.Adapt<OpFile>();
|
|
|
file.Id = 0;
|
|
|
file.LinkId = bookingOrderId;
|
|
|
await tenantDb.Insertable<OpFile>(file).ExecuteCommandAsync();
|
|
|
}
|
|
|
|
|
|
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
|
|
|
{
|
|
|
BookingSlotType = latestSlot.BookingSlotType,
|
|
|
CarrierId = latestSlot.CarrierId.HasValue? latestSlot.CarrierId.Value:0,
|
|
|
ContractNo = latestSlot.ContractNo,
|
|
|
Vessel = latestSlot.Vessel,
|
|
|
Voyno = latestSlot.Voyno,
|
|
|
PortDischargeId = latestSlot.PortLoadCode,
|
|
|
//PORTDISCHARGEID = latestSlot.PORTDISCHARGEID,
|
|
|
});
|
|
|
// 更新库存
|
|
|
//await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new Event.BookingSlotStockUpdateModel
|
|
|
//{
|
|
|
// BOOKING_SLOT_TYPE = latestSlot.BOOKING_SLOT_TYPE,
|
|
|
// CARRIERID = latestSlot.CARRIERID,
|
|
|
// CONTRACT_NO = latestSlot.CONTRACT_NO,
|
|
|
// VESSEL = latestSlot.VESSEL,
|
|
|
// VOYNO = latestSlot.VOYNO,
|
|
|
// PORTLOADID = latestSlot.PORTLOADID,
|
|
|
// PORTDISCHARGEID = latestSlot.PORTDISCHARGEID,
|
|
|
// TenantId = latestSlot.TenantId,
|
|
|
//}));
|
|
|
}
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
Monitor.Exit(ImportLockObj);
|
|
|
}
|
|
|
|
|
|
return (true, "引入成功");
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 检索舱位对应的订舱订单(BY 舱位主键)
|
|
|
/// </summary>
|
|
|
/// <param name="id">舱位ID</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<BookingSlotWithOrderDto> SearchBookingSlotWithOrderById(long id)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 刷新库存
|
|
|
/// </summary>
|
|
|
/// <param name="input"></param>
|
|
|
/// <returns></returns>
|
|
|
public async Task RefreshStock(BookingSlotStockUpdateModel input)
|
|
|
{
|
|
|
//input.TenantId = UserManager.TENANT_ID;
|
|
|
//更新库存
|
|
|
//await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", input));
|
|
|
}
|
|
|
|
|
|
#region 订舱编号检索舱位信息
|
|
|
/// <summary>
|
|
|
/// 订舱编号检索舱位信息
|
|
|
/// </summary>
|
|
|
/// <param name="slotBookingNo">订舱编号</param>
|
|
|
/// <param name="CarrierId">船公司ID</param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<long> QueryBookingSlot(string slotBookingNo, string CarrierId)
|
|
|
{
|
|
|
long id = 0;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
|
|
|
|
|
|
var model = tenantDb.Queryable<BookingSlotBase>().First(x => x.SlotBookingNo == slotBookingNo && x.CarrierCode == CarrierId);
|
|
|
|
|
|
//if (model == null)
|
|
|
//throw Oops.Bah("舱位信息不存在");
|
|
|
|
|
|
id = model.Id;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
//_logger.LogInformation($"订舱编号检索舱位信息失败,原因:{ex.Message}");
|
|
|
}
|
|
|
|
|
|
return id;
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
/// <summary>
|
|
|
/// 库存查询
|
|
|
/// </summary>
|
|
|
/// <param name="input"></param>
|
|
|
/// <returns></returns>
|
|
|
public async Task<dynamic> PageStock(BookingSlotStockPageInput input)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 生成合票订舱订单
|
|
|
/// </summary>
|
|
|
/// <param name="model">生成订舱订单请求</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<TaskManageOrderResultDto> MergeCreateBookingOrder(BookingGenerateDto model)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 估算差异重要提醒
|
|
|
/// </summary>
|
|
|
/// <param name="bcSrcDto">原舱位详情</param>
|
|
|
/// <param name="bcTargetDto">新舱位详情</param>
|
|
|
/// <param name="slotId">舱位ID</param>
|
|
|
/// <returns></returns>
|
|
|
[NonAction]
|
|
|
public async Task MeasureDiffCautionTask(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto, long slotId)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 检索舱位对应的订舱订单(BY 订舱编号)
|
|
|
/// </summary>
|
|
|
/// <param name="slotBookingNo">订舱编号</param>
|
|
|
/// <param name="tenantId">租户ID</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
|
|
|
public async Task<BookingSlotWithOrderDto> SearchBookingSlotWithOrderByNo(string slotBookingNo, long tenantId)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 导入舱位
|
|
|
/// </summary>
|
|
|
/// <param name="file">导入舱位文件</param>
|
|
|
/// <returns>返回回执</returns>
|
|
|
public async Task<TaskManageOrderResultDto> ImportSlotFromFile(IFormFile file)
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
Task<DataResult<List<BookingSlotBaseWithCtnDto>>> IBookingSlotService.GetAvailableSlots(BookingSlotBaseDto slotInput, List<long> slotIdListInput, PageWithTotal pageInfo)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<dynamic> IBookingSlotService.Page(BookingSlotBasePageInput input)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<long> IBookingSlotService.InnerApiReceive(BookingSlotBaseApiDto dto, DynameFileInfo file, DynameFileInfo modifyFile)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<List<CompareResultDetailInfo>> IBookingSlotService.GetSlotCompareResult(long id, string batchNo)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<TaskManageOrderResultDto> IBookingSlotService.CreateBookingOrder(BookingGenerateDto model)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<string> IBookingSlotService.ExcuteCompare(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
|
|
|
Task<List<BookingSlotBaseSaveOutput>> IBookingSlotService.GetSlotList(long[] ids)
|
|
|
{
|
|
|
throw new NotImplementedException();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static class LetterIndexUtil
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 根据当前字母获取它在26个英文字母中的下一个字母
|
|
|
/// </summary>
|
|
|
public static char GetNextLetter(char currentLetter)
|
|
|
{
|
|
|
if (currentLetter == 'z') return 'a';
|
|
|
if (currentLetter == 'Z') return 'A';
|
|
|
return (char)(currentLetter + 1);
|
|
|
}
|
|
|
}
|
|
|
}
|