using HslCommunication; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEA_Common; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.OrderEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.SquareCabin; using WIDESEA_IBasicService; using WIDESEA_ISquareCabinServices; using WIDESEA_IWMsInfoServices; using WIDESEA_Model.Models; using static WIDESEA_DTO.SquareCabin.OrderDto; namespace WIDESEA_SquareCabinServices { public class DeliveryOrderServices : ServiceBase>, IDeliveryOrderServices { static string SearchDate = ""; private readonly IBasicService _basicService; private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IInventory_BatchServices _inventory_BatchServices; private readonly IInventoryInfoService _inventoryInfoService; private readonly IDeliveryOrderDetailServices _deliveryOrderDetailServices; private readonly ISupplyTaskService _supplyTaskService; public IRepository Repository => BaseDal; public DeliveryOrderServices(IRepository BaseDal, IBasicService basicService, IUnitOfWorkManage unitOfWorkManage, IInventory_BatchServices inventory_BatchServices, IInventoryInfoService inventoryInfoService, IDeliveryOrderDetailServices deliveryOrderDetailServices, ISupplyTaskService supplyTaskService) : base(BaseDal) { _basicService = basicService; _unitOfWorkManage = unitOfWorkManage; _deliveryOrderDetailServices = deliveryOrderDetailServices; _supplyTaskService = supplyTaskService; _inventory_BatchServices = inventory_BatchServices; _inventoryInfoService = inventoryInfoService; } /// /// 获取上游出库单 0成功1失败 /// /// /// //public WebResponseContent GetUpstreamOutOrder() //{ // var responseContent = new WebResponseContent(); // try // { // // 请求地址 // var url = "http://121.37.118.63:80/GYZ2/95fck/outOrder"; // //if (string.IsNullOrEmpty(SearchDate)) SearchDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // //// 请求参数 // var requestData = new // { // //searchDate = SearchDate // searchDate = "2022-10-10 20:45:16" // 正确的格式 // }; // //SearchDate = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd HH:mm:ss"); // // 发起请求 // var result = HttpHelper.Post(url, requestData.ToJsonString()); // // 反序列化 // var response = JsonConvert.DeserializeObject>(result); // if (response.resultCode != "0") // { // SendErrorToUpstream(3, "", response.resultMsg ?? "上游接口返回失败", ""); // return responseContent.Error(response.resultMsg ?? "上游接口返回失败"); // } // if (response.data == null || !response.data.Any()) // { // return responseContent.OK("无新出库单数据"); // } // // 获取所有已存在的出库单号 // var existingOutOrderNos = BaseDal.Db.Queryable() // .Select(x => x.Out_no) // .ToList(); // // 过滤掉已存在的出库单 // var newOutOrders = response.data // .Where(outorder => !existingOutOrderNos.Contains(outorder.order_no))//order_no出库单号 // .ToList(); // if (!newOutOrders.Any()) // { // return responseContent.OK("所有出库单已存在,无需新增"); // } // Db.Ado.BeginTran(); // try // { // List _DeliveryOrders = new List(); // ////存储出库单号 // //List orderNos = new List(); // foreach (var outorder in newOutOrders) // { // var entityOrder = new Dt_DeliveryOrder // { // Out_no = outorder.order_no, // Out_type = outorder.order_type, // Client_no = outorder.client_no, // Client_name = outorder.client_name, // Account_time = outorder.account_time, // Warehouse_no=outorder.warehouse_no, // OutStatus = "未完成", // //Details = outorder.details.Select(d => new Dt_DeliveryOrderDetail // //{ // // // InsertNav 会自动设置关联字段 DeliveryOrderId // // Goods_no = d.goods_no, // // Order_qty = d.order_qty, // // Batch_num = d.batch_num, // // Exp_date = d.exp_date, // // OotDetailStatus = "新建", // // Status = outorder.warehouse_no == "001" ? 0 : 2, //如果是001房那么将状态设置为0,2为人工处理 // //}).ToList() // }; // #region 根据出库单详情查找物料名称、批次的库存信息(Dt_InventoryInfo);根据先入先出,CreateDate // //根据物料名称查找物料信息 // foreach (var item in outorder.details) // { // // 将上游出库数量转为正数 // item.order_qty = Math.Abs(item.order_qty); // var medication = BaseDal.Db.Queryable() // .Where(m => m.Goods_no == item.goods_no) // .First(); // } // //根据箱规判断是否有散件,计算出散件数量和整件数 // //根据入库时间分组,有散件就优先分配立库数量,整件优先分配平库数量 // #endregion // _DeliveryOrders.Add(entityOrder); // }; // // 使用 InsertNav 一次性插入主表和子表数据 // BaseDal.Db.InsertNav(_DeliveryOrders).Include(x => x.Details).ExecuteCommand(); // // 这里可以添加下发到 WCS 的逻辑 // // var result = EdiOut(); // 发给下游 // Db.Ado.CommitTran(); // return responseContent.OK("同步出库单成功"); // } // catch (Exception ex) // { // Db.Ado.RollbackTran(); // SendErrorToUpstream(3, "", ex.Message, ""); // return responseContent.Error("同步失败: " + ex.Message); // } // } // catch (Exception ex) // { // // 全局异常时,也推送异常给上游 // SendErrorToUpstream(3, "", ex.Message, ""); // return responseContent.Error("同步失败: " + ex.Message); // } //} public WebResponseContent GetUpstreamOutOrder() { var responseContent = new WebResponseContent(); try { var url = "http://121.37.118.63:80/GYZ2/95fck/outOrder"; var requestData = new { searchDate = "2022-10-10 20:45:16" }; var result = HttpHelper.Post(url, requestData.ToJsonString()); var response = JsonConvert.DeserializeObject>(result); if (response.resultCode != "0") { SendErrorToUpstream(3, "", response.resultMsg ?? "上游接口返回失败", ""); return responseContent.Error(response.resultMsg ?? "上游接口返回失败"); } if (response.data == null || !response.data.Any()) { return responseContent.OK("无新出库单数据"); } // 已存在出库单号 var existingOutOrderNos = BaseDal.Db.Queryable() .Select(x => x.Out_no) .ToList(); // 新出库单 var newOutOrders = response.data .Where(outorder => !existingOutOrderNos.Contains(outorder.order_no)) .ToList(); if (!newOutOrders.Any()) { return responseContent.OK("所有出库单已存在,无需新增"); } Db.Ado.BeginTran(); try { List _DeliveryOrders = new List(); foreach (var outorder in newOutOrders) { var entityOrder = new Dt_DeliveryOrder { Out_no = outorder.order_no, Out_type = outorder.order_type, Client_no = outorder.client_no, Client_name = outorder.client_name, Account_time = outorder.account_time, Warehouse_no = outorder.warehouse_no, OutStatus = "未完成", Details = new List() }; // 遍历出库明细 foreach (var item in outorder.details) { // 1️⃣ 转为正数(上游可能传负数) item.order_qty = Math.Abs(item.order_qty); decimal orderQty = (decimal)item.order_qty; // 2️⃣ 查物料基础信息(获取箱规) var medication = BaseDal.Db.Queryable() .Where(m => m.Goods_no == item.goods_no) .First(); if (medication == null) { SendErrorToUpstream(3, "", $"找不到物料信息:{item.goods_no}", ""); continue; } decimal boxQty = medication.BoxQty <= 0 ? 1 : medication.BoxQty; // 3️⃣ 计算整件与散件数量 var fullBoxes = (int)(orderQty / boxQty); // 整件箱数 var partialQty = orderQty % boxQty; // 散件数量 // 若上游给了批次号,则优先匹配 string requestedBatch = string.IsNullOrEmpty(item.batch_num) ? null : item.batch_num; // helper: 查询库存函数(按入库时间升序) Func> queryInventoryByStockStatus = (stockStatus) => { var q = BaseDal.Db.Queryable() .Where(i => i.MaterielCode == item.goods_no && (i.StockQuantity - i.OutboundQuantity) > 0 && i.StockStatus == stockStatus); if (!string.IsNullOrEmpty(requestedBatch)) q = q.Where(i => i.BatchNo == requestedBatch); return q.OrderBy(i => i.InDate).ToList(); }; // 4️⃣分配散件(优先立库 Status=0) decimal remainingPartial = partialQty; if (remainingPartial > 0) { var invList_ly = queryInventoryByStockStatus(1); foreach (var inv in invList_ly) { if (remainingPartial <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available <= 0) continue; decimal use = Math.Min(available, remainingPartial); var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = use, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 0, //立库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)use; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingPartial -= use; } // 立库不够 → 平库补 (Status=2) if (remainingPartial > 0) { var invList_pk = queryInventoryByStockStatus(2); foreach (var inv in invList_pk) { if (remainingPartial <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available <= 0) continue; decimal use = Math.Min(available, remainingPartial); var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = use, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 2, //平库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)use; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingPartial -= use; } } if (remainingPartial > 0) { SendErrorToUpstream(3, "", $"出库单[{outorder.order_no}]物料[{item.goods_no}]散件库存不足,未分配:{remainingPartial}", ""); } } //分配整件(优先平库 Status=2) int remainingFullBoxes = fullBoxes; if (remainingFullBoxes > 0) { var invList_pk = queryInventoryByStockStatus(2); foreach (var inv in invList_pk) { if (remainingFullBoxes <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available < boxQty) continue; int canProvideBoxes = (int)(available / boxQty); if (canProvideBoxes <= 0) continue; int useBoxes = Math.Min(canProvideBoxes, remainingFullBoxes); decimal useQty = useBoxes * boxQty; var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = useQty, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 2, //平库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)useQty; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingFullBoxes -= useBoxes; } // 平库不够 → 立库补 (Status=1) if (remainingFullBoxes > 0) { var invList_ly = queryInventoryByStockStatus(1); foreach (var inv in invList_ly) { if (remainingFullBoxes <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available < boxQty) continue; int canProvideBoxes = (int)(available / boxQty); if (canProvideBoxes <= 0) continue; int useBoxes = Math.Min(canProvideBoxes, remainingFullBoxes); decimal useQty = useBoxes * boxQty; var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = useQty, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 0, //立库(补整箱) Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)useQty; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingFullBoxes -= useBoxes; } } if (remainingFullBoxes > 0) { decimal unfilledQty = remainingFullBoxes * boxQty; SendErrorToUpstream(3, "", $"出库单[{outorder.order_no}]物料[{item.goods_no}]整箱库存不足,未分配数量:{unfilledQty}", ""); } } } _DeliveryOrders.Add(entityOrder); } // 插入主表+明细 BaseDal.Db.InsertNav(_DeliveryOrders) .Include(x => x.Details) .ExecuteCommand(); Db.Ado.CommitTran(); return responseContent.OK("同步出库单成功"); } catch (Exception ex) { Db.Ado.RollbackTran(); SendErrorToUpstream(3, "", ex.Message, ""); return responseContent.Error("同步失败: " + ex.Message); } } catch (Exception ex) { SendErrorToUpstream(3, "", ex.Message, ""); return responseContent.Error("同步失败: " + ex.Message); } } /// /// 过滤没有对商品进行维护的出库单进行过滤 /// /// public WebResponseContent GetUpstreamOutOrder2() { var responseContent = new WebResponseContent(); try { var url = "http://121.37.118.63:80/GYZ2/95fck/outOrder"; var requestData = new { searchDate = "2022-10-10 20:45:16" }; var result = HttpHelper.Post(url, requestData.ToJsonString()); var response = JsonConvert.DeserializeObject>(result); if (response.resultCode != "0") { SendErrorToUpstream(3, "", response.resultMsg ?? "上游接口返回失败", ""); return responseContent.Error(response.resultMsg ?? "上游接口返回失败"); } if (response.data == null || !response.data.Any()) { return responseContent.OK("无新出库单数据"); } // 已存在出库单号 var existingOutOrderNos = BaseDal.Db.Queryable() .Select(x => x.Out_no) .ToList(); // 新出库单 var newOutOrders = response.data .Where(outorder => !existingOutOrderNos.Contains(outorder.order_no)) .ToList(); if (!newOutOrders.Any()) { return responseContent.OK("所有出库单已存在,无需新增"); } Db.Ado.BeginTran(); try { List _DeliveryOrders = new List(); List orderNos = new(); foreach (var outorder in newOutOrders) { bool skipOrder = false; // 标记是否跳过该入库单 var entityOrder = new Dt_DeliveryOrder { Out_no = outorder.order_no, Out_type = outorder.order_type, Client_no = outorder.client_no, Client_name = outorder.client_name, Account_time = outorder.account_time, Warehouse_no = outorder.warehouse_no, OutStatus = "未完成", Details = new List() }; // 遍历出库明细 foreach (var item in outorder.details) { // 1️⃣ 转为正数(上游可能传负数) item.order_qty = Math.Abs(item.order_qty); decimal orderQty = (decimal)item.order_qty; // 2️⃣ 查物料基础信息(获取箱规) var medication = BaseDal.Db.Queryable() .Where(m => m.MaterielCode == item.goods_no) .First(); //如果物料信息不存在,跳过整个入库单 if (medication == null) { skipOrder = true; Console.WriteLine($"跳过入库单 {outorder.order_no},原因:未找到商品 [{item.goods_no}] 的物料信息。"); break; } // 若物料不存在或 MaterielSourceType 为空,则跳过整个出库单 if (medication == null || !Enum.IsDefined(typeof(MaterielSourceTypeEnum), medication.MaterielSourceType)) { skipOrder = true; break; } if (medication == null) { SendErrorToUpstream(3, "", $"找不到物料信息:{item.goods_no}", ""); continue; } decimal boxQty = medication.BoxQty <= 0 ? 1 : medication.BoxQty; // 3️⃣ 计算整件与散件数量 var fullBoxes = (int)(orderQty / boxQty); // 整件箱数 var partialQty = orderQty % boxQty; // 散件数量 // 若上游给了批次号,则优先匹配 string requestedBatch = string.IsNullOrEmpty(item.batch_num) ? null : item.batch_num; // helper: 查询库存函数(按入库时间升序) // 定义一个委托变量:输入int参数,返回List Func> queryInventoryByStockStatus = (stockStatus) => { // 1. 创建基础查询 var q = BaseDal.Db.Queryable() .Where(i => i.MaterielCode == item.goods_no && // 物料编号匹配 (i.StockQuantity - i.OutboundQuantity) > 0 && // 可用库存>0 i.StockStatus == stockStatus); // 库存状态匹配 // 2. 条件筛选(如果有批次号要求) if (!string.IsNullOrEmpty(requestedBatch)) q = q.Where(i => i.BatchNo == requestedBatch); // 3. 执行查询并返回结果 return q.OrderBy(i => i.InDate).ToList(); // 按入库时间排序 }; // 4️⃣分配散件(优先立库 Status=0) decimal remainingPartial = partialQty; if (remainingPartial > 0) { var invList_ly = queryInventoryByStockStatus(0); foreach (var inv in invList_ly) { if (remainingPartial <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available <= 0) continue; decimal use = Math.Min(available, remainingPartial); var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = use, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 0, //立库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)use; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingPartial -= use; } // 立库不够 → 平库补 (Status=2) if (remainingPartial > 0) { var invList_pk = queryInventoryByStockStatus(2); foreach (var inv in invList_pk) { if (remainingPartial <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available <= 0) continue; decimal use = Math.Min(available, remainingPartial); var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = use, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 2, //平库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)use; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingPartial -= use; } } if (remainingPartial > 0) { SendErrorToUpstream(3, "", $"出库单[{outorder.order_no}]物料[{item.goods_no}]散件库存不足,未分配:{remainingPartial}", ""); } } //分配整件(优先平库 Status=2) int remainingFullBoxes = fullBoxes; if (remainingFullBoxes > 0) { var invList_pk = queryInventoryByStockStatus(2); foreach (var inv in invList_pk) { if (remainingFullBoxes <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available < boxQty) continue; int canProvideBoxes = (int)(available / boxQty); if (canProvideBoxes <= 0) continue; int useBoxes = Math.Min(canProvideBoxes, remainingFullBoxes); decimal useQty = useBoxes * boxQty; var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = useQty, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 2, //平库 Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)useQty; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingFullBoxes -= useBoxes; } // 平库不够 → 立库补 (Status=1) if (remainingFullBoxes > 0) { var invList_ly = queryInventoryByStockStatus(1); foreach (var inv in invList_ly) { if (remainingFullBoxes <= 0) break; decimal available = (decimal)(inv.StockQuantity - inv.OutboundQuantity); if (available < boxQty) continue; int canProvideBoxes = (int)(available / boxQty); if (canProvideBoxes <= 0) continue; int useBoxes = Math.Min(canProvideBoxes, remainingFullBoxes); decimal useQty = useBoxes * boxQty; var detail = new Dt_DeliveryOrderDetail { Goods_no = item.goods_no, Order_qty = useQty, Batch_num = inv.BatchNo, Exp_date = inv.ValidityPeriod, OotDetailStatus = "新建", Status = 0, //立库(补整箱) Reservoirarea = inv.LocationCode }; entityOrder.Details.Add(detail); inv.OutboundQuantity += (float)useQty; BaseDal.Db.Updateable(inv).ExecuteCommand(); remainingFullBoxes -= useBoxes; } } // ❗如果跳过该单,则直接continue,不保存 if (skipOrder) { Console.WriteLine($"跳过入库单 {outorder.order_no},因为存在未定义物料属性的商品。"); continue; } if (remainingFullBoxes > 0) { decimal unfilledQty = remainingFullBoxes * boxQty; SendErrorToUpstream(3, "", $"出库单[{outorder.order_no}]物料[{item.goods_no}]整箱库存不足,未分配数量:{unfilledQty}", ""); } } } _DeliveryOrders.Add(entityOrder); } // 插入主表+明细 BaseDal.Db.InsertNav(_DeliveryOrders) .Include(x => x.Details) .ExecuteCommand(); Db.Ado.CommitTran(); return responseContent.OK("同步出库单成功"); } catch (Exception ex) { Db.Ado.RollbackTran(); SendErrorToUpstream(3, "", ex.Message, ""); return responseContent.Error("同步失败: " + ex.Message); } } catch (Exception ex) { SendErrorToUpstream(3, "", ex.Message, ""); return responseContent.Error("同步失败: " + ex.Message); } } /// /// 出库单推送给 WCS /// /// public WebResponseContent EdiOut() { var responseContent = new WebResponseContent(); try { // 1. 查询符合条件的订单(表头=新建 && 包含有效明细) var outOrders = BaseDal.Db.CopyNew().Queryable() .Where(o => o.OutStatus == "新建") .Includes(o => o.Details, d => d.MedicineGoods) .ToList(); // 2. 再过滤掉不符合条件的明细(只保留 Status=0 ) foreach (var order in outOrders) { order.Details = order.Details.Where(d => d.Status == 0).ToList(); } if (outOrders == null || !outOrders.Any()) { Console.WriteLine("没有符合条件的订单需要推送"); return responseContent.Error("没有符合条件的订单需要推送"); } foreach (var order in outOrders) { try { string materialCode = "YY";//默认值 //获取当前订单的第一个明细项 var firstDetail = order.Details.FirstOrDefault(); if (firstDetail?.MedicineGoods != null && !string.IsNullOrEmpty(firstDetail.MedicineGoods.MaterielErpType)) { //如果条件满足,将物料代码设置为第一个明细项对应的药品物料代码 materialCode = firstDetail.MedicineGoods.MaterielErpType; } // 3. 组装 DTO var ediDto = new TowcsDto.ToediOutInfo { customerCode = "905", materialCode = materialCode, externalOrderNo = order.Out_no, outOrderType = order.Out_type == "1" ? "10" : order.Out_type == "2" ? "20" : "30", priority = 1, Is_cancel = 0, details = order.Details.Select(d => new TowcsDto.ToeOutdiInDetail { batchNo = d.Batch_num, productCode = d.Goods_no, productName = d.MedicineGoods?.MaterielName, productSpecifications = d.MedicineGoods?.MaterielModel, quantity = (int)d.Order_qty, //stocktakingDetails = order.Out_type == "3" // ? new List // { // new ToOutediInStock { palletCode = "FC00001", quantity = d.Order_qty.ToString() } // } // : null }).ToList() }; // 4. 调用接口 var url = "http://172.16.1.2:9357/file-admin/api/out/ediOut"; var result = HttpHelper.Post(url, ediDto.ToJsonString()); var resp = JsonConvert.DeserializeObject>(result); if (resp != null && resp.code == "0") { // 更新表头状态 BaseDal.Db.Updateable() .SetColumns(o => new Dt_DeliveryOrder { OutStatus = "开始" }) .Where(o => o.Id == order.Id) .ExecuteCommand(); // 更新明细状态 BaseDal.Db.Updateable() .SetColumns(d => new Dt_DeliveryOrderDetail { Status = 1, OotDetailStatus = "已完成" }) .Where(d => d.DeliveryOrderId == order.Id && d.Status == 0) .ExecuteCommand(); Console.WriteLine($"订单 {order.Out_no} 推送成功"); } else { SendErrorToUpstream(3, order.Out_no, resp?.msg ?? "WCS 推送失败", ""); Console.WriteLine($"订单 {order.Out_no} 推送失败:{resp?.msg}"); } //删除全部状为已完成的明细和表头,移入历史表 } catch (Exception ex) { SendErrorToUpstream(3, order.Out_no, ex.Message, ""); Console.WriteLine($"订单 {order.Out_no} 推送异常:{ex.Message}"); } } return responseContent.OK("出库订单推送完成"); } catch (Exception ex) { Console.WriteLine("EdiOut 异常:" + ex.Message); return responseContent.Error("出库订单推送失败:" + ex.Message); } } //盘点 拿整个批次信息表的商品批号和商品编号来进行盘点 public WebResponseContent InventoryGood(string batchNo, string goodsNo) { var response = new WebResponseContent(); try { // 1️⃣ 查找指定批次与物料的库存信息 var batchInfo = BaseDal.Db.Queryable() .Where(x => x.BatchNo == batchNo && x.MaterielCode == goodsNo) .First(); if (batchInfo == null) return response.Error($"未找到该物料 [{goodsNo}] 批次 [{batchNo}] 的库存信息"); // 2️⃣ 组装请求 DTO(完全符合接口文档结构) var ediDto = new TowcsDto.ToediOutInfo { customerCode = "905", materialCode = "YY", // 物料类型CODE externalOrderNo = $"PDCK-{batchInfo.Id}", // 外部出库单号 outOrderType = "20", // 盘点出库单 priority = 1, Is_cancel = 0, details = new List { new TowcsDto.ToeOutdiInDetail { batchNo = batchInfo.BatchNo, productCode = batchInfo.MaterielCode, productName = batchInfo.MaterielName, productSpecifications = batchInfo.MaterielSpec, quantity = (int)batchInfo.SupplyQuantity, //stocktakingDetails = new List //{ // // 盘点明细可根据实际托盘拆分;此处示例仅1条 // new TowcsDto.ToOutediInStock // { // palletCode = "FC00001", // quantity = batchInfo.SupplyQuantity.ToString() // } //} } } }; // 3️⃣ 调用接口 string url = "http://172.16.1.2:9357/file-admin/api/out/ediOut"; var result = HttpHelper.Post(url, ediDto.ToJsonString()); var resp = JsonConvert.DeserializeObject>(result); // 4️⃣ 响应处理 if (resp == null) return response.Error("WCS 无响应"); if (resp.code != "0") return response.Error($"WCS返回失败: {resp.msg}"); return response.OK("盘点出库下发成功"); } catch (Exception ex) { return response.Error("盘点失败:" + ex.Message); } } /// /// 出库报完成接口 /// /// 出库单号 /// public WebResponseContent CompleteAllOutOrders() { var responseContent = new WebResponseContent(); try { // 查找所有“开始”状态的出库单 var orders = BaseDal.Db.Queryable() .Where(o => o.OutStatus == "开始") .ToList(); if (orders == null || !orders.Any()) { return responseContent.OK("暂无需要处理的出库单"); } int successCount = 0; int failCount = 0; foreach (var order in orders) { try { Db.Ado.BeginTran(); // 查询该单的明细 var details = BaseDal.Db.Queryable() .Where(d => d.DeliveryOrderId == order.Id) .ToList(); // 判断明细是否全部完成 var completedCount = details.Count(d => d.OotDetailStatus == "已完成"); var totalCount = details.Count; if (totalCount > 0 && completedCount == totalCount) { // 更新状态为已完成 BaseDal.Db.Updateable() .SetColumns(o => o.OutStatus == "已完成") .Where(o => o.Id == order.Id) .ExecuteCommand(); // 调用上游接口 var url = "http://121.37.118.63:80/GYZ2/95fck/outOrderOk"; var requestDate = new { order_no = order.Out_no }; var result = HttpHelper.Post(url, requestDate.ToJsonString()); var response = JsonConvert.DeserializeObject(result); if (response.resultCode == "0") { // ✅ 插入历史表(表头 + 明细) var orderHistory = new Dt_DeliveryOrder_Hty { Id = order.Id, Out_no = order.Out_no, Out_type = order.Out_type, Client_no = order.Client_no, Client_name = order.Client_name, Account_time = order.Account_time, Warehouse_no = order.Warehouse_no, OutStatus = "已完成", Details = details.Select(d => new Dt_DeliveryOrderDetail { Id = d.Id, DeliveryOrderId = d.DeliveryOrderId, Reservoirarea = d.Reservoirarea, Goods_no = d.Goods_no, Order_qty = d.Order_qty, Batch_num = d.Batch_num, Exp_date = d.Exp_date, OotDetailStatus = d.OotDetailStatus, Status = d.Status }).ToList() }; // 插入表头历史 var historyId = BaseDal.Db.Insertable(orderHistory).ExecuteReturnIdentity(); // 插入明细历史(带新外键) var detailHistories = details.Select(d => new Dt_DeliveryOrderDetail_Hty { Id = d.Id, DeliveryOrderId = order.Id, Reservoirarea = d.Reservoirarea, Goods_no = d.Goods_no, Order_qty = d.Order_qty, Batch_num = d.Batch_num, Exp_date = d.Exp_date, OotDetailStatus = d.OotDetailStatus, Status = d.Status }).ToList(); BaseDal.Db.Insertable(detailHistories).ExecuteCommand(); // 删除原始数据(明细 → 表头) BaseDal.Db.Deleteable().Where(d => d.DeliveryOrderId == order.Id).ExecuteCommand(); BaseDal.Db.Deleteable().Where(o => o.Id == order.Id).ExecuteCommand(); Db.Ado.CommitTran(); successCount++; } else { Db.Ado.RollbackTran(); failCount++; SendErrorToUpstream(4, "", $"上游接口返回失败: {response.resultMsg}", order.Out_no); } } else { // 有未完成明细,不更新 Db.Ado.RollbackTran(); } } catch (Exception ex) { Db.Ado.RollbackTran(); failCount++; SendErrorToUpstream(1, "", ex.Message, order.Out_no); } } return responseContent.OK($"批量处理完成:成功 {successCount} 单,失败 {failCount} 单。"); } catch (Exception ex) { return responseContent.Error("批量处理失败:" + ex.Message); } } /// /// 推送异常信息给上游系统 1.入库单接口;2.入库单报完成接口;3.出库单接口;4.出库报完成接口;5.药品基础信息同步接口;6.供应商信息接口;7.客户信息接口;8.库存查询接口 /// public void SendErrorToUpstream(int type, string code, string message, string remark) { try { var url = "http://121.37.118.63:80/GYZ2/95fck/exceptionLog"; var requestData = new { type = type.ToString(), code = code, message = message, remark = remark }; var result = HttpHelper.Post(url, requestData.ToJsonString()); // 可以反序列化检查 resultCode 是否为0 } catch (Exception e) { // 这里不要再抛异常了,避免死循环 Console.WriteLine("异常接口推送失败:" + e.Message); } } public WebResponseContent GetPdDeliveryOrders(SaveModel saveModel) { WebResponseContent content = new WebResponseContent(); try { int pageNo = saveModel.MainData["pageNo"].ObjToInt(); string warehouseCode = saveModel.MainData["warehouseId"].ToString(); string orderNo = saveModel.MainData["orderNo"].ToString(); List dt_ReceiveOrders = new List(); if (string.IsNullOrEmpty(orderNo)) { dt_ReceiveOrders = Db.Queryable().Where(x => (x.OutStatus == "新建" || x.OutStatus == "开始") && x.Warehouse_no == warehouseCode && x.Out_type == "3").Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 5); } else { dt_ReceiveOrders = Db.Queryable().Where(x => (x.Out_no.Contains(orderNo) || x.Client_no.Contains(orderNo)) && (x.OutStatus == "新建" || x.OutStatus == "开始" && x.Out_type == "3") && x.Warehouse_no == warehouseCode).OrderByDescending(x => x.CreateDate).Includes(x => x.Details).ToPageList(pageNo, 5); } content.OK(data: dt_ReceiveOrders); } catch (Exception) { throw; } return content; } public WebResponseContent GetDeliveryOrders(SaveModel saveModel) { WebResponseContent content = new WebResponseContent(); try { int pageNo = saveModel.MainData["pageNo"].ObjToInt(); string warehouseCode = saveModel.MainData["warehouseId"].ToString(); string orderNo = saveModel.MainData["orderNo"].ToString(); List dt_ReceiveOrders = new List(); if (string.IsNullOrEmpty(orderNo)) { dt_ReceiveOrders = Db.Queryable().Where(x => (x.OutStatus == "新建" || x.OutStatus == "开始") && x.Warehouse_no == warehouseCode && x.Out_type != "3").Includes(x => x.Details).OrderByDescending(x => x.CreateDate).ToPageList(pageNo, 5); } else { dt_ReceiveOrders = Db.Queryable().Where(x => (x.Out_no.Contains(orderNo) || x.Client_no.Contains(orderNo)) && (x.OutStatus == "新建" || x.OutStatus == "开始" && x.Out_type != "3") && x.Warehouse_no == warehouseCode).OrderByDescending(x => x.CreateDate).Includes(x => x.Details).ToPageList(pageNo, 5); } content.OK(data: dt_ReceiveOrders); } catch (Exception) { throw; } return content; } public WebResponseContent GetDeliveryOrderDetail(int pageNo, string orderNo, bool isPick) { WebResponseContent content = new WebResponseContent(); Dt_DeliveryOrder cabinOrder = new Dt_DeliveryOrder(); if (isPick) cabinOrder = Db.Queryable().Includes(x => x.Details).First(x => x.Out_no == orderNo && x.Out_type == "3"); else cabinOrder = Db.Queryable().Includes(x => x.Details).First(x => x.Out_no == orderNo && x.Out_type != "3"); List? cabinOrderDetails = cabinOrder.Details?.Where(x => x.Reservoirarea == pageNo.ToString()).ToList(); content.OK(data: cabinOrderDetails); return content; } public WebResponseContent MatPicking(SaveModel saveModel) { WebResponseContent content = new WebResponseContent(); try { var LocationCode = saveModel.MainData["LocationCode"].ToString(); var orderNo = saveModel.MainData["orderNo"].ToString(); var batchNo = saveModel.MainData["batchNo"].ToString(); var Inqty = saveModel.MainData["Inqty"].ObjToInt(); var warehouseCode = saveModel.MainData["warehouseCode"].ToString(); Dt_DeliveryOrder cabinOrder = BaseDal.Db.Queryable().Where(x => x.Out_no == orderNo && x.Warehouse_no == warehouseCode && x.Out_type == "3").Includes(x => x.Details).First(); if (cabinOrder == null) return WebResponseContent.Instance.Error($"盘点单已完成"); Dt_DeliveryOrderDetail cabinOrderDetail = cabinOrder.Details.Where(x => x.Batch_num == batchNo && x.Reservoirarea == warehouseCode).First(); if (cabinOrderDetail == null) return WebResponseContent.Instance.Error($"盘点单明细已完成"); Dt_MaterielInfo materielInfo = _basicService.MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == cabinOrderDetail.Goods_no); if (materielInfo == null) return WebResponseContent.Instance.Error($"请维护物料编号【{cabinOrderDetail.Goods_no}】的物料信息"); cabinOrderDetail.Order_Outqty += Inqty; if (cabinOrderDetail.Order_Outqty > cabinOrderDetail.Order_qty) return WebResponseContent.Instance.Error($"实盘数量不可超出账面数量"); #region 处理出库单,货位,库存,库存批次信息 _unitOfWorkManage.BeginTran(); #region 出库单 cabinOrder.OutStatus = "开始"; cabinOrderDetail.OotDetailStatus = "开始"; if (cabinOrderDetail.Order_Outqty == cabinOrderDetail.Order_qty) { cabinOrderDetail.OotDetailStatus = "已完成"; _deliveryOrderDetailServices.Repository.DeleteAndMoveIntoHty(cabinOrderDetail, OperateTypeEnum.自动完成); } else { _deliveryOrderDetailServices.Repository.UpdateData(cabinOrderDetail); } var cabinOrder1 = BaseDal.Db.Queryable().Where(x => x.Out_no == cabinOrder.Out_no && x.Out_type == "3").Includes(x => x.Details).First(); if (cabinOrder1.Details == null || cabinOrder1.Details.Count < 1) cabinOrder.OutStatus = "已完成"; if (cabinOrder.OutStatus == "已完成") Repository.DeleteAndMoveIntoHty(cabinOrder, OperateTypeEnum.自动完成); else Repository.UpdateData(cabinOrder); #endregion #region 库存 Dt_InventoryInfo inventoryInfo = _inventoryInfoService.Repository.QueryFirst(x => x.BatchNo == cabinOrderDetail.Batch_num && x.MaterielCode == cabinOrderDetail.Goods_no && x.LocationCode == LocationCode); if (inventoryInfo == null) return WebResponseContent.Instance.Error($"未找到货位【{LocationCode}】的库存信息"); inventoryInfo.SupplyQuantity += Inqty; _inventoryInfoService.UpdateData(inventoryInfo); #endregion #region 任务记录 Dt_SupplyTask supplyTask = new Dt_SupplyTask() { WarehouseCode = cabinOrderDetail.Reservoirarea, BatchNo = inventoryInfo.BatchNo, MaterielName = inventoryInfo.MaterielName, MaterielCode = inventoryInfo.MaterielCode, MaterielSpec = inventoryInfo.MaterielSpec, TaskType = TaskTypeEnum.OutInventory.ObjToInt(), CreateDate = DateTime.Now, Creater = App.User.UserName, LocationCode = LocationCode, OrderNo = cabinOrder.Out_no, StockQuantity = inventoryInfo.StockQuantity, SupplyQuantity = Inqty, Remark = "盘点" }; _supplyTaskService.AddData(supplyTask); #endregion #region 库存批次 Dt_Inventory_Batch inventory_Batch = _inventory_BatchServices.Repository.QueryFirst(x => x.BatchNo == inventoryInfo.BatchNo && x.MaterielCode == inventoryInfo.MaterielCode); if (inventory_Batch != null) { inventory_Batch.SupplyQuantity += Inqty; _inventory_BatchServices.UpdateData(inventory_Batch); } #endregion _unitOfWorkManage.CommitTran(); #endregion content.OK(cabinOrderDetail.Order_Outqty.ToString()); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error(ex.Message); } return content; } public WebResponseContent FeedbackOut(SaveModel saveModel) { WebResponseContent content = new WebResponseContent(); try { var LocationCode = saveModel.MainData["LocationCode"].ToString(); var orderNo = saveModel.MainData["orderNo"].ToString(); var batchNo = saveModel.MainData["batchNo"].ToString(); var Inqty = saveModel.MainData["Inqty"].ObjToInt(); var warehouseCode = saveModel.MainData["warehouseCode"].ToString(); Dt_DeliveryOrder cabinOrder = BaseDal.Db.Queryable().Where(x => x.Out_no == orderNo && x.Warehouse_no == warehouseCode && x.Out_type != "3").Includes(x => x.Details).First(); if (cabinOrder == null) return WebResponseContent.Instance.Error($"出库单已完成"); Dt_DeliveryOrderDetail cabinOrderDetail = cabinOrder.Details.Where(x => x.Batch_num == batchNo && x.Reservoirarea == warehouseCode).First(); if (cabinOrderDetail == null) return WebResponseContent.Instance.Error($"出库单明细已完成"); Dt_MaterielInfo materielInfo = _basicService.MaterielInfoService.Repository.QueryFirst(x => x.MaterielCode == cabinOrderDetail.Goods_no); if (materielInfo == null) return WebResponseContent.Instance.Error($"请维护物料编号【{cabinOrderDetail.Goods_no}】的物料信息"); cabinOrderDetail.Order_Outqty += Inqty; if (cabinOrderDetail.Order_Outqty > cabinOrderDetail.Order_qty) return WebResponseContent.Instance.Error($"出库数量不可超出单据数量"); #region 处理出库单,货位,库存,库存批次信息 _unitOfWorkManage.BeginTran(); #region 出库单 cabinOrder.OutStatus = "开始"; cabinOrderDetail.OotDetailStatus = "开始"; if (cabinOrderDetail.Order_Outqty == cabinOrderDetail.Order_qty) { cabinOrderDetail.OotDetailStatus = "已完成"; _deliveryOrderDetailServices.Repository.DeleteAndMoveIntoHty(cabinOrderDetail, OperateTypeEnum.自动完成); } else { _deliveryOrderDetailServices.Repository.UpdateData(cabinOrderDetail); } var cabinOrder1 = BaseDal.Db.Queryable().Where(x => x.Out_no == cabinOrder.Out_no && x.Out_type != "3").Includes(x => x.Details).First(); if (cabinOrder1.Details == null || cabinOrder1.Details.Count < 1) cabinOrder.OutStatus = "已完成"; Repository.UpdateData(cabinOrder); #endregion #region 库存 Dt_InventoryInfo inventoryInfo = _inventoryInfoService.Repository.QueryFirst(x => x.BatchNo == cabinOrderDetail.Batch_num && x.MaterielCode == cabinOrderDetail.Goods_no && x.LocationCode == LocationCode); if (inventoryInfo == null) return WebResponseContent.Instance.Error($"未找到货位【{LocationCode}】的库存信息"); inventoryInfo.StockQuantity -= Inqty; if (inventoryInfo.StockQuantity <= 0) _inventoryInfoService.DeleteData(inventoryInfo); else _inventoryInfoService.UpdateData(inventoryInfo); #endregion #region 货位 var location = _basicService.LocationInfoService.Repository.QueryFirst(x => x.LocationCode == LocationCode); if (location == null) return WebResponseContent.Instance.Error($"请维护货位编号【{LocationCode}】的货位信息"); if (location.EnableStatus == EnableStatusEnum.Disable.ObjToInt()) return WebResponseContent.Instance.Error($"货位编号【{LocationCode}】已禁用,请恢复正常再使用"); Dt_InventoryInfo inventoryInfo1 = _inventoryInfoService.Repository.QueryFirst(x => x.LocationCode == LocationCode); if (inventoryInfo1 == null) { location.LocationStatus = LocationStatusEnum.Free.ObjToInt(); _basicService.LocationInfoService.UpdateData(location); } #endregion #region 任务记录 Dt_SupplyTask supplyTask = new Dt_SupplyTask() { WarehouseCode = cabinOrderDetail.Reservoirarea, BatchNo = inventoryInfo.BatchNo, MaterielName = inventoryInfo.MaterielName, MaterielCode = inventoryInfo.MaterielCode, MaterielSpec = inventoryInfo.MaterielSpec, TaskType = TaskTypeEnum.OutPick.ObjToInt(), CreateDate = DateTime.Now, Creater = App.User.UserName, LocationCode = location.LocationCode, OrderNo = cabinOrder.Out_no, StockQuantity = Inqty, SupplyQuantity = 0, Remark = "出库" }; _supplyTaskService.AddData(supplyTask); #endregion #region 库存批次 Dt_Inventory_Batch inventory_Batch = _inventory_BatchServices.Repository.QueryFirst(x => x.BatchNo == inventoryInfo.BatchNo && x.MaterielCode == inventoryInfo.MaterielCode); if (inventory_Batch != null) { inventory_Batch.StockQuantity -= Inqty; if (inventory_Batch.StockQuantity <= 0) _inventory_BatchServices.DeleteData(inventory_Batch); else _inventory_BatchServices.UpdateData(inventory_Batch); } #endregion _unitOfWorkManage.CommitTran(); #endregion content.OK(cabinOrderDetail.Order_Outqty.ToString()); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); content.Error(ex.Message); } return content; } } }