diff --git a/src/Oms.Application/Dtos/Orders/OrderChangePostShipStatusInput.cs b/src/Oms.Application/Dtos/Orders/OrderChangePostShipStatusInput.cs
new file mode 100644
index 0000000..3babb24
--- /dev/null
+++ b/src/Oms.Application/Dtos/Orders/OrderChangePostShipStatusInput.cs
@@ -0,0 +1,29 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Oms.Application.Dtos.Orders;
+
+///
+/// 出库后状态校正入参:仅允许在待上网 / 运输中 / 派送成功 / 派送失败之间变更;派送成功只进不出。
+///
+public class OrderChangePostShipStatusInput
+{
+ ///
+ /// 订单主键。
+ ///
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// 目标订单状态(pendingOnline / shipping / deliverySuccess / deliveryFailed)。
+ ///
+ [Required]
+ [StringLength(32)]
+ public string TargetStatus { get; set; } = string.Empty;
+
+ ///
+ /// 变更备注(必填,落操作日志)。
+ ///
+ [Required]
+ [StringLength(512)]
+ public string Remark { get; set; } = string.Empty;
+}
diff --git a/src/Oms.Application/Services/Orders/OrderService.cs b/src/Oms.Application/Services/Orders/OrderService.cs
index ced7591..9f6dd5a 100644
--- a/src/Oms.Application/Services/Orders/OrderService.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.cs
@@ -237,7 +237,101 @@ public partial class OrderService : ApplicationService
order.OrderStatus = OrderStatusCodes.DeliverySuccess;
order.SignTime = DateTime.Now;
await UpdateOrderAsync(order);
+ await ApplyDeliverySuccessMarketingAsync(order);
+ }
+ ///
+ /// 出库后状态校正:仅待上网 / 运输中 / 派送成功 / 派送失败互改;派送成功只进不出。
+ /// 目标为派送成功时同步 SignTime 并触发引荐分成 / 首签券(与 mark-delivery-success 一致)。
+ ///
+ /// 订单 Id、目标状态、必填备注。
+ [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 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();
await commissionManager.OnOrderDeliverySuccessAsync(order.Id);
diff --git a/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs b/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
index b164f5d..71173e7 100644
--- a/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
+++ b/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
@@ -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
};
}