Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WmsEmptyOutstockService .cs
2024-09-12 14:07:03 +08:00

353 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using JNPF.Common.Core.Manager;
using JNPF.Common.Dtos.VisualDev;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Security;
using JNPF.EventBus;
using JNPF.FriendlyException;
using JNPF.Logging;
using JNPF.Systems.Interfaces.System;
using JNPF.VisualDev;
using JNPF.VisualDev.Entitys;
using JNPF.VisualDev.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SqlSugar;
using Tnb.BasicData.Entities;
using Tnb.WarehouseMgr.Entities;
using Tnb.WarehouseMgr.Entities.Attributes;
using Tnb.WarehouseMgr.Entities.Consts;
using Tnb.WarehouseMgr.Entities.Dto;
using Tnb.WarehouseMgr.Entities.Dto.Inputs;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
using Result = Tnb.WarehouseMgr.Entities.Dto.Outputs.Result;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// 空载具出库
/// </summary>
[OverideVisualDev(ModuleConsts.MODULE_WMSEMPTYOUTSTK_ID)]
[ServiceModule(BizTypeId)]
public class WmsEmptyOutstockService : BaseWareHouseService, IWmsEmptyOutstockService
{
private const string BizTypeId = "26122265173285";
private readonly ISqlSugarClient _db;
private readonly IRunService _runService;
private readonly IVisualDevService _visualDevService;
private readonly IWareHouseService _wareHouseService;
private readonly IBillRullService _billRullService;
private readonly IUserManager _userManager;
public WmsEmptyOutstockService(
ISqlSugarRepository<WmsCarryH> repository,
IRunService runService,
IVisualDevService visualDevService,
IWareHouseService wareHouseService,
IUserManager userManager,
IBillRullService billRullService,
IEventPublisher eventPublisher
)
{
_db = repository.AsSugarClient();
_runService = runService;
_visualDevService = visualDevService;
_wareHouseService = wareHouseService;
_userManager = userManager;
_billRullService = billRullService;
OverideFuncs.CreateAsync = WmsEmptyOut;
}
public async Task<dynamic> WmsEmptyOut(VisualDevModelDataCrInput input)
{
SemaphoreSlim semaphoreSlim = null;
try
{
string warehouse_id = input.data[nameof(OutStockStrategyQuery.warehouse_id)].ToString();
semaphoreSlim = _wareHouseService.GetSemaphore("outstock", warehouse_id);
await semaphoreSlim.WaitAsync();
await _db.Ado.BeginTranAsync();
/*//入库取终点
var inStockStrategyInput = new InStockStrategyQuery { warehouse_id = input.data[nameof(InStockStrategyQuery.warehouse_id)].ToString(), Size = 1 };
var endLocations = await _wareHouseService.InStockStrategy(inStockStrategyInput);*/
//判断目标库位是否自动签收
BasLocation loc = await _db.Queryable<BasLocation>().SingleAsync(it => it.id == input.data[nameof(WmsPointH.location_id)].ToString());
int qty = int.Parse(input.data[nameof(OutStockStrategyQuery.qty)].ToString());
//出库取起点,获取所有符合输入的载具规格的载具
OutStockStrategyQuery OutStockStrategyInput = new()
{
carrystd_id = input.data[nameof(OutStockStrategyQuery.carrystd_id)].ToString(),
warehouse_id = warehouse_id,
Size = qty
};
List<WmsCarryH>? carrys = await _wareHouseService.OutStockStrategy(OutStockStrategyInput);
Logger.Information($"根据出库策略获取的载具数量:{carrys?.Count}");
//var carrys = await _db.Queryable<WmsCarryH>().LeftJoin<BasLocation>((a, b) => a.location_id == b.id)
// .Where((a, b) => a.carrystd_id == input.data[nameof(WmsEmptyOutstockH.carrystd_id)].ToString()
// && a.carry_status == ((int)EnumCarryStatus.空闲).ToString() && a.is_lock == 0 && b.is_lock == 0 && b.is_type == ((int)EnumLocationType.存储库位).ToString())
// .ToListAsync();
// 判断最终目标库位是否可以放置当前载具
WmsEmptyOutstockH wmsEmptyOutstockH = null;
if (carrys?.Count > 0)
{
WmsCarryH curCarry = carrys[^carrys.Count];
bool isMatch = await IsCarryAndLocationMatchByCarryStd(curCarry, loc);
if (!isMatch)
{
throw new AppFriendlyException("该载具无法放置到目标库位", 500);
}
// VisualDevEntity? templateEntity = await _visualDevService.GetInfoById(ModuleConsts.MODULE_WMSEMPTYOUTSTK_ID, true);
// await _runService.Create(templateEntity, input);
input.data["create_time"] = DateTime.Now;
input.data["create_id"] = _userManager?.UserId!=null ? _userManager.UserId : WmsWareHouseConst.AdministratorUserId;
if (input.data.TryGetValue("bill_code", out Object value))
{
if (value == null || value.ToString().IsEmpty())
{
input.data["bill_code"] = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_EMPTYOUTSTK_ENCODE).GetAwaiter().GetResult();
}
}
wmsEmptyOutstockH = JsonConvert.DeserializeObject<WmsEmptyOutstockH>(JsonConvert.SerializeObject(input.data));
wmsEmptyOutstockH.id = SnowflakeIdHelper.NextId();
await _db.Insertable(wmsEmptyOutstockH).ExecuteCommandAsync();
}
WmsPointH? sPoint = null;
WmsPointH? ePoint = null;
if (input.data.ContainsKey(nameof(WmsPointH.location_id)))
{
ePoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == input.data[nameof(WmsPointH.location_id)].ToString() && it.is_lock == 0);
}
//根据每个载具的起始库位做路径运算
if (carrys?.Count > 0)
{
if (qty > carrys.Count)
{
throw new AppFriendlyException($"实际可出空载具数量只有 {carrys.Count}", 500);
}
Logger.Information($"【WmsEmptyOut】 qty={qty}");
for (int i = 0; i < qty; i++)
{
sPoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == carrys[i].location_id);
bool isOk = false;
if (sPoint != null && ePoint != null)
{
List<WmsPointH> points = new List<WmsPointH>();
if (sPoint.area_code != ePoint.area_code)
{
points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
if (points.Count <= 2)
{
throw new AppFriendlyException($"sPoint {sPoint.point_code} ePoint{ePoint.point_code}该路径不存在", 500);
}
}
else
{
points.Add(sPoint);
points.Add(ePoint);
}
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
List<WmsPretaskH> preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
WmsPointH? sPoint = it.FirstOrDefault();
WmsPointH? ePoint = it.LastOrDefault();
WmsPretaskH preTask = new()
{
org_id = wmsEmptyOutstockH.org_id,
startlocation_id = sPoint?.location_id!,
startlocation_code = sPoint?.location_code!,
endlocation_id = ePoint?.location_id!,
endlocation_code = ePoint?.location_code!,
start_floor = sPoint?.floor.ToString(),
end_floor = ePoint?.floor.ToString(),
startpoint_id = sPoint?.id!,
startpoint_code = sPoint?.point_code!,
endpoint_id = ePoint?.id!,
endpoint_code = ePoint?.point_code!,
bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(),
status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID,
biz_type = WmsWareHouseConst.BIZTYPE_WMSEPTYOUTSTK_ID,
task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID,
carry_id = carrys![i].id,
carry_code = carrys![i].carry_code,
area_id = sPoint?.area_id!,
area_code = it.Key,
// require_id = input.data["ReturnIdentity"].ToString(),
require_id = wmsEmptyOutstockH.id,
require_code = input.data[nameof(preTask.bill_code)]?.ToString()!,
create_id = wmsEmptyOutstockH.create_id,
create_time = DateTime.Now
};
return preTask;
}).ToList();
//更新页面
//赋值签收状态
Logger.Information($"空载具出库生成的预任务数量:{preTasks.Count}");
//if (loc.is_sign == 0)
//{
// preTasks[^1].is_sign = 0; // 修改最后一个元素的是否签收值
//}
isOk = await _wareHouseService.GenPreTask(preTasks, null!, _db);
if (isOk)
{
GenPreTaskUpInput preTaskUpInput = new()
{
RquireId = wmsEmptyOutstockH.id!,
CarryId = carrys![i].id,
CarryStartLocationId = points!.FirstOrDefault()!.location_id!,
CarryStartLocationCode = points!.FirstOrDefault()!.location_code!,
LocationIds = points!.Select(x => x.location_id).ToList()!
};
//更新明细表
WmsEmptyOutstockD wmsEmptyOutstockD = new()
{
id = SnowflakeIdHelper.NextId(),
bill_id = preTaskUpInput.RquireId,
biz_type = WmsWareHouseConst.BIZTYPE_WMSEPTYOUTSTK_ID,
location_id = ePoint.location_id!,
status = WmsWareHouseConst.BILLSTATUS_ON_ID,
carry_id = carrys[i].id,
carry_code = carrys[i].carry_code,
create_id = wmsEmptyOutstockH.create_id,
create_time = DateTime.Now
};
_ = await _db.Insertable(wmsEmptyOutstockD)
.ExecuteCommandAsync();
//根据空载具出库Id回更单据状态
_ = await _db.Updateable<WmsEmptyOutstockH>().SetColumns(it => new WmsEmptyOutstockH { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == preTaskUpInput.RquireId).ExecuteCommandAsync();
await _wareHouseService.GenInStockTaskHandleAfter(preTaskUpInput,
it => new WmsCarryH { is_lock = 1 },
it => new BasLocation { is_lock = 1 }, _db);
}
}
else
{
throw new AppFriendlyException("无可出库的空载具或目标库位不存在或者目标库位被锁", 500);
}
}
}
else
{
throw new AppFriendlyException("没有匹配的空载具可以出库", 500);
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
Logger.LogWarning($"空载具出库错误 {ex.Message}");
Logger.LogWarning($"空载具出库错误 {ex.StackTrace}");
await _db.Ado.RollbackTranAsync();
throw;
}
finally
{
semaphoreSlim.Release();
await InvokeGenPretaskExcute();
}
return Task.FromResult(true);
}
public override async Task ModifyAsync(WareHouseUpInput input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
try
{
await _db.Ado.BeginTranAsync();
//根据载具更新明细表状态
bool isOk = await _db.Updateable<WmsEmptyOutstockD>().SetColumns(it => new WmsEmptyOutstockD { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(it => it.bill_id == input.requireId && input.carryIds.Contains(it.carry_id)).ExecuteCommandHasChangeAsync();
List<WmsEmptyOutstockD> emptyCarrys = await _db.Queryable<WmsEmptyOutstockD>().Where(it => it.bill_id == input.requireId).ToListAsync();
// 判断所有明细是否都完成
if (emptyCarrys?.Count > 0 && emptyCarrys.All(x => x.status == WmsWareHouseConst.BILLSTATUS_COMPLETE_ID))
{
isOk = await _db.Updateable<WmsEmptyOutstockH>().SetColumns(it => new WmsEmptyOutstockH { status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID }).Where(it => it.id == input.requireId).ExecuteCommandHasChangeAsync();
}
if (!isOk)
{
throw Oops.Oh(ErrorCode.COM1001);
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
/// MES空载具出库接口
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
public async Task<dynamic> MESEmptyCarryOutStk(MESEmptyCarryOutStkInput input)
{
if (input.IsNull())
{
throw new ArgumentNullException("input");
}
try
{
BasLocation location = await _db.Queryable<BasLocation>().SingleAsync(it => it.location_code == input.location_code && it.is_type != EnumLocationType..ToString()) ?? throw new AppFriendlyException("无此库位或为存储库位", 500);
Dictionary<string, object> dic = new()
{
[nameof(WmsEmptyOutstockH.id)] = SnowflakeIdHelper.NextId(),
[nameof(WmsEmptyOutstockH.org_id)] = input.org_id,
[nameof(WmsEmptyOutstockH.location_id)] = location.id,
[nameof(WmsEmptyOutstockH.carrystd_id)] = input.carrystd_id,
[nameof(WmsEmptyOutstockH.bill_code)] = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_EMPTYOUTSTK_ENCODE).GetAwaiter().GetResult(),
[nameof(WmsEmptyOutstockH.status)] = WmsWareHouseConst.BILLSTATUS_ADD_ID,
[nameof(WmsEmptyOutstockH.qty)] = input.qty,
[nameof(WmsEmptyOutstockH.biz_type)] = WmsWareHouseConst.BIZTYPE_WMSEPTYOUTSTK_ID,
["warehouse_id"] = input.warehouse_id,
[nameof(WmsEmptyOutstockH.create_id)] = input.create_id,
[nameof(WmsEmptyOutstockH.create_time)] = DateTime.Now
};
VisualDevModelDataCrInput visualDevModelDataCrInput = new()
{
data = dic,
};
await WmsEmptyOut(visualDevModelDataCrInput);
}
catch (Exception ex)
{
Log.Error(ex.Message,ex);
await _db.Ado.RollbackTranAsync();
return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, ex.Message);
}
return new Result();
}
}
}