功能:发货链接支持永久有效,默认 TTL=0
- DELIVERY_LINK_TTL_MINUTES 设为 0 或负数时链接永久有效(expires_at 存 NULL), 默认值由 120 改为 0,本地 .env 同步改为永久 - 新增 delivery_link_generated_at 列区分从未生成与永久链接,兼容历史数据 - 永久链接授权仅校验 HMAC 签名、不校验过期(exp=0),作废/恢复语义不变 - 前端链接有效期列对永久链接显示"永久有效"
This commit is contained in:
@@ -179,6 +179,71 @@ func TestDeliveryLinkAfterDeliveredReusesButNeverGenerates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliveryLinkPermanentWhenTTLZero(t *testing.T) {
|
||||
db := newServiceTestDB(t)
|
||||
merchantID, product := seedFulfillmentMerchant(t, db, "delivery-permanent", 5000, 5, 100)
|
||||
fulfillmentSvc := NewFulfillmentService(db, nil)
|
||||
deliverySvc := NewDeliveryService(fulfillmentSvc, "https://bff.example", "dlc", "https://shop.example", "link-secret", 0)
|
||||
|
||||
created, err := fulfillmentSvc.CreateOrder(CreateFulfillmentOrderInput{
|
||||
MerchantID: merchantID,
|
||||
APIClientID: 1,
|
||||
ClientOrderNo: "delivery-permanent-001",
|
||||
SKU: product.SKU,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create order: %v", err)
|
||||
}
|
||||
link, err := deliverySvc.GetOrCreateDeliveryLink(merchantID, created.Order.OrderNo, "https://shop.example")
|
||||
if err != nil {
|
||||
t.Fatalf("get delivery link: %v", err)
|
||||
}
|
||||
if link.ExpiresAt != nil || link.Exp != 0 {
|
||||
t.Fatalf("permanent link should have nil expires_at and exp=0, got %+v", link)
|
||||
}
|
||||
// 永久链接授权通过(不校验过期)。
|
||||
if _, err := deliverySvc.GetOrder(created.Order.OrderNo, DeliveryLinkAuth{Exp: link.Exp, Sign: link.Sign}); err != nil {
|
||||
t.Fatalf("permanent link should authorize: %v", err)
|
||||
}
|
||||
// 数据库中 expires_at 为 NULL、generated_at 已记录。
|
||||
var order model.FulfillmentOrder
|
||||
if err := db.Where("order_no = ?", created.Order.OrderNo).First(&order).Error; err != nil {
|
||||
t.Fatalf("reload order: %v", err)
|
||||
}
|
||||
if order.DeliveryLinkExpiresAt != nil {
|
||||
t.Fatalf("permanent link should store NULL expires_at, got %v", *order.DeliveryLinkExpiresAt)
|
||||
}
|
||||
if order.DeliveryLinkGeneratedAt == nil {
|
||||
t.Fatalf("permanent link should record generated_at")
|
||||
}
|
||||
// 再次获取直接复用,URL 与签名保持稳定。
|
||||
reused, err := deliverySvc.GetOrCreateDeliveryLink(merchantID, created.Order.OrderNo, "https://shop.example")
|
||||
if err != nil {
|
||||
t.Fatalf("reuse permanent link: %v", err)
|
||||
}
|
||||
if reused.DeliveryURL != link.DeliveryURL || reused.Exp != link.Exp {
|
||||
t.Fatalf("permanent link should be stable, got %+v", reused)
|
||||
}
|
||||
// 作废后永久链接立即失效。
|
||||
if err := deliverySvc.RevokeDeliveryLink(merchantID, 1, created.Order.OrderNo); err != nil {
|
||||
t.Fatalf("revoke: %v", err)
|
||||
}
|
||||
if _, err := deliverySvc.GetOrder(created.Order.OrderNo, DeliveryLinkAuth{Exp: link.Exp, Sign: link.Sign}); err == nil {
|
||||
t.Fatalf("revoked permanent link should be rejected")
|
||||
}
|
||||
// 恢复后重新变为永久有效。
|
||||
restored, err := deliverySvc.RestoreDeliveryLink(merchantID, 1, created.Order.OrderNo, "https://shop.example")
|
||||
if err != nil {
|
||||
t.Fatalf("restore permanent link: %v", err)
|
||||
}
|
||||
if restored.ExpiresAt != nil {
|
||||
t.Fatalf("restored permanent link should keep nil expires_at, got %v", restored.ExpiresAt)
|
||||
}
|
||||
if _, err := deliverySvc.GetOrder(created.Order.OrderNo, DeliveryLinkAuth{Exp: restored.Exp, Sign: restored.Sign}); err != nil {
|
||||
t.Fatalf("restored permanent link should authorize: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliveryGoodIDIncludesMedalAndCoinProducts(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"honor_medal_x2": "682ef39ca8f40c4234c59f45",
|
||||
|
||||
Reference in New Issue
Block a user