You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4457 lines
207 KiB
C#

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;
using DS.Module.Core.Extensions;
4 months ago
using DS.Module.Core.Constants;
using DS.Module.Core.Data;
using DS.WMS.Core.TaskPlat.Dtos;
4 months ago
using NPOI.XSSF.UserModel;
using AngleSharp.Dom;
using DS.WMS.Core.TaskPlat.Entity;
using Microsoft.VisualBasic.FileIO;
3 months ago
using Microsoft.Extensions.Logging;
using AnyDiff.Extensions;
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;
4 months ago
private readonly ICodeLanesService _codeLanesService;
private readonly ISeaExportCommonService _seaExportCommonService;
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";
4 months ago
//BC任务或舱位生成订舱订单时客户联系人必填
const string CONST_CREATE_BOOKING_NEED_CONTACT = "BC_TASK_OR_SLOT_BOOKING_NEED_CONTACT";
/*
*
*/
const string IS_ENABLE_CUSTOMER_AUTHORITY = "IS_ENABLE_CUSTOMER_AUTHORITY";
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>();
4 months ago
_mappingCarrierService = _serviceProvider.GetRequiredService<IMappingCarrierService>();
_codeCountryService = _serviceProvider.GetRequiredService<ICodeCountryService>();
4 months ago
_codeLanesService = _serviceProvider.GetRequiredService<ICodeLanesService>();
_clientInfoService = _serviceProvider.GetRequiredService<IClientInfoService>();
_seaExportCommonService = _serviceProvider.GetRequiredService<ISeaExportCommonService>();
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
4 months ago
|| oldObj.PortLoadCode != model.PortLoadCode
|| oldObj.PortDischargeCode != model.PortDischargeCode)
{
isNeedUpdateOldStock = true;
}
await tenantDb.Updateable<BookingSlotBase>(model).ExecuteCommandAsync();
if (isNeedUpdateOldStock)
{
//更新库存
4 months ago
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
{
BookingSlotType = oldObj.BookingSlotType,
CarrierCode = oldObj.CarrierCode,
ContractNo = oldObj.ContractNo,
Vessel = oldObj.Vessel,
Voyno = oldObj.Voyno,
4 months ago
PortLoadId = oldObj.PortLoadCode,
PortDischargeId = oldObj.PortDischargeCode,
4 months ago
TenantId = long.Parse(user.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();
}
}
var delUseToList = tenantDb.Queryable<BookingSlotUseTo>().Where(x => x.SlotId == model.Id).ToList();
if (delUseToList.Count > 0)
await tenantDb.Deleteable<BookingSlotUseTo>(delUseToList).ExecuteCommandAsync();
if (input.UseToList != null)
{
foreach (var useTo in input.UseToList)
{
var newUseTo = useTo.Adapt<BookingSlotUseTo>();
newUseTo.SlotId = model.Id;
await tenantDb.Insertable<BookingSlotUseTo>(newUseTo).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()).GetAwaiter().GetResult()?.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();
}
if (input.UseToList != null)
{
foreach (var useTo in input.UseToList)
{
var newUseTo = useTo.Adapt<BookingSlotUseTo>();
newUseTo.SlotId = model.Id;
await tenantDb.Insertable<BookingSlotUseTo>(newUseTo).ExecuteCommandAsync();
}
}
//await InsLog("Add", model.Id, "新增舱位");
}
//更新库存
4 months ago
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)
});
var inputDto = new BookingSlotBaseApiDto
{
DataObj = new BookingSlotBaseApiSaveDto
{
4 months ago
PortDischargeCode = model.PortDischargeCode,
PortDischarge = model.PortDischarge,
4 months ago
PortLoadCode = model.PortLoadCode,
PortLoad = model.PortLoad,
PlaceDelivery = model.PlaceDelivery,
4 months ago
PlaceDeliveryCode = model.PlaceDeliveryCode,
PlaceReceipt = model.PlaceReceipt,
4 months ago
PlaceReceiptCode = 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
2REGEX_PATTERN_TXT
3JSON
*/
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))
{
4 months ago
isSucc = CheckLabel("PORTLOADID", dto.DataObj.PortLoadCode, 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))
{
4 months ago
isSucc = CheckLabel("PORTDISCHARGEID", dto.DataObj.PortDischargeCode, 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>>();
var useToList = await tenantDb.Queryable<BookingSlotUseTo>().Where(x => x.SlotId == id).ToListAsync();
rtn.UseToList = useToList.Adapt<List<BookingSlotUseToDto>>();
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,
4 months ago
CreateBy = 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?.Id ?? 0;
}
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);
}
/// <summary>
/// 舱位接收保存、取消接口(任务台使用)
/// </summary>
public async Task<DataResult<BookingSlotBase?>> ApiReceiveTask(TaskFlowDataContext dataContext)
{
var messageInfo = dataContext.Get<TaskManageOrderMessageInfo>(TaskFlowDataNameConst.TaskManageOrderMessageInfo);
if (messageInfo == null)
{
throw new ArgumentNullException($"缺少参数:{TaskFlowDataNameConst.TaskManageOrderMessageInfo}");
}
4 months ago
var taskBcInfo = dataContext.Get<TaskBCInfo>(TaskFlowDataNameConst.TaskBCInfo);
if (taskBcInfo == null)
{
4 months ago
Logger.Log(NLog.LogLevel.Info, $"执行ApiReceiveTask时未获取到{TaskFlowDataNameConst.TaskBCInfo}");
}
DynameFileInfo? bcFileInfo = dataContext.Get<DynameFileInfo>(TaskFlowDataNameConst.BCFileInfo);
DynameFileInfo? bcNoticeFileInfo = dataContext.Get<DynameFileInfo>(TaskFlowDataNameConst.BCNotifyFileInfo);
var taskBCInfoDto = messageInfo.Main.BCInfo;
var allMapCarrierList = await _mappingCarrierService.GetAllList();
MappingCarrierRes? carrierInfo = null;
if (allMapCarrierList.Succeeded)
{
//carrierInfo = allMapCarrierList.Data.FirstOrDefault(t => t.LinkId == taskBCInfoDto.CarrierId && t.Module == CONST_MAPPING_CARRIER_MODULE);
carrierInfo = allMapCarrierList.Data.Where(t => t.MapCode.Equals(taskBCInfoDto.CarrierId, StringComparison.OrdinalIgnoreCase) && t.Module == MappingModuleConst.CONST_MAPPING_CARRIER_MODULE).FirstOrDefault();
}
BookingSlotBaseApiDto slotModel = new BookingSlotBaseApiDto
{
DataObj = new BookingSlotBaseApiSaveDto
{
CarrierId = carrierInfo?.LinkId,
4 months ago
CarrierCode = carrierInfo?.MapCode,
Carrier = carrierInfo?.MapName,
SlotBookingNo = taskBCInfoDto.MBLNo,
BookingParty = taskBCInfoDto.BookingParty,
BookingSlotType = taskBCInfoDto.BookingSlotType,
BookingSlotTypeName = taskBCInfoDto.BookingSlotTypeName,
Vessel = taskBCInfoDto.Vessel,
Voyno = taskBCInfoDto.VoyNo,
VGMSubmissionCutDate = taskBCInfoDto.VGMCutoffTime,
//WeekAt = taskBCInfoDto.WeekAt,
CarriageType = taskBCInfoDto.CarriageType,
CarriageTypeName = taskBCInfoDto.CarriageTypeName,
ContractNo = taskBCInfoDto.ContractNo,
CtnStat = taskBCInfoDto.CtnStat,
CYCutDate = taskBCInfoDto.CYCutoffTime,
DetensionFreeDays = taskBCInfoDto.DetensionFreeDays,
ETD = taskBCInfoDto.ETD,
ETA = taskBCInfoDto.ETA,
LaneCode = taskBCInfoDto.LaneCode,
LaneName = taskBCInfoDto.LaneName,
ManifestCutDate = taskBCInfoDto.ManifestCutDate,
MDGFCutDate = taskBCInfoDto.MDGFCutDate,
PlaceDelivery = taskBCInfoDto.PlaceDelivery,
PlaceReceipt = taskBCInfoDto.PlaceReceipt,
PortDischarge = taskBCInfoDto.PortDischarge,
PortLoad = taskBCInfoDto.Portload,
SICutDate = taskBCInfoDto.SICutDate,
4 months ago
CustomSICutDate = taskBCInfoDto.CustomSICutDate,
TransferPort1 = taskBCInfoDto.TransferPort1,
TransferPort2 = taskBCInfoDto.TransferPort2,
PriceCalculationDate = taskBCInfoDto.PriceCalculationDate,
CtnList = new List<BookingSlotCtnSaveInput>()
},
OpType = messageInfo.Head.RequestAction?.ToLower(),
BatchNo = messageInfo.Main.TaskBatchNo
};
if (int.TryParse(taskBCInfoDto.WeekAt, out int week))
{
slotModel.DataObj.WeekAt = week;
}
if (taskBCInfoDto.CtnList.Count > 0)
{
var ctnCodeList = (await _codeCtnService.GetAllList()).Data ?? new List<Code.Dtos.CodeCtnRes>();
taskBCInfoDto.CtnList.ForEach(t =>
{
if (string.IsNullOrEmpty(t.CtnCode))
{
var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) && a.CtnName.Equals(t.CtnALL, StringComparison.OrdinalIgnoreCase));
t.CtnCode = ctnCode != null ? ctnCode.EdiCode : "";
}
BookingSlotCtnSaveInput ctn = new BookingSlotCtnSaveInput
{
CtnCode = t.CtnCode,
CtnAll = t.CtnALL,
CtnNum = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1
};
slotModel.DataObj.CtnList.Add(ctn);
});
}
var rlt = await InnerApiReceive(slotModel, bcFileInfo, bcNoticeFileInfo);
// 回写舱位主键到BC任务
4 months ago
if (rlt.Succeeded && rlt.Data != null && taskBcInfo != null)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
4 months ago
//var taskBcInfo = await tenantDb.Queryable<TaskBCInfo>().Where(x => x.Id == taskBcId).FirstAsync();
if (taskBcInfo != null)
{
if(taskBcInfo.BOOKING_SLOT_ID == null)
{
taskBcInfo.BOOKING_SLOT_ID = rlt.Data.Id;
await tenantDb.Updateable<TaskBCInfo>(taskBcInfo).UpdateColumns(x => new
{
x.BOOKING_SLOT_ID
}).ExecuteCommandAsync();
}
var taskBaseInfo = await tenantDb.Queryable<TaskBaseInfo>().Where(x => x.Id == taskBcInfo.TASK_ID).FirstAsync();
if (taskBaseInfo.IS_PUBLIC == 1)
{
}
}
}
return rlt;
}
#endregion
#region 舱位接收保存、取消接口(内部接口)
/// <summary>
/// 舱位接收保存、取消接口(内部接口)
/// </summary>
/// <param name="dto">舱位详情</param>
/// <param name="file">原文件</param>
/// <param name="modifyFile">修改文件</param>
/// <returns>返回回执</returns>
public async Task<DataResult<BookingSlotBase?>> InnerApiReceive(BookingSlotBaseApiDto dto, DynameFileInfo file = null, DynameFileInfo modifyFile = null)
{
long id = 0;
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
BookingSlotBase model = null;
//接口方法直接调用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 =>
{
4 months ago
if ((!string.IsNullOrWhiteSpace(t.CtnAll) && string.IsNullOrWhiteSpace(t.CtnCode)) || (!string.IsNullOrWhiteSpace(t.CtnAll) && t.CtnAll == 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;
4 months ago
dto.DataObj.PortLoadCode = portInfo.Data.EdiCode;
3 months ago
dto.DataObj.PortLoadId = portInfo.Data.Id;
}
}
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());
4 months ago
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;
4 months ago
dto.DataObj.PortDischargeCode = portInfo.Data?.EdiCode;
3 months ago
dto.DataObj.PortDischargeId = portInfo.Data?.Id;
}
}
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());
}
}
//自动转换对应标签
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.Item2;
Logger.Log(NLog.LogLevel.Info, $"保存文件路径:{fileFullPath}");
if (!string.IsNullOrWhiteSpace(fileFullPath))
{
//将格式单附件写入订舱的附件
await SaveEDIFile(id, fileFullPath, file.FileName, long.Parse(user.TenantId), file.FileBytes.Length,
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME);
}
}
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.Item2;
Logger.Log(NLog.LogLevel.Info, $"保存文件路径(变更文件):{fileFullPath}");
if (!string.IsNullOrWhiteSpace(fileFullPath))
{
//将格式单附件写入订舱的附件
await SaveEDIFile(id, fileFullPath, modifyFile.FileName, long.Parse(user.TenantId), modifyFile.FileBytes.Length,
CONST_BC_NOTICE_FILE_CODE, CONST_BC_NOTICE_FILE_NAME);
}
}
//触发标签自动绑定
await GenerateSlotLabel(dto, id);
}
else if (dto.OpType == "update")
{
model = tenantDb.Queryable<BookingSlotBase>().First(x => x.SlotBookingNo == dto.DataObj.SlotBookingNo);
if (model == null)
{
throw new Exception($"未找到订舱编号为 {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);
model.Id = id;
// 1.判断新的舱位信息的7个库存统计维度是否发生变化
// 2.如果有变化,则需要更新旧的库存信息
bool isNeedUpdateOldStock = false;
if (oldObj.Vessel != model.Vessel
|| oldObj.Voyno != model.Voyno
|| oldObj.BookingSlotType != model.BookingSlotType
|| oldObj.CarrierId != model.CarrierId
4 months ago
|| oldObj.PortLoadCode != model.PortLoadCode
|| oldObj.PortDischargeCode != model.PortDischargeCode)
{
isNeedUpdateOldStock = true;
}
await tenantDb.Updateable<BookingSlotBase>(model).IgnoreColumns(x=>new {
x.CreateBy,
x.CreateTime,
x.CreateUserName
}).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,
4 months ago
PortLoadId = oldObj.PortLoadCode,
PortDischargeId = oldObj.PortDischargeCode,
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.Item2;
Logger.Log(NLog.LogLevel.Info, $"保存文件路径:{fileFullPath}");
if (!string.IsNullOrWhiteSpace(fileFullPath))
{
//将格式单附件写入订舱的附件
await SaveEDIFile(id, fileFullPath, file.FileName, long.Parse(user.TenantId), file.FileBytes.Length,
CONST_BC_MODIFY_FILE_CODE, CONST_BC_MODIFY_FILE_NAME);
}
}
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.Item2;
Logger.Log(NLog.LogLevel.Info, $"保存文件路径(变更文件):{fileFullPath}");
if (!string.IsNullOrWhiteSpace(fileFullPath))
{
//将格式单附件写入订舱的附件
await SaveEDIFile(id, fileFullPath, modifyFile.FileName, long.Parse(user.TenantId), modifyFile.FileBytes.Length,
CONST_BC_MODIFY_NOTICE_FILE_CODE, CONST_BC_MODIFY_NOTICE_FILE_NAME);
}
}
//一般更新数据指的是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 = tenantDb.Queryable<BookingSlotBase>().First(x => x.SlotBookingNo == slotNO);
if (model == null)
{
throw new Exception($"未找到订舱编号为 {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<BookingSlotBase?>.FailedData(model);
return DataResult<BookingSlotBase?>.Success(model);
}
#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<DataResult<string>> SaveEDIFile(long boookId, string FilePath, string fileName, long tenantId, int fileSize,
string fileTypeCode = "bc", string fileTypeName = "Booking Confirmation", string moudle = "BookingSlot")
{
/*
*/
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var newFile = new OpFile
{
4 months ago
//Id = SnowFlakeSingle.Instance.NextId(),
FileName = fileName,
FilePath = FilePath,
TypeCode = fileTypeCode,
TypeName = fileTypeName,
LinkId = boookId,
FileSize = fileSize,
FileType = Path.GetExtension(fileName),
Extension = Path.GetExtension(fileName),
OrgId = user.OrgId
};
4 months ago
await tenantDb.Insertable<OpFile>(newFile).ExecuteCommandAsync();
4 months ago
return DataResult<string>.Success(string.Empty);
}
#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();
4 months ago
var map = mapCachePortLoad.Data.FirstOrDefault(x => x.Module == MappingModuleConst.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();
4 months ago
var map = mapCachePort.Data.FirstOrDefault(x => x.Module == MappingModuleConst.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]
4 months ago
public async Task<DataResult<string>> 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} 开始请求比对结果");
4 months ago
var rlt = await ExcuteCompare(bcSrcDto, bcTargetDto);
var compareResult = rlt.Data;
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),
4 months ago
CreateUserName = user.UserName,
UpdateBy = long.Parse(user.UserId),
4 months ago
UpdateUserName = user.UserName,
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);
4 months ago
hisInfo.UpdateUserName = 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,
4 months ago
it.UpdateUserName
}).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());
}
4 months ago
return DataResult<string>.Success(string.Empty);
}
#endregion
#region 请求BC比对
/// <summary>
/// 请求BC比对
/// </summary>
/// <param name="bcSrcDto">BC详情</param>
/// <param name="bcTargetDto">BC变更后详情</param>
/// <returns>返回回执</returns>
4 months ago
public async Task<DataResult<TaskManageExcuteResultDto>> ExcuteCompare(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto)
{
TaskManageExcuteResultDto model = null;
/*
1URL
2JSON
3POST
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}");
}
}
4 months ago
if (model != null)
return DataResult<TaskManageExcuteResultDto>.Success(model);
return DataResult<TaskManageExcuteResultDto>.FailedData(model); ;
}
#endregion
#region 获取合票详情(生成合票需要先调此方法)
/// <summary>
/// 获取合票详情(生成合票需要先调此方法)
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<DataResult<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)));
}
}
4 months ago
var getRlt = await GetAvailableSlots(null, model.MergeList, null);
var list = getRlt.Data;
//舱位合票失败,校验库存为不可用,请确认正确的库存
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 DataResult<BookingSlotMergeResultDto>.Success(rlt);
}
#endregion
#region 舱位引入
/// <summary>
/// 分页查询可用的舱位及箱子列表
/// </summary>
/// <param name="input">可选:舱位查询条件</param>
/// <param name="pageInfo">可选:分页信息</param>
public async Task<DataResult<SqlSugarPagedList<BookingSlotBaseWithCtnDto>>> GetAvailableSlots(BookingSlotBaseDto input, PageWithTotal pageInfo)
{
4 months ago
var rlt = await GetAvailableSlots(input, null, pageInfo);
SqlSugarPagedList<BookingSlotBaseWithCtnDto> pageResult = new()
{
PageIndex = pageInfo.PageNo,
PageSize = pageInfo.PageSize,
TotalCount = pageInfo.Total,
4 months ago
Items = rlt.Data,
};
4 months ago
return DataResult<SqlSugarPagedList<BookingSlotBaseWithCtnDto>>.Success(pageResult);
}
#endregion
#region 查询可用的舱位及箱子列表
/// <summary>
/// 查询可用的舱位及箱子列表
/// </summary>
/// <param name="slotInput">筛选条件1舱位信息、箱型</param>
/// <param name="slotIdListInput">筛选条件2舱位主键列表</param>
/// <param name="pageInfo">筛选条件3分页</param>
/// <returns>可用的舱位列表(含可用的箱子列表)</returns>
4 months ago
public async Task<DataResult<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.EdiCode == c.ctnCode)?.CtnName ?? throw new Exception($"舱位信息中存在未收录的箱型:{c.ctnCode},需要在箱型字典中补充"),
}).ToList();
}
}
4 months ago
return DataResult<List<BookingSlotBaseWithCtnDto>>.Success(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();
4 months ago
var lsRlt = await GetAvailableSlots(null, slotIdList);
// 查询可用舱位及箱子列表
4 months ago
var latestSlotList = lsRlt.Data;
// 判断余量是否满足需求
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.Id);
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>
public 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 == MappingModuleConst.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,
4 months ago
OperatorName = generateModel.OpName,
Doc = generateModel.DocId.HasValue ? generateModel.DocId.Value : 0,
4 months ago
DocName = generateModel.DocName,
//ROUTEID = generateModel.RouteID?.ToString(),
//ROUTE = generateModel.Route,
//CZRemark = generateModel.CZRemark,
//ShenQingXiangShi = generateModel.ShenQingXiangShi,
//LineManageID = generateModel.LineManageID?.ToString(),
//LineName = generateModel.LineManage,
4 months ago
VGMCloseDate = bookingSlotBase.VGMSubmissionCutDate,
ClosingDate = bookingSlotBase.CYCutDate,
CloseDocDate = bookingSlotBase.SICutDate,
CustomerService = generateModel.CustServiceId.HasValue ? generateModel.CustServiceId.Value : 0,
4 months ago
CustomerServiceName = 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,
BLType = "整箱",
StlName = "票结",
CtnInfo = new List<OpCtnReq>()
};
if (bookingSlotBase.ETD.HasValue)
{
bkModel.AccountDate = bookingSlotBase.ETD.Value.ToString("yyyy-MM");
}
else
{
bkModel.AccountDate = DateTime.Now.ToString("yyyy-MM");
}
if (generateModel.CtnList == null)
{
var ctnList = (await GetAvailableCtnsBySlot(bookingSlotBase.Id)).Data;
if (ctnList == null || ctnList.Count == 0)
{
throw new Exception("可用舱位为空");
}
generateModel.CtnList = ctnList;
}
// 判断是否为拆票的舱位如果为拆票提单号需要加上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;
bkModel.BLType = "拆票主票";
}
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;
bkModel.BLType = "拆票分票";
}
//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;
if (custNo == masterBookingSlotNo)
{
bkModel.BLType = "合票主票";
}
else
{
bkModel.BLType = "合票分票";
}
}
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 =>
{
if (string.IsNullOrEmpty(t.CtnCode) && !string.IsNullOrEmpty(t.CtnAll))
{
var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.CtnName) && a.CtnName.Equals(t.CtnAll, StringComparison.OrdinalIgnoreCase));
t.CtnCode = ctnCode != null ? $"{ctnCode.CtnSize}{ctnCode.CtnType}" : "(箱型未收录)";
}
OpCtnReq ctn = new OpCtnReq
{
CtnCode = t.CtnCode,
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);
if (bkRlt.Data == null)
{
throw new Exception("根据舱位生成订舱后订舱主键为空messsage:" + bkRlt.Message);
}
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(new ImportSlotsDto
{
4 months ago
slots = importSlots,
bookingOrderId = id,
isCheck = false,
generateModel = 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.Id);
}
if (djyCustomerContactMan != null)
{
var bookingContact = bookingContactList
.FirstOrDefault(x => x.Email.Equals(djyCustomerContactMan.Email, StringComparison.OrdinalIgnoreCase));
if (bookingContact == null)
{
bookingContact = new BusinessOrderContact
{
Name = djyCustomerContactMan.Name,
BusinessId = id,
Email = djyCustomerContactMan.Email,
Note = djyCustomerContactMan.Note,
CreateTime = DateTime.Now,
CreateBy = long.Parse(user.UserId),
4 months ago
CreateUserName = user.UserName
};
tenantDb.Insertable<BusinessOrderContact>(bookingContact).ExecuteCommand();
//_bookingOrderContactRepository.Insert(bookingContact);
}
else
{
bookingContact.Name = djyCustomerContactMan.Name;
bookingContact.Email = djyCustomerContactMan.Email;
bookingContact.Note = djyCustomerContactMan.Note;
bookingContact.UpdateTime = DateTime.Now;
bookingContact.UpdateBy = long.Parse(user.UserId);
4 months ago
bookingContact.UpdateUserName = user.UserName;
tenantDb.Updateable<BusinessOrderContact>(bookingContact).UpdateColumns(it => new
{
it.Name,
it.Email,
it.Note,
it.UpdateTime,
it.UpdateBy,
4 months ago
it.UpdateUserName
}).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 fileRlt = _sysFileService.MoveFile(id.ToString(), fileFullPath, batchNo
, false, null, true).GetAwaiter().GetResult().Data;
//如果确认文件读取成功
var bookFilePath = fileRlt.Item2;
//将格式单附件写入订舱的附件
await SaveEDIFile(id, bookFilePath, bookFilePath, long.Parse(user.TenantId), fileRlt.Item4,
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME);
}
}
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))
{
Tuple<string, string, string, int>? fileRtl = _sysFileService.MoveFile(id.ToString(), fileFullPath, batchNo
, false, "bcnoticefile", true).GetAwaiter().GetResult().Data;
//如果确认文件读取成功
var bookFilePath = fileRtl.Item2;
//将格式单附件写入订舱的附件
await SaveEDIFile(id, bookFilePath, bookFilePath, long.Parse(user.TenantId), fileRtl.Item4,
CONST_BC_FILE_CODE, CONST_BC_FILE_NAME);
}
}
}
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
4 months ago
#region 为指定订舱记录引入舱位信息
/// <summary>
/// 为指定订舱记录引入舱位信息
/// </summary>
4 months ago
/// <param name="model">引入的舱位请求参数</param>
/// <returns>返回回执</returns>
public async Task<DataResult<string>> ImportSlots(ImportSlotsDto model)
{
4 months ago
model.slots ??= new List<BookingSlotBaseWithCtnDto>();
Monitor.Enter(ImportLockObj);
try
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
4 months ago
if (model.isCheck)
{
(bool isExists, bool isEnough, string message) checkResult = CheckImportSlots(model.slots, model.bookingOrderId).GetAwaiter().GetResult();
if (checkResult.isExists || !checkResult.isEnough)
4 months ago
return DataResult<string>.FailedData(checkResult.message);
}
4 months ago
var slotIdList = model.slots.Select(s => s.Id).ToList();
List<BookingSlotBase> latestSlotList = tenantDb.Queryable<BookingSlotBase>().Where(b => slotIdList.Contains(b.Id)).ToList();
4 months ago
foreach (var inSlotItem in model.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.CreateUserName)
.Ignore(dest => dest.UpdateUserName);
//.Ignore(dest => dest.TenantId)
//.Ignore(dest => dest.TenantName);
var newSlotAllocation = latestSlot.Adapt<BookingSlotAllocation>(config);
newSlotAllocation.Id = 0;
newSlotAllocation.BookingSlotId = latestSlot.Id;
4 months ago
newSlotAllocation.BookingId = model.bookingOrderId;
newSlotAllocation.AlloBillNo = latestSlot.SlotBookingNo;
newSlotAllocation.FinalBillNo = latestSlot.SlotBookingNo;
newSlotAllocation.PlaceReceiptId = latestSlot.PlaceReceiptCode;
newSlotAllocation.PlaceDeliveryId = latestSlot.PlaceDeliveryCode;
newSlotAllocation.PortLoadId = latestSlot.PortLoadCode;
newSlotAllocation.PortDischargeId = latestSlot.PortDischargeCode;
4 months ago
if (model.generateModel != null)
{
newSlotAllocation.CustomerId = model.generateModel.CustomerId;
newSlotAllocation.CustomerName = model.generateModel.CustomerName;
newSlotAllocation.CustServiceId = model.generateModel.CustServiceId?.ToString();
newSlotAllocation.CustService = model.generateModel.CustServiceName;
newSlotAllocation.SaleId = model.generateModel.SaleId?.ToString();
newSlotAllocation.Sale = model.generateModel.SaleName;
newSlotAllocation.DocId = model.generateModel.DocId?.ToString();
newSlotAllocation.Doc = model.generateModel.DocName;
newSlotAllocation.OpId = model.generateModel.OpId?.ToString();
newSlotAllocation.Op = model.generateModel.OpName;
newSlotAllocation.Business = model.generateModel.BUSINESS;
newSlotAllocation.BusinessId = model.generateModel.BUSINESSID;
newSlotAllocation.SaleTime = model.generateModel.SALE_TIME;
newSlotAllocation.Shipper = model.generateModel.SHIPPER;
newSlotAllocation.GoodsName = model.generateModel.GOODSNAME;
newSlotAllocation.SellingPrice = model.generateModel.SELLING_PRICE;
newSlotAllocation.SplitOrMergeFlag = model.generateModel.SplitOrMerge;
if (model.generateModel.SplitOrMerge == 1 || model.generateModel.SplitOrMerge == 2)
{
4 months ago
newSlotAllocation.AlloBillNo = model.generateModel.NewMBlNo;
}
}
tenantDb.Insertable<BookingSlotAllocation>(newSlotAllocation).ExecuteReturnEntity();
// 保存关联的箱信息
var insertCtnList = inSlotItem.CtnList.Select(c => new BookingSlotAllocationCtn()
{
SlotAllocId = newSlotAllocation.Id,
CtnCode = c.CtnCode,
CtnAll = c.CtnAll,
CtnNum = c.CtnNum
}).ToList();
insertCtnList.ForEach(c =>
{
tenantDb.Insertable<BookingSlotAllocationCtn>(c).ExecuteCommand();
});
// 为订舱保存附件信息
var lastestBcFile = tenantDb.Queryable<OpFile>().Where(x => x.TypeCode == "bc" && x.LinkId == latestSlot.Id)
.OrderByDescending(x => x.Id)
.First();
if (lastestBcFile != null)
{
var file = lastestBcFile.Adapt<OpFile>();
file.Id = 0;
4 months ago
file.LinkId = model.bookingOrderId;
tenantDb.Insertable<OpFile>(file).ExecuteCommand();
}
var lastestBcModFile = tenantDb.Queryable<OpFile>().Where(x => x.TypeCode == "bc_notice" && x.LinkId == latestSlot.Id)
.OrderByDescending(x => x.Id)
.First();
if (lastestBcFile != null)
{
var file = lastestBcFile.Adapt<OpFile>();
file.Id = 0;
file.LinkId = model.bookingOrderId;
tenantDb.Insertable<OpFile>(file).ExecuteCommand();
}
if (lastestBcModFile != null)
{
var file = lastestBcModFile.Adapt<OpFile>();
file.Id = 0;
file.LinkId = model.bookingOrderId;
tenantDb.Insertable<OpFile>(file).ExecuteCommand();
}
_bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
{
BookingSlotType = latestSlot.BookingSlotType,
CarrierId = latestSlot.CarrierId.HasValue ? latestSlot.CarrierId.Value : 0,
ContractNo = latestSlot.ContractNo,
Vessel = latestSlot.Vessel,
Voyno = latestSlot.Voyno,
4 months ago
PortLoadId = latestSlot.PortLoadCode,
PortDischargeId = latestSlot.PortLoadCode,
}).GetAwaiter().GetResult();
}
var bookingSlotBase = model.slots.FirstOrDefault();
//这里更新订舱的详情
SeaExportOpenEditReq bkModel = new SeaExportOpenEditReq
{
MBLNO = bookingSlotBase.SlotBookingNo.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,
VGMCloseDate = bookingSlotBase.VGMSubmissionCutDate,
ClosingDate = bookingSlotBase.CYCutDate,
CloseDocDate = bookingSlotBase.SICutDate,
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>()
};
if (bookingSlotBase.ETD.HasValue)
{
bkModel.AccountDate = bookingSlotBase.ETD.Value.ToString("yyyy-MM");
}
else
{
bkModel.AccountDate = DateTime.Now.ToString("yyyy-MM");
}
var ctnList = model.slots.SelectMany(b => b.CtnList).ToList();
bkModel.CtnList = ctnList.GroupBy(a => a.CtnCode).Select(a =>
{
var currList = a.ToList();
return new OpCtnReq
{
CtnCode = a.Key,
CtnAll = currList.FirstOrDefault().CtnAll,
CtnNum = currList.Sum(b => b.CtnNum)
};
}).ToList();
var saveSeaExportRlt = _seaExportCommonService.SeaExportOpenEdit(bkModel).GetAwaiter().GetResult();
if (!saveSeaExportRlt.Succeeded)
{
Logger.Log(NLog.LogLevel.Info, $"引入失败,更新海运出口失败,原因:{saveSeaExportRlt.Message}");
}
// if (generateModel.CtnList == null)
//{
// var ctnList = (await GetAvailableCtnsBySlot(bookingSlotBase.Id)).Data;
// if (ctnList == null || ctnList.Count == 0)
// {
// throw new Exception("可用舱位为空");
// }
// generateModel.CtnList = ctnList;
//}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Info, $"引入失败,原因:{ex.Message}");
3 months ago
return DataResult<string>.Failed($"引入失败,原因:{ex.Message}");
}
finally
{
Monitor.Exit(ImportLockObj);
}
4 months ago
return DataResult<string>.Success("引入成功");
}
4 months ago
#endregion
#region 检索舱位对应的订舱订单(BY 舱位主键)
/// <summary>
/// 检索舱位对应的订舱订单(BY 舱位主键)
/// </summary>
/// <param name="id">舱位ID</param>
/// <returns>返回回执</returns>
public async Task<DataResult<BookingSlotWithOrderDto>> SearchBookingSlotWithOrderById(long id)
{
BookingSlotWithOrderDto dto = null;
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var slotInfo = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(a => a.Id == id);
if (slotInfo == null)
{
Logger.Log(NLog.LogLevel.Info, $"id={id} 获取舱位失败,舱位不存在或已作废");
return DataResult<BookingSlotWithOrderDto>.FailedData(dto);
}
var list = tenantDb.Queryable<BookingSlotAllocation>().Where(a => a.BookingSlotId == id).ToList();
dto = new BookingSlotWithOrderDto
{
BookingSlotId = slotInfo.Id,
};
if (list.Count > 0)
{
dto.HasBookingOrder = true;
dto.BookingOrderList = list.Select(x => x.Id).ToList();
}
return DataResult<BookingSlotWithOrderDto>.Success(dto);
}
#endregion
#region 刷新库存
/// <summary>
/// 刷新库存
/// </summary>
/// <param name="input">请求参数</param>
/// <returns>返回回执</returns>
public async Task<DataResult<string>> RefreshStock(BookingSlotStockUpdateModel input)
{
return await _bookingSlotStockService.BookingSlotStock(input);
}
#endregion
#region 订舱编号检索舱位信息
/// <summary>
/// 订舱编号检索舱位信息
/// </summary>
/// <param name="slotBookingNo">订舱编号</param>
/// <param name="CarrierId">船公司ID</param>
/// <returns></returns>
public async Task<DataResult<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 DataResult<long>.Success(id);
}
#endregion
#region 库存台账查询
/// <summary>
/// 库存台账查询
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<DataResult<List<BookingSlotStockDto>>> GetPageStockAsync(PageRequest querySearch)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//序列化查询条件
var whereList = db.ConfigQuery.Context.Utilities.JsonToConditionalModels(querySearch.QueryCondition);
var result = tenantDb.Queryable<BookingSlotStock>()
.Select<BookingSlotStockDto>()
.Where(whereList);
var list = result.ToList();
return await result.ToQueryPageAsync(querySearch.PageCondition);
}
#endregion
/// <summary>
/// 生成合票订舱订单
/// </summary>
/// <param name="model">生成订舱订单请求</param>
/// <returns>返回回执</returns>
public async Task<DataResult<TaskManageOrderResultDto>> MergeCreateBookingOrder(BookingGenerateDto model)
{
return null;
}
/// <summary>
/// 估算差异重要提醒
/// </summary>
/// <param name="bcSrcDto">原舱位详情</param>
/// <param name="bcTargetDto">新舱位详情</param>
/// <param name="slotId">舱位ID</param>
/// <returns></returns>
public async Task<DataResult> MeasureDiffCautionTask(ParserBCInfoDto bcSrcDto, ParserBCInfoDto bcTargetDto, long slotId)
{
return DataResult.Successed(string.Empty);
}
#region 检索舱位对应的订舱订单(BY 订舱编号)
/// <summary>
/// 检索舱位对应的订舱订单(BY 订舱编号)
/// </summary>
/// <param name="slotBookingNo">订舱编号</param>
/// <param name="tenantId">租户ID</param>
/// <returns>返回回执</returns>
public async Task<DataResult<BookingSlotWithOrderDto>> SearchBookingSlotWithOrderByNo(string slotBookingNo, long tenantId)
{
BookingSlotWithOrderDto dto = null;
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var slotInfo = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(a => a.SlotBookingNo == slotBookingNo && a.Deleted == false);
if (slotInfo == null)
{
Logger.Log(NLog.LogLevel.Info, $"slotBookingNo={slotBookingNo} 获取舱位失败,舱位不存在或已作废");
}
var list = tenantDb.Queryable<BookingSlotAllocation>().Where(a => a.SlotBookingNo == slotBookingNo && a.Deleted == false).ToList();
dto = new BookingSlotWithOrderDto
{
BookingSlotId = slotInfo.Id,
};
if (list.Count > 0)
{
dto.HasBookingOrder = true;
var bkNoList = list.Select(x => x.BookingId).ToList();
var bkList = tenantDb.Queryable<SeaExport>().Where(a => bkNoList.Contains(a.Id) && a.Deleted == false).ToList();
if (bkList.Count > 0)
{
dto.BookingOrderList = bkList.Select(x => x.Id).ToList();
}
else
{
dto.BookingOrderList = new List<long>();
}
}
return DataResult<BookingSlotWithOrderDto>.Success(dto);
}
#endregion
4 months ago
#region 导入舱位
/// <summary>
/// 导入舱位
/// </summary>
/// <param name="file">导入舱位文件</param>
/// <returns>返回回执</returns>
public async Task<DataResult<List<object>>> ImportSlotFromFile(IFormFile file)
{
4 months ago
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
bool succ = false;
List<object> list = new List<object>();
4 months ago
try
{
4 months ago
if (file == null)
{
//附件不能为空
return DataResult<List<object>>.Failed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportFileNull)));
4 months ago
}
FileInfo fileInfo = new FileInfo(file.FileName);
if (fileInfo.Extension != ".xlsx")
{
//请上传指定模板文件
return DataResult<List<object>>.Failed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportFileTypeError)));
4 months ago
}
string fileRoot = AppSetting.app(new string[] { "FileSettings", "BasePath" });
string relativePath = AppSetting.app(new string[] { "FileSettings", "RelativePath" });
var tempDic = Path.Combine(fileRoot, relativePath, DateTime.Now.Ticks.ToString());
4 months ago
Directory.CreateDirectory(tempDic);
var filePath = Path.Combine(tempDic, file.FileName);
using (var stream = File.Create(filePath))
{
await file.CopyToAsync(stream);
}
using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
var readbook = new XSSFWorkbook(fs);
var sheet = readbook.GetSheet("导入");
if (sheet == null)
{
//内容为空
return DataResult<List<object>>.Failed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportExcelEmpty)));
4 months ago
}
var rowCount = sheet.LastRowNum;
if (rowCount <= 1)
{
//内容为空
return DataResult<List<object>>.Failed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportExcelEmpty)));
4 months ago
}
Dictionary<BookingSlotBase, List<BookingSlotCtn>> data = new(rowCount);
//List<BookingSlotBase> data = new(rowCount);
var cacheMappCarrier = _mappingCarrierService.GetAllList().GetAwaiter().GetResult().Data;
var cachePort = _codePortService.GetAllList().GetAwaiter().GetResult().Data;
var cacheLane = _codeLanesService.GetAllList().GetAwaiter().GetResult().Data;
var cacheCtnCode = _codeCtnService.GetAllList().GetAwaiter().GetResult().Data;
BookingSlotBase lastSlot = null;
for (int i = 1; i < rowCount; i++)
{
var row = sheet.GetRow(i);
if (row == null)
{
continue;
}
if (string.IsNullOrWhiteSpace(row.GetCell(0)?.StringCellValue))
{
if (string.IsNullOrWhiteSpace(row.GetCell(23)?.ToString()))
{
continue;
}
BookingSlotCtn ctnExt = new();
// 解析箱信息
for (int n = 23; n <= 24; n++)
{
var cell = row.GetCell(n);
if (cell == null) continue;
var value = cell.ToString();
if (string.IsNullOrWhiteSpace(value)) continue;
switch (n)
{
case 23:
{
ctnExt.CtnAll = value;
ctnExt.CtnCode = cacheCtnCode.FirstOrDefault(x => x.CtnName == value)?.EdiCode;
4 months ago
break;
}
case 24:
{
if (int.TryParse(value, out int temp)) ctnExt.CtnNum = temp; break;
}
}
}
if (!string.IsNullOrEmpty(ctnExt.CtnCode) && data.TryGetValue(lastSlot, out var ctnList))
{
ctnList.Add(ctnExt);
}
continue;
}
var slot = new BookingSlotBase();
// 解析舱位信息
for (int n = 0; n <= 22; n++)
{
var cell = row.GetCell(n);
if (cell == null) continue;
//var value = cell.StringCellValue;
var value = cell.ToString().Trim();
if (string.IsNullOrWhiteSpace(value)) continue;
switch (n)
{
case 0: slot.SlotBookingNo = value; break;
case 1: slot.CarrierCode = value; break;
case 2: slot.Vessel = value; break;
case 3: slot.Voyno = value; break;
case 4: slot.ContractNo = value; break;
case 5: slot.BookingSlotTypeName = value; break;
case 6:
slot.ETD = cell.DateCellValue; break;
//{
// if (DateTime.TryParse(value, out DateTime temp)) slot.ETD = temp; break;
//}
case 7:
slot.ETA = cell.DateCellValue; break;
//{
// if (DateTime.TryParse(value, out DateTime temp)) slot.ETA = temp; break;
//}
case 8: slot.BookingParty = value; break;
case 9: slot.PlaceReceipt = value; break;
case 10: slot.PlaceDelivery = value; break;
case 11: slot.PortLoadCode = value; break;
case 12: slot.PortDischargeCode = value; break;
case 13:
{
if (int.TryParse(value, out int temp)) slot.WeekAt = temp; break;
}
case 14:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.SI_CUT_DATE = temp; break;
slot.SICutDate = cell.DateCellValue; break;
}
case 15:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.VGM_SUBMISSION_CUT_DATE = temp; break;
slot.VGMSubmissionCutDate = cell.DateCellValue; break;
}
case 16:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.CY_CUT_DATE = temp; break;
slot.CYCutDate = cell.DateCellValue; break;
}
case 17:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.MANIFEST_CUT_DATE = temp; break;
slot.ManifestCutDate = cell.DateCellValue; break;
}
case 18:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.MDGF_CUT_DATE = temp; break;
slot.MDGFCutDate = cell.DateCellValue; break;
}
case 19: slot.LaneName = value; break; //
case 20:
{
if (int.TryParse(value, out int temp)) slot.DetensionFreeDays = temp; break;
}
case 21:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.CreatedTime = temp; break;
slot.CreateTime = cell.DateCellValue.Value; break;
}
case 22:
{
//if (DateTime.TryParse(value, out DateTime temp)) slot.PRICE_CALCULATION_DATE = temp; break;
slot.PriceCalculationDate = cell.DateCellValue; break;
}
default: break;
}
}
// 特殊处理
if (!string.IsNullOrWhiteSpace(slot.CarrierCode)) slot.Carrier = cacheMappCarrier.FirstOrDefault(x => x.MapCode == slot.CarrierCode)?.MapName;
4 months ago
if (!string.IsNullOrWhiteSpace(slot.PortLoadCode)) slot.PortLoad = cachePort.FirstOrDefault(x => x.EdiCode == slot.PortLoadCode)?.PortName;
if (!string.IsNullOrWhiteSpace(slot.PortDischargeCode)) slot.PortDischarge = cachePort.FirstOrDefault(x => x.EdiCode == slot.PortDischargeCode)?.PortName;
if (!string.IsNullOrWhiteSpace(slot.LaneName)) slot.LaneCode = cacheLane.FirstOrDefault(x => x.LaneName == slot.LaneName)?.LaneEnName;
4 months ago
if (!string.IsNullOrWhiteSpace(slot.BookingSlotTypeName))
slot.BookingSlotType = slot.BookingSlotTypeName switch
{
"合约订舱" => "CONTRACT_ORDER",
"SPOT订舱" => "SPOT_ORDER",
_ => null
};
var ctns = new List<BookingSlotCtn>();
BookingSlotCtn ctn = new();
// 解析箱信息
for (int n = 23; n <= 24; n++)
{
var cell = row.GetCell(n);
if (cell == null) continue;
var value = cell.ToString();
if (string.IsNullOrWhiteSpace(value)) continue;
switch (n)
{
case 23:
{
ctn.CtnAll = value;
ctn.CtnCode = cacheCtnCode.FirstOrDefault(x => x.CtnName == value)?.EdiCode;
4 months ago
break;
}
case 24:
{
if (int.TryParse(value, out int temp)) ctn.CtnNum = temp; break;
}
}
}
if (!string.IsNullOrEmpty(ctn.CtnCode))
{
ctns.Add(ctn);
}
data.Add(slot, ctns);
lastSlot = slot;
}
// 判断是否已经存在
var noList = data.Select(x => x.Key).Select(x => x.SlotBookingNo).ToList();
var existsNoList = await tenantDb.Queryable<BookingSlotBase>()
.Where(x => noList.Contains(x.SlotBookingNo))
.Select(x => x.SlotBookingNo)
.ToListAsync();
4 months ago
foreach (var item in data)
{
if (existsNoList.Contains(item.Key.SlotBookingNo))
{
list.Add(new
{
IsSuccess = false,
FailReason = "此订舱编号已存在",
SlotBookingNo = item.Key.SlotBookingNo
});
continue;
}
await tenantDb.Insertable<BookingSlotBase>(item.Key).ExecuteReturnEntityAsync();
var id = item.Key.Id;
if (item.Value.Any())
{
item.Value.ForEach(x =>
{
x.SlotId = id;
});
await tenantDb.Insertable<BookingSlotCtn>(item.Value).ExecuteCommandAsync();
}
list.Add(new
{
IsSuccess = true,
SlotBookingNo = item.Key.SlotBookingNo
});
}
succ = true;
4 months ago
var group = data.Keys.Where(x =>
!existsNoList.Contains(x.SlotBookingNo)
&& !string.IsNullOrEmpty(x.Vessel)
&& !string.IsNullOrEmpty(x.Voyno)
&& !string.IsNullOrEmpty(x.ContractNo)
&& !string.IsNullOrEmpty(x.BookingSlotType)
&& !string.IsNullOrEmpty(x.CarrierCode)
&& !string.IsNullOrEmpty(x.PortLoadCode)
&& !string.IsNullOrEmpty(x.PortDischargeCode))
.GroupBy(x => new
{
x.Vessel,
x.Voyno,
x.CarrierCode,
x.BookingSlotType,
x.PortDischargeCode,
x.PortLoadCode,
x.ContractNo
}).ToList();
foreach (var item in group)
{
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
{
BookingSlotType = item.Key.BookingSlotType,
CarrierCode = item.Key.CarrierCode,
ContractNo = item.Key.ContractNo,
Vessel = item.Key.Vessel,
Voyno = item.Key.Voyno,
PortLoadId = item.Key.PortLoadCode,
PortDischargeId = item.Key.PortDischargeCode,
TenantId = long.Parse(user.TenantId)
});
}
}
catch (Exception ex)
{
Logger.Log(NLog.LogLevel.Error, $"导入舱位异常,原因:{ex.Message}");
return DataResult<List<object>>.Failed(string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportException)), ex.Message));
4 months ago
}
if (succ)
{
return DataResult<List<object>>.Success(list);
}
return DataResult<List<object>>.Failed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotImportFail)));
}
4 months ago
#endregion
#region 导出舱位为Excel
/// <summary>
/// 导出舱位为Excel
/// </summary>
/// <param name="querySearch">请求参数</param>
4 months ago
/// <returns></returns>
public async Task<DataResult<string>> ExportOrder(PageRequest querySearch)
4 months ago
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//序列化查询条件
var whereList = db.ConfigQuery.Context.Utilities.JsonToConditionalModels(querySearch.QueryCondition);
List<string> ctnCodeArr = new List<string>();
List<long> labelIdArray = new List<long>();
if (whereList.Any(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)))
4 months ago
{
var codList = whereList.Where(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)).ToList();
ctnCodeArr = codList.Select(t => ((ConditionalModel)t).FieldValue).ToList();
codList.ForEach(t =>
{
whereList.Remove(t);
});
4 months ago
}
if (whereList.Any(t => ((ConditionalModel)t).FieldName.Equals("labelIdArray", StringComparison.OrdinalIgnoreCase)))
4 months ago
{
var codList = whereList.Where(t => ((ConditionalModel)t).FieldName.Equals("labelIdArray", StringComparison.OrdinalIgnoreCase)).ToList();
labelIdArray = codList.Select(t => long.Parse(((ConditionalModel)t).FieldValue)).ToList();
4 months ago
codList.ForEach(t =>
{
whereList.Remove(t);
});
4 months ago
}
var select = tenantDb.Queryable<BookingSlotBase>()
.LeftJoin<BookingSlotCtn>((a, b) => a.Id == b.SlotId)
.Where(whereList)
.WhereIF(ctnCodeArr != null && ctnCodeArr.Count > 0, (a, b) => b != null
&& !string.IsNullOrWhiteSpace(b.CtnCode)
&& ctnCodeArr.Contains(b.CtnCode) && b.Deleted == false)
.WhereIF(labelIdArray != null && labelIdArray.Count > 0,
a => SqlFunc.Subqueryable<BookingLabelAllocation>()
.Where(x => x.BusinessId == a.Id && labelIdArray.Contains(x.LabelId))
.Any())
.Select<BookingSlotBaseDto>().Distinct();
4 months ago
//var sql = select.OrderByDescending(u => u.CreatedTime).ToSqlString();
var entities = await select.OrderByDescending(u => u.Id).ToListAsync();
var data = entities.Adapt<List<BookingSlotBaseDto>>();
4 months ago
var slotIds = entities.Select(x => x.Id);
if (slotIds.Any())
{
// 查询舱位绑定的销售信息,赋值到舱位对象中
List<BookingSlotSaleInfoDto> allocationInfoList = await tenantDb.Queryable<BookingSlotAllocation>()
.Where(x => slotIds.Contains(x.BookingSlotId))
4 months ago
.Select(x => new BookingSlotSaleInfoDto
{
Id = x.Id,
BookingId = x.BookingId,
BookingSlotId = x.BookingSlotId,
CustomerId = x.CustomerId,
CustomerName = x.CustomerName,
CustServiceId = x.CustService,
CustService = x.CustService,
SaleId = x.SaleId,
Sale = x.Sale,
OpId = x.OpId,
Op = x.Op,
DocId = x.DocId,
Doc = x.Doc,
Business = x.Business,
BusinessId = x.BusinessId,
SaleTime = x.SaleTime,
Shipper = x.Shipper,
GoodsName = x.GoodsName,
SellingPrice = x.SellingPrice
4 months ago
}).ToListAsync();
4 months ago
if (allocationInfoList.Any())
{
// 判断是否启用了委托单位查看控制权限
var paramConfig = _configService.GetConfig(IS_ENABLE_CUSTOMER_AUTHORITY, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
// 判断是否启用了委托单位查看控制权限
bool isEnableCustomerAuthority = false;
if (!string.IsNullOrWhiteSpace(paramConfig) && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
{
isEnableCustomerAuthority = true;
4 months ago
}
List<long> userList = new List<long>();
List<string> userListStr = new List<string>();
//if (isEnableCustomerAuthority)
//{
// userList = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuDjyCustomer);
// if (userList == null || userList.Count == 0)
// {
// isEnableCustomerAuthority = false;
// }
// else
// {
// userListStr = userList.Select(x => x.ToString()).ToList();
// }
//}
var saleInfoGroup = allocationInfoList.GroupBy(x => x.BookingSlotId);
4 months ago
foreach (var item in saleInfoGroup)
{
if (isEnableCustomerAuthority)
{
// 遍历销售信息,如果销售信息中的“销售、操作、单证、客服、创建人”中不在当前登陆人的权限范围,则隐藏客户信息
foreach (BookingSlotSaleInfoDto saleInfoItem in item)
{
if (!userList.Contains(saleInfoItem.CreateBy)
&& !userListStr.Contains(saleInfoItem.OpId)
&& !userListStr.Contains(saleInfoItem.DocId)
&& !userListStr.Contains(saleInfoItem.SaleId)
&& !userListStr.Contains(saleInfoItem.CustServiceId))
4 months ago
{
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 = "--";
4 months ago
}
}
}
var slot = data.FirstOrDefault(x => x.Id == item.Key);
if (slot != null)
{
slot.BookingSlotSaleInfoList = item.ToList();
}
}
}
// 查询舱位绑定的标签信息,赋值到舱位对象中
var labelCacheList = await _bookingLabelService.List(1);
var labelAllocationList = await tenantDb.Queryable<BookingLabelAllocation>()
4 months ago
.Where(x => slotIds.Contains(x.BusinessId))
.ToListAsync();
if (labelAllocationList.Any())
{
var labelInfoGroup = labelAllocationList.GroupBy(x => x.BusinessId);
foreach (var item in labelInfoGroup)
{
var slot = data.FirstOrDefault(x => x.Id == item.Key);
if (slot != null)
{
slot.LabelList = item.Select(x =>
{
var labelCache = labelCacheList.Data.FirstOrDefault(l => l.Id == x.LabelId);
4 months ago
if (labelCache != null)
{
return new BookingLabelBaseDto
{
Id = x.LabelId,
Name = labelCache.Name,
Color = labelCache.Color,
Scope = labelCache.Scope
};
}
return null;
}).ToList();
slot.LabelList.RemoveAll(x => x == null);
}
}
}
}
string fileRoot = AppSetting.app(new string[] { "FileSettings", "BasePath" });
string relativePath = AppSetting.app(new string[] { "FileSettings", "RelativePath" });
var tempDic = Path.Combine(fileRoot, relativePath, DateTime.Now.Ticks.ToString());
Directory.CreateDirectory(tempDic);
var fileAbsPath = Path.Combine(tempDic, "");
//var opt = App.GetOptions<PrintTemplateOptions>();
//var dirAbs = opt.basePath;
//if (string.IsNullOrEmpty(dirAbs))
//{
// dirAbs = App.WebHostEnvironment.WebRootPath;
//}
//var fileAbsPath = Path.Combine(dirAbs, "upload/printtemplate/舱位信息导出模板.xlsx");
4 months ago
if (!File.Exists(fileAbsPath))
{
//舱位台账导出模板【舱位台账导出模板】文件不存在
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotExportTemplateNull)));
4 months ago
}
var fs = new FileStream(fileAbsPath, FileMode.Open);
var excelwork = new XSSFWorkbook(fs);
var sheet = excelwork.GetSheet("导出");
var rowIndex = 1;
var dateStr = "yyyy-MM-dd";
var dateTimeStr = "yyyy-MM-dd HH:mm:ss";
foreach (BookingSlotBaseDto item in data)
4 months ago
{
var row = sheet.GetRow(rowIndex);
if (row == null)
{
row = sheet.CreateRow(rowIndex);
}
for (int i = 0; i <= 35; i++)
{
var cell = row.GetCell(i);
if (cell == null)
{
cell = row.CreateCell(i);
}
var value = i switch
{
0 => item.SlotBookingNo,
1 => item.CarrierCode,
2 => item.Vessel,
3 => item.Voyno,
4 => item.ContractNo,
5 => item.BookingSlotType,
4 months ago
6 => item.ETD?.ToString(dateTimeStr),
7 => item.ETA?.ToString(dateTimeStr),
8 => item.BookingParty,
9 => item.IsCancellation ? "是" : "",
10 => item.PlaceReceipt,
11 => item.PlaceDelivery,
12 => item.PortLoad,
13 => item.PortDischarge,
14 => item.CtnStat,
15 => item.WeekAt?.ToString(),
16 => item.SICutDate?.ToString(dateTimeStr),
17 => item.VGMSubmissionCutDate?.ToString(dateTimeStr),
18 => item.CYCutDate?.ToString(dateTimeStr),
19 => item.ManifestCutDate?.ToString(dateTimeStr),
20 => item.MDGFCutDate?.ToString(dateTimeStr),
21 => item.LaneName,
22 => item.DetensionFreeDays?.ToString(),
23 => item.CreateTime.ToString(dateTimeStr),
24 => item.VGMRltStat,
25 => item.SIRltStat,
26 => item.TakeCtnRltStat,
27 => item.ReturnCtnRltStat,
28 => item.NominationRltStat,
29 => item.AmendmentRltStat,
30 => item.CancellationRltStat,
31 => item.DischargeFullRltStat,
32 => item.GateOutFullRltStat,
4 months ago
33 => "",
34 => item.Remark,
35 => item.PriceCalculationDate?.ToString(dateStr),
4 months ago
_ => ""
};
cell.SetCellValue(value);
}
if (item.BookingSlotSaleInfoList != null && item.BookingSlotSaleInfoList.Count > 0)
{
for (int m = 0; m < item.BookingSlotSaleInfoList.Count; m++)
{
BookingSlotSaleInfoDto saleItem = item.BookingSlotSaleInfoList[m];
var row2 = sheet.GetRow(rowIndex);
if (row2 == null)
{
row2 = sheet.CreateRow(rowIndex);
}
for (int i = 36; i <= 42; i++)
{
var cell2 = row2.GetCell(i);
if (cell2 == null)
{
cell2 = row2.CreateCell(i);
}
var value2 = i switch
{
36 => saleItem.CustomerName,
37 => saleItem.CustService,
38 => saleItem.Sale,
39 => saleItem.Shipper,
40 => saleItem.GoodsName,
41 => saleItem.SellingPrice?.ToString(),
42 => saleItem.SaleTime?.ToString(dateTimeStr),
4 months ago
_ => ""
};
cell2.SetCellValue(value2);
}
// 如果不是最后一条数据,创建新行
if (m < item.BookingSlotSaleInfoList.Count - 1)
{
rowIndex++;
}
}
}
rowIndex++;
}
//var fileFullPath = Path.Combine(App.WebHostEnvironment.WebRootPath, App.GetOptions<TempFileOptions>().Path);//服务器路径
//if (!Directory.Exists(fileFullPath))
//{
// Directory.CreateDirectory(fileFullPath);
//}
4 months ago
var fileName = $"舱位导出_{DateTime.Now.ToString("yyyyMMdd-HHmmss")}.xlsx";//名称
var filestream = new FileStream(Path.Combine("", fileName), FileMode.OpenOrCreate, FileAccess.ReadWrite);
4 months ago
excelwork.Write(filestream);
await Task.Delay(2000);
//return HttpUtility.UrlEncode(fileName, Encoding.GetEncoding("UTF-8"));
return DataResult<string>.Success(fileName);
4 months ago
}
#endregion
4 months ago
/// <summary>
/// 舱位台账查询
/// </summary>
/// <param name="querySearch">查询条件</param>
/// <returns></returns>
public async Task<DataResult<List<BookingSlotBaseDto>>> GetPageAsync(PageRequest querySearch)
{
4 months ago
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
long batchNo = SnowFlakeSingle.Instance.NextId();
DateTime bDate = DateTime.Now;
Logger.Log(NLog.LogLevel.Info, $"批次={batchNo} 开始查询台账");
4 months ago
//序列化查询条件
var whereList = db.ConfigQuery.Context.Utilities.JsonToConditionalModels(querySearch.QueryCondition);
List<string> ctnCodeArr = new List<string>();
List<long> labelIdArray = new List<long>();
if (whereList.Any(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)))
{
var codList = whereList.Where(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)).ToList();
ctnCodeArr = codList.Select(t => ((ConditionalModel)t).FieldValue).ToList();
codList.ForEach(t =>
{
whereList.Remove(t);
});
}
if (whereList.Any(t => ((ConditionalModel)t).FieldName.Equals("labelIdArray", StringComparison.OrdinalIgnoreCase)))
{
var codList = whereList.Where(t => ((ConditionalModel)t).FieldName.Equals("labelIdArray", StringComparison.OrdinalIgnoreCase)).ToList();
labelIdArray = codList.Select(t => long.Parse(((ConditionalModel)t).FieldValue)).ToList();
codList.ForEach(t =>
{
whereList.Remove(t);
});
}
4 months ago
var result = tenantDb.Queryable<BookingSlotBase>()
.LeftJoin<BookingSlotCtn>((a, b) => a.Id == b.SlotId)
.Where(whereList)
.WhereIF(ctnCodeArr != null && ctnCodeArr.Count > 0, (a, b) => b != null
&& !string.IsNullOrWhiteSpace(b.CtnCode)
&& ctnCodeArr.Contains(b.CtnCode) && b.Deleted == false)
.WhereIF(labelIdArray != null && labelIdArray.Count > 0,
a => SqlFunc.Subqueryable<BookingLabelAllocation>()
.Where(x => x.BusinessId == a.Id && labelIdArray.Contains(x.LabelId))
.Any())
.Select<BookingSlotBaseDto>().Distinct();
4 months ago
var data = await result.ToQueryPageAsync(querySearch.PageCondition);
var slotIds = data.Data.Select(x => x.Id);
if (slotIds.Any())
{
// 查询舱位绑定的销售信息,赋值到舱位对象中
List<BookingSlotSaleInfoDto> allocationInfoList = await tenantDb.Queryable<BookingSlotAllocation>()
.Where(x => slotIds.Contains(x.BookingSlotId))
.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,
Business = x.Business,
BusinessId = x.BusinessId,
SaleTime = x.SaleTime,
Shipper = x.Shipper,
GoodsName = x.GoodsName,
SellingPrice = x.SellingPrice,
CreateBy = x.CreateBy
}).ToListAsync();
if (allocationInfoList.Any())
{
var paramConfig = _configService.GetConfig(IS_ENABLE_CUSTOMER_AUTHORITY, long.Parse(user.TenantId), false).GetAwaiter().GetResult()?.Data?.Value;
// 判断是否启用了委托单位查看控制权限
bool isEnableCustomerAuthority = false;
if (!string.IsNullOrWhiteSpace(paramConfig) && paramConfig.Equals("ENABLE", StringComparison.OrdinalIgnoreCase))
{
isEnableCustomerAuthority = true;
}
List<long> userList = new List<long>();
List<string> userListStr = new List<string>();
//if (isEnableCustomerAuthority)
//{
// userList = await _sysDataUserMenuService.GetDataScopeList(MenuConst.MenuDjyCustomer);
// if (userList == null || userList.Count == 0)
// {
// isEnableCustomerAuthority = false;
// }
// else
// {
// userListStr = userList.Select(x => x.ToString()).ToList();
// }
//}
var saleInfoGroup = allocationInfoList.GroupBy(x => x.BookingSlotId);
foreach (var item in saleInfoGroup)
{
if (isEnableCustomerAuthority)
{
// 遍历销售信息,如果销售信息中的“销售、操作、单证、客服、创建人”中不在当前登陆人的权限范围,则隐藏客户信息
foreach (BookingSlotSaleInfoDto saleInfoItem in item)
{
if (!userList.Contains(saleInfoItem.CreateBy)
&& !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 = "--";
}
}
}
var slot = data.Data.FirstOrDefault(x => x.Id == item.Key);
if (slot != null)
{
slot.BookingSlotSaleInfoList = item.ToList();
}
}
}
// 查询舱位绑定的标签信息,赋值到舱位对象中
var labelCacheList = await _bookingLabelService.List(1);
var labelAllocationList = await tenantDb.Queryable<BookingLabelAllocation>()
.Where(x => slotIds.Contains(x.BusinessId))
.ToListAsync();
if (labelAllocationList.Any())
{
var labelInfoGroup = labelAllocationList.GroupBy(x => x.BusinessId);
foreach (var item in labelInfoGroup)
{
var slot = data.Data.FirstOrDefault(x => x.Id == item.Key);
if (slot != null)
{
slot.LabelList = item.Select(x =>
{
var labelCache = labelCacheList.Data.FirstOrDefault(l => l.Id == x.LabelId);
if (labelCache != null)
{
return new BookingLabelBaseDto
{
Id = x.LabelId,
Name = labelCache.Name,
Color = labelCache.Color,
Scope = labelCache.Scope
};
}
return null;
}).ToList();
slot.LabelList.RemoveAll(x => x == null);
}
}
}
}
DateTime eDate = DateTime.Now;
TimeSpan ts = eDate.Subtract(bDate);
var timeDiff = ts.TotalMilliseconds;
Logger.Log(NLog.LogLevel.Info, $"批次={batchNo} 请求完成,耗时:{timeDiff}ms.");
4 months ago
return data;
}
4 months ago
#region 获取舱位变更比对结果
/// <summary>
/// 获取舱位变更比对结果
/// </summary>
/// <param name="id">舱位主键</param>
/// <param name="batchNo">批次号</param>
/// <returns>返回舱位变更比对结果</returns>
public async Task<DataResult<List<CompareResultDetailInfo>>> GetSlotCompareResult(long id, string batchNo)
{
4 months ago
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var compareInfo = await tenantDb.Queryable<BookingSlotCompare>()
.FirstAsync(t => t.SlotId == id && t.CompareBatchNo == batchNo);
if (compareInfo == null)
{
//舱位变更比对结果不存在
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCompareNull)));
}
if (string.IsNullOrWhiteSpace(compareInfo.CompareRlt))
{
//获取舱位变更比对结果错误,比对内容不存在
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCompareJsonNull)));
}
if (!string.IsNullOrWhiteSpace(compareInfo.CompareRlt))
{
var data = JsonConvert.DeserializeObject<List<CompareResultDetailInfo>>(compareInfo.CompareRlt);
return DataResult<List<CompareResultDetailInfo>>.Success(data);
4 months ago
}
return DataResult<List<CompareResultDetailInfo>>.Success(new List<CompareResultDetailInfo>());
}
4 months ago
#endregion
#region 获取舱位详情列表
/// <summary>
/// 获取舱位详情列表
/// </summary>
/// <param name="ids">舱位ID组</param>
/// <returns>返回舱位详情</returns>
public async Task<DataResult<List<BookingSlotBaseSaveOutput>>> GetSlotList(long[] ids)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var slotList = await tenantDb.Queryable<BookingSlotBase>().Where(u => ids.Contains(u.Id) && u.Deleted == false).ToListAsync();
if (slotList.Count == 0)
{
//未查询到此舱位信息,可能已被删除,请重新查询后重试
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotBaseInfoNull)));
}
var data = slotList.Select(a => a.Adapt<BookingSlotBaseSaveOutput>()).ToList();
if (data.Count > 0)
return DataResult<List<BookingSlotBaseSaveOutput>>.Success(data);
return DataResult<List<BookingSlotBaseSaveOutput>>.FailedData(data);
}
#endregion
#region 作废舱位(可以批量)
/// <summary>
/// 作废舱位(可以批量)
/// </summary>
/// <param name="ids">舱位主键数组</param>
/// <returns>返回回执</returns>
public async Task<DataResult> Delete(long[] ids)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
foreach (long id in ids)
{
var slot = await tenantDb.Queryable<BookingSlotBase>().FirstAsync(x => x.Id == id);
if (slot == null)
{
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotBaseInfoNull)));
}
slot.Deleted = true;
slot.DeleteBy = long.Parse(user.UserId);
slot.DeleteUserName = user.UserName;
slot.DeleteTime = DateTime.Now;
await tenantDb.Updateable<BookingSlotBase>(slot).ExecuteCommandAsync();
var ctnList = tenantDb.Queryable<BookingSlotCtn>().Where(x => x.SlotId == id).ToList();
ctnList.ForEach(t =>
{
t.Deleted = true;
t.DeleteTime = DateTime.Now;
t.DeleteBy = long.Parse(user.UserId);
t.DeleteUserName = user.UserName;
tenantDb.Updateable<BookingSlotCtn>(t).ExecuteCommand();
});
var alloc = tenantDb.Queryable<BookingSlotAllocation>().Where(a => a.BookingSlotId == id && a.Deleted == false).ToList();
if (alloc.Count > 0)
{
alloc.ForEach(t =>
{
t.Deleted = true;
t.DeleteTime = DateTime.Now;
t.DeleteBy = long.Parse(user.UserId);
t.DeleteUserName = user.UserName;
tenantDb.Updateable<BookingSlotAllocation>(t).ExecuteCommand();
});
}
//更新库存
await _bookingSlotStockService.BookingSlotStock(new BookingSlotStockUpdateModel
{
BookingSlotType = slot.BookingSlotType,
CarrierCode = slot.CarrierCode,
ContractNo = slot.ContractNo,
Vessel = slot.Vessel,
Voyno = slot.Voyno,
PortLoadId = slot.PortLoadCode,
PortDischargeId = slot.PortDischargeCode,
TenantId = long.Parse(user.TenantId)
});
}
return DataResult.Successed(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotDeleteSucc)));
}
#endregion
4 months ago
/// <summary>
/// 查询指定舱位可用的箱子列表
/// </summary>
/// <param name="slotId">舱位主键</param>
/// <returns>可用的箱子列表</returns>
public async Task<DataResult<List<BookingSlotCtnDto>>> GetAvailableCtnsBySlot(long slotId)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
if (await tenantDb.Queryable<BookingSlotBase>().AnyAsync(x => x.Id == slotId && x.IsCancellation == false) == false)
{
//获取舱位失败,舱位不存在或已作废
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BookingSlotCreateRecordDeletedOrNoExists)));
}
// 1. 【舱位基础表】与【箱子表】做关联并根据【舱位主键】、【箱型】做分组统计出【总的箱量】作为queryable1
var queryable1 = tenantDb.Queryable<BookingSlotBase, BookingSlotCtn>((bas, ctn) => bas.Id == ctn.SlotId)
.Where(bas => bas.IsCancellation == false && bas.Id == slotId)
.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)
.Where((alc, ctn) => alc.BookingSlotId == slotId)
.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,
numResidue = SqlFunc.IsNull(q1.numAll - q2.numUse, q1.numAll)
})
.MergeTable()
.Where(r => r.numResidue > 0);
// 4. 执行ToList(),得到可用的【舱位主键】、【箱型】、【箱量】列表
var canUselist = await queryable3.ToListAsync();
List<CodeCtnRes> ctnCodeCache = new List<CodeCtnRes>();
var allCtnCodeList = await _codeCtnService.GetAllList();
if (allCtnCodeList.Succeeded)
{
ctnCodeCache = allCtnCodeList.Data;
}
List<BookingSlotCtnDto> result = canUselist.Select(c => new BookingSlotCtnDto()
{
CtnCode = c.ctnCode,
CtnNum = c.numResidue,
CtnAll = ctnCodeCache.FirstOrDefault(e => e.EdiCode == c.ctnCode)?.CtnName ?? throw new Exception($"舱位信息中存在未收录的箱型:{c.ctnCode},需要在箱型字典中补充"),
4 months ago
}).ToList();
return DataResult<List<BookingSlotCtnDto>>.Success(result);
}
#region 获取现舱位查询
/// <summary>
/// 获取现舱位查询
/// </summary>
/// <param name="querySearch">查询条件</param>
/// <returns></returns>
public async Task<DataResult<List<BookingSlotBaseWithCtnDto>>> GetAvailableBookingSlots(PageRequest querySearch)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//序列化查询条件
var whereList = db.ConfigQuery.Context.Utilities.JsonToConditionalModels(querySearch.QueryCondition);
List<string> ctnCodeArr = new List<string>();
if (whereList.Any(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)))
{
var codList = whereList.Where(t => ((ConditionalModel)t).FieldName.Equals("ctnStat", StringComparison.OrdinalIgnoreCase)).ToList();
ctnCodeArr = codList.Select(t => ((ConditionalModel)t).FieldValue).ToList();
codList.ForEach(t =>
{
whereList.Remove(t);
});
}
if (querySearch.PageCondition.SortConditions == null || querySearch.PageCondition.SortConditions.Length == 0)
{
querySearch.PageCondition.SortConditions = new SortCondition[]{new SortCondition
{
SortField = nameof(BookingSlotBase.CreateTime),
ListSortDirection = System.ComponentModel.ListSortDirection.Descending
}};
}
// 1. 【舱位基础表】与【箱子表】做关联并根据【舱位主键】、【箱型】做分组统计出【总的箱量】作为queryable1
var queryable1 = tenantDb.Queryable<BookingSlotBase>().InnerJoin<BookingSlotCtn>((bas, ctn) => bas.Id == ctn.SlotId)
.Where(whereList)
.Where(bas => bas.IsCancellation == false)
.WhereIF(ctnCodeArr != null && ctnCodeArr.Count > 0, (a, b) => b != null
&& !string.IsNullOrWhiteSpace(b.CtnCode)
&& ctnCodeArr.Contains(b.CtnCode) && b.Deleted == false)
.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>().InnerJoin<BookingSlotAllocationCtn>((alc, ctn) => alc.Id == ctn.SlotAllocId)
.Where((alc, ctn) => alc.Deleted == false)
.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 CtnStatInfo
{
id = q1.id,
ctnCode = q1.ctnCode,
numAll = q1.numAll,
numResidue = SqlFunc.IsNull(q1.numAll - q2.numUse, q1.numAll)
})
.MergeTable()
.Where(r => r.numResidue > 0);
var canUselist = await queryable3.ToListAsync();
List<long> ids = new List<long>();
if (canUselist.Count > 0)
{
ids = canUselist.Select(a => a.id).Distinct().ToList();
}
var baseList = await tenantDb.Queryable<BookingSlotBase>().Where(u => ids.Contains(u.Id))
.OrderBy<BookingSlotBase>(querySearch.PageCondition.SortConditions)
.Select<BookingSlotBaseWithCtnDto>()
.ToPageListAsync(querySearch.PageCondition.PageIndex, querySearch.PageCondition.PageSize);
List<CodeCtnRes> ctnCodeCache = new List<CodeCtnRes>();
var allCtnist = await _codeCtnService.GetAllList();
if (allCtnist.Succeeded)
{
ctnCodeCache = allCtnist.Data;
}
// 构建结果
foreach (var item in baseList)
{
var ctnList = canUselist.Where(c => c.id == item.Id).ToList();
if (ctnList?.Any() == true)
{
item.CtnList = ctnList.Select(c =>
{
var ctnCode = ctnCodeCache.FirstOrDefault(e => !string.IsNullOrWhiteSpace(e.EdiCode) && e.EdiCode == c.ctnCode);
if (ctnCode == null)
throw new Exception($"舱位信息中存在未收录的箱型:{c.ctnCode},需要在箱型字典中补充");
return new BookingSlotCtnDto()
{
CtnCode = c.ctnCode,
CtnNum = c.numResidue,
TotalNum = c.numAll,
CtnAll = ctnCode.CtnName
};
}).ToList();
}
}
if (baseList.Count > 0)
return DataResult<List<BookingSlotBaseWithCtnDto>>.Success(baseList);
return DataResult<List<BookingSlotBaseWithCtnDto>>.FailedData(baseList);
}
#endregion
#region 引入现舱关联海运出口
/// <summary>
/// 引入现舱关联海运出口
/// </summary>
/// <param name="model">请求参数</param>
/// <returns></returns>
public async Task<DataResult<string>> BringInBookingSlotToOrder(BringInBookingSlotReq model)
{
/*
1
2
*/
if (model.seaExportId == 0)
{
//海运出口主键不能为空
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SeaExportIdNotNull)));
}
SeaExportRes orderInfo = null;
var orderRlt = _seaExportService.GetSeaExportInfo(model.seaExportId.ToString()).GetAwaiter().GetResult();
if (orderRlt.Succeeded)
{
orderInfo = orderRlt.Data;
}
if (orderInfo == null)
{
//海运出口详情获取失败,已作废或数据不存在
throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.SeaExportInfoNotExists)));
}
var generateDto = new BookingGenerateDto()
{
CustomerId = orderInfo.CustomerId,
CustomerName = orderInfo.CustomerName,
CustServiceId = orderInfo.CustomerService,
CustServiceName = orderInfo.CustomerServiceName,
SaleId = orderInfo.SaleId,
SaleName = orderInfo.Sale,
GOODSNAME = orderInfo.GoodsName,
};
if (model.slots.Any(k => k.SplitOrMerge == 1 || k.SplitOrMerge == 2))
{
generateDto.BookingReferNo = orderInfo.OrderNo;
generateDto.NewMBlNo = orderInfo.MBLNO;
generateDto.NewSubBlNo = orderInfo.HBLNO;
}
return await ImportSlots(new ImportSlotsDto
{
slots = model.slots,
isCheck = false,
bookingOrderId = model.seaExportId,
generateModel = generateDto
});
}
#endregion
#region 获取舱位用途配置列表
/// <summary>
/// 获取舱位用途配置列表
/// </summary>
/// <returns></returns>
public async Task<DataResult<List<BookingSlotUseToConfigDto>>> GetSlotUseToConfig()
{
var data = EnumExtensions.GetEnumDescDictionary(typeof(BookingSlotUseToEnum))
.Select(x => new BookingSlotUseToConfigDto
{
code = x.Key,
name = x.Value
}).ToList();
return DataResult<List<BookingSlotUseToConfigDto>>.Success(data);
}
#endregion
3 months ago
#region 舱位对外开放更新接口
/// <summary>
/// 舱位对外开放更新接口
/// </summary>
/// <param name="req">舱位更新请求</param>
/// <returns>返回回执</returns>
public async Task<DataResult> BookingSlotOpenEdit(BookingSlotOpenEditReq req)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
var slot = tenantDb.Queryable<BookingSlotBase>().Where(x => x.Id == req.Id).First();
var oldSlot = slot.Adapt<BookingSlotBaseSaveOutput>();
var dic = req.GetPropertiesArray();
var info = req.Adapt(slot);
var newOld = slot.Adapt<BookingSlotBaseSaveOutput>();
await tenantDb.Updateable(info).UpdateColumns(dic).EnableDiffLogEvent().ExecuteCommandAsync();
await SaveSlotLogAsync(new BookingSlotSaveLog()
{
OperateType = "Update",
OldOrder = oldSlot,
NewOrder = newOld,
SourceCode = "OpenEdit",
SourceName = "开放对接更新",
}, tenantDb);
return await Task.FromResult(DataResult.Successed("更新成功!", MultiLanguageConst.DataUpdateSuccess));
}
#endregion
#region 海运出口差异日志
/// <summary>
/// 忽略的字段
/// </summary>
private static readonly List<string> IgnoreColumns = new List<string>()
{
"CreateTime",
"CreateUserName",
"CreateBy",
"UpdateTime",
"UpdateUserName",
"UpdateBy",
"DeleteTime",
"DeleteUserName",
"DeleteBy",
"TenantId",
"TenantName",
};
public async Task SaveSlotLogAsync(BookingSlotSaveLog req, SqlSugarScopeProvider tenantDb)
{
var diff = req.NewOrder.Diff(req.OldOrder);
StringBuilder sb = new StringBuilder();
foreach (var item in diff)
{
Console.WriteLine($"{item.PropertyType} - {item.Property}: {item.LeftValue} => {item.RightValue}");
if (item.LeftValue.IsNotNull() && item.RightValue.IsNotNull())
{
if (IgnoreColumns.Contains(item.Property))
continue;
if (!item.LeftValue.Equals(item.RightValue))
{
sb.Append($"[字段:{item.Property},修改前:{item.LeftValue},修改后:{item.RightValue}]");
}
}
}
var log = new OpBusinessLog()
{
BusinessId = req.NewOrder.Id,
OperateType = "Update",
OldValue = JsonConvert.SerializeObject(req.OldOrder),
NewValue = JsonConvert.SerializeObject(req.NewOrder),
DiffData = sb.ToString(),
SourceCode = req.SourceCode,
SourceName = req.SourceName,
};
await tenantDb.Insertable(log).ExecuteCommandAsync();
}
#endregion
}
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);
}
}
public class CtnStatInfo
{
public long id { get; set; }
public string ctnCode { get; set; }
public int numAll { get; set; }
public int numResidue { get; set; }
}
}