namespace Admin.NET.Plugin.AiDOP.WorkOrder; /// 领料建单 / 工单下达面向业务用户的失败提示(不暴露内部错误码作主文案)。 public static class PickBillUserMessages { public static string ForReleaseFailure(string? reasonCode, string? reason = null, string? hint = null, IEnumerable? items = null) { var involved = FormatItems(items); var msg = (reasonCode ?? "").Trim().ToUpperInvariant() switch { "MES_UNREACHABLE" => "下达失败!因无法连接 MES 端数据库,请联系系统管理员后重试。", "MES_WRITE_FAILED" => "下达失败!MES 端写入领料单失败,请联系系统管理员。", "SEQ_FAILED" => "下达失败!MES 端领料单号取号失败,请联系系统管理员。", "NO_KEEPER" => "下达失败!部分物料未配置保管员或库位,请先在仓储基础数据中补齐后重试。" + involved, "KEEPER_RULE_UNSAFE" => "下达失败!物料号或保管员职责区间含不支持的字符,请联系系统管理员处理。" + involved, "NO_DETAIL" => "下达失败!工单无物料明细,请先同步或维护物料后重试。", "ITEM_INVALID" => "下达失败!工单物料主数据缺失或无效,请先补齐物料主数据后重试。", "WO_STATE_INVALID" => "下达失败!当前工单状态不允许下达,请刷新列表后重试。", "ORPHAN_DETECTED" => "下达失败!MES 端存在异常领料单数据,请联系系统管理员处理。", "WO_MES_NOT_READY" => "下达失败!MES 端尚未具备完整工单(头/明细/工序),请先完成订单评审或计划刷新推送,或调用工单推送补偿后重试。", _ => BuildFallback(reason, hint) }; return msg; } /// MES 补偿按钮等非「下达」入口,措辞改为「建领料失败」。 public static string ForPickCreateFailure(string? reasonCode, string? reason = null, string? hint = null, IEnumerable? items = null) => ForReleaseFailure(reasonCode, reason, hint, items) .Replace("下达失败!", "建领料失败!", StringComparison.Ordinal); private static string BuildFallback(string? reason, string? hint) { if (!string.IsNullOrWhiteSpace(reason) && reason.Contains("下达失败", StringComparison.Ordinal)) return reason.Trim(); if (!string.IsNullOrWhiteSpace(reason) && LooksLikeConnectionIssue(reason)) return "下达失败!因无法连接 MES 端数据库,请联系系统管理员后重试。"; var detail = string.IsNullOrWhiteSpace(reason) ? "原因未知" : Trunc(reason.Trim(), 120); var action = string.IsNullOrWhiteSpace(hint) ? "请联系系统管理员。" : hint.Trim(); return $"下达失败!{detail}。{action}"; } private static bool LooksLikeConnectionIssue(string text) { return text.Contains("不可达", StringComparison.OrdinalIgnoreCase) || text.Contains("timeout", StringComparison.OrdinalIgnoreCase) || text.Contains("连接", StringComparison.Ordinal) || text.Contains("network", StringComparison.OrdinalIgnoreCase) || text.Contains("MES_UNREACHABLE", StringComparison.OrdinalIgnoreCase); } private static string FormatItems(IEnumerable? items) { if (items == null) return ""; var list = items.Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComparer.OrdinalIgnoreCase).Take(15).ToList(); return list.Count == 0 ? "" : " 涉及物料:" + string.Join("、", list) + (list.Count >= 15 ? "…" : ""); } private static string Trunc(string s, int max) => s.Length <= max ? s : s[..max] + "…"; }