|
|
|
@ -31,6 +31,8 @@ namespace Myshipping.Application
|
|
|
|
|
private readonly SqlSugarRepository<BookingSlotBase> _repBase;
|
|
|
|
|
private readonly SqlSugarRepository<BookingSlotCtn> _repCtn;
|
|
|
|
|
private readonly SqlSugarRepository<BookingSlotStock> _repStock;
|
|
|
|
|
private readonly SqlSugarRepository<BookingSlotAllocation> _repAllocation;
|
|
|
|
|
private readonly SqlSugarRepository<BookingSlotAllocationCtn> _repAllocationCtn;
|
|
|
|
|
|
|
|
|
|
private readonly SqlSugarRepository<BookingLog> _repBookingLog;
|
|
|
|
|
private readonly SqlSugarRepository<BookingLogDetail> _repBookingLogDetail;
|
|
|
|
@ -47,13 +49,15 @@ namespace Myshipping.Application
|
|
|
|
|
SqlSugarRepository<BookingLogDetail> repBookingLogDetail,
|
|
|
|
|
ILogger<BookingSlotService> logger,
|
|
|
|
|
ISysCacheService cache,
|
|
|
|
|
IEventPublisher publisher)
|
|
|
|
|
IEventPublisher publisher,
|
|
|
|
|
SqlSugarRepository<BookingSlotAllocation> repAllocation)
|
|
|
|
|
{
|
|
|
|
|
_repBase = repBase;
|
|
|
|
|
_repCtn = repCtn;
|
|
|
|
|
_repStock = repStock;
|
|
|
|
|
_repBookingLog = repBookingLog;
|
|
|
|
|
_repBookingLogDetail = repBookingLogDetail;
|
|
|
|
|
_repAllocation = repAllocation;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_logger = logger;
|
|
|
|
@ -405,7 +409,9 @@ namespace Myshipping.Application
|
|
|
|
|
//更新库存
|
|
|
|
|
await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", input));
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 舱位引入
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询可用的舱位及箱子
|
|
|
|
|
/// </summary>
|
|
|
|
@ -413,7 +419,7 @@ namespace Myshipping.Application
|
|
|
|
|
public async Task<List<BookingSlotBaseWithCtnDto>> GetAvailableSlots([FromQuery] BookingSlotBaseDto input)
|
|
|
|
|
{
|
|
|
|
|
return await GetAvailableSlots(input, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查询可用的舱位及箱子列表
|
|
|
|
@ -511,6 +517,113 @@ namespace Myshipping.Application
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 检查指定订舱记录,是否可以引入舱位列表
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="slots">待引入的舱位列表</param>
|
|
|
|
|
/// <param name="bookingOrderId">待关联的订舱记录</param>
|
|
|
|
|
/// <returns>(指定订舱记录是否已经引入过舱位数据,现有舱位及箱子是否满足需求,提示信息)</returns>
|
|
|
|
|
[NonAction]
|
|
|
|
|
public async Task<(bool isExists, bool isEnough, string message)> CheckImportSlots(List<BookingSlotBaseWithCtnDto> slots, long bookingOrderId)
|
|
|
|
|
{
|
|
|
|
|
slots ??= new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
|
|
|
|
// 判断是否已存在引用关系
|
|
|
|
|
if (bookingOrderId != 0 && await _repAllocation.IsExistsAsync(a => a.BOOKING_ID == bookingOrderId))
|
|
|
|
|
{
|
|
|
|
|
return (true, false, $"订舱主键{bookingOrderId}已引用舱位");
|
|
|
|
|
}
|
|
|
|
|
var slotIdList = slots.Select(s => s.Id).ToList();
|
|
|
|
|
|
|
|
|
|
// 查询可用舱位及箱子列表
|
|
|
|
|
var latestSlotList = await GetAvailableSlots(null, slotIdList);
|
|
|
|
|
|
|
|
|
|
// 判断余量是否满足需求
|
|
|
|
|
foreach (var inSlotItem in slots)
|
|
|
|
|
{
|
|
|
|
|
var latestSlot = latestSlotList.FirstOrDefault(b => b.Id == inSlotItem.Id);
|
|
|
|
|
if (latestSlot == null)
|
|
|
|
|
{
|
|
|
|
|
return (false, false, $"订舱编号为{inSlotItem.SLOT_BOOKING_NO}的舱位已被占用或取消,请重新引入");
|
|
|
|
|
}
|
|
|
|
|
if (inSlotItem.CtnList?.Any() == false)
|
|
|
|
|
{
|
|
|
|
|
return (false, false, $"每个舱位至少选择一个箱子,订舱编号:{inSlotItem.SLOT_BOOKING_NO}");
|
|
|
|
|
}
|
|
|
|
|
foreach (var inCtnItem in inSlotItem.CtnList)
|
|
|
|
|
{
|
|
|
|
|
var latestCtn = latestSlot.CtnList.FirstOrDefault(c => c.CTNCODE == inCtnItem.CTNCODE);
|
|
|
|
|
if (latestCtn == null)
|
|
|
|
|
{
|
|
|
|
|
return (false, false, $"订舱编号为{latestSlot.SLOT_BOOKING_NO}的舱位中,箱型为{inCtnItem.CTNALL}的箱子已被占用或取消,请重新引入");
|
|
|
|
|
}
|
|
|
|
|
if (latestCtn.CTNNUM < inCtnItem.CTNNUM)
|
|
|
|
|
{
|
|
|
|
|
return (false, false, $"订舱编号为{latestSlot.SLOT_BOOKING_NO}的舱位中,箱型为{inCtnItem.CTNALL}的箱子当前剩余{latestCtn.CTNNUM}个,少于所需的{inCtnItem.CTNNUM}个,请重新引入");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (false, true, $"可以引入");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task ImportSlots(List<BookingSlotBaseWithCtnDto> slots, long bookingOrderId, bool isCheck)
|
|
|
|
|
{
|
|
|
|
|
slots ??= new List<BookingSlotBaseWithCtnDto>();
|
|
|
|
|
|
|
|
|
|
if (isCheck)
|
|
|
|
|
{
|
|
|
|
|
(bool isExists, bool isEnough, string message) checkResult = await CheckImportSlots(slots, bookingOrderId);
|
|
|
|
|
|
|
|
|
|
if (checkResult.isExists || !checkResult.isEnough)
|
|
|
|
|
throw Oops.Bah(checkResult.message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var slotIdList = slots.Select(s => s.Id).ToList();
|
|
|
|
|
List<BookingSlotBase> latestSlotList = await _repBase.AsQueryable().Where(b => slotIdList.Contains(b.Id)).ToListAsync();
|
|
|
|
|
foreach (var inSlotItem in slots)
|
|
|
|
|
{
|
|
|
|
|
var latestSlot = latestSlotList.First(b => b.Id == inSlotItem.Id);
|
|
|
|
|
|
|
|
|
|
var config = new TypeAdapterConfig();
|
|
|
|
|
config.ForType<BookingSlotBase, BookingSlotAllocation>()
|
|
|
|
|
.Ignore(dest => dest.CreatedTime)
|
|
|
|
|
.Ignore(dest => dest.UpdatedTime)
|
|
|
|
|
.Ignore(dest => dest.CreatedUserId)
|
|
|
|
|
.Ignore(dest => dest.UpdatedUserId)
|
|
|
|
|
.Ignore(dest => dest.CreatedUserName)
|
|
|
|
|
.Ignore(dest => dest.UpdatedUserName)
|
|
|
|
|
.Ignore(dest => dest.TenantId)
|
|
|
|
|
.Ignore(dest => dest.TenantName);
|
|
|
|
|
|
|
|
|
|
var newSlotAllocation = latestSlot.Adapt<BookingSlotAllocation>(config);
|
|
|
|
|
newSlotAllocation.Id = 0;
|
|
|
|
|
newSlotAllocation.BOOKING_SLOT_ID = latestSlot.Id;
|
|
|
|
|
newSlotAllocation.BOOKING_ID = bookingOrderId;
|
|
|
|
|
newSlotAllocation.ALLO_BILL_NO = latestSlot.SLOT_BOOKING_NO;
|
|
|
|
|
newSlotAllocation.FINAL_BILL_NO = latestSlot.SLOT_BOOKING_NO;
|
|
|
|
|
await _repAllocation.InsertAsync(newSlotAllocation);
|
|
|
|
|
|
|
|
|
|
var insertCtnList = inSlotItem.CtnList.Select(c => new BookingSlotAllocationCtn()
|
|
|
|
|
{
|
|
|
|
|
SLOT_ALLOC_ID = newSlotAllocation.Id,
|
|
|
|
|
CTNCODE = c.CTNCODE,
|
|
|
|
|
CTNALL = c.CTNALL,
|
|
|
|
|
CTNNUM = c.CTNNUM
|
|
|
|
|
});
|
|
|
|
|
await _repAllocationCtn.InsertAsync(insertCtnList);
|
|
|
|
|
|
|
|
|
|
// 更新库存
|
|
|
|
|
await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new Event.BookingSlotStockUpdateModel
|
|
|
|
|
{
|
|
|
|
|
BOOKING_SLOT_TYPE = latestSlot.BOOKING_SLOT_TYPE,
|
|
|
|
|
CARRIERID = latestSlot.CARRIERID,
|
|
|
|
|
CONTRACT_NO = latestSlot.CONTRACT_NO,
|
|
|
|
|
VESSEL = latestSlot.VESSEL,
|
|
|
|
|
VOYNO = latestSlot.VOYNO
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|