All checks were successful
Build and Deploy / deploy (push) Successful in 1m0s
进程重启或事务回滚不再丢掉 9610、轨迹和揽收;排货完成后再补轨迹、面单和计费相关触发。 Co-authored-by: Cursor <cursoragent@cursor.com>
203 lines
7.3 KiB
C#
203 lines
7.3 KiB
C#
using Fake.Application;
|
|
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? HandlerNames { get; set; }
|
|
|
|
public string? Remark { get; set; }
|
|
|
|
public IEnumerable<int>? ExtraReceiverUserIds { get; set; }
|
|
}
|
|
|
|
public class OrderExceptionWorkflowService(
|
|
IOrderRepository orderRepository,
|
|
IOrderExceptionEventRepository orderExceptionEventRepository,
|
|
IIssueTemplateRepository issueTemplateRepository,
|
|
IssueHandlerResolver issueHandlerResolver,
|
|
OrderIssueNotificationService issueNotificationService) : IScopedDependency
|
|
{
|
|
public async Task<string?> TryMarkProblematicAsync(
|
|
Order order,
|
|
ProblematicMarkRequest request,
|
|
int operatorUserId,
|
|
bool sendNotification)
|
|
{
|
|
var current = await orderRepository.FirstOrDefaultAsync(x => x.Id == order.Id) ?? order;
|
|
if (!OrderExceptionStatusRules.CanMarkException(current.OrderStatus))
|
|
{
|
|
return OrderExceptionStatusRules.GetForbiddenReason(current.OrderStatus);
|
|
}
|
|
|
|
IssueTemplate? template = null;
|
|
if (request.IssueTemplateId is int templateId && templateId > 0)
|
|
{
|
|
template = await issueTemplateRepository.FirstOrDefaultAsync(x => x.Id == templateId);
|
|
}
|
|
|
|
IssueHandlerResolution handlerResolution;
|
|
try
|
|
{
|
|
handlerResolution = await issueHandlerResolver.ResolveAsync(current, template, request.HandlerNames);
|
|
}
|
|
catch (BusinessException ex)
|
|
{
|
|
return ex.Message;
|
|
}
|
|
|
|
var context = IssuePlaceholderContext.FromOrder(current, request.IssueType, request.Title);
|
|
var renderedTitle = IssuePlaceholderRenderer.Render(request.Title, context);
|
|
var renderedContent = IssuePlaceholderRenderer.Render(request.Content, context);
|
|
|
|
var notifyMethod = request.NotifyMethod;
|
|
if (IssueHandlerTypeCodes.IsCustomer(handlerResolution.HandlerType))
|
|
{
|
|
notifyMethod = IssueNotifyMethodCodes.InApp;
|
|
}
|
|
|
|
var fromStatus = current.OrderStatus;
|
|
var isAppend = string.Equals(fromStatus, OrderStatusCodes.Problematic, StringComparison.OrdinalIgnoreCase);
|
|
if (!isAppend)
|
|
{
|
|
current.PreviousOrderStatus = fromStatus;
|
|
current.OrderStatus = OrderStatusCodes.Problematic;
|
|
}
|
|
|
|
current.HandleStatus = OrderHandleStatusCodes.Pending;
|
|
current.IssueType = request.IssueType;
|
|
current.IssueTitle = renderedTitle;
|
|
current.IssueContent = renderedContent;
|
|
current.IssueTemplateId = request.IssueTemplateId;
|
|
current.IssueRemark = request.Remark;
|
|
current.IssueTime = DateTime.Now;
|
|
current.ClaimType = null;
|
|
current.ClaimAmount = null;
|
|
current.ClaimCurrency = null;
|
|
current.ClaimReason = null;
|
|
current.ClaimTime = null;
|
|
|
|
await orderRepository.UpdateAsync(current);
|
|
order.OrderStatus = current.OrderStatus;
|
|
order.PreviousOrderStatus = current.PreviousOrderStatus;
|
|
order.HandleStatus = current.HandleStatus;
|
|
order.IssueType = current.IssueType;
|
|
order.IssueTitle = current.IssueTitle;
|
|
order.IssueContent = current.IssueContent;
|
|
order.IssueTemplateId = current.IssueTemplateId;
|
|
order.IssueRemark = current.IssueRemark;
|
|
order.IssueTime = current.IssueTime;
|
|
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 = notifyMethod,
|
|
HandlerNames = handlerResolution.HandlerNames,
|
|
HandlerType = handlerResolution.HandlerType,
|
|
HandlerUserId = handlerResolution.HandlerUserId,
|
|
Remark = request.Remark
|
|
});
|
|
|
|
if (sendNotification && !string.IsNullOrWhiteSpace(notifyMethod))
|
|
{
|
|
var notifyUserIds = handlerResolution.NotifyUserIds.Count > 0
|
|
? handlerResolution.NotifyUserIds
|
|
: null;
|
|
await issueNotificationService.DispatchAsync(
|
|
current,
|
|
renderedTitle,
|
|
renderedContent,
|
|
notifyMethod,
|
|
operatorUserId,
|
|
notifyUserIds,
|
|
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;
|
|
}
|
|
}
|