新增 mark-problematic/mark-claimed/handle-status 接口,异常事件审计表与占位符渲染;inApp/email 通知及下单/入库/出库自动触发运行时。 Co-authored-by: Cursor <cursoragent@cursor.com>
155 lines
5.4 KiB
C#
155 lines
5.4 KiB
C#
using Fake.DependencyInjection;
|
|
using Oms.Domain.ChannelsAggregate.Consts;
|
|
using Oms.Domain.ChannelsAggregate.Entities;
|
|
using Oms.Domain.ChannelsAggregate.Repositories;
|
|
using Oms.Domain.OrdersAggregate.Consts;
|
|
using Oms.Domain.OrdersAggregate.Entities;
|
|
using Oms.Domain.OrdersAggregate.Repositories;
|
|
using Oms.Domain.Shared.Enums;
|
|
|
|
namespace Oms.Application.Services.Orders.Issues;
|
|
|
|
public sealed class ProblematicMarkRequest
|
|
{
|
|
public string IssueType { get; set; } = string.Empty;
|
|
|
|
public string Title { get; set; } = string.Empty;
|
|
|
|
public string Content { get; set; } = string.Empty;
|
|
|
|
public int? IssueTemplateId { get; set; }
|
|
|
|
public string? NotifyMethod { get; set; }
|
|
|
|
public string? Remark { get; set; }
|
|
|
|
public IEnumerable<int>? ExtraReceiverUserIds { get; set; }
|
|
}
|
|
|
|
public class OrderExceptionWorkflowService(
|
|
IOrderRepository orderRepository,
|
|
IOrderExceptionEventRepository orderExceptionEventRepository,
|
|
IIssueTemplateRepository issueTemplateRepository,
|
|
OrderIssueNotificationService issueNotificationService) : IScopedDependency
|
|
{
|
|
public async Task<string?> TryMarkProblematicAsync(
|
|
Order order,
|
|
ProblematicMarkRequest request,
|
|
int operatorUserId,
|
|
bool sendNotification)
|
|
{
|
|
if (!OrderExceptionStatusRules.CanMarkException(order.OrderStatus))
|
|
{
|
|
return OrderExceptionStatusRules.GetForbiddenReason(order.OrderStatus);
|
|
}
|
|
|
|
var context = IssuePlaceholderContext.FromOrder(order, request.IssueType, request.Title);
|
|
var renderedTitle = IssuePlaceholderRenderer.Render(request.Title, context);
|
|
var renderedContent = IssuePlaceholderRenderer.Render(request.Content, context);
|
|
|
|
var fromStatus = order.OrderStatus;
|
|
order.PreviousOrderStatus = fromStatus;
|
|
order.OrderStatus = OrderStatusCodes.Problematic;
|
|
order.HandleStatus = OrderHandleStatusCodes.Pending;
|
|
order.IssueType = request.IssueType;
|
|
order.IssueTitle = renderedTitle;
|
|
order.IssueContent = renderedContent;
|
|
order.IssueTemplateId = request.IssueTemplateId;
|
|
order.IssueRemark = request.Remark;
|
|
order.IssueTime = DateTime.Now;
|
|
order.ClaimType = null;
|
|
order.ClaimAmount = null;
|
|
order.ClaimCurrency = null;
|
|
order.ClaimReason = null;
|
|
order.ClaimTime = null;
|
|
|
|
await orderRepository.UpdateAsync(order);
|
|
await orderExceptionEventRepository.InsertAsync(new OrderExceptionEvent
|
|
{
|
|
OrderId = order.Id,
|
|
EventType = OrderExceptionEventTypeCodes.MarkProblematic,
|
|
FromStatus = fromStatus,
|
|
ToStatus = OrderStatusCodes.Problematic,
|
|
FromHandleStatus = null,
|
|
ToHandleStatus = OrderHandleStatusCodes.Pending,
|
|
IssueType = request.IssueType,
|
|
Title = renderedTitle,
|
|
Content = renderedContent,
|
|
IssueTemplateId = request.IssueTemplateId,
|
|
NotifyMethod = request.NotifyMethod,
|
|
Remark = request.Remark
|
|
});
|
|
|
|
if (sendNotification)
|
|
{
|
|
await issueNotificationService.DispatchAsync(
|
|
order,
|
|
renderedTitle,
|
|
renderedContent,
|
|
request.NotifyMethod,
|
|
operatorUserId,
|
|
request.ExtraReceiverUserIds);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<ProblematicMarkRequest?> BuildRequestFromTemplateAsync(
|
|
string? organizationId,
|
|
string issueType,
|
|
string? titleOverride,
|
|
string? contentOverride,
|
|
string? remark)
|
|
{
|
|
var normalizedType = issueType.Trim().ToLowerInvariant();
|
|
if (!IssueTypeCodes.All.Contains(normalizedType))
|
|
{
|
|
normalizedType = IssueTypeCodes.Other;
|
|
}
|
|
|
|
var normalizedOrg = NormalizeOrganizationId(organizationId);
|
|
var hasOrgFilter = normalizedOrg != null;
|
|
var orgValue = normalizedOrg ?? string.Empty;
|
|
|
|
var templates = await issueTemplateRepository.GetListAsync(x =>
|
|
x.Status == EnableStatus.Enabled
|
|
&& x.IssueType == normalizedType
|
|
&& (!hasOrgFilter
|
|
|| x.OrganizationId == orgValue
|
|
|| x.OrganizationId == null
|
|
|| x.OrganizationId == string.Empty));
|
|
|
|
var template = templates.FirstOrDefault(x => x.OrganizationId == normalizedOrg)
|
|
?? templates.FirstOrDefault(x => string.IsNullOrWhiteSpace(x.OrganizationId))
|
|
?? templates.FirstOrDefault();
|
|
|
|
var title = !string.IsNullOrWhiteSpace(titleOverride)
|
|
? titleOverride.Trim()
|
|
: template?.Title?.Trim();
|
|
var content = !string.IsNullOrWhiteSpace(contentOverride)
|
|
? contentOverride.Trim()
|
|
: template?.Content?.Trim();
|
|
|
|
if (string.IsNullOrWhiteSpace(title) || string.IsNullOrWhiteSpace(content))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new ProblematicMarkRequest
|
|
{
|
|
IssueType = normalizedType,
|
|
Title = title,
|
|
Content = content,
|
|
IssueTemplateId = template?.Id,
|
|
NotifyMethod = template == null ? null : IssueNotifyMethodCodes.Normalize(template.NotifyMethod),
|
|
Remark = remark
|
|
};
|
|
}
|
|
|
|
private static string? NormalizeOrganizationId(string? organizationId)
|
|
{
|
|
var text = organizationId?.Trim();
|
|
return string.IsNullOrWhiteSpace(text) ? null : text;
|
|
}
|
|
}
|