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 端存在异常领料单数据,请联系系统管理员处理。",
_ => 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] + "…";
}