feat: support expiring cashier sessions

This commit is contained in:
shiran
2026-07-21 17:53:25 +08:00
parent 0fd4b6cf16
commit 653f380051
4 changed files with 23 additions and 6 deletions
+2
View File
@@ -53,12 +53,14 @@ func main() {
ClientType: "pc", ClientType: "pc",
NotifyURL: "https://merchant.example.com/pay/notify", NotifyURL: "https://merchant.example.com/pay/notify",
ReturnURL: "https://merchant.example.com/pay/return", ReturnURL: "https://merchant.example.com/pay/return",
ExpireTime: "15", // 可选,分钟数或绝对时间;默认 10 分钟
}) })
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
fmt.Println(order.CashierURL) fmt.Println(order.CashierURL)
fmt.Println(order.ExpireTime, order.PageToken)
} }
``` ```
+8 -2
View File
@@ -32,6 +32,9 @@ func TestSubmitPostsSignedForm(t *testing.T) {
if params["sign_type"] != "MD5" { if params["sign_type"] != "MD5" {
t.Fatalf("sign_type = %s", params["sign_type"]) t.Fatalf("sign_type = %s", params["sign_type"])
} }
if params["expire_time"] != "15" {
t.Fatalf("expire_time = %s", params["expire_time"])
}
if !VerifySign(params, "secret") { if !VerifySign(params, "secret") {
t.Fatalf("invalid sign: %s", params["sign"]) t.Fatalf("invalid sign: %s", params["sign"])
} }
@@ -43,7 +46,9 @@ func TestSubmitPostsSignedForm(t *testing.T) {
"order_no": "P123", "order_no": "P123",
"out_trade_no": params["out_trade_no"], "out_trade_no": params["out_trade_no"],
"amount": 100, "amount": 100,
"cashier_url": "http://pay.test/cashier/?orderNo=P123", "cashier_url": "http://pay.test/cashier/P123",
"expire_time": "2026-07-21T10:15:00+08:00",
"page_token": "page-token-1",
}, },
}) })
})) }))
@@ -59,11 +64,12 @@ func TestSubmitPostsSignedForm(t *testing.T) {
Name: "test", Name: "test",
Money: "1.00", Money: "1.00",
Type: "alipay", Type: "alipay",
ExpireTime: "15",
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if resp.OrderNo != "P123" || resp.Amount != 100 { if resp.OrderNo != "P123" || resp.Amount != 100 || resp.PageToken != "page-token-1" || resp.ExpireTime == nil {
t.Fatalf("unexpected response: %+v", resp) t.Fatalf("unexpected response: %+v", resp)
} }
} }
+1
View File
@@ -91,6 +91,7 @@ func submit(cfg globalConfig, args []string) error {
fs.StringVar(&req.ReturnURL, "return-url", "", "merchant sync return URL") fs.StringVar(&req.ReturnURL, "return-url", "", "merchant sync return URL")
fs.StringVar(&req.Body, "body", "", "order description") fs.StringVar(&req.Body, "body", "", "order description")
fs.StringVar(&req.Attach, "attach", "", "extra data") fs.StringVar(&req.Attach, "attach", "", "extra data")
fs.StringVar(&req.ExpireTime, "expire-time", "", "order lifetime in minutes or an absolute expiration time (default 10 minutes)")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} }
+12 -4
View File
@@ -20,6 +20,9 @@ type SubmitRequest struct {
ReturnURL string ReturnURL string
Body string Body string
Attach string Attach string
// ExpireTime accepts a positive lifetime in minutes, RFC3339, or YYYY-MM-DD HH:mm:ss.
// Empty uses the platform default of 10 minutes.
ExpireTime string
} }
func (r SubmitRequest) params() map[string]string { func (r SubmitRequest) params() map[string]string {
@@ -33,14 +36,17 @@ func (r SubmitRequest) params() map[string]string {
"return_url": r.ReturnURL, "return_url": r.ReturnURL,
"body": r.Body, "body": r.Body,
"attach": r.Attach, "attach": r.Attach,
"expire_time": r.ExpireTime,
}) })
} }
type SubmitResponse struct { type SubmitResponse struct {
OrderNo string `json:"order_no"` OrderNo string `json:"order_no"`
OutTradeNo string `json:"out_trade_no"` OutTradeNo string `json:"out_trade_no"`
Amount int64 `json:"amount"` Amount int64 `json:"amount"`
CashierURL string `json:"cashier_url"` CashierURL string `json:"cashier_url"`
ExpireTime *time.Time `json:"expire_time"`
PageToken string `json:"page_token"`
} }
type QueryRequest struct { type QueryRequest struct {
@@ -64,6 +70,7 @@ type QueryResponse struct {
Completed bool `json:"completed"` Completed bool `json:"completed"`
ChannelChecked bool `json:"channel_checked"` ChannelChecked bool `json:"channel_checked"`
PaidAt *time.Time `json:"paid_at"` PaidAt *time.Time `json:"paid_at"`
ExpireTime *time.Time `json:"expire_time"`
} }
type RefundRequest struct { type RefundRequest struct {
@@ -128,6 +135,7 @@ type Order struct {
IsManual bool `json:"is_manual"` IsManual bool `json:"is_manual"`
PaidAt *time.Time `json:"paid_at"` PaidAt *time.Time `json:"paid_at"`
CreatedAt *time.Time `json:"created_at"` CreatedAt *time.Time `json:"created_at"`
ExpireTime *time.Time `json:"expire_time"`
} }
type ManualRequest struct { type ManualRequest struct {