Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WmsInStockService.cs

536 lines
27 KiB
C#
Raw 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.Extension;
using JNPF.Common.Filter;
using JNPF.Common.Security;
using JNPF.EventBus;
using JNPF.FriendlyException;
using JNPF.Systems.Interfaces.System;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Tnb.BasicData.Entities;
using Tnb.Common.Utils;
using Tnb.ProductionMgr.Interfaces;
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.Dto.Outputs;
using Tnb.WarehouseMgr.Entities.Dto.Queries;
using Tnb.WarehouseMgr.Entities.Enums;
using Tnb.WarehouseMgr.Interfaces;
namespace Tnb.WarehouseMgr
{
/// <summary>
/// 入库申请服务
/// </summary>
[ServiceModule(BizTypeId)]
public class WmsInStockService : BaseWareHouseService, IWmsInStockService
{
private const string BizTypeId = "26191496816421";
private readonly ISqlSugarClient _db;
private readonly IDictionaryDataService _dictionaryDataService;
private readonly IUserManager _userManager;
private readonly IWareHouseService _wareHouseService;
private readonly IBillRullService _billRullService;
private readonly IPrdInstockService _prdInstockService;
private static Dictionary<string, object> _dicBillCodes = new();
public WmsInStockService(
ISqlSugarRepository<WmsInstockH> repository,
IDictionaryDataService dictionaryDataService,
IUserManager userManager,
IBillRullService billRullService,
IWareHouseService wareHouseService,
IPrdInstockService prdInstockService,
IEventPublisher eventPublisher
)
{
_db = repository.AsSugarClient();
_dictionaryDataService = dictionaryDataService;
_userManager = userManager;
_billRullService = billRullService;
_wareHouseService = wareHouseService;
_prdInstockService = prdInstockService;
}
/// <summary>
/// 根据入库申请单ID获取申请单明细信息
/// </summary>
/// <param name="billId"></param>
/// <returns></returns>
[HttpGet]
public async Task<dynamic> GetInStockDetailsListById([FromRoute] string billId)
{
Dictionary<string, object> dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID);
List<WmsInstockD> items = await _db.Queryable<WmsInstockD>().LeftJoin<BasWarehouse>((a, b) => a.warehouse_id == b.id)
.Select((a, b) => new WmsInstockD
{
warehouse_name = b.whname
}, true)
.Where(a => a.bill_id == billId).ToListAsync();
_db.ThenMapper(items,
it => it.line_status = dic.ContainsKey(it.line_status) ? dic[it.line_status]?.ToString()! : "");
return items;
}
/// <summary>
/// 条码打印
/// </summary>
/// <param name="input">
/// <br/>{
/// <br/> BillIds入库申请单Id列表
/// <br/>}
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
[HttpPost]
public async Task BarCodePrint(BarCodePrintInput input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
if (input.BillIds == null || input.BillIds.Count == 0)
{
throw new ArgumentException($"parameter {nameof(input.BillIds)} not be null or zero");
}
try
{
await _db.Ado.BeginTranAsync();
if (_dicBillCodes.Count < 1)
{
_dicBillCodes = await _db.Queryable<WmsInstockH>().ToDictionaryAsync(x => x.id, x => x.bill_code);
}
List<WmsInstockD> inStockDetails = await _db.Queryable<WmsInstockD>().Where(it => input.BillIds.Contains(it.bill_id)).ToListAsync();
if (inStockDetails?.Count > 0)
{
List<WmsTempCode> wmsTempCodes = new();
for (int i = 0; i < inStockDetails.Count; i++)
{
if (inStockDetails[i] is null)
{
continue;
}
decimal? minPacking = (await _db.Queryable<BasMaterial>().FirstAsync(it => it.id == inStockDetails[i].material_id))?.minpacking;
int codeNum = 0;
if (inStockDetails[i].pr_qty.HasValue && minPacking.HasValue && minPacking.Value > 0)
{
int mod = (int)(inStockDetails[i].pr_qty!.Value % minPacking.Value);
codeNum = (int)(mod > 0 ? (inStockDetails[i].pr_qty!.Value / minPacking.Value) + 1 : inStockDetails[i].pr_qty!.Value / minPacking.Value);
if (inStockDetails[i].pr_qty!.Value > minPacking.Value)
{
for (int j = 0; j < codeNum; j++)
{
int index = j + 1;
WmsTempCode barCode = await CreateInstock(inStockDetails[i], index);
if (minPacking.HasValue)
{
barCode.codeqty = index < codeNum ? minPacking : mod > 0 ? mod : minPacking;
}
wmsTempCodes.Add(barCode);
}
}
else if (inStockDetails[i].pr_qty!.Value <= minPacking.Value)
{
WmsTempCode barCode = await CreateInstock(inStockDetails[i], i + 1);
wmsTempCodes.Add(barCode);
}
}
else if (!minPacking.HasValue)
{
WmsTempCode barCode = await CreateInstock(inStockDetails[i], i + 1);
wmsTempCodes.Add(barCode);
}
}
int row = await _db.Insertable(wmsTempCodes).ExecuteCommandAsync();
if (row > 0)
{
_ = await _db.Updateable<WmsInstockH>().SetColumns(it => new WmsInstockH { print_status = WmsWareHouseConst.BARCODE_PRINT_STATUS_COMPLETE_ID }).Where(it => input.BillIds.Contains(it.id)).ExecuteCommandAsync();
}
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
}
}
private Task<WmsTempCode> CreateInstock(WmsInstockD detail, int no)
{
string code = $"{detail.material_code}{detail.code_batch}{no.ToString().PadLeft(4, '0')}";
WmsTempCode barCode = new()
{
org_id = detail.org_id,
material_id = detail.material_id,
material_code = detail.material_code,
barcode = code,
code_batch = detail.code_batch,
codeqty = detail.pr_qty!.Value,
unit_id = detail.unit_id,
is_lock = 0,
is_end = 0,
require_id = detail.bill_id,
require_code = _dicBillCodes.ContainsKey(detail.bill_id) ? _dicBillCodes[detail.bill_id]?.ToString() : "",
create_id = _userManager.UserId,
create_time = DateTime.Now
};
return Task.FromResult(barCode);
}
public override async Task ModifyAsync(WareHouseUpInput input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
//更具distaskCode的barcode 更新 instockcode 的 is_end 为 1
try
{
await _db.Ado.BeginTranAsync();
if (input.distaskCodes?.Count > 0)
{
IEnumerable<string> barCodes = input.distaskCodes.Select(x => x.barcode);
_ = await _db.Updateable<WmsInstockCode>().SetColumns(it => new WmsInstockCode { is_end = 1 }).Where(it => barCodes.Contains(it.barcode)).ExecuteCommandAsync();
var instockCodes = await _db.Queryable<WmsInstockCode>().Where(it => barCodes.Contains(it.barcode)).Select(it => new
{
id = it.bill_d_id,
barcode_qty = it.codeqty,
}).ToListAsync();
Dictionary<string, List<decimal>> dic = instockCodes.GroupBy(g => g.id).ToDictionary(x => x.Key, x => x.Select(d => d.barcode_qty).ToList());
List<string> ids = instockCodes.Select(it => it.id).ToList();
List<WmsInstockD> instockDetails = await _db.Queryable<WmsInstockD>().Where(it => ids.Contains(it.id)).ToListAsync();
foreach (WmsInstockD item in instockDetails)
{
if (dic.ContainsKey(item.id))
{
item.qty += dic[item.id].Sum(x => x);
if (item.qty >= item.pr_qty)
{
item.line_status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID;
}
}
}
_ = await _db.Updateable(instockDetails).ExecuteCommandAsync();
WmsInstockH instock = await _db.Queryable<WmsInstockH>().SingleAsync(it => it.id == input.requireId);
if (instock.IsNull())
{
ArgumentNullException.ThrowIfNull(nameof(instock));
}
if (instock.sync_status != WmsWareHouseConst.SYNC_STATUS_NONEEDSYNC)
{
//如果是自动单据,需要回更上层系统
Dictionary<string, string> pars = new() { { nameof(WmsInstockH.source_id), instock?.source_id ?? string.Empty } };
dynamic callBackRes = await _prdInstockService.SyncInstock(pars);
instock!.sync_status = callBackRes == true ? WmsWareHouseConst.SYNC_STATUS__SYNCCOMPLETE : WmsWareHouseConst.SYNC_STATUS__SYNCFAILED;
_ = await _db.Updateable(instock).UpdateColumns(it => it.sync_status).ExecuteCommandAsync();
}
List<WmsInstockD> allInstockDetails = await _db.Queryable<WmsInstockD>().Where(it => it.bill_id == input.requireId).ToListAsync();
if (allInstockDetails.All(x => x.line_status == WmsWareHouseConst.BILLSTATUS_COMPLETE_ID))
{
instock.status = WmsWareHouseConst.BILLSTATUS_COMPLETE_ID;
}
else
{
//任务没有结束,更新状态为工作中
instock.status = WmsWareHouseConst.BILLSTATUS_ON_ID;
}
_ = await _db.Updateable(instock).UpdateColumns(it => it.status).ExecuteCommandAsync();
}
await _db.Ado.CommitTranAsync();
}
catch (Exception)
{
await _db.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
/// 入库申请-MES对接功能
/// MES系统下发时需要有对应的入库申请数据和载具信息起始库位ID,入库仓库
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<dynamic> MESCreateInstock(MESCreateInstockInput input)
{
bool isSuccessFul = false;
try
{
await _db.Ado.BeginTranAsync();
//入库申请主表
WmsInstockH instock = input.instock.Adapt<WmsInstockH>();
//入库申请物料明细表
List<WmsInstockD> instockds = input.instockds.Adapt<List<WmsInstockD>>();
//入库申请条码明细表
List<WmsInstockCode> instockcodes = input.instockcodes.Adapt<List<WmsInstockCode>>();
//入库取终点 //出库起点
InStockStrategyQuery inStockStrategyInput = new() { warehouse_id = instock?.warehouse_id!, Size = 1 };
List<BasLocation> endLocations = await _wareHouseService.InStockStrategy(inStockStrategyInput);
WmsPointH sPoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_code == input.instock.location_code);
WmsPointH ePoint = await _db.Queryable<WmsPointH>().FirstAsync(it => it.location_id == endLocations[0].id);
WmsCarryH carry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.carry_code == input.instock.carry_code);
BasLocation loc = await _db.Queryable<BasLocation>().FirstAsync(it => it.id == endLocations[0].id);
bool isMatch = await IsCarryAndLocationMatchByCarryStd(carry, loc);
if (!isMatch)
{
throw new AppFriendlyException("库位与载具规格不匹配", 500);
}
loc = await _db.Queryable<BasLocation>().FirstAsync(it => it.location_code == input.instock.location_code && it.is_type != EnumLocationType..ToString());
//如果数据不全或有误,
if (carry.IsNull() || loc.IsNull() || instockds?.Count < 1 || instockcodes?.Count < 1)
{
//报错, 提示数据不全或有误。
throw new AppFriendlyException("数据不全或有误!", 500);
}
// 生成入库申请数据,添加其他数据 主表
instock.id = SnowflakeIdHelper.NextId();
instock.carry_id = carry.id;
instock.location_id = loc.id;
instock.biz_type = WmsWareHouseConst.BIZTYPE_WMSINSTOCK_ID;
instock.bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_INSTOCK_ENCODE).GetAwaiter().GetResult();
instock.generate_type = "0";// 自动
instock.sync_status = WmsWareHouseConst.SYNC_STATUS_NONEEDSYNC;//未同步
instock.print_status = WmsWareHouseConst.PRINT_STATUS_PRINTCOMPLETE;//已打印
instock.status = WmsWareHouseConst.BILLSTATUS_ADD_ID;// 新增
instock.create_time = DateTime.Now;
_ = await _db.Insertable(instock).ExecuteCommandAsync();
//明细表
foreach (WmsInstockD instockd in instockds!)
{
instockd.id = SnowflakeIdHelper.NextId();
instockd.bill_id = instock.id;
instockd.line_status = WmsWareHouseConst.BILLSTATUS_ADD_ID;
instockd.qty = 0;
instock.create_time = instock.create_time;
instock.create_id = instock.create_id;
}
_ = await _db.Insertable(instockds).ExecuteCommandAsync();
List<WmsInstockCode> items = instockds.Adapt<List<WmsInstockCode>>();
List<WmsInstockCode> instockCOdes = new();
//条码表
foreach (WmsInstockCode instockcode in instockcodes!)
{
instockcode.id = SnowflakeIdHelper.NextId();
string materialCode = instockcode.material_code;
string? codeBatch = instockcode.code_batch;
WmsInstockCode? b = items.Find(x => x.material_code == materialCode && x.code_batch == codeBatch);
if (b != null)
{
WmsInstockCode c = DeepCopyHelper<WmsInstockCode>.DeepCopy(b);
c.id = SnowflakeIdHelper.NextId();
c.bill_d_id = instockds?.Find(x => x.material_code == materialCode && x.code_batch == codeBatch)?.id ?? "";
c.barcode = instockcode.barcode;
c.codeqty = instockcode.codeqty;
c.is_end = 0;// 未结束
c.create_time = instock.create_time;
c.create_id = instock.create_id;
instockCOdes.Add(c);
}
}
string orgId = _userManager.User.OrganizeId;
_ = await _db.Insertable(instockCOdes).CallEntityMethod(it => it.Create(orgId)).ExecuteCommandAsync();
//生成预任务申请
if (sPoint != null && ePoint != null)
{
List<WmsPointH> points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
if (points.Count <= 2)
{
throw new AppFriendlyException("该路径不存在", 500);
}
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 = _userManager.User.OrganizeId,
startlocation_id = sPoint?.location_id ?? string.Empty,
startlocation_code = sPoint?.location_code ?? string.Empty,
endlocation_id = ePoint?.location_id ?? string.Empty,
endlocation_code = ePoint?.location_code ?? string.Empty,
start_floor = sPoint?.floor.ToString(),
end_floor = ePoint?.floor.ToString(),
bill_code = _billRullService.GetBillNumber(WmsWareHouseConst.WMS_PRETASK_H_ENCODE).GetAwaiter().GetResult(),
status = WmsWareHouseConst.PRETASK_BILL_STATUS_DXF_ID,
biz_type = instock?.biz_type ?? string.Empty,
task_type = WmsWareHouseConst.WMS_PRETASK_INSTOCK_TYPE_ID,
carry_id = instock?.carry_id ?? string.Empty,
carry_code = instock?.carry_code ?? string.Empty,
area_id = sPoint?.area_id ?? string.Empty,
area_code = it.Key,
require_id = instock?.id ?? string.Empty,
require_code = instock?.bill_code ?? string.Empty,
create_id = _userManager.UserId,
create_time = DateTime.Now
};
return preTask;
}).ToList();
//生成预任务条码信息
List<WmsPretaskCode> pretaskCodes = new();
foreach (WmsPretaskH? pt in preTasks)
{
if (instockCOdes.Count > 0)
{
foreach (WmsInstockCode jo in instockCOdes)
{
WmsPretaskCode ptc = pt.Adapt<WmsPretaskCode>();
ptc.id = SnowflakeIdHelper.NextId();
ptc.bill_id = pt.id;
ptc.material_id = jo.material_id;
ptc.material_code = jo.material_code;
ptc.barcode = jo.barcode;
ptc.codeqty = jo.codeqty;
ptc.unit_id = jo.unit_id!;
ptc.code_batch = jo.code_batch;
pretaskCodes.Add(ptc);
}
}
}
//生成预任务,同时如果包含条码信息同时插入条码记录
bool isOk = await _wareHouseService.GenPreTask(preTasks, pretaskCodes);
if (isOk)
{
GenPreTaskUpInput preTaskUpInput = new()
{
RquireId = instock?.id,
CarryId = instock?.carry_id!,
CarryStartLocationId = points.FirstOrDefault()?.location_id,
CarryStartLocationCode = points.FirstOrDefault()?.location_code,
LocationIds = (points?.Select(x => x.location_id)?.ToList() ?? Enumerable.Empty<string?>().ToList()) as List<string>
};
//创建预任务操作记录
string operBillId = string.Empty;
if (instock != null)
{
WmsHandleH handleH = instock.Adapt<WmsHandleH>();
operBillId = handleH.id = SnowflakeIdHelper.NextId();
handleH.startlocation_id = instock.location_id!;
handleH.carry_id = instock.carry_id!;
handleH.carry_code = instock.carry_code!;
preTaskUpInput.PreTaskRecord = handleH;
}
//创建预任务条码操作记录
if (instockcodes?.Count > 0)
{
foreach (WmsInstockCode jo in instockcodes)
{
WmsHandleCode handleCode = jo.Adapt<WmsHandleCode>();
handleCode.id = SnowflakeIdHelper.NextId();
handleCode.org_id = _userManager.User.OrganizeId;
handleCode.bill_id = operBillId;
handleCode.create_id = _userManager.UserId;
handleCode.create_time = DateTime.Now;
preTaskUpInput.PreTaskHandleCodes.Add(handleCode);
}
}
//生成载具条码记录
List<WmsCarryCode> carryCodes = preTaskUpInput.PreTaskHandleCodes.Adapt<List<WmsCarryCode>>();
carryCodes.ForEach(x =>
{
x.id = SnowflakeIdHelper.NextId();
x.is_out = 0;
x.carry_id = instock!.carry_id!;
x.warehouse_id = instock!.warehouse_id!;
});
_ = await _db.Insertable(carryCodes).ExecuteCommandAsync();
await _wareHouseService.GenInStockTaskHandleAfter(preTaskUpInput,
it => new WmsCarryH { carry_code = instock!.carry_code!, is_lock = 1, carry_status = ((int)EnumCarryStatus.).ToString(), location_id = preTaskUpInput.CarryStartLocationId, location_code = preTaskUpInput.CarryStartLocationCode },
it => new BasLocation { is_lock = 1 });
if (instockCOdes?.Count > 0)
{
_ = await _db.Updateable<WmsInstockD>().SetColumns(it => new WmsInstockD { line_status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => instockCOdes.Select(x => x.bill_d_id).Contains(it.id)).ExecuteCommandAsync();
_ = await _db.Updateable<WmsInstockH>().SetColumns(it => new WmsInstockH { status = WmsWareHouseConst.BILLSTATUS_ON_ID }).Where(it => it.id == instock!.id).ExecuteCommandAsync();
}
isSuccessFul = true;
}
}
}
await _db.Ado.CommitTranAsync();
}
catch (Exception ex)
{
isSuccessFul = false;
JNPF.Logging.Log.Error(ex.Message);
await _db.Ado.RollbackTranAsync();
//return await ToApiResult(JNPF.Common.Enums.HttpStatusCode.InternalServerError, ex.Message);
}
finally
{
await InvokeGenPretaskExcute();
}
return isSuccessFul;
}
/// <summary>
/// 物料标签查询
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<dynamic> MesFetchInOutStockInfoByBarCode(MaterialLabelQuery input)
{
if (input.IsNull())
{
_ = new ArgumentException(nameof(input));
}
if (input.barcode?.Count < 1)
{
_ = new ArgumentException(nameof(input.barcode));
}
SqlSugarPagedList<MaterailLabelOutput> pagedList = await _db.Queryable<WmsInstockH>().InnerJoin<WmsInstockCode>((a, b) => a.id == b.bill_id)
.LeftJoin<WmsOutstockCode>((a, b, c) => b.barcode == c.barcode)
.WhereIF(!string.IsNullOrEmpty(input.org_id), (a, b, c) => a.org_id == input.org_id)
.Where((a, b, c) => input.barcode.Contains(b.barcode))
.Select((a, b, c) => new MaterailLabelOutput
{
barcode_qty = b.codeqty,
in_bill_code = a.bill_code,
instock_time = a.create_time,
out_bill_code = SqlFunc.Subqueryable<WmsOutstockH>().Where(it => it.id == c.bill_id).Select(it => it.bill_code),
outstock_time = SqlFunc.Subqueryable<WmsOutstockH>().Where(it => it.id == c.bill_id).Select(it => it.create_time),
}, true)
.ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult<MaterailLabelOutput>.SqlSugarPageResult(pagedList);
}
}
}