统一订单单状态模型
This commit is contained in:
@@ -80,7 +80,7 @@ func TestFulfillmentCreateOrderDebitsWalletAndIsIdempotent(t *testing.T) {
|
||||
if first.Idempotent {
|
||||
t.Fatalf("first create should not be idempotent")
|
||||
}
|
||||
if first.Order.Amount != 400 || first.Order.PaymentStatus != model.PaymentStatusPaid || first.Order.FulfillmentStatus != model.FulfillmentStatusPending {
|
||||
if first.Order.Amount != 400 || first.Order.OrderStatus != model.OrderStatusPaid {
|
||||
t.Fatalf("unexpected order: %+v", first.Order)
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ func TestDashboardScopesPlatformAndMerchantData(t *testing.T) {
|
||||
if merchantStats.ProductCount != 1 || merchantStats.ActiveProductCount != 1 {
|
||||
t.Fatalf("merchant product stats should only include current merchant, got %+v", merchantStats)
|
||||
}
|
||||
if merchantStats.OrderCount != 1 || merchantStats.PendingOrderCount != 1 || merchantStats.TotalSales != 100 {
|
||||
if merchantStats.OrderCount != 1 || merchantStats.PaidOrderCount != 1 || merchantStats.TotalSales != 100 {
|
||||
t.Fatalf("merchant order stats should only include current merchant, got %+v", merchantStats)
|
||||
}
|
||||
if merchantStats.WalletAvailableBalance != 900 {
|
||||
@@ -216,7 +216,7 @@ func TestDashboardScopesPlatformAndMerchantData(t *testing.T) {
|
||||
if platformStats.Scope != "platform" {
|
||||
t.Fatalf("expected platform scope, got %s", platformStats.Scope)
|
||||
}
|
||||
if platformStats.OrderCount != 2 || platformStats.PendingOrderCount != 2 || platformStats.TotalSales != 400 {
|
||||
if platformStats.OrderCount != 2 || platformStats.PaidOrderCount != 2 || platformStats.TotalSales != 400 {
|
||||
t.Fatalf("platform order stats should include all merchants, got %+v", platformStats)
|
||||
}
|
||||
if platformStats.WalletAvailableBalance < 2600 {
|
||||
@@ -319,7 +319,7 @@ func TestFulfillmentCancelRefundsOnceAndRestoresStock(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("cancel order: %v", err)
|
||||
}
|
||||
if cancelled.PaymentStatus != model.PaymentStatusRefunded || cancelled.FulfillmentStatus != model.FulfillmentStatusCancelled {
|
||||
if cancelled.OrderStatus != model.OrderStatusCancelled {
|
||||
t.Fatalf("unexpected cancelled order: %+v", cancelled)
|
||||
}
|
||||
if _, err := svc.CancelOrder(merchantID, 12, created.Order.OrderNo, "重复取消"); err != nil {
|
||||
@@ -343,7 +343,7 @@ func TestFulfillmentCancelRefundsOnceAndRestoresStock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFulfillmentStatusTransitions(t *testing.T) {
|
||||
func TestOrderStatusTransitions(t *testing.T) {
|
||||
db := newServiceTestDB(t)
|
||||
merchantID, product := seedFulfillmentMerchant(t, db, "merchant-c", 1000, -1, 100)
|
||||
svc := NewFulfillmentService(db, nil)
|
||||
@@ -356,37 +356,37 @@ func TestFulfillmentStatusTransitions(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("create order: %v", err)
|
||||
}
|
||||
processing, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
delivering, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 13,
|
||||
OrderNo: created.Order.OrderNo,
|
||||
Status: model.FulfillmentStatusProcessing,
|
||||
Status: model.OrderStatusDelivering,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("mark processing: %v", err)
|
||||
t.Fatalf("mark delivering: %v", err)
|
||||
}
|
||||
if processing.FulfillmentStatus != model.FulfillmentStatusProcessing {
|
||||
t.Fatalf("expected processing, got %s", processing.FulfillmentStatus)
|
||||
if delivering.OrderStatus != model.OrderStatusDelivering {
|
||||
t.Fatalf("expected delivering, got %s", delivering.OrderStatus)
|
||||
}
|
||||
succeeded, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
delivered, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 13,
|
||||
OrderNo: created.Order.OrderNo,
|
||||
Status: model.FulfillmentStatusSucceeded,
|
||||
Status: model.OrderStatusDelivered,
|
||||
ProviderOrderNo: "provider-1",
|
||||
ResultData: map[string]string{"ok": "true"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("mark succeeded: %v", err)
|
||||
t.Fatalf("mark delivered: %v", err)
|
||||
}
|
||||
if succeeded.FulfillmentStatus != model.FulfillmentStatusSucceeded || succeeded.DeliveredAt == nil {
|
||||
t.Fatalf("unexpected succeeded order: %+v", succeeded)
|
||||
if delivered.OrderStatus != model.OrderStatusDelivered || delivered.DeliveredAt == nil {
|
||||
t.Fatalf("unexpected delivered order: %+v", delivered)
|
||||
}
|
||||
_, err = svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 13,
|
||||
OrderNo: created.Order.OrderNo,
|
||||
Status: model.FulfillmentStatusFailed,
|
||||
Status: model.OrderStatusShipFailed,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatalf("should reject rollback after success")
|
||||
@@ -406,19 +406,19 @@ func TestMarkProcessingTimeoutsMarksStaleOrdersFailed(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("create order: %v", err)
|
||||
}
|
||||
processing, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
delivering, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 13,
|
||||
OrderNo: created.Order.OrderNo,
|
||||
Status: model.FulfillmentStatusProcessing,
|
||||
Status: model.OrderStatusDelivering,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("mark processing: %v", err)
|
||||
t.Fatalf("mark delivering: %v", err)
|
||||
}
|
||||
if err := db.Model(&model.FulfillmentOrder{}).
|
||||
Where("id = ?", processing.ID).
|
||||
Where("id = ?", delivering.ID).
|
||||
Update("updated_at", time.Now().Add(-time.Hour)).Error; err != nil {
|
||||
t.Fatalf("age processing order: %v", err)
|
||||
t.Fatalf("age delivering order: %v", err)
|
||||
}
|
||||
|
||||
changed, err := svc.MarkProcessingTimeouts(30*time.Minute, 10)
|
||||
@@ -429,10 +429,10 @@ func TestMarkProcessingTimeoutsMarksStaleOrdersFailed(t *testing.T) {
|
||||
t.Fatalf("expected one timed out order, got %d", changed)
|
||||
}
|
||||
var order model.FulfillmentOrder
|
||||
if err := db.First(&order, processing.ID).Error; err != nil {
|
||||
if err := db.First(&order, delivering.ID).Error; err != nil {
|
||||
t.Fatalf("query order: %v", err)
|
||||
}
|
||||
if order.FulfillmentStatus != model.FulfillmentStatusFailed || !strings.Contains(order.FailureReason, "履约超时") {
|
||||
if order.OrderStatus != model.OrderStatusShipFailed || !strings.Contains(order.FailureReason, "履约超时") {
|
||||
t.Fatalf("expected failed timeout order, got %+v", order)
|
||||
}
|
||||
if !strings.Contains(order.ResultData, `"timeout":true`) {
|
||||
@@ -453,28 +453,28 @@ func TestMarkProcessingTimeoutsSkipsRecentOrders(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("create order: %v", err)
|
||||
}
|
||||
processing, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
delivering, err := svc.UpdateFulfillment(FulfillmentUpdateInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 13,
|
||||
OrderNo: created.Order.OrderNo,
|
||||
Status: model.FulfillmentStatusProcessing,
|
||||
Status: model.OrderStatusDelivering,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("mark processing: %v", err)
|
||||
t.Fatalf("mark delivering: %v", err)
|
||||
}
|
||||
changed, err := svc.MarkProcessingTimeouts(30*time.Minute, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("mark timeouts: %v", err)
|
||||
}
|
||||
if changed != 0 {
|
||||
t.Fatalf("recent processing order should not time out, got %d", changed)
|
||||
t.Fatalf("recent delivering order should not time out, got %d", changed)
|
||||
}
|
||||
var order model.FulfillmentOrder
|
||||
if err := db.First(&order, processing.ID).Error; err != nil {
|
||||
if err := db.First(&order, delivering.ID).Error; err != nil {
|
||||
t.Fatalf("query order: %v", err)
|
||||
}
|
||||
if order.FulfillmentStatus != model.FulfillmentStatusProcessing {
|
||||
t.Fatalf("expected processing order, got %+v", order)
|
||||
if order.OrderStatus != model.OrderStatusDelivering {
|
||||
t.Fatalf("expected delivering order, got %+v", order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,18 +534,16 @@ func TestWalletAdjustIsIdempotentPerMerchant(t *testing.T) {
|
||||
|
||||
func TestCanFulfill(t *testing.T) {
|
||||
ok, reason := CanFulfill(&model.FulfillmentOrder{
|
||||
PaymentStatus: model.PaymentStatusPaid,
|
||||
FulfillmentStatus: model.FulfillmentStatusFailed,
|
||||
OrderStatus: model.OrderStatusShipFailed,
|
||||
})
|
||||
if !ok || reason != "" {
|
||||
t.Fatalf("failed paid order should be fulfillable")
|
||||
}
|
||||
ok, _ = CanFulfill(&model.FulfillmentOrder{
|
||||
PaymentStatus: model.PaymentStatusRefunded,
|
||||
FulfillmentStatus: model.FulfillmentStatusPending,
|
||||
OrderStatus: model.OrderStatusCancelled,
|
||||
})
|
||||
if ok {
|
||||
t.Fatalf("refunded order should not be fulfillable")
|
||||
t.Fatalf("cancelled order should not be fulfillable")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,7 +586,7 @@ func TestCreateTestOrderCreatesFulfillableOrderWithoutBilling(t *testing.T) {
|
||||
if !strings.HasPrefix(order.OrderNo, "O") || order.ClientOrderNo != "TEST-"+order.OrderNo {
|
||||
t.Fatalf("unexpected test order numbers: %+v", order)
|
||||
}
|
||||
if order.PaymentStatus != model.PaymentStatusPaid || order.FulfillmentStatus != model.FulfillmentStatusPending {
|
||||
if order.OrderStatus != model.OrderStatusPaid {
|
||||
t.Fatalf("unexpected test order status: %+v", order)
|
||||
}
|
||||
canShip, reason := CanFulfill(order)
|
||||
@@ -631,15 +629,15 @@ func TestCreateTestOrderSupportsFailedFulfillableStatus(t *testing.T) {
|
||||
svc := NewFulfillmentService(db, nil)
|
||||
|
||||
order, err := svc.CreateTestOrder(CreateTestOrderInput{
|
||||
MerchantID: merchantID,
|
||||
SKU: product.SKU,
|
||||
FulfillmentStatus: model.FulfillmentStatusFailed,
|
||||
Note: "等待重新发货",
|
||||
MerchantID: merchantID,
|
||||
SKU: product.SKU,
|
||||
OrderStatus: model.OrderStatusShipFailed,
|
||||
Note: "等待重新发货",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create failed test order: %v", err)
|
||||
}
|
||||
if order.FulfillmentStatus != model.FulfillmentStatusFailed || order.FailureReason != "等待重新发货" {
|
||||
if order.OrderStatus != model.OrderStatusShipFailed || order.FailureReason != "等待重新发货" {
|
||||
t.Fatalf("unexpected failed test order: %+v", order)
|
||||
}
|
||||
openOrder, err := svc.QueryOpenOrder(order.OrderNo)
|
||||
@@ -694,7 +692,7 @@ func TestHandleShipNotifyUpdatesOrderAndEnqueuesMerchantCallback(t *testing.T) {
|
||||
if err := db.First(&order, created.Order.ID).Error; err != nil {
|
||||
t.Fatalf("query order: %v", err)
|
||||
}
|
||||
if order.FulfillmentStatus != model.FulfillmentStatusSucceeded || order.ProviderOrderNo != "SRC-10001" || order.DeliveredAt == nil {
|
||||
if order.OrderStatus != model.OrderStatusDelivered || order.ProviderOrderNo != "SRC-10001" || order.DeliveredAt == nil {
|
||||
t.Fatalf("unexpected order after source notify: %+v", order)
|
||||
}
|
||||
var delivery model.CallbackDelivery
|
||||
@@ -771,7 +769,7 @@ func TestHandleShipNotifySuccessClearsPreviousResultFailureReason(t *testing.T)
|
||||
if err := db.First(&order, created.Order.ID).Error; err != nil {
|
||||
t.Fatalf("query order: %v", err)
|
||||
}
|
||||
if order.FulfillmentStatus != model.FulfillmentStatusSucceeded || order.FailureReason != "" {
|
||||
if order.OrderStatus != model.OrderStatusDelivered || order.FailureReason != "" {
|
||||
t.Fatalf("success should clear order failure reason, got %+v", order)
|
||||
}
|
||||
if strings.Contains(order.ResultData, "fail_reason") {
|
||||
|
||||
Reference in New Issue
Block a user