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.Enums; using JNPF.FriendlyException; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev; using JNPF.VisualDev.Interfaces; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using SqlSugar; using Tnb.BasicData.Entities; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Entity; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 调拨出库单(原材料) /// [OverideVisualDev(ModuleConsts.MODULE_WmsRawmatTransferoutstock_ID)] public class WmsRawmatTransferoutstockService : BaseWareHouseService { private readonly ISqlSugarClient _db; private readonly IUserManager _userManager; private readonly IBillRullService _billRullService; private readonly IRunService _runService; private readonly IVisualDevService _visualDevService; private readonly IWmsPDAScanInStockService _wmsPDAScanInStock; private readonly IWareHouseService _wareHouseService; public WmsRawmatTransferoutstockService( ISqlSugarRepository repository, IUserManager userManager, IBillRullService billRullService, IRunService runService, IVisualDevService visualDevService, IWmsPDAScanInStockService wmsPDAScanInStock, IWareHouseService wareHouseService) { _db = repository.AsSugarClient(); _userManager = userManager; _billRullService = billRullService; _runService = runService; _visualDevService = visualDevService; _wmsPDAScanInStock = wmsPDAScanInStock; _wareHouseService = wareHouseService; } public override async Task ModifyAsync(WareHouseUpInput input) { if (input == null) { throw new ArgumentNullException(nameof(input)); } } /// /// 获取物料库存 /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task MaterialInventory(MaterialTransferGetMaterialInventoryInput input) { try { if (input.palletCount <= 0) { throw new AppFriendlyException("托盘数必须大于0", 500); } if (string.IsNullOrEmpty(input.material_id)) { throw new AppFriendlyException("物料id不可为空", 500); } if (string.IsNullOrEmpty(input.code_batch)) { throw new AppFriendlyException("批号不可为空", 500); } OutStockStrategyQuery outStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_YCL_ID, material_id = input.material_id, code_batch = input.code_batch, Size = input.palletCount, Region_id = WmsWareHouseConst.REGION_Purchase_ID, PolicyCode = WmsWareHouseConst.POLICY_YCLOUTSTOCK, AvoidBusyPassage = true }; List items = await _wareHouseService.OutStockStrategy(outStockStrategyInput); decimal qty = _db.Queryable().Where(r => items.Select(a => a.id).Contains(r.carry_id) && r.material_id == input.material_id && r.code_batch == input.code_batch).Sum(r => r.codeqty); JObject keyValuePairs = new JObject(); keyValuePairs["realPalletCount"] = items.Count; keyValuePairs["realInvQty"] = qty; return await ToApiResult(HttpStatusCode.OK, "成功", keyValuePairs); } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } } /// /// 按托下发(到集中供料或外协) /// /// /// /// [HttpPost, NonUnify, AllowAnonymous] public async Task Distribute(MaterialTransferDistributeInput input) { try { await _s_taskExecuteSemaphore_YCLOutstock.WaitAsync(); if (string.IsNullOrEmpty(input.source_id)) { throw new AppFriendlyException("来源单据id不可为空", 500); } if (input.palletCount <= 0) { throw new AppFriendlyException("托盘数必须大于0", 500); } if (input.qty <= 0) { throw new AppFriendlyException("数量必须大于0", 500); } if (string.IsNullOrEmpty(input.code_batch)) { throw new AppFriendlyException("批号不可为空", 500); } WmsMaterialTransferD wmsMaterialTransferD = await _db.Queryable().FirstAsync(it => it.id == input.source_id); WmsMaterialTransfer wmsMaterialTransfer = await _db.Queryable().FirstAsync(it => it.id == wmsMaterialTransferD.bill_id); if (wmsMaterialTransferD.yxfqty >= wmsMaterialTransferD.qty) { throw new AppFriendlyException("已下发数量已达到转库数量", 500); } await _db.Ado.BeginTranAsync(); OutStockStrategyQuery outStockStrategyInput = new() { warehouse_id = WmsWareHouseConst.WAREHOUSE_YCL_ID, material_id = wmsMaterialTransferD.material_id, code_batch = input.code_batch, Size = input.palletCount, Region_id = WmsWareHouseConst.REGION_Purchase_ID, PolicyCode = WmsWareHouseConst.POLICY_YCLOUTSTOCK, AvoidBusyPassage = true }; List items = await _wareHouseService.OutStockStrategy(outStockStrategyInput); if (items.Count == 0) { throw new AppFriendlyException($@"没有可以出库的载具", 500); } decimal qty = _db.Queryable().Where(r => items.Select(a => a.id).Contains(r.carry_id) && r.material_id == wmsMaterialTransferD.material_id && r.code_batch == input.code_batch).Sum(r => r.codeqty); // 暂定PDA上查询到的物料批次和库存数量与提交时获取的不一致时,需要前台重新获取库存接口 if (input.palletCount != items.Count || input.qty != qty) { throw new AppFriendlyException($@"当前实际托盘数量为{input.palletCount} 实际库存数量为{qty},与前台数据不一致,请重新获取库存", HttpStatusCode.InternalServerError); } List endLocations = new List(); // 集中供料区三工位 if (wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_JZGL_ID) { // 根据三工位任务数平均分配任务 暂定 endLocations = _db.Queryable().Where(r => _wareHouseService.GetFloor1GLSGWOutstockLocation().Contains(r.id) && r.is_lock == 0 && r.is_use == "0") .OrderBy("is_lock, task_nums, location_code").ToList(); } // 中储仓三工位 else if (wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_ZC_ID) { // 根据三工位任务数平均分配任务 暂定 endLocations = _db.Queryable().Where(r => _wareHouseService.GetFloor1WXSGWOutstockLocation().Contains(r.id) && r.is_lock == 0 && r.is_use == "0") .OrderBy("is_lock, task_nums, location_code").ToList(); } if (endLocations.Count() < input.palletCount) { throw new AppFriendlyException($@"可用的终点库位数量为{endLocations.Count()}个 下发数量为{input.palletCount}个 请检查终点库位的锁定和占用状态", 500); } foreach (var wmsCarryH in items) { BasLocation startLocation = await _db.Queryable().Where(r => r.id == wmsCarryH.location_id).FirstAsync(); BasLocation endLocation = null; // 集中供料区三工位 if (wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_JZGL_ID) { // 根据三工位任务数平均分配任务 暂定 endLocation = await _db.Queryable().Where(r => _wareHouseService.GetFloor1GLSGWOutstockLocation().Contains(r.id) && r.is_lock == 0 && r.is_use == "0").OrderBy("is_lock, task_nums, location_code").FirstAsync(); } // 中储仓三工位 else if (wmsMaterialTransfer.warehouse_instock == WmsWareHouseConst.WAREHOUSE_ZC_ID) { // 根据三工位任务数平均分配任务 暂定 endLocation = await _db.Queryable().Where(r => _wareHouseService.GetFloor1WXSGWOutstockLocation().Contains(r.id) && r.is_lock == 0 && r.is_use == "0").OrderBy("is_lock, task_nums, location_code").FirstAsync(); } if (endLocation == null) { throw new AppFriendlyException($@"没有可用的终点库位!请检查终点库位的锁定和占用状态", 500); } CommonCreatePretaskInput commonCreatePretaskInput = new CommonCreatePretaskInput(); commonCreatePretaskInput.startlocation_id = startLocation.id; commonCreatePretaskInput.endlocation_id = endLocation.id; commonCreatePretaskInput.task_type = WmsWareHouseConst.WMS_PRETASK_OUTSTOCK_TYPE_ID; commonCreatePretaskInput.biz_type = WmsWareHouseConst.BIZTYPE_WMSMATERIALTRANSFER_ID; commonCreatePretaskInput.source_id = input.source_id; commonCreatePretaskInput.carry_id = wmsCarryH.id; commonCreatePretaskInput.carry_code = wmsCarryH.carry_code; commonCreatePretaskInput.isExcuteMission = false; Entities.Dto.Outputs.Result res = await _wareHouseService.CommonCreatePretask(commonCreatePretaskInput, _db); if (res.code != HttpStatusCode.OK) { Logger.LogInformation($@"生成预任务失败"); throw new AppFriendlyException($@"生成预任务失败", 500); } } // 更新子表已下发数量 await _db.Updateable().SetColumns(r => r.yxfqty == r.yxfqty + input.qty).Where(r => r.id == input.source_id).ExecuteCommandAsync(); await _db.Ado.CommitTranAsync(); } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); Logger.LogError("【Distribute】" + ex.Message); Logger.LogError("【Distribute】" + ex.StackTrace); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } finally { _ = _s_taskExecuteSemaphore_YCLOutstock.Release(); InvokeGenPretaskExcute(); } return await ToApiResult(HttpStatusCode.OK, "成功"); } } }