在ERP_WMS_interactiveService中添加物料编码聚合功能,通过配置控制是否启用 优化WmOutOrderService中的物料匹配逻辑,支持处理多个零件号
372 lines
14 KiB
C#
372 lines
14 KiB
C#
using Infrastructure;
|
||
using Infrastructure.Attribute;
|
||
using Newtonsoft.Json;
|
||
using NLog;
|
||
using System;
|
||
using System.Globalization;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Net.Http;
|
||
using System.Threading.Tasks;
|
||
using U8Server.Util;
|
||
using ZR.Model.MES.wms;
|
||
using ZR.Service.mes.wms_u8.IService;
|
||
|
||
namespace ZR.Service.mes.wms_u8
|
||
{
|
||
[AppService(ServiceType = typeof(IERP_WMS_interactive), ServiceLifetime = LifeTime.Transient)]
|
||
public class ERP_WMS_interactiveService : IERP_WMS_interactive
|
||
{
|
||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||
// 假设接口密钥(需根据实际文档填写)
|
||
//private const string ApiSecret = "your_api_secret"; // 替换为实际密钥
|
||
|
||
#region 同步方法
|
||
public ERP_WMS_interactiveModelResult Inbounded(string urlBase, List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
return ProcessSyncRequest(urlBase, models, "inbounded", isInbound: true);
|
||
}
|
||
|
||
public ERP_WMS_interactiveModelResult Outbounded(string urlBase, List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
return ProcessSyncRequest(urlBase, models, "outbounded", isInbound: false);
|
||
}
|
||
/// <summary>
|
||
/// 根据物料编码聚合模型数据
|
||
/// </summary>
|
||
/// <param name="models">原始模型列表</param>
|
||
/// <returns>聚合后的模型列表</returns>
|
||
private List<ERP_WMS_interactiveModelQuery> AggregateModelsByMaterialCode(List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
if (models == null || models.Count == 0)
|
||
return models;
|
||
|
||
// 按物料编码分组并计算总数量
|
||
var aggregatedModels = models
|
||
.GroupBy(m => m.materialCode)
|
||
.Select(g =>
|
||
{
|
||
// 获取分组内的第一个模型
|
||
var firstModel = g.First();
|
||
|
||
return new ERP_WMS_interactiveModelQuery
|
||
{
|
||
customerCode = firstModel.customerCode, // 使用分组内第一个模型的客户编码
|
||
materialCode = g.Key,
|
||
location = firstModel.location, // 位置留空
|
||
Qty = g.Sum(m =>
|
||
{
|
||
// 确保数量可以转换为数字
|
||
if (decimal.TryParse(m.Qty, out decimal qty))
|
||
return qty;
|
||
return 0;
|
||
}).ToString(),
|
||
LotNo = firstModel.LotNo,
|
||
createTime = firstModel.createTime,
|
||
userID = firstModel.userID,
|
||
guid = Guid.NewGuid().ToString(),
|
||
lineno = firstModel.lineno,
|
||
|
||
};
|
||
})
|
||
.ToList();
|
||
|
||
return aggregatedModels;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 异步方法
|
||
public async Task<ERP_WMS_interactiveModelResult> InboundedAsync(string urlBase, List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
return await ProcessAsyncRequest(urlBase, models, "inbounded", isInbound: true);
|
||
}
|
||
|
||
public async Task<ERP_WMS_interactiveModelResult> OutboundedAsync(string urlBase, List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
return await ProcessAsyncRequest(urlBase, models, "outbounded", isInbound: false);
|
||
}
|
||
#endregion
|
||
|
||
#region 公共处理方法
|
||
/// <summary>
|
||
/// 同步请求处理(抽取公共逻辑)
|
||
/// </summary>
|
||
private ERP_WMS_interactiveModelResult ProcessSyncRequest(string urlBase, List<ERP_WMS_interactiveModelQuery> models, string action, bool isInbound)
|
||
{
|
||
var operation = isInbound ? "入库" : "出库";
|
||
_logger.Info($"开始处理{operation}请求 - URL基础: {urlBase}, 记录数: {models?.Count ?? 0}");
|
||
|
||
// 1. 基础参数校验
|
||
if (!ValidateBaseParams(urlBase, models, operation, out var errorMsg))
|
||
{
|
||
_logger.Error($"{operation}请求失败: {errorMsg}");
|
||
return null;
|
||
}
|
||
|
||
// 2. 构建URL和请求数据
|
||
string url = BuildUrl(urlBase, action, models);
|
||
string requestData = JsonConvert.SerializeObject(models);
|
||
_logger.Debug($"{operation}请求数据: {requestData}");
|
||
|
||
try
|
||
{
|
||
_logger.Trace($"发送{operation}同步HTTP请求 - URL: {url}");
|
||
object result = HttpHelper.HttpPost(url, requestData, "application/json", 5, null);
|
||
|
||
// 4. 处理响应(同步方法假设HttpPost返回已反序列化对象,需根据实际HttpHelper调整)
|
||
return ProcessSyncResponse(result, operation, url);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return HandleException(ex, operation, url, requestData);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步请求处理(抽取公共逻辑)
|
||
/// </summary>
|
||
// 配置项:控制是否启用物料编码聚合功能
|
||
private static bool EnableMaterialAggregation = true; // 默认为false,不启用聚合
|
||
|
||
private async Task<ERP_WMS_interactiveModelResult> ProcessAsyncRequest(string urlBase, List<ERP_WMS_interactiveModelQuery> models, string action, bool isInbound)
|
||
{
|
||
var operation = isInbound ? "异步入库" : "异步出库";
|
||
_logger.Info($"开始处理{operation}请求 - URL基础: {urlBase}, 记录数: {models?.Count ?? 0}");
|
||
|
||
// 1. 基础参数校验
|
||
if (!ValidateBaseParams(urlBase, models, operation, out var errorMsg))
|
||
{
|
||
_logger.Error($"{operation}请求失败: {errorMsg}");
|
||
return null;
|
||
}
|
||
|
||
// 2. 根据配置决定是否聚合数据
|
||
List<ERP_WMS_interactiveModelQuery> processedModels = models;
|
||
if (EnableMaterialAggregation)
|
||
{
|
||
processedModels = AggregateModelsByMaterialCode(models);
|
||
_logger.Info($"{operation}请求数据已聚合 - 聚合前记录数: {models.Count}, 聚合后记录数: {processedModels.Count}");
|
||
}
|
||
|
||
// 3. 构建URL和请求数据
|
||
string url = BuildUrl(urlBase, action, processedModels);
|
||
string requestData = JsonConvert.SerializeObject(processedModels);
|
||
_logger.Debug($"{operation}请求数据: {requestData}");
|
||
|
||
try
|
||
{
|
||
_logger.Trace($"发送{operation}异步HTTP请求 - URL: {url}");
|
||
string resultJson = await HttpHelper.HttpPostAsync(url, requestData, "application/json", 5, null);
|
||
|
||
// 4. 处理响应(先校验JSON格式,再反序列化)
|
||
return await ProcessAsyncResponse(resultJson, operation, url);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return HandleException(ex, operation, url, requestData);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 工具方法
|
||
/// <summary>
|
||
/// 构建URL(避免双斜杠问题,并添加查询字符串参数)
|
||
/// </summary>
|
||
private string BuildUrl(string urlBase, string action, List<ERP_WMS_interactiveModelQuery> models)
|
||
{
|
||
// 移除urlBase结尾的斜杠,再拼接路径
|
||
string baseUrl = $"{urlBase.TrimEnd('/')}/wms/mes/{action}";
|
||
|
||
// 构建请求参数
|
||
string requestData = JsonConvert.SerializeObject(models);
|
||
var headers = BuildHeaders(requestData);
|
||
|
||
// 构建查询字符串
|
||
var queryString = string.Join("&", headers.Select(kv => $"{WebUtility.UrlEncode(kv.Key)}={WebUtility.UrlEncode(kv.Value)}"));
|
||
|
||
if (!string.IsNullOrEmpty(queryString))
|
||
{
|
||
baseUrl += $"?{queryString}";
|
||
}
|
||
|
||
return baseUrl;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建请求参数(原构建请求头的逻辑)
|
||
/// </summary>
|
||
private Dictionary<string, string> BuildHeaders(string requestData)
|
||
{
|
||
string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture);
|
||
string appid = "gN9yId!!lfwaRoi3";
|
||
|
||
// 签名生成规则:通常为appid + timestamp + requestData + secret的MD5(需根据接口文档调整)
|
||
//string signSource = $"{appid}{timestamp}{requestData}{ApiSecret}";
|
||
string sign = GetSign.GetBy16Md5(); // 修正签名生成逻辑
|
||
|
||
return new Dictionary<string, string>
|
||
{
|
||
{ "appid", appid },
|
||
{ "timestamp", timestamp },
|
||
{ "sign", sign },
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 基础参数校验
|
||
/// </summary>
|
||
private bool ValidateBaseParams(string urlBase, List<ERP_WMS_interactiveModelQuery> models, string operation, out string errorMsg)
|
||
{
|
||
if (string.IsNullOrEmpty(urlBase))
|
||
{
|
||
errorMsg = "基础URL为空";
|
||
return false;
|
||
}
|
||
|
||
if (models == null || !models.Any())
|
||
{
|
||
errorMsg = "请求数据为空";
|
||
return false;
|
||
}
|
||
|
||
errorMsg = string.Empty;
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理同步响应(假设HttpHelper返回已反序列化对象,需根据实际情况调整)
|
||
/// </summary>
|
||
private ERP_WMS_interactiveModelResult ProcessSyncResponse(object result, string operation, string url)
|
||
{
|
||
if (result == null)
|
||
{
|
||
_logger.Warn($"{operation}请求返回空结果 - URL: {url}");
|
||
return null;
|
||
}
|
||
|
||
if (result is ERP_WMS_interactiveModelResult modelResult)
|
||
{
|
||
_logger.Info($"{operation}请求处理成功 - 结果: {modelResult.result}, 消息: {modelResult.message}");
|
||
return modelResult;
|
||
}
|
||
|
||
_logger.Error($"{operation}请求返回意外类型 - 类型: {result.GetType().FullName}, URL: {url}");
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理异步响应(先校验JSON格式)
|
||
/// </summary>
|
||
private async Task<ERP_WMS_interactiveModelResult> ProcessAsyncResponse(string resultJson, string operation, string url)
|
||
{
|
||
if (string.IsNullOrEmpty(resultJson))
|
||
{
|
||
_logger.Warn($"{operation}请求返回空结果 - URL: {url}");
|
||
return null;
|
||
}
|
||
|
||
// 检查是否为已知异常标识
|
||
if (resultJson == "异常:*")
|
||
{
|
||
_logger.Warn($"{operation}请求返回异常标识 - URL: {url}");
|
||
return null;
|
||
}
|
||
|
||
// 验证JSON格式
|
||
if (!IsValidJson(resultJson))
|
||
{
|
||
_logger.Error($"{operation}请求返回非JSON数据 - URL: {url}, 响应内容: {resultJson}");
|
||
return new ERP_WMS_interactiveModelResult
|
||
{
|
||
result = "fail",
|
||
message = $"{operation}响应格式错误,非JSON数据"
|
||
};
|
||
}
|
||
|
||
// 反序列化
|
||
try
|
||
{
|
||
var result = JsonConvert.DeserializeObject<ERP_WMS_interactiveModelResult>(resultJson);
|
||
if (result != null)
|
||
{
|
||
_logger.Info($"{operation}请求处理成功 - 结果: {result.code}, 消息: {result.message}");
|
||
return result;
|
||
}
|
||
else
|
||
{
|
||
_logger.Warn($"{operation}请求反序列化结果为空 - URL: {url}");
|
||
return null;
|
||
}
|
||
}
|
||
catch (JsonReaderException ex)
|
||
{
|
||
_logger.Error(ex, $"{operation}请求JSON解析失败 - URL: {url}, 响应内容: {resultJson}");
|
||
return new ERP_WMS_interactiveModelResult
|
||
{
|
||
result = "fail",
|
||
message = $"{operation}响应解析错误: {ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异常处理(细化异常类型)
|
||
/// </summary>
|
||
private ERP_WMS_interactiveModelResult HandleException(Exception ex, string operation, string url, string requestData)
|
||
{
|
||
var errorMsg = $"{operation}处理异常";
|
||
|
||
// 区分异常类型
|
||
if (ex is HttpRequestException httpEx)
|
||
{
|
||
_logger.Error(httpEx, $"{operation}HTTP请求失败 - URL: {url}, 请求数据: {requestData}");
|
||
errorMsg += $": HTTP请求失败: {httpEx.Message}";
|
||
}
|
||
else if (ex is JsonReaderException jsonEx)
|
||
{
|
||
_logger.Error(jsonEx, $"{operation}JSON解析失败 - URL: {url}, 请求数据: {requestData}");
|
||
errorMsg += $": 数据解析失败: {jsonEx.Message}";
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(ex, $"{operation}未知异常 - URL: {url}, 请求数据: {requestData}");
|
||
errorMsg += $": 未知错误: {ex.Message}";
|
||
}
|
||
|
||
return new ERP_WMS_interactiveModelResult
|
||
{
|
||
result = "fail",
|
||
message = errorMsg
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证JSON格式是否有效
|
||
/// </summary>
|
||
private bool IsValidJson(string json)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(json))
|
||
return false;
|
||
|
||
json = json.Trim();
|
||
// 基本格式校验:以{或[开头,以}或]结尾
|
||
if ((json.StartsWith("{") && json.EndsWith("}")) || (json.StartsWith("[") && json.EndsWith("]")))
|
||
{
|
||
try
|
||
{
|
||
// 尝试解析验证
|
||
JsonConvert.DeserializeObject(json);
|
||
return true;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
#endregion
|
||
}
|
||
} |