Persist generated/printed/downstream labels in t_order_file, drop Order.LabelUrl generate-status fields, and expose file list/upload/delete APIs with customer read-only systemLabel access. Co-authored-by: Cursor <cursoragent@cursor.com>
177 lines
6.7 KiB
C#
177 lines
6.7 KiB
C#
using Fake.Application;
|
|
using Newtonsoft.Json;
|
|
using Oms.Application.Dtos.Orders;
|
|
using Oms.Application.Labeling;
|
|
using Oms.Application.Services.Orders.Issues;
|
|
using Oms.Domain.OrdersAggregate.Consts;
|
|
using Oms.Domain.OrdersAggregate.Entities;
|
|
|
|
namespace Oms.Application.Services.Orders;
|
|
|
|
public partial class OrderService
|
|
{
|
|
internal Task PayForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
PayAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal Task PreDeclareForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
PreDeclareAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal Task InterceptForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
InterceptAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal Task CancelInterceptForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
CancelInterceptAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal Task DeleteForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
DeleteAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal Task<OrderPrintOutput> PrintForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
|
PrintAsync(new OrderActionInput { Id = orderId });
|
|
|
|
internal async Task<LabelPdfGenerateResult> GenerateLabelPdfForBatchAsync(
|
|
int orderId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var order = await GetOrderOrThrowAsync(orderId);
|
|
var mapped = (await MapOrderOutputsAsync([order])).First();
|
|
return await LabelPdfGenerationService.GenerateAndPersistAsync(
|
|
order,
|
|
mapped,
|
|
templateIdOverride: null,
|
|
operatorName: null,
|
|
operatorUserId: 0,
|
|
cancellationToken);
|
|
}
|
|
|
|
internal async Task MarkProblematicForBatchAsync(
|
|
int orderId,
|
|
string? payloadJson,
|
|
int operatorUserId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var input = DeserializeBatchPayload<OrderMarkProblematicInput>(payloadJson)
|
|
?? throw new BusinessException("问题件参数无效");
|
|
input.OrderIds = [orderId];
|
|
|
|
var payload = await ResolveProblematicPayloadAsync(input);
|
|
var request = new ProblematicMarkRequest
|
|
{
|
|
IssueType = payload.IssueType,
|
|
Title = payload.Title,
|
|
Content = payload.Content,
|
|
IssueTemplateId = payload.IssueTemplateId,
|
|
NotifyMethod = payload.NotifyMethod,
|
|
Remark = payload.Remark,
|
|
};
|
|
|
|
var order = await GetOrderOrThrowAsync(orderId);
|
|
var sendNotification = !string.IsNullOrWhiteSpace(request.NotifyMethod);
|
|
var reason = await ExceptionWorkflowService.TryMarkProblematicAsync(
|
|
order,
|
|
request,
|
|
operatorUserId,
|
|
sendNotification);
|
|
if (!string.IsNullOrWhiteSpace(reason))
|
|
{
|
|
throw new BusinessException(reason);
|
|
}
|
|
}
|
|
|
|
internal async Task MarkClaimedForBatchAsync(
|
|
int orderId,
|
|
string? payloadJson,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var input = DeserializeBatchPayload<OrderMarkClaimedInput>(payloadJson)
|
|
?? throw new BusinessException("理赔件参数无效");
|
|
var payload = NormalizeClaimedPayload(input);
|
|
var order = await GetOrderOrThrowAsync(orderId);
|
|
|
|
if (!OrderExceptionStatusRules.CanMarkException(order.OrderStatus))
|
|
{
|
|
throw new BusinessException(OrderExceptionStatusRules.GetForbiddenReason(order.OrderStatus));
|
|
}
|
|
|
|
var fromStatus = order.OrderStatus;
|
|
order.PreviousOrderStatus = fromStatus;
|
|
order.OrderStatus = OrderStatusCodes.Claimed;
|
|
order.HandleStatus = OrderHandleStatusCodes.Pending;
|
|
order.ClaimType = payload.ClaimType;
|
|
order.ClaimAmount = payload.ClaimAmount;
|
|
order.ClaimCurrency = payload.ClaimCurrency;
|
|
order.ClaimReason = payload.ClaimReason;
|
|
order.ClaimTime = DateTime.Now;
|
|
order.IssueType = null;
|
|
order.IssueTitle = null;
|
|
order.IssueContent = null;
|
|
order.IssueTemplateId = null;
|
|
order.IssueRemark = null;
|
|
order.IssueTime = null;
|
|
|
|
await OrderRepository.UpdateAsync(order);
|
|
await OrderExceptionEventRepository.InsertAsync(new OrderExceptionEvent
|
|
{
|
|
OrderId = order.Id,
|
|
EventType = OrderExceptionEventTypeCodes.MarkClaimed,
|
|
FromStatus = fromStatus,
|
|
ToStatus = OrderStatusCodes.Claimed,
|
|
FromHandleStatus = null,
|
|
ToHandleStatus = OrderHandleStatusCodes.Pending,
|
|
ClaimType = payload.ClaimType,
|
|
ClaimAmount = payload.ClaimAmount,
|
|
ClaimCurrency = payload.ClaimCurrency,
|
|
ClaimReason = payload.ClaimReason,
|
|
Remark = payload.Remark,
|
|
});
|
|
}
|
|
|
|
internal async Task UpdateHandleStatusForBatchAsync(
|
|
int orderId,
|
|
string? payloadJson,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var input = DeserializeBatchPayload<OrderHandleStatusUpdateInput>(payloadJson)
|
|
?? throw new BusinessException("处理状态参数无效");
|
|
var targetStatus = input.HandleStatus?.Trim().ToLowerInvariant();
|
|
if (!string.Equals(targetStatus, OrderHandleStatusCodes.Processed, StringComparison.Ordinal))
|
|
{
|
|
throw new BusinessException("仅支持标记为已处理");
|
|
}
|
|
|
|
var order = await GetOrderOrThrowAsync(orderId);
|
|
if (order.OrderStatus is not (OrderStatusCodes.Problematic or OrderStatusCodes.Claimed))
|
|
{
|
|
throw new BusinessException("仅问题件或理赔件可更新处理状态");
|
|
}
|
|
|
|
if (OrderHandleStatusCodes.IsProcessed(order.HandleStatus))
|
|
{
|
|
throw new BusinessException("订单已处理");
|
|
}
|
|
|
|
order.HandleStatus = OrderHandleStatusCodes.Processed;
|
|
await OrderRepository.UpdateAsync(order);
|
|
await OrderExceptionEventRepository.InsertAsync(new OrderExceptionEvent
|
|
{
|
|
OrderId = order.Id,
|
|
EventType = OrderExceptionEventTypeCodes.HandleProcessed,
|
|
FromStatus = order.OrderStatus,
|
|
ToStatus = order.OrderStatus,
|
|
FromHandleStatus = OrderHandleStatusCodes.Pending,
|
|
ToHandleStatus = OrderHandleStatusCodes.Processed,
|
|
Remark = input.Remark?.Trim(),
|
|
});
|
|
}
|
|
|
|
private static T? DeserializeBatchPayload<T>(string? payloadJson)
|
|
where T : class
|
|
{
|
|
if (string.IsNullOrWhiteSpace(payloadJson))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return JsonConvert.DeserializeObject<T>(payloadJson);
|
|
}
|
|
}
|