新增 ChangePostShipStatus,限制发货后四态白名单,妥投成功仅可进入不可改出。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a69e69d5b6
commit
3c85b7325f
@ -0,0 +1,29 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Oms.Application.Dtos.Orders;
|
||||
|
||||
/// <summary>
|
||||
/// 出库后状态校正入参:仅允许在待上网 / 运输中 / 派送成功 / 派送失败之间变更;派送成功只进不出。
|
||||
/// </summary>
|
||||
public class OrderChangePostShipStatusInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单主键。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标订单状态(pendingOnline / shipping / deliverySuccess / deliveryFailed)。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(32)]
|
||||
public string TargetStatus { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 变更备注(必填,落操作日志)。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(512)]
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
}
|
||||
@ -237,7 +237,101 @@ public partial class OrderService : ApplicationService
|
||||
order.OrderStatus = OrderStatusCodes.DeliverySuccess;
|
||||
order.SignTime = DateTime.Now;
|
||||
await UpdateOrderAsync(order);
|
||||
await ApplyDeliverySuccessMarketingAsync(order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出库后状态校正:仅待上网 / 运输中 / 派送成功 / 派送失败互改;派送成功只进不出。
|
||||
/// 目标为派送成功时同步 SignTime 并触发引荐分成 / 首签券(与 mark-delivery-success 一致)。
|
||||
/// </summary>
|
||||
/// <param name="input">订单 Id、目标状态、必填备注。</param>
|
||||
[HttpPost("/order/change-post-ship-status")]
|
||||
[UnitOfWork(IsTransactional = true, IsolationLevel = IsolationLevel.ReadCommitted)]
|
||||
public async Task ChangePostShipStatusAsync([FromBody] OrderChangePostShipStatusInput input)
|
||||
{
|
||||
var target = NormalizePostShipStatus(input.TargetStatus);
|
||||
if (target == null)
|
||||
{
|
||||
throw new BusinessException("目标状态仅支持:待上网、运输中、派送成功、派送失败");
|
||||
}
|
||||
|
||||
var remark = input.Remark?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(remark))
|
||||
{
|
||||
throw new BusinessException("请填写变更备注");
|
||||
}
|
||||
|
||||
var order = await GetOrderOrThrowAsync(input.Id);
|
||||
var fromStatus = order.OrderStatus?.Trim() ?? string.Empty;
|
||||
if (!IsPostShipChangeableStatus(fromStatus))
|
||||
{
|
||||
throw new BusinessException(
|
||||
$"订单状态为「{OmsDocHelper.GetOrderStatusName(fromStatus)}」,仅出库后状态可校正");
|
||||
}
|
||||
|
||||
if (string.Equals(fromStatus, OrderStatusCodes.DeliverySuccess, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new BusinessException("派送成功不可回退");
|
||||
}
|
||||
|
||||
if (string.Equals(fromStatus, target, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new BusinessException("目标状态与当前状态相同");
|
||||
}
|
||||
|
||||
var beforeSnap = await CaptureOrderAuditSnapshotAsync(order);
|
||||
order.OrderStatus = target;
|
||||
if (string.Equals(target, OrderStatusCodes.DeliverySuccess, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
order.SignTime = DateTime.Now;
|
||||
}
|
||||
|
||||
order.UpdateTime = DateTime.Now;
|
||||
await UpdateOrderAsync(order);
|
||||
|
||||
if (string.Equals(target, OrderStatusCodes.DeliverySuccess, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
order = await GetOrderOrThrowAsync(order.Id);
|
||||
await ApplyDeliverySuccessMarketingAsync(order);
|
||||
}
|
||||
|
||||
order = await GetOrderOrThrowAsync(order.Id);
|
||||
var afterSnap = await CaptureOrderAuditSnapshotAsync(order);
|
||||
var fromName = OmsDocHelper.GetOrderStatusName(fromStatus) ?? fromStatus;
|
||||
var toName = OmsDocHelper.GetOrderStatusName(target) ?? target;
|
||||
await OperationLogWriter.TryWriteAsync(
|
||||
order,
|
||||
OrderOperationActionCodes.ChangePostShipStatus,
|
||||
beforeSnap,
|
||||
afterSnap,
|
||||
$"{fromName} → {toName};{remark}");
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> PostShipChangeableStatuses = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
OrderStatusCodes.PendingOnline,
|
||||
OrderStatusCodes.Shipping,
|
||||
OrderStatusCodes.DeliverySuccess,
|
||||
OrderStatusCodes.DeliveryFailed
|
||||
};
|
||||
|
||||
private static bool IsPostShipChangeableStatus(string? status) =>
|
||||
!string.IsNullOrWhiteSpace(status) && PostShipChangeableStatuses.Contains(status.Trim());
|
||||
|
||||
private static string? NormalizePostShipStatus(string? raw)
|
||||
{
|
||||
var value = raw?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(value) || !PostShipChangeableStatuses.Contains(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return PostShipChangeableStatuses.First(x =>
|
||||
string.Equals(x, value, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private async Task ApplyDeliverySuccessMarketingAsync(Order order)
|
||||
{
|
||||
var commissionManager = LazyServiceProvider.GetRequiredService<ReferralCommissionManager>();
|
||||
await commissionManager.OnOrderDeliverySuccessAsync(order.Id);
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ public static class OrderOperationActionCodes
|
||||
public const string Print = "print";
|
||||
public const string Inbound = "inbound";
|
||||
public const string Outbound = "outbound";
|
||||
public const string ChangePostShipStatus = "changePostShipStatus";
|
||||
|
||||
public static string GetActionName(string action) => action switch
|
||||
{
|
||||
@ -35,6 +36,7 @@ public static class OrderOperationActionCodes
|
||||
Print => "打印面单",
|
||||
Inbound => "入库",
|
||||
Outbound => "出库",
|
||||
ChangePostShipStatus => "修改出库后状态",
|
||||
_ => action
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user