admin/src/Oms.Application/Services/Orders/Issues/AutoTriggerRuntimeService.cs
zzh b2355104cf feat: 完善揽收单与问题件处理能力
补齐揽收单字段/并发戳与问题件处理人配置,扩展异常工作流与下单同步揽收出参;移除已收货状态并补充相关 SQL 脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-04 11:49:23 +08:00

175 lines
6.0 KiB
C#

using Fake.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Oms.Domain.ChannelsAggregate.Consts;
using Oms.Domain.ChannelsAggregate.Entities;
using Oms.Domain.ChannelsAggregate.Repositories;
using Oms.Domain.OrdersAggregate.Entities;
using Oms.Domain.OrdersAggregate.Repositories;
using Oms.Domain.Shared.Enums;
namespace Oms.Application.Services.Orders.Issues;
public class AutoTriggerRuntimeService(
IAutoTriggerRepository autoTriggerRepository,
IOrderRepository orderRepository,
OrderAutoTriggerService orderAutoTriggerService,
OrderExceptionWorkflowService exceptionWorkflowService,
OrderIssueNotificationService issueNotificationService,
IServiceScopeFactory scopeFactory,
ILogger<AutoTriggerRuntimeService> logger) : IScopedDependency
{
private const string InterceptOperation = "拦截";
/// <summary>
/// 后台异步触发,避免拉长入库/出库扫码请求。
/// </summary>
public void EnqueueFire(int orderId, AutoTriggerTiming timing, int operatorUserId)
{
if (orderId <= 0)
{
return;
}
_ = Task.Run(async () =>
{
try
{
using var scope = scopeFactory.CreateScope();
var runtime = scope.ServiceProvider.GetRequiredService<AutoTriggerRuntimeService>();
await runtime.FireByOrderIdAsync(orderId, timing, operatorUserId);
}
catch (Exception ex)
{
logger.LogWarning(
ex,
"异步自动触发失败 OrderId={OrderId} Timing={Timing}",
orderId,
timing);
}
});
}
public async Task FireAsync(Order order, AutoTriggerTiming timing, int operatorUserId)
{
if (order.Id <= 0)
{
return;
}
var context = await orderAutoTriggerService.BuildPostCommitContextAsync(order);
var triggers = await autoTriggerRepository.GetListAsync(x => x.Status == EnableStatus.Enabled);
var orderedTriggers = triggers
.Where(x => AutoTriggerTimingCodes.Matches(x.TriggerTiming, timing))
.Select(x => (Trigger: x, Priority: AutoTriggerRuleResolver.GetPriority(x)))
.OrderBy(x => x.Priority)
.ThenBy(x => x.Trigger.Id)
.Select(x => x.Trigger)
.ToList();
foreach (var trigger in orderedTriggers)
{
if (timing == AutoTriggerTiming.OrderCreate
&& string.Equals(trigger.Operation?.Trim(), InterceptOperation, StringComparison.Ordinal))
{
continue;
}
if (!AutoTriggerConditionMatcher.Matches(context, trigger.TriggerCondition))
{
continue;
}
try
{
await ExecuteTriggerAsync(order, trigger, operatorUserId);
}
catch (Exception ex)
{
logger.LogWarning(ex, "自动触发失败 OrderId={OrderId} TriggerId={TriggerId}", order.Id, trigger.Id);
}
}
}
public async Task FireByOrderIdAsync(int orderId, AutoTriggerTiming timing, int operatorUserId)
{
var order = await orderRepository.FirstOrDefaultAsync(x => x.Id == orderId);
if (order == null)
{
return;
}
await FireAsync(order, timing, operatorUserId);
}
private async Task ExecuteTriggerAsync(
Order order,
AutoTrigger trigger,
int operatorUserId)
{
var operation = trigger.Operation?.Trim();
if (string.Equals(operation, InterceptOperation, StringComparison.Ordinal))
{
if (order.IsIntercept == 0)
{
order.IsIntercept = 1;
await orderRepository.UpdateAsync(order);
}
return;
}
if (string.Equals(operation, "警告", StringComparison.Ordinal))
{
var title = string.IsNullOrWhiteSpace(trigger.PromptMessage)
? "订单预警"
: trigger.PromptMessage.Trim();
var content = string.IsNullOrWhiteSpace(trigger.TriggerCondition)
? $"运单 {{serviceNo}} 触发自动警告规则"
: trigger.TriggerCondition.Trim();
var context = IssuePlaceholderContext.FromOrder(order, null, title);
await issueNotificationService.DispatchAsync(
order,
IssuePlaceholderRenderer.Render(title, context),
IssuePlaceholderRenderer.Render(content, context),
IssueNotifyMethodCodes.InApp,
operatorUserId,
null,
AutoTriggerConditionMatcher.ParseNotifierUserIds(trigger.Notifier));
return;
}
if (!string.Equals(operation, "问题件", StringComparison.Ordinal))
{
return;
}
var issueType = AutoTriggerConditionMatcher.ResolveIssueType(trigger.TriggerCondition);
var request = await exceptionWorkflowService.BuildRequestFromTemplateAsync(
order.OrganizationId,
issueType,
trigger.PromptMessage,
null,
$"自动触发#{trigger.Id}");
if (request == null)
{
logger.LogInformation(
"自动触发问题件跳过:未匹配问题模板 OrderId={OrderId} TriggerId={TriggerId}",
order.Id,
trigger.Id);
return;
}
request.ExtraReceiverUserIds = AutoTriggerConditionMatcher.ParseNotifierUserIds(trigger.Notifier);
var reason = await exceptionWorkflowService.TryMarkProblematicAsync(order, request, operatorUserId, true);
if (!string.IsNullOrWhiteSpace(reason))
{
logger.LogInformation(
"自动触发问题件未执行 OrderId={OrderId} TriggerId={TriggerId} Reason={Reason}",
order.Id,
trigger.Id,
reason);
}
}
}