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.Enums; using JNPF.Common.Security; using JNPF.EventBus; using JNPF.FriendlyException; using JNPF.Systems.Entitys.System; using JNPF.Systems.Interfaces.System; using JNPF.VisualDev; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Npgsql; using SqlSugar; using Tnb.BasicData; using Tnb.BasicData.Entities; using Tnb.BasicData.Interfaces; using Tnb.ProductionMgr.Entities.Entity; using Tnb.ProductionMgr.Interfaces; using Tnb.WarehouseMgr.Entities; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Dto.Inputs; using Tnb.WarehouseMgr.Entities.Entity; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { [OverideVisualDev(ModuleConsts.MODULE_WmsInventorycheck_ID)] public class WmsInventorycheckService : BaseWareHouseService { 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 readonly IThirdApiRecordService _thirdApiRecordService; private static Dictionary _dicBillCodes = new(); public WmsInventorycheckService( ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService, IUserManager userManager, IBillRullService billRullService, IWareHouseService wareHouseService, IPrdInstockService prdInstockService, IThirdApiRecordService thirdApiRecordService, IEventPublisher eventPublisher ) { _db = repository.AsSugarClient(); _dictionaryDataService = dictionaryDataService; _userManager = userManager; _billRullService = billRullService; _wareHouseService = wareHouseService; _thirdApiRecordService = thirdApiRecordService; _prdInstockService = prdInstockService; } /// /// 盘点单提交 /// /// /// [HttpPost] public async Task Submit(WmsInventorycheckSubmitInput input) { try { return await ToApiResult(HttpStatusCode.OK, "成功"); } catch (PostgresException ex) { Logger.LogError(ex.Message); Logger.LogError(ex.StackTrace); throw new AppFriendlyException($"{ex.Message}", 500); } catch (Exception ex) { Logger.LogInformation(ex.Message); Logger.LogInformation(ex.StackTrace); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } } /// /// 获取仓库中该物料批次的所有库位库存信息 /// /// /// [HttpPost] public async Task> MaterialLocationQty(WmsInventoryCheckQtyInput input) { if(string.IsNullOrEmpty(input.material_id)) throw Oops.Bah("物料id不能为空"); if (string.IsNullOrEmpty(input.warehouse_id)) throw Oops.Bah("仓库id不能为空"); if (string.IsNullOrEmpty(input.code_batch)) throw Oops.Bah("物料批次不能为空"); var result=new List(); var items = await _db.Queryable().InnerJoin((a, b) => a.carry_id == b.id) .InnerJoin((a, b, c) => b.location_id == c.id).InnerJoin((a, b, c, d) => c.wh_id == d.id) .LeftJoin((a, b, c, d, e) => e.barcode == a.barcode) .InnerJoin((a, b, c, d, e, f) => f.id == a.material_id) .LeftJoin((a, b, c, d, e, f, g) => g.EnCode == f.unit_id && g.DictionaryTypeId == WmsWareHouseConst.UNITTYPEID) .Where((a, b, c, d, e, f) => c.is_type == ((int)EnumLocationType.存储库位).ToString() && d.id == input.warehouse_id && a.material_id == input.material_id && a.code_batch==input.code_batch ) .Select((a, b, c, d, e, f, g) => new WmsInventoryCheckSearchOut { material_code=a.material_code, material_name = f.name, material_id = f.id, location_id = c.id, location_code=c.location_code, code_batch = a.code_batch, material_specifition=f.material_specification, material_standard=f.material_standard, qty=0, carry_id=a.carry_id, carry_code=b.carry_code }, true).ToListAsync(); List carryCodes = await _db.Queryable() .InnerJoin((a, b) => a.carry_id == b.id) .InnerJoin((a, b, c) => b.location_id == c.id).Where((a, b, c) => c.is_type == ((int)EnumLocationType.存储库位).ToString() && c.wh_id == input.warehouse_id && a.material_id == input.material_id && a.code_batch==input.code_batch).Select((a, b, c) => new WmsCarryCode { warehouse_id = c.wh_id }, true).ToListAsync(); var storeMap = items.DistinctBy(x => new { x.material_id, x.location_id, x.code_batch }).ToDictionary(x => new { x.material_id, x.location_id, x.code_batch }, x => x); var group = items.GroupBy(g => new { g.material_id, g.location_id, g.code_batch }); foreach (var itGroup in group) { _ = storeMap.TryGetValue(itGroup.Key, out WmsInventoryCheckSearchOut? stockReport); List curCarryCodes = carryCodes.FindAll(x => x.material_id == itGroup.Key.material_id && x.location_id == itGroup.Key.location_id && x.code_batch == itGroup.Key.code_batch); stockReport.qty = 0; curCarryCodes.ForEach(x => { stockReport.qty += x.codeqty; }); result.Add(stockReport); } return result; } /// /// 修改盘点的物料数量 /// /// [HttpPost] public async Task SaveCheck(WmsInventoryCheckDSubmitInput input) { try { if (string.IsNullOrEmpty(input.checkd_bill_id)) throw Oops.Bah("盘点子表id不能为空"); await _db.Ado.BeginTranAsync(); var wmsInventoryCheckD = await _db.Queryable().Where(r => r.id == input.checkd_bill_id).FirstAsync(); if (wmsInventoryCheckD == null) throw Oops.Bah($"盘点单子表id:{input.checkd_bill_id}数据不存在"); if (wmsInventoryCheckD.check_status == "1") throw Oops.Bah($"该盘点单已完成盘点,不能重复盘点"); var wmsInventoryCheckH = await _db.Queryable().Where(r => r.id == wmsInventoryCheckD.bill_id).FirstAsync(); //汇总实际数量 decimal actual_qty = (input.details != null && input.details.Count > 0) ? input.details.Sum(r => (r.check_qty.HasValue ? r.check_qty.Value : 0)) : 0; await _db.Updateable() .SetColumns(r => r.actual_qty == actual_qty) .SetColumns(r => r.check_time == DateTime.Now) .SetColumns(r => r.checker_id == _userManager.UserId) .SetColumns(r=>r.check_status=="1") .Where(r => r.id == wmsInventoryCheckD.id).ExecuteCommandAsync(); //查找到盘点任务单下面所有的物料明细 var noChecks = await _db.Queryable().Where(r => r.bill_id == wmsInventoryCheckH.id).ToListAsync(); if(noChecks!=null && noChecks.Where(r=>r.check_status=="0" || string.IsNullOrEmpty(r.check_status)).Count()>0) //存在还没完成盘点的物料明细 { await _db.Updateable() .SetColumns(r => r.check_status == "1") .Where(r => r.id == wmsInventoryCheckH.id).ExecuteCommandAsync(); } else if(noChecks != null && noChecks.Where(r => r.check_status == "0" || string.IsNullOrEmpty(r.check_status)).Count() == 0) //盘点任务单下的物料明细都已盘点完成,任务单状态变成已盘点 { await _db.Updateable() .SetColumns(r => r.check_status == "2") .SetColumns(r=>r.check_time==DateTime.Now) .Where(r => r.id == wmsInventoryCheckH.id).ExecuteCommandAsync(); } //先删除盘点记录表里面和此物料盘点明细有关的所有记录,再把此次盘点的详情保存到记录表 await _db.Deleteable().Where(r => r.bill_id == wmsInventoryCheckH.id && r.mat_bill_id == wmsInventoryCheckD.id).ExecuteCommandAsync(); if(input.details!=null && input.details.Count > 0) { var WmsInventorycheckRecords=new List(); foreach (var item in input.details) { var record = new WmsInventorycheckRecord() { create_id = _userManager.UserId, create_time = DateTime.Now, bill_id = wmsInventoryCheckH.id, mat_bill_id = wmsInventoryCheckD.id, carry_id = item.carry_id, carry_code = item.carry_code, location_id = item.location_id, location_code = item.location_code, code_batch = item.code_batch, search_qty = item.qty.HasValue ? item.qty.Value.ToString() : "0", check_qty = item.check_qty.HasValue ? item.check_qty.Value.ToString() : "0" }; WmsInventorycheckRecords.Add(record); } await _db.Insertable(WmsInventorycheckRecords).ExecuteCommandAsync(); } #region 调用bip接口 List> requestData = new List>(); List tableIds = new List(); tableIds.Add(wmsInventoryCheckD.material_id); List erpExtendFields = await _db.Queryable().Where(x => tableIds.Contains(x.table_id)).ToListAsync(); Dictionary erpRequestData = new Dictionary(); erpRequestData.Add("cspecialhid", wmsInventoryCheckH.erp_pk);//盘点单主表id List> erpRequestDataDetails = new List>(); erpRequestDataDetails.Add(new Dictionary() { ["cspecialbid"] = wmsInventoryCheckD.erp_line_pk, //盘点单子表id ["cspeciallid"] = wmsInventoryCheckH.erp_pk, //盘点单主表id ["crowno"] = wmsInventoryCheckD.lineno, //行号 ["ncountnum"] = actual_qty, //实际盘点总数量 ["cmaterialoid"] = erpExtendFields.Find(x => x.table_id == wmsInventoryCheckD.material_id)?.cmaterialoid ?? null, //物料id }); erpRequestData.Add("dtls", erpRequestDataDetails); requestData.Add(erpRequestData); BasFactoryConfig config = await _db.Queryable().FirstAsync(x => x.enabled == 1 && x.key == FactoryConfigConst.BIPURL); ThirdWebapiRecord thirdWebapiRecord = new ThirdWebapiRecord(); thirdWebapiRecord.id = SnowflakeIdHelper.NextId(); thirdWebapiRecord.third_name = WmsWareHouseConst.BIP; thirdWebapiRecord.name = "盘点单"; thirdWebapiRecord.method = "POST"; thirdWebapiRecord.url = config.value + "uapws/rest/InvCount/save"; //thirdWebapiRecord.url = WmsWareHouseConst.BIP_DOMAIN + "uapws/rest/InvCount/save"; thirdWebapiRecord.request_data = JsonConvert.SerializeObject(requestData); thirdWebapiRecord.create_time = DateTime.Now; thirdWebapiRecord.remark = "【WmsInventorycheckService SubmitCheck】盘点单主表id:" + wmsInventoryCheckH.id + ",盘点单子表id:" + wmsInventoryCheckD.id; await _db.Insertable(thirdWebapiRecord).ExecuteCommandAsync(); BasFactoryConfig callErp = await _db.Queryable().FirstAsync(x => x.enabled == 1 && x.key == FactoryConfigConst.CALLERP); if (callErp.value == "1") { await _thirdApiRecordService.Send(new List { thirdWebapiRecord }, "自动", _db); } #endregion await _db.Ado.CommitTranAsync(); return await ToApiResult(HttpStatusCode.OK, "成功"); } catch (Exception ex) { await _db.Ado.RollbackTranAsync(); Logger.LogInformation(ex.Message); Logger.LogInformation(ex.StackTrace); return await ToApiResult(HttpStatusCode.InternalServerError, ex.Message); } } } }