|
|
using Furion;
|
|
|
using Furion.EventBus;
|
|
|
using Mapster;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
using Myshipping.Core;
|
|
|
using SqlSugar;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace Myshipping.Application.Event
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 运踪
|
|
|
/// </summary>
|
|
|
public class BookingSlotStockSubscriber : IEventSubscriber
|
|
|
{
|
|
|
private readonly ILogger<BookingSlotStockSubscriber> _logger;
|
|
|
|
|
|
public BookingSlotStockSubscriber(
|
|
|
ILogger<BookingSlotStockSubscriber> logger)
|
|
|
{
|
|
|
_logger = logger;
|
|
|
}
|
|
|
|
|
|
//更新库存
|
|
|
[EventSubscribe("BookingSlotStock:Update")]
|
|
|
public async Task BookingSlotStock(EventHandlerExecutingContext context)
|
|
|
{
|
|
|
BookingSlotStockUpdateModel paraObj = context.Source.Payload as BookingSlotStockUpdateModel;
|
|
|
await BookingSlotStock(paraObj);
|
|
|
}
|
|
|
|
|
|
public async Task BookingSlotStock(BookingSlotStockUpdateModel paraObj)
|
|
|
{
|
|
|
_logger.LogInformation($"收到更新库存订阅请求:{paraObj.ToJsonString()}");
|
|
|
|
|
|
var _repBase = App.GetService<SqlSugarRepository<BookingSlotBase>>();
|
|
|
var _repCtn = App.GetService<SqlSugarRepository<BookingSlotCtn>>();
|
|
|
var _repStock = App.GetService<SqlSugarRepository<BookingSlotStock>>();
|
|
|
var _repAlloc = App.GetService<SqlSugarRepository<BookingSlotAllocation>>();
|
|
|
var _repAllocCtn = App.GetService<SqlSugarRepository<BookingSlotAllocationCtn>>();
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(paraObj.VESSEL)
|
|
|
|| string.IsNullOrEmpty(paraObj.VOYNO)
|
|
|
|| string.IsNullOrEmpty(paraObj.CONTRACT_NO)
|
|
|
|| string.IsNullOrEmpty(paraObj.BOOKING_SLOT_TYPE)
|
|
|
|| string.IsNullOrEmpty(paraObj.CARRIERID)
|
|
|
|| string.IsNullOrEmpty(paraObj.PORTLOADID)
|
|
|
|| string.IsNullOrEmpty(paraObj.PORTDISCHARGEID))
|
|
|
{
|
|
|
_logger.LogInformation($"收到更新库存订阅请求:部分参数存在空值,结束");
|
|
|
return;
|
|
|
}
|
|
|
var baseList = await _repBase.AsQueryable().Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted
|
|
|
&& x.TenantId == paraObj.TenantId
|
|
|
&& x.VESSEL == paraObj.VESSEL
|
|
|
&& x.VOYNO == paraObj.VOYNO
|
|
|
&& x.CONTRACT_NO == paraObj.CONTRACT_NO
|
|
|
&& x.BOOKING_SLOT_TYPE == paraObj.BOOKING_SLOT_TYPE
|
|
|
&& x.CARRIERID == paraObj.CARRIERID
|
|
|
&& x.PORTLOADID == paraObj.PORTLOADID
|
|
|
&& x.PORTDISCHARGEID == paraObj.PORTDISCHARGEID)
|
|
|
.OrderByDescending(x => x.UpdatedTime)
|
|
|
.ToListAsync();
|
|
|
|
|
|
var stockObj = await _repStock.AsQueryable().Filter(null, true)
|
|
|
.FirstAsync(x => !x.IsDeleted
|
|
|
&& x.TenantId == paraObj.TenantId
|
|
|
&& x.VESSEL == paraObj.VESSEL
|
|
|
&& x.VOYNO == paraObj.VOYNO
|
|
|
&& x.CONTRACT_NO == paraObj.CONTRACT_NO
|
|
|
&& x.BOOKING_SLOT_TYPE == paraObj.BOOKING_SLOT_TYPE
|
|
|
&& x.CARRIERID == paraObj.CARRIERID
|
|
|
&& x.PORTLOADID == paraObj.PORTLOADID
|
|
|
&& x.PORTDISCHARGEID == paraObj.PORTDISCHARGEID);
|
|
|
|
|
|
if (!baseList.Any())
|
|
|
{
|
|
|
if (stockObj != null)
|
|
|
{
|
|
|
// 从库存表删除这7项维度的库存数据
|
|
|
await _repStock.DeleteAsync(x => x.Id == stockObj.Id);
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var isInsert = stockObj == null;
|
|
|
var idTemp = stockObj?.Id;
|
|
|
|
|
|
stockObj = baseList[0].Adapt(stockObj);
|
|
|
|
|
|
if (isInsert)
|
|
|
{
|
|
|
stockObj.Id = 0;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
stockObj.Id = (long)idTemp;
|
|
|
}
|
|
|
|
|
|
// 总舱位数
|
|
|
stockObj.TOTAL_ORDERS = baseList.Count;
|
|
|
|
|
|
// 取消舱位数
|
|
|
stockObj.CANCEL_NUM = baseList.Count(x => x.IS_CANCELLATION);
|
|
|
|
|
|
// 舱位主键列表
|
|
|
var slotBaseIdList = baseList.Select(x => x.Id).ToList();
|
|
|
|
|
|
// 总的箱型箱量
|
|
|
var ctnAllList = await _repCtn.AsQueryable().Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted && slotBaseIdList.Contains(x.SLOT_ID))
|
|
|
.GroupBy(x => x.CTNALL)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.CTNALL,
|
|
|
CTNNUM = SqlFunc.AggregateSum(x.CTNNUM)
|
|
|
}).ToListAsync();
|
|
|
stockObj.CTN_STAT = string.Join(' ', ctnAllList.Select(c => c.CTNALL + "*" + c.CTNNUM));
|
|
|
|
|
|
// 总箱数
|
|
|
stockObj.TOTAL_CTNS = ctnAllList.Sum(x => x.CTNNUM);
|
|
|
|
|
|
// 订舱引用表主键与订舱主表主键
|
|
|
var lstAllocKeyList = await _repAlloc.AsQueryable()
|
|
|
.Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted && slotBaseIdList.Contains(x.BOOKING_SLOT_ID))
|
|
|
.Select(x => new { x.Id, x.BOOKING_SLOT_ID })
|
|
|
.ToListAsync();
|
|
|
|
|
|
// 如果舱位未被引用过,可以直接确定库存
|
|
|
if (!lstAllocKeyList.Any())
|
|
|
{
|
|
|
// 已使用舱位数
|
|
|
stockObj.USE_NUM = 0;
|
|
|
// 已使用的箱型箱量
|
|
|
stockObj.USE_CTN_STAT = "";
|
|
|
// 已使用的箱数
|
|
|
stockObj.USE_CTNS_NUM = 0;
|
|
|
|
|
|
// 剩余的箱型箱量
|
|
|
stockObj.REMAIN_CTN_STAT = stockObj.CTN_STAT;
|
|
|
// 剩余箱数
|
|
|
stockObj.REMAIN_CTNS_NUM = stockObj.TOTAL_CTNS;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// 已使用舱位数
|
|
|
//stockObj.USE_NUM = lstAllocKeyList.DistinctBy(x => x.BOOKING_SLOT_ID).Count();
|
|
|
|
|
|
// 订舱引用表主键列表
|
|
|
var allocIdList = lstAllocKeyList.Select(x => x.Id).ToList();
|
|
|
var allocSlotIdList = lstAllocKeyList.Select(x => x.BOOKING_SLOT_ID).Distinct().ToList();
|
|
|
var userCtnNumList = await _repAllocCtn.AsQueryable().Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted && allocIdList.Contains(x.SLOT_ALLOC_ID))
|
|
|
.GroupBy(x => x.SLOT_ALLOC_ID)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.SLOT_ALLOC_ID,
|
|
|
CTNNUM = SqlFunc.AggregateSum(x.CTNNUM)
|
|
|
}).ToListAsync();
|
|
|
var hasCtnNumList = await _repCtn.AsQueryable().Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted && allocSlotIdList.Contains(x.SLOT_ID))
|
|
|
.GroupBy(x => x.SLOT_ID)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.SLOT_ID,
|
|
|
CTNNUM = SqlFunc.AggregateSum(x.CTNNUM)
|
|
|
})
|
|
|
.ToListAsync();
|
|
|
var useNum = 0;
|
|
|
foreach (long slotId in allocSlotIdList)
|
|
|
{
|
|
|
List<long> temp1 = lstAllocKeyList.Where(x => x.BOOKING_SLOT_ID == slotId).Select(x => x.Id).ToList();
|
|
|
var userNum = userCtnNumList.Where(x => temp1.Contains(x.SLOT_ALLOC_ID)).Sum(x => x.CTNNUM);
|
|
|
var hasNum = hasCtnNumList.Where(x => x.SLOT_ID == slotId).Sum(x => x.CTNNUM);
|
|
|
if (userNum >= hasNum)
|
|
|
{
|
|
|
useNum++;
|
|
|
}
|
|
|
}
|
|
|
// 已使用舱位数
|
|
|
stockObj.USE_NUM = useNum;
|
|
|
|
|
|
// 已使用的箱型箱量
|
|
|
var userCtnList = await _repAllocCtn.AsQueryable()
|
|
|
.Filter(null, true)
|
|
|
.Where(x => !x.IsDeleted && allocIdList.Contains(x.SLOT_ALLOC_ID))
|
|
|
.GroupBy(x => x.CTNALL)
|
|
|
.Select(x => new
|
|
|
{
|
|
|
x.CTNALL,
|
|
|
CTNNUM = SqlFunc.AggregateSum(x.CTNNUM)
|
|
|
}).ToListAsync();
|
|
|
stockObj.USE_CTN_STAT = string.Join(' ', userCtnList.Select(c => c.CTNALL + "*" + c.CTNNUM));
|
|
|
|
|
|
// 已使用的箱数
|
|
|
stockObj.USE_CTNS_NUM = userCtnList.Sum(x => x.CTNNUM);
|
|
|
|
|
|
// 剩余的箱型箱量
|
|
|
Dictionary<string, int> remainCtnList = new(ctnAllList.Count);
|
|
|
foreach (var item in ctnAllList)
|
|
|
{
|
|
|
var useItem = userCtnList.FirstOrDefault(x => x.CTNALL == item.CTNALL);
|
|
|
if (useItem == null)
|
|
|
{
|
|
|
remainCtnList.Add(item.CTNALL, item.CTNNUM);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
int remainCtnNum = item.CTNNUM - useItem.CTNNUM;
|
|
|
if (remainCtnNum > 0)
|
|
|
{
|
|
|
remainCtnList.Add(item.CTNALL, remainCtnNum);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
stockObj.REMAIN_CTN_STAT = string.Join(' ', remainCtnList.Select(x => x.Key + "*" + x.Value));
|
|
|
|
|
|
// 剩余箱数
|
|
|
stockObj.REMAIN_CTNS_NUM = stockObj.TOTAL_CTNS - stockObj.USE_CTNS_NUM;
|
|
|
}
|
|
|
|
|
|
if (isInsert)
|
|
|
{
|
|
|
await _repStock.InsertAsync(stockObj);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
await _repStock.UpdateAsync(stockObj);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 刷新库存统计对象
|
|
|
/// </summary>
|
|
|
public class BookingSlotStockUpdateModel
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
/// 船名
|
|
|
/// </summary>
|
|
|
public string VESSEL { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 航次号
|
|
|
/// </summary>
|
|
|
public string VOYNO { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 合约号
|
|
|
/// </summary>
|
|
|
public string CONTRACT_NO { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 订舱方式 CONTRACT_ORDER-合约订舱;SPOT_ORDER-SPOT订舱
|
|
|
/// </summary>
|
|
|
public string BOOKING_SLOT_TYPE { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 船公司代号
|
|
|
/// </summary>
|
|
|
public string CARRIERID { get; set; }
|
|
|
|
|
|
///// <summary>
|
|
|
///// 收货地
|
|
|
///// </summary>
|
|
|
//public string PLACERECEIPT { get; set; }
|
|
|
///// <summary>
|
|
|
///// 交货地
|
|
|
///// </summary>
|
|
|
//public string PLACEDELIVERY { get; set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// 装货港代码
|
|
|
/// </summary>
|
|
|
public string PORTLOADID { get; set; }
|
|
|
/// <summary>
|
|
|
/// 卸货港代码
|
|
|
/// </summary>
|
|
|
public string PORTDISCHARGEID { get; set; }
|
|
|
/// <summary>
|
|
|
/// 租户Id
|
|
|
/// </summary>
|
|
|
public long? TenantId { get; set; }
|
|
|
}
|
|
|
}
|