using Dm.filter; using MailKit.Search; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Org.BouncyCastle.Asn1.Ocsp; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection.Metadata; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using WIDESEA_Common.OrderEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.Helper; using WIDESEA_DTO.Allocate; using WIDESEA_DTO.Basic; using WIDESEA_DTO.Inbound; using WIDESEA_DTO.Outbound; using WIDESEA_IBasicService; using WIDESEA_IOutboundService; using WIDESEA_Model.Models; namespace WIDESEA_BasicService { public class TransferDataDto { public DateTime TransferTime { get; set; } public List Items { get; set; } } public class TransferItemDto { public string MaterialCode { get; set; } public decimal TotalQuantity { get; set; } public List Locations { get; set; } } public class LocationInfoDto { public string LocationCode { get; set; } public decimal Quantity { get; set; } public List Barcodes { get; set; } } public class BarcodeInfoDto { public string Barcode { get; set; } public decimal Quantity { get; set; } } public class InvokeMESService : IInvokeMESService { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; private string UserName = "12312"; private string Password = "1"; private readonly IRepository _feedbacktomesRepository; private readonly IRepository _stockInfoDetailRepository; private readonly IRepository _stockInfoRepository; private readonly IRepository _inboundOrderRepository; private readonly IRepository _pickingRecoreRepository; private readonly IMaterialUnitService _materialUnitService; private readonly IOutboundOrderService _outboundOrderService; private readonly IOutboundOrderDetailService _outboundOrderDetailService; private readonly IOutStockLockInfoService _outStockLockInfoService; public InvokeMESService(IHttpClientFactory httpClientFactory, ILogger logger, IRepository feedbacktomesRepository, IRepository stockInfoDetailRepository, IRepository stockInfoRepository, IRepository inboundOrderRepository, IOutboundOrderService outboundOrderService, IOutboundOrderDetailService outboundOrderDetailService, IOutStockLockInfoService outStockLockInfoService, IMaterialUnitService materialUnitService, IRepository pickingRecoreRepository) { _httpClientFactory = httpClientFactory; _logger = logger; _feedbacktomesRepository = feedbacktomesRepository; _stockInfoDetailRepository = stockInfoDetailRepository; _stockInfoRepository = stockInfoRepository; _inboundOrderRepository = inboundOrderRepository; _outboundOrderService = outboundOrderService; _outboundOrderDetailService = outboundOrderDetailService; _outStockLockInfoService = outStockLockInfoService; _materialUnitService = materialUnitService; _pickingRecoreRepository = pickingRecoreRepository; } /// /// 入库反馈 /// /// /// /// public async Task FeedbackInbound(FeedbackInboundRequestModel model) { string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() }); var content = new StringContent(json, Encoding.UTF8, "application/json"); var _client = _httpClientFactory.CreateClient("MESUrl"); _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Add("Accept", "application/json"); _logger.LogInformation("InvokeMESService FeedbackInbound : " + json); var response = await _client.PostAsync("AldMaterialWarehousing/MaterialWarehousing", content); string body = await response.Content.ReadAsStringAsync(); _logger.LogInformation("InvokeMESService FeedbackInbound body: " + body); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(body); } return JsonConvert.DeserializeObject(body); } /// /// 出库反馈 /// /// /// /// public async Task FeedbackOutbound(FeedbackOutboundRequestModel model) { string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() }); var content = new StringContent(json, Encoding.UTF8, "application/json"); var _client = _httpClientFactory.CreateClient("MESUrl"); _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Add("Accept", "application/json"); _logger.LogInformation("InvokeMESService FeedbackOutbound : "+ model.orderNo +" , " + json); var response = await _client.PostAsync("AldMaterialOutbound/MaterialOutbound", content); string body = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(body); } _logger.LogInformation("InvokeMESService FeedbackOutbound body: " + body); return JsonConvert.DeserializeObject(body); } public async Task FeedbackAllocate(AllocateDto model) { _logger.LogInformation($"InvokeMESService FeedbackAllocate 序列化前: {JsonConvert.SerializeObject(model)}"); string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Include }); var content = new StringContent(json, Encoding.UTF8, "application/json"); var _client = _httpClientFactory.CreateClient("MESUrl"); _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Add("Accept", "application/json"); _logger.LogInformation("InvokeMESService FeedbackAllocate : " + json); var response = await _client.PostAsync("AldAllocationOperation/AllocationOperation", content); string body = await response.Content.ReadAsStringAsync(); _logger.LogInformation("InvokeMESService FeedbackAllocate body: " + body); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(body); } return JsonConvert.DeserializeObject(body); } public async Task NewMaterielToMes(MaterielToMesDTO model) { string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() }); //string userDataEncoded = Uri.EscapeDataString(json); ////string baseUrl = "http://mestest.ald.com//OrBitWCFServiceR15/orbitwebapi.ashx?"; //string userTicket = await GetToken(UserName, Password); //string api = "WMS_BarcodeInformation"; var client = _httpClientFactory.CreateClient("MESUrl"); // 拼接 URL 参数 // string url = $"{client.BaseAddress}UserTicket={userTicket}&API={api}&UserData={userDataEncoded}"; client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add("Accept", "application/json"); var content = new StringContent(json, Encoding.UTF8, "application/json"); _logger.LogInformation("InvokeMESService NewMaterielToMes : " + json); using var response = await client.PostAsync("AldBarcodeInformation/BarcodeInformation", content); var responseText = await response.Content.ReadAsStringAsync(); _logger.LogInformation("InvokeMESService NewMaterielToMes body: " + responseText); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(responseText); } return JsonConvert.DeserializeObject(responseText); } public async Task GetToken(String username, string password) { var clientHandler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate, }; //var client = new HttpClient(clientHandler); var client = _httpClientFactory.CreateClient("MESUrl"); client.DefaultRequestHeaders.Clear(); var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri($"{client.BaseAddress}UserName={username}&UserPassword={password}"), Headers ={ { "Accept", "*/*" }, { "User-Agent", "PostmanRuntime-ApipostRuntime/1.1.0" }, { "Connection", "keep-alive" }, }, Content = new MultipartFormDataContent { }, }; using (var response = await client.SendAsync(request)) { response.EnsureSuccessStatusCode(); var body = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { throw new HttpRequestException(body); } return body; } } /// /// /// /// /// 入库传1 出库传2 /// public async Task BatchOrderFeedbackToMes(List orderNos, int inout) { if (inout == 1) { foreach (var orderNo in orderNos) { try { var stockinfos = _stockInfoRepository.Db.Queryable("info").Where(info => info.StockStatus == 6) .Where(it => SqlFunc.Subqueryable().Where(s => s.StockId == it.Id && s.OrderNo == orderNo).Any()) .ToList(); var feeds = _feedbacktomesRepository.Db.Queryable().Where(x => x.OrderNo == orderNo && x.ReportStatus == 1).Select(o => o.PalletCode).ToList(); var unreports = stockinfos.Where(x => !feeds.Contains(x.PalletCode)).ToList(); if (unreports != null && !unreports.Any()) { return WebResponseContent.Instance.Error("没有需要回传的数据"); } foreach (var item in unreports) { var lists = _stockInfoDetailRepository.Db.Queryable().Where(x => x.StockId == item.Id).ToList(); if (lists.Any()) { var inboundOrder = _inboundOrderRepository.Db.Queryable().First(x => x.InboundOrderNo == lists.FirstOrDefault().OrderNo); if (inboundOrder != null) { if (inboundOrder.OrderType == (int)InOrderTypeEnum.AllocatInbound)//调拨入库 { var allocate = SqlSugarHelper.DbWMS.Queryable().Where(x => x.OrderNo == inboundOrder.InboundOrderNo).First(); var allocatefeedmodel = new AllocateDto { ReqCode = Guid.NewGuid().ToString(), ReqTime = DateTime.Now.ToString(), BusinessType = "2", FactoryArea = inboundOrder.FactoryArea, OperationType = 1, Operator = inboundOrder.Operator, OrderNo = inboundOrder.UpperOrderNo, fromWarehouse = allocate?.FromWarehouse ?? "", toWarehouse = allocate?.ToWarehouse ?? "", Details = new List() }; var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.InboundOrderRowNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new AllocateDtoDetail { MaterialCode = group.Key.MaterielCode, LineNo = group.Key.InboundOrderRowNo, WarehouseCode = group.Key.WarehouseCode, Qty = group.Sum(x => x.BarcodeQty), Unit = group.Key.BarcodeUnit, Barcodes = group.Select(row => new BarcodeInfo { Barcode = row.Barcode, Qty = row.BarcodeQty, BatchNo = row.BatchNo, SupplyCode = row.SupplyCode, Unit = row.BarcodeUnit }).ToList() }).ToList(); allocatefeedmodel.Details = groupedData; var result = await FeedbackAllocate(allocatefeedmodel); if (result != null && result.code == 200) { _feedbacktomesRepository.Db.Insertable(new Dt_FeedbackToMes { OrderNo = orderNo, PalletCode = item.PalletCode, ReportStatus = 1 }).ExecuteCommand(); } } else { var feedmodel = new FeedbackInboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString(), business_type = inboundOrder.BusinessType, factoryArea = inboundOrder.FactoryArea, operationType = 1, Operator = inboundOrder.Operator, orderNo = inboundOrder.UpperOrderNo, status = inboundOrder.OrderStatus, details = new List() }; var groupedData = lists.GroupBy(item => new { item.MaterielCode, item.SupplyCode, item.BatchNo, item.InboundOrderRowNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new FeedbackInboundDetailsModel { materialCode = group.Key.MaterielCode, supplyCode = group.Key.SupplyCode, batchNo = group.Key.BatchNo, lineNo = group.Key.InboundOrderRowNo, qty = group.Sum(x => x.BarcodeQty), // warehouseCode = group.Key.WarehouseCode=="0"?"1072": group.Key.WarehouseCode, warehouseCode = group.Key.WarehouseCode, unit = group.Key.BarcodeUnit, barcodes = group.Select(row => new FeedbackBarcodesModel { barcode = row.Barcode, qty = row.BarcodeQty }).ToList() }).ToList(); feedmodel.details = groupedData; var result = await FeedbackInbound(feedmodel); if (result != null && result.code == 200) { _feedbacktomesRepository.Db.Insertable(new Dt_FeedbackToMes { OrderNo = orderNo, PalletCode = item.PalletCode, ReportStatus = 1 }).ExecuteCommand(); } } } } } } catch (Exception ex) { _logger.LogInformation("InvokeMESService BatchOrderFeedbackToMes 回写MES失败: " + ex.Message); return WebResponseContent.Instance.Error(ex.Message); } } } else if (inout == 2) { foreach (var orderNo in orderNos) { var outboundOrder = await _outboundOrderService.Db.Queryable().FirstAsync(x => x.OrderNo == orderNo); if (outboundOrder != null && outboundOrder.IsBatch == 0) { var result = await HandleOutboundOrderToMESCompletion(outboundOrder, orderNo); return result; } else if (outboundOrder != null && outboundOrder.IsBatch == 1) { var result = await HandleOutboundOrderBatchToMESCompletion(outboundOrder, orderNo); return result; } } } return WebResponseContent.Instance.OK(); } private async Task HandleOutboundOrderBatchToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo) { // 定义默认返回(成功态) WebResponseContent response = WebResponseContent.Instance.OK("回传MES处理完成"); //0 = 未回传,1 = 已回传成功,2 = 回传失败 try { // 校验:已回传直接返回错误 if (outboundOrder.ReturnToMESStatus == 1) { return WebResponseContent.Instance.Error("该单已经回传!"); } // 查询订单明细(仅查询未回传成功的) var orderDetails = await _outboundOrderDetailService.Db.Queryable() .LeftJoin((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo && item.ReturnToMESStatus != 1) .Select((o, item) => o) .ToListAsync(); if (!orderDetails.Any()) { return WebResponseContent.Instance.Error("暂无需要处理的订单明细"); } var pickingRecords = await _pickingRecoreRepository.Db.Queryable().Where(x => x.OrderNo == orderNo && x.ReturnToMESStatus != 1 && !x.IsCancelled).ToListAsync(); if (!pickingRecords.Any()) return WebResponseContent.Instance.Error("没有需要回传的分拣记录"); var documentNo = UniqueValueGenerator.Generate(); var feedModel = new FeedbackOutboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), business_type = outboundOrder.BusinessType, factoryArea = outboundOrder.FactoryArea, operationType = 1, Operator = outboundOrder.Operator!=""? outboundOrder.Operator:App.User.UserName, orderNo = outboundOrder.UpperOrderNo, documentsNO = documentNo, status = outboundOrder.OrderStatus, details = new List() }; var detailIds = new List(); // 填充明细和条码信息 foreach (var detail in orderDetails) { // 查询该明细对应的锁定条码记录 var detailPicks = pickingRecords.Where(x => x.OrderNo == orderNo && detail.Id == x.OrderDetailId).ToList(); if (!detailPicks.Any()) { continue; } var detailModel = new FeedbackOutboundDetailsModel { materialCode = detail.MaterielCode, lineNo = detail.lineNo, warehouseCode = detail.WarehouseCode, qty = detail.BarcodeQty, currentDeliveryQty = 0, unit = detail.BarcodeUnit, barcodes = new List() }; // 填充条码信息(含单位转换) foreach (var item in detailPicks) { if (item.PickQuantity <= 0) { continue; } var barModel = new WIDESEA_DTO.Outbound.BarcodesModel { barcode = item.Barcode, supplyCode = item.SupplyCode, batchNo = item.BatchNo, unit = item.BarcodeUnit, qty = item.PickQuantity }; // 单位不一致时转换 if (detail.BarcodeUnit != detail.Unit) { var convertResult = await _materialUnitService.ConvertAsync( item.MaterielCode, item.PickQuantity, detail.Unit, detail.BarcodeUnit); barModel.unit = convertResult.Unit; barModel.qty = convertResult.Quantity; } else { barModel.qty = item.PickQuantity; } detailModel.currentDeliveryQty += barModel.qty; detailModel.barcodes.Add(barModel); } detailIds.Add(detail.Id); feedModel.details.Add(detailModel); } feedModel.details = feedModel.details.GroupBy(item => new { item.materialCode, item.lineNo, item.warehouseCode, item.unit,item.qty }).Select(group => new FeedbackOutboundDetailsModel { materialCode = group.Key.materialCode, lineNo = group.Key.lineNo, warehouseCode = group.Key.warehouseCode, qty = group.Key.qty, currentDeliveryQty = group.Sum(x => x.currentDeliveryQty), unit = group.Key.unit, barcodes = group.SelectMany(x => x.barcodes.GroupBy(o => new { o.barcode, o.supplyCode, o.batchNo, o.unit }).Select(row => new WIDESEA_DTO.Outbound.BarcodesModel { barcode = row.Key.barcode, supplyCode = row.Key.supplyCode, batchNo = row.Key.batchNo, unit = row.Key.unit, qty = row.Sum(y => y.qty) })).ToList() }).ToList(); var allCompleted = true; // 筛选待回传的明细(ReturnToMESStatus=0) var pendingDetails = orderDetails.Where(x => x.ReturnToMESStatus == 0).ToList(); foreach (var detail in pendingDetails) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; } } // 存在回传失败的明细(ReturnToMESStatus=2),标记未完成 if (orderDetails.Any(x => x.ReturnToMESStatus == 2)) { allCompleted = false; } // 更新订单状态 int newStatus = allCompleted ? (int)OutOrderStatusEnum.出库完成 : (int)OutOrderStatusEnum.出库中; if (outboundOrder.OrderStatus != newStatus) { int updateCount = await _outboundOrderService.Db.Updateable() .SetColumns(x => x.OrderStatus == newStatus) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); if (updateCount <= 0) { _logger.LogWarning($"更新出库单状态失败 - OrderNo: {orderNo}, 目标状态: {newStatus}"); } } // 调用MES回传接口 var mesResult = await FeedbackOutbound(feedModel); if (mesResult == null || mesResult.code != 200) { // 更新明细为回传失败(ReturnToMESStatus=2) await _outboundOrderDetailService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrderDetail { ReturnToMESStatus = 2, documentsNO = documentNo, }) .Where(x => detailIds.Contains(x.Id)) .ExecuteCommandAsync(); return WebResponseContent.Instance.Error($"回传MES失败"); } foreach (var record in pickingRecords.Where(x => detailIds.Contains(x.OrderDetailId)).ToList()) { record.ReturnToMESStatus = 1; } var updates = pickingRecords.Where(x => detailIds.Contains(x.OrderDetailId)).ToList(); updates.ForEach(x => { x.ReturnToMESStatus = 1; }); await _pickingRecoreRepository.Db.Updateable(updates).ExecuteCommandAsync(); if (allCompleted) { //MES回传成功:更新明细为回传成功状态 await _outboundOrderDetailService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrderDetail { ReturnToMESStatus = 1, documentsNO = documentNo, }) .Where(x => detailIds.Contains(x.Id)) .ExecuteCommandAsync(); } // 校验是否所有明细都完成,更新订单最终状态 if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成) { await _outboundOrderService.Db.Updateable() .SetColumns(x => new Dt_OutboundOrder { ReturnToMESStatus = 1, OrderStatus = newStatus }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } else { // 二次校验是否所有未回传明细都已完成 var dbOrderDetails = await _outboundOrderDetailService.Db.Queryable() .LeftJoin((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo && item.ReturnToMESStatus != 1) .Select((o, item) => o) .ToListAsync(); var secAllCompleted = true; foreach (var detail in dbOrderDetails.Where(x => x.ReturnToMESStatus == 0).ToList()) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { secAllCompleted = false; break; } } if (secAllCompleted) { await _outboundOrderService.Db.Updateable() .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 1, OrderStatus = OutOrderStatusEnum.出库完成.ObjToInt(), }) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } } // 回传成功的最终返回 response = WebResponseContent.Instance.OK($"回传MES成功,单据号:{documentNo}"); } catch (Exception ex) { // 全局异常捕获:记录详细日志 + 返回错误 string errorMsg = $"处理出库单回传MES时发生异常 - OrderNo: {orderNo}, Error: {ex.Message}, StackTrace: {ex.StackTrace}"; _logger.LogError(ex, errorMsg); // 记录带异常堆栈的日志 // 异常返回(给前端的友好提示,隐藏堆栈信息) response = WebResponseContent.Instance.Error("处理回传MES时发生异常,请联系管理员"); } return response; } private async Task HandleOutboundOrderToMESCompletion(Dt_OutboundOrder outboundOrder, string orderNo) { // 前置参数校验:空值直接返回错误 if (outboundOrder == null) { return WebResponseContent.Instance.Error("出库单实体为空,无法处理回传MES"); } if (string.IsNullOrWhiteSpace(orderNo)) { return WebResponseContent.Instance.Error("订单号为空,无法处理回传MES"); } try { if (outboundOrder.ReturnToMESStatus == 1) { return WebResponseContent.Instance.Error($"OrderNo: {orderNo}, 该单已经回传!"); } var orderDetails = await _outboundOrderDetailService.Db.Queryable() .LeftJoin((o, item) => o.OrderId == item.Id) .Where((o, item) => item.OrderNo == orderNo) .Select((o, item) => o) .ToListAsync(); // 无明细场景返回警告 if (!orderDetails.Any()) { return WebResponseContent.Instance.Error($"OrderNo: {orderNo} 未查询到订单明细"); } // 判断是否所有明细完成出库 bool allCompleted = true; foreach (var detail in orderDetails) { if (detail.OverOutQuantity < detail.NeedOutQuantity) { allCompleted = false; break; } } // 更新订单状态(修正语法错误:== → =) int newStatus = allCompleted ? (int)OutOrderStatusEnum.出库完成 : (int)OutOrderStatusEnum.出库中; if (outboundOrder.OrderStatus != newStatus) { await _outboundOrderService.Db.Updateable() .SetColumns(x => x.OrderStatus == newStatus) // 关键修正:赋值而非判断 .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); } // 仅分拣完成时向MES反馈 if (allCompleted && newStatus == (int)OutOrderStatusEnum.出库完成) { var feedmodel = new FeedbackOutboundRequestModel { reqCode = Guid.NewGuid().ToString(), reqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), business_type = outboundOrder.BusinessType, factoryArea = outboundOrder.FactoryArea, operationType = 1, Operator = outboundOrder.Operator, orderNo = outboundOrder.UpperOrderNo, documentsNO = outboundOrder.OrderNo, status = outboundOrder.OrderStatus, details = new List() }; // 构建明细数据 foreach (var detail in orderDetails) { var detailLocks = await _outStockLockInfoService.Db.Queryable() .Where(x => x.OrderNo == orderNo && x.OrderDetailId == detail.Id && (x.Status == (int)OutLockStockStatusEnum.拣选完成 || x.Status == (int)OutLockStockStatusEnum.已回库)) .ToListAsync(); var groupdata = detailLocks.GroupBy(item => new { item.MaterielCode, item.lineNo, item.BarcodeUnit, item.WarehouseCode }) .Select(group => new FeedbackOutboundDetailsModel { materialCode = group.Key.MaterielCode, lineNo = group.Key.lineNo, warehouseCode = group.Key.WarehouseCode, qty = group.Sum(x => x.PickedQty), currentDeliveryQty = group.Sum(x => x.PickedQty), unit = group.Key.BarcodeUnit, barcodes = group.Select(lockInfo => new WIDESEA_DTO.Outbound.BarcodesModel { barcode = lockInfo.CurrentBarcode, supplyCode = lockInfo.SupplyCode, batchNo = lockInfo.BatchNo, unit = lockInfo.BarcodeUnit, qty = lockInfo.PickedQty }).ToList() }).ToList(); feedmodel.details.AddRange(groupdata); } // 调用MES接口 var result = await FeedbackOutbound(feedmodel); if (result == null) { return WebResponseContent.Instance.Error($"OrderNo: {orderNo} MES回传接口返回空"); } if (result.code == 200) { // 回传成功:更新回传状态 await _outboundOrderDetailService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 1) .Where(x => x.OrderId == outboundOrder.Id) .ExecuteCommandAsync(); await _outboundOrderService.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 1) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); await _pickingRecoreRepository.Db.Updateable() .SetColumns(x => x.ReturnToMESStatus == 1) .Where(x => x.OrderNo == orderNo) .ExecuteCommandAsync(); return WebResponseContent.Instance.OK("回传MES成功"); } else { var errorMsg = $"OrderNo: {orderNo} 回传MES失败,错误码:{result.code},错误信息:{result.message ?? "无"}"; _logger.LogError(errorMsg); return WebResponseContent.Instance.Error(errorMsg); } } return WebResponseContent.Instance.OK("订单状态已更新,未完全完成分拣无需回传MES"); } catch (Exception ex) { // 全局异常捕获:返回错误+记录详细日志 var errorMsg = $"OrderNo: {orderNo} 处理回传MES时发生异常:{ex.Message}"; _logger.LogError(ex, errorMsg); // 记录堆栈信息便于排查 return WebResponseContent.Instance.Error("处理回传MES时发生异常,请联系管理员"); } } } public static class UniqueValueGenerator { // 原子计数器(线程安全,每次递增1,避免同一Ticks重复) private static long _counter = 0; /// /// 生成唯一值(支持高并发) /// /// 格式:yyyyMMdd + Ticks + 3位计数器(如2025112563867890123001) public static string Generate() { var now = DateTime.Now; string datePart = now.ToString("MMdd"); long ticksPart = now.Ticks; // 原子递增计数器(取模1000,确保计数器仅3位,控制长度) long counterPart = Interlocked.Increment(ref _counter) % 1000; // 拼接:计数器补0为3位(避免位数不一致) return $"{datePart}{ticksPart}"; } public static string GenerateCount() { var now = DateTime.Now; string datePart = now.ToString("yyyyMMddHHmmss"); // 原子递增计数器(取模1000,确保计数器仅3位,控制长度) long counterPart = Interlocked.Increment(ref _counter) % 1000; // 拼接:计数器补0为3位(避免位数不一致) return $"{datePart}{counterPart:D3}"; } } }