Files
tnb.server/WarehouseMgr/Tnb.WarehouseMgr/WmsInStockService.cs
2023-08-04 15:31:28 +08:00

481 lines
25 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aop.Api.Domain;
using JNPF.Common.Core.Manager;
using JNPF.Common.Dtos.VisualDev;
using JNPF.Common.Extension;
using JNPF.Common.Security;
using JNPF.FriendlyException;
using JNPF.Logging;
using JNPF.Systems.Interfaces.System;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Minio.DataModel;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using Senparc.Weixin.Work.AdvancedAPIs.OaDataOpen;
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.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
)
{
_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)
{
var dic = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_INSTOCK_D_BILL_STATUS_TYPEID);
var 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);
}
var 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;
var minPacking = (await _db.Queryable<BasMaterial>().FirstAsync(it => it.id == inStockDetails[i].material_id))?.minpacking;
var codeNum = 0;
if (inStockDetails[i].pr_qty.HasValue && minPacking.HasValue && minPacking.Value > 0)
{
var 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++)
{
var index = j + 1;
WmsTempCode barCode = await CreateInstock(inStockDetails[i], index);
if (minPacking.HasValue)
{
if (index < codeNum)
{
barCode.codeqty = minPacking;
}
else
{
if (mod > 0) barCode.codeqty = mod;
else barCode.codeqty = 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);
}
}
var 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)
{
var 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)
{
var 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();
var dic = instockCodes.GroupBy(g => g.id).ToDictionary(x => x.Key, x => x.Select(d => d.barcode_qty).ToList());
var ids = instockCodes.Select(it => it.id).ToList();
var instockDetails = await _db.Queryable<WmsInstockD>().Where(it => ids.Contains(it.id)).ToListAsync();
foreach (var 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();
var 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 } };
var 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();
}
var 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]
public async Task<dynamic> MESCreateInstock(MESCreateInstockInput input)
{
var 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>>();
//入库取终点 //出库起点
var inStockStrategyInput = new InStockStrategyQuery { warehouse_id = instock?.warehouse_id!, Size = 1 };
var 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);
var carry = await _db.Queryable<WmsCarryH>().SingleAsync(it => it.carry_code == input.instock.carry_code);
var loc = await _db.Queryable<BasLocation>().FirstAsync(it => it.id == endLocations[0].id);
var 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 = "1";// 自动
instock.sync_status = WmsWareHouseConst.SYNC_STATUS__NOTSYNC;//未同步
instock.print_status = WmsWareHouseConst.PRINT_STATUS_PRINTCOMPLETE;//已打印
instock.status = WmsWareHouseConst.BILLSTATUS_ADD_ID;// 新增
instock.create_time = DateTime.Now;
await _db.Insertable(instock).ExecuteCommandAsync();
//明细表
foreach (var 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();
var items = instockds.Adapt<List<WmsInstockCode>>();
List<WmsInstockCode> instockCOdes = new();
//条码表
foreach (var instockcode in instockcodes!)
{
instockcode.id = SnowflakeIdHelper.NextId();
var materialCode = instockcode.material_code;
var codeBatch = instockcode.code_batch;
var b = items.Find(x => x.material_code == materialCode && x.code_batch == codeBatch);
if (b != null)
{
var 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);
}
}
var orgId = _userManager.User.OrganizeId;
await _db.Insertable(instockCOdes).CallEntityMethod(it => it.Create(orgId)).ExecuteCommandAsync();
//生成预任务申请
if (sPoint != null && ePoint != null)
{
var points = await _wareHouseService.PathAlgorithms(sPoint.id, ePoint.id);
//根据获取的路径点生成预任务,生成顺序必须预路径算法返回的起终点的顺序一致(预任务顺序)
if (points?.Count > 0)
{
if (points.Count <= 2) throw new AppFriendlyException("该路径不存在", 500);
var preTasks = points.Where(it => !it.location_id.IsNullOrEmpty()).GroupBy(g => g.area_code).Select(it =>
{
var sPoint = it.FirstOrDefault();
var 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 (var pt in preTasks)
{
if (instockCOdes.Count > 0)
{
foreach (var jo in instockCOdes)
{
var 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);
}
}
}
//生成预任务,同时如果包含条码信息同时插入条码记录
var 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>
};
//创建预任务操作记录
var operBillId = string.Empty;
if (instock != null)
{
var 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 (var 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);
}
}
//生成载具条码记录
var 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, is_use = ((int)EnumCarryStatus.).ToString() });
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);
}
return isSuccessFul;
}
}
}