Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
a0b5e5bf
Unverified
Commit
a0b5e5bf
authored
Apr 26, 2026
by
Wesley Liddick
Committed by
GitHub
Apr 26, 2026
Browse files
Merge pull request #1973 from Nobody-Zhang/main
fix(payment): 修复 Zpay 退款接口调用
parents
41d06573
1a0cabbf
Changes
2
Show whitespace changes
Inline
Side-by-side
backend/internal/payment/provider/easypay.go
View file @
a0b5e5bf
...
@@ -25,6 +25,7 @@ const (
...
@@ -25,6 +25,7 @@ const (
easypayStatusPaid
=
1
easypayStatusPaid
=
1
easypayHTTPTimeout
=
10
*
time
.
Second
easypayHTTPTimeout
=
10
*
time
.
Second
maxEasypayResponseSize
=
1
<<
20
// 1MB
maxEasypayResponseSize
=
1
<<
20
// 1MB
maxEasypayErrorSummary
=
512
tradeStatusSuccess
=
"TRADE_SUCCESS"
tradeStatusSuccess
=
"TRADE_SUCCESS"
signTypeMD5
=
"MD5"
signTypeMD5
=
"MD5"
paymentModePopup
=
"popup"
paymentModePopup
=
"popup"
...
@@ -42,17 +43,55 @@ type EasyPay struct {
...
@@ -42,17 +43,55 @@ type EasyPay struct {
// config keys: pid, pkey, apiBase, notifyUrl, returnUrl, cid, cidAlipay, cidWxpay
// config keys: pid, pkey, apiBase, notifyUrl, returnUrl, cid, cidAlipay, cidWxpay
func
NewEasyPay
(
instanceID
string
,
config
map
[
string
]
string
)
(
*
EasyPay
,
error
)
{
func
NewEasyPay
(
instanceID
string
,
config
map
[
string
]
string
)
(
*
EasyPay
,
error
)
{
for
_
,
k
:=
range
[]
string
{
"pid"
,
"pkey"
,
"apiBase"
,
"notifyUrl"
,
"returnUrl"
}
{
for
_
,
k
:=
range
[]
string
{
"pid"
,
"pkey"
,
"apiBase"
,
"notifyUrl"
,
"returnUrl"
}
{
if
config
[
k
]
==
""
{
if
strings
.
TrimSpace
(
config
[
k
]
)
==
""
{
return
nil
,
fmt
.
Errorf
(
"easypay config missing required key: %s"
,
k
)
return
nil
,
fmt
.
Errorf
(
"easypay config missing required key: %s"
,
k
)
}
}
}
}
cfg
:=
make
(
map
[
string
]
string
,
len
(
config
))
for
k
,
v
:=
range
config
{
cfg
[
k
]
=
v
}
cfg
[
"apiBase"
]
=
normalizeEasyPayAPIBase
(
cfg
[
"apiBase"
])
return
&
EasyPay
{
return
&
EasyPay
{
instanceID
:
instanceID
,
instanceID
:
instanceID
,
config
:
c
onfi
g
,
config
:
c
f
g
,
httpClient
:
&
http
.
Client
{
Timeout
:
easypayHTTPTimeout
},
httpClient
:
&
http
.
Client
{
Timeout
:
easypayHTTPTimeout
},
},
nil
},
nil
}
}
func
normalizeEasyPayAPIBase
(
apiBase
string
)
string
{
base
:=
strings
.
TrimSpace
(
apiBase
)
if
base
==
""
{
return
""
}
if
parsed
,
err
:=
url
.
Parse
(
base
);
err
==
nil
&&
parsed
.
Scheme
!=
""
&&
parsed
.
Host
!=
""
{
parsed
.
RawQuery
=
""
parsed
.
Fragment
=
""
parsed
.
RawPath
=
""
parsed
.
Path
=
trimEasyPayEndpointPath
(
parsed
.
Path
)
return
strings
.
TrimRight
(
parsed
.
String
(),
"/"
)
}
return
strings
.
TrimRight
(
trimEasyPayEndpointPath
(
base
),
"/"
)
}
func
trimEasyPayEndpointPath
(
path
string
)
string
{
path
=
strings
.
TrimRight
(
strings
.
TrimSpace
(
path
),
"/"
)
lower
:=
strings
.
ToLower
(
path
)
for
_
,
endpoint
:=
range
[]
string
{
"/submit.php"
,
"/mapi.php"
,
"/api.php"
}
{
if
strings
.
HasSuffix
(
lower
,
endpoint
)
{
return
strings
.
TrimRight
(
path
[
:
len
(
path
)
-
len
(
endpoint
)],
"/"
)
}
}
return
path
}
func
(
e
*
EasyPay
)
apiBase
()
string
{
if
e
==
nil
{
return
""
}
return
normalizeEasyPayAPIBase
(
e
.
config
[
"apiBase"
])
}
func
(
e
*
EasyPay
)
Name
()
string
{
return
"EasyPay"
}
func
(
e
*
EasyPay
)
Name
()
string
{
return
"EasyPay"
}
func
(
e
*
EasyPay
)
ProviderKey
()
string
{
return
payment
.
TypeEasyPay
}
func
(
e
*
EasyPay
)
ProviderKey
()
string
{
return
payment
.
TypeEasyPay
}
func
(
e
*
EasyPay
)
SupportedTypes
()
[]
payment
.
PaymentType
{
func
(
e
*
EasyPay
)
SupportedTypes
()
[]
payment
.
PaymentType
{
...
@@ -104,8 +143,7 @@ func (e *EasyPay) createRedirectPayment(req payment.CreatePaymentRequest) (*paym
...
@@ -104,8 +143,7 @@ func (e *EasyPay) createRedirectPayment(req payment.CreatePaymentRequest) (*paym
for
k
,
v
:=
range
params
{
for
k
,
v
:=
range
params
{
q
.
Set
(
k
,
v
)
q
.
Set
(
k
,
v
)
}
}
base
:=
strings
.
TrimRight
(
e
.
config
[
"apiBase"
],
"/"
)
payURL
:=
e
.
apiBase
()
+
"/submit.php?"
+
q
.
Encode
()
payURL
:=
base
+
"/submit.php?"
+
q
.
Encode
()
return
&
payment
.
CreatePaymentResponse
{
PayURL
:
payURL
},
nil
return
&
payment
.
CreatePaymentResponse
{
PayURL
:
payURL
},
nil
}
}
...
@@ -127,7 +165,7 @@ func (e *EasyPay) createAPIPayment(ctx context.Context, req payment.CreatePaymen
...
@@ -127,7 +165,7 @@ func (e *EasyPay) createAPIPayment(ctx context.Context, req payment.CreatePaymen
params
[
"sign"
]
=
easyPaySign
(
params
,
e
.
config
[
"pkey"
])
params
[
"sign"
]
=
easyPaySign
(
params
,
e
.
config
[
"pkey"
])
params
[
"sign_type"
]
=
signTypeMD5
params
[
"sign_type"
]
=
signTypeMD5
body
,
err
:=
e
.
post
(
ctx
,
strings
.
TrimRight
(
e
.
config
[
"apiBase"
],
"/"
)
+
"/mapi.php"
,
params
)
body
,
err
:=
e
.
post
(
ctx
,
e
.
apiBase
(
)
+
"/mapi.php"
,
params
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"easypay create: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"easypay create: %w"
,
err
)
}
}
...
@@ -171,7 +209,7 @@ func (e *EasyPay) QueryOrder(ctx context.Context, tradeNo string) (*payment.Quer
...
@@ -171,7 +209,7 @@ func (e *EasyPay) QueryOrder(ctx context.Context, tradeNo string) (*payment.Quer
"act"
:
"order"
,
"pid"
:
e
.
config
[
"pid"
],
"act"
:
"order"
,
"pid"
:
e
.
config
[
"pid"
],
"key"
:
e
.
config
[
"pkey"
],
"out_trade_no"
:
tradeNo
,
"key"
:
e
.
config
[
"pkey"
],
"out_trade_no"
:
tradeNo
,
}
}
body
,
err
:=
e
.
post
(
ctx
,
e
.
config
[
"
apiBase
"
]
+
"/api.php"
,
params
)
body
,
err
:=
e
.
post
(
ctx
,
e
.
apiBase
()
+
"/api.php"
,
params
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"easypay query: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"easypay query: %w"
,
err
)
}
}
...
@@ -234,25 +272,128 @@ func (e *EasyPay) VerifyNotification(_ context.Context, rawBody string, _ map[st
...
@@ -234,25 +272,128 @@ func (e *EasyPay) VerifyNotification(_ context.Context, rawBody string, _ map[st
}
}
func
(
e
*
EasyPay
)
Refund
(
ctx
context
.
Context
,
req
payment
.
RefundRequest
)
(
*
payment
.
RefundResponse
,
error
)
{
func
(
e
*
EasyPay
)
Refund
(
ctx
context
.
Context
,
req
payment
.
RefundRequest
)
(
*
payment
.
RefundResponse
,
error
)
{
params
:=
map
[
string
]
string
{
attempts
:=
e
.
refundAttempts
(
req
)
"pid"
:
e
.
config
[
"pid"
],
"key"
:
e
.
config
[
"pkey"
],
if
len
(
attempts
)
==
0
{
"trade_no"
:
req
.
TradeNo
,
"out_trade_no"
:
req
.
OrderID
,
"money"
:
req
.
Amount
,
return
nil
,
fmt
.
Errorf
(
"easypay refund missing order identifier"
)
}
}
body
,
err
:=
e
.
post
(
ctx
,
e
.
config
[
"apiBase"
]
+
"/api.php?act=refund"
,
params
)
var
firstErr
error
for
i
,
attempt
:=
range
attempts
{
body
,
status
,
err
:=
e
.
postRaw
(
ctx
,
e
.
apiBase
()
+
"/api.php?act=refund"
,
attempt
.
params
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"easypay refund: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"easypay refund request: %w"
,
err
)
}
if
err
:=
parseEasyPayRefundResponse
(
status
,
body
);
err
!=
nil
{
if
firstErr
==
nil
{
firstErr
=
err
}
}
if
i
+
1
<
len
(
attempts
)
&&
isEasyPayRefundOrderNotFound
(
err
)
{
continue
}
return
nil
,
err
}
return
&
payment
.
RefundResponse
{
RefundID
:
attempt
.
refundID
,
Status
:
payment
.
ProviderStatusSuccess
},
nil
}
return
nil
,
firstErr
}
type
easyPayRefundAttempt
struct
{
params
map
[
string
]
string
refundID
string
}
func
(
e
*
EasyPay
)
refundAttempts
(
req
payment
.
RefundRequest
)
[]
easyPayRefundAttempt
{
base
:=
map
[
string
]
string
{
"pid"
:
e
.
config
[
"pid"
],
"key"
:
e
.
config
[
"pkey"
],
"money"
:
req
.
Amount
,
}
var
attempts
[]
easyPayRefundAttempt
if
orderID
:=
strings
.
TrimSpace
(
req
.
OrderID
);
orderID
!=
""
{
params
:=
cloneStringMap
(
base
)
params
[
"out_trade_no"
]
=
orderID
attempts
=
append
(
attempts
,
easyPayRefundAttempt
{
params
:
params
,
refundID
:
orderID
})
}
if
tradeNo
:=
strings
.
TrimSpace
(
req
.
TradeNo
);
tradeNo
!=
""
{
params
:=
cloneStringMap
(
base
)
params
[
"trade_no"
]
=
tradeNo
attempts
=
append
(
attempts
,
easyPayRefundAttempt
{
params
:
params
,
refundID
:
tradeNo
})
}
return
attempts
}
func
cloneStringMap
(
in
map
[
string
]
string
)
map
[
string
]
string
{
out
:=
make
(
map
[
string
]
string
,
len
(
in
))
for
k
,
v
:=
range
in
{
out
[
k
]
=
v
}
return
out
}
func
isEasyPayRefundOrderNotFound
(
err
error
)
bool
{
if
err
==
nil
{
return
false
}
msg
:=
err
.
Error
()
lower
:=
strings
.
ToLower
(
msg
)
return
strings
.
Contains
(
msg
,
"订单编号不存在"
)
||
strings
.
Contains
(
msg
,
"订单不存在"
)
||
strings
.
Contains
(
lower
,
"order not found"
)
||
strings
.
Contains
(
lower
,
"not exist"
)
}
func
parseEasyPayRefundResponse
(
status
int
,
body
[]
byte
)
error
{
summary
:=
summarizeEasyPayResponse
(
body
)
if
status
<
http
.
StatusOK
||
status
>=
http
.
StatusMultipleChoices
{
return
fmt
.
Errorf
(
"easypay refund HTTP %d: %s"
,
status
,
summary
)
}
trimmed
:=
strings
.
TrimSpace
(
string
(
body
))
if
trimmed
==
""
{
return
fmt
.
Errorf
(
"easypay refund empty response (HTTP %d): %s"
,
status
,
summary
)
}
lower
:=
strings
.
ToLower
(
trimmed
)
if
strings
.
HasPrefix
(
lower
,
"<!doctype html"
)
||
strings
.
HasPrefix
(
lower
,
"<html"
)
||
(
strings
.
HasPrefix
(
lower
,
"<"
)
&&
strings
.
Contains
(
lower
,
"html"
))
{
return
fmt
.
Errorf
(
"easypay refund non-JSON response (HTTP %d): %s"
,
status
,
summary
)
}
var
resp
struct
{
var
resp
struct
{
Code
int
`json:"code"`
Code
any
`json:"code"`
Msg
string
`json:"msg"`
Msg
string
`json:"msg"`
}
}
if
err
:=
json
.
Unmarshal
(
body
,
&
resp
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
(
body
,
&
resp
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"easypay
parse
refund: %
w
"
,
err
)
return
fmt
.
Errorf
(
"easypay refund
non-JSON response (HTTP %d)
: %
s
"
,
status
,
summary
)
}
}
if
resp
.
Code
!=
easypayCodeSuccess
{
if
!
easyPayResponseCodeIsSuccess
(
resp
.
Code
)
{
return
nil
,
fmt
.
Errorf
(
"easypay refund failed: %s"
,
resp
.
Msg
)
msg
:=
strings
.
TrimSpace
(
resp
.
Msg
)
if
msg
==
""
{
msg
=
summary
}
return
fmt
.
Errorf
(
"easypay refund failed (HTTP %d): %s"
,
status
,
msg
)
}
return
nil
}
func
easyPayResponseCodeIsSuccess
(
code
any
)
bool
{
switch
v
:=
code
.
(
type
)
{
case
float64
:
return
int
(
v
)
==
easypayCodeSuccess
case
string
:
n
,
err
:=
strconv
.
Atoi
(
strings
.
TrimSpace
(
v
))
return
err
==
nil
&&
n
==
easypayCodeSuccess
default
:
return
false
}
}
return
&
payment
.
RefundResponse
{
RefundID
:
req
.
TradeNo
,
Status
:
payment
.
ProviderStatusSuccess
},
nil
}
func
summarizeEasyPayResponse
(
body
[]
byte
)
string
{
summary
:=
strings
.
Join
(
strings
.
Fields
(
string
(
body
)),
" "
)
if
summary
==
""
{
return
"<empty>"
}
if
len
(
summary
)
>
maxEasypayErrorSummary
{
return
summary
[
:
maxEasypayErrorSummary
]
+
"..."
}
return
summary
}
}
func
(
e
*
EasyPay
)
resolveCID
(
paymentType
string
)
string
{
func
(
e
*
EasyPay
)
resolveCID
(
paymentType
string
)
string
{
...
@@ -269,21 +410,34 @@ func (e *EasyPay) resolveCID(paymentType string) string {
...
@@ -269,21 +410,34 @@ func (e *EasyPay) resolveCID(paymentType string) string {
}
}
func
(
e
*
EasyPay
)
post
(
ctx
context
.
Context
,
endpoint
string
,
params
map
[
string
]
string
)
([]
byte
,
error
)
{
func
(
e
*
EasyPay
)
post
(
ctx
context
.
Context
,
endpoint
string
,
params
map
[
string
]
string
)
([]
byte
,
error
)
{
body
,
_
,
err
:=
e
.
postRaw
(
ctx
,
endpoint
,
params
)
return
body
,
err
}
func
(
e
*
EasyPay
)
postRaw
(
ctx
context
.
Context
,
endpoint
string
,
params
map
[
string
]
string
)
([]
byte
,
int
,
error
)
{
form
:=
url
.
Values
{}
form
:=
url
.
Values
{}
for
k
,
v
:=
range
params
{
for
k
,
v
:=
range
params
{
form
.
Set
(
k
,
v
)
form
.
Set
(
k
,
v
)
}
}
req
,
err
:=
http
.
NewRequestWithContext
(
ctx
,
http
.
MethodPost
,
endpoint
,
strings
.
NewReader
(
form
.
Encode
()))
req
,
err
:=
http
.
NewRequestWithContext
(
ctx
,
http
.
MethodPost
,
endpoint
,
strings
.
NewReader
(
form
.
Encode
()))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
0
,
err
}
}
req
.
Header
.
Set
(
"Content-Type"
,
"application/x-www-form-urlencoded"
)
req
.
Header
.
Set
(
"Content-Type"
,
"application/x-www-form-urlencoded"
)
resp
,
err
:=
e
.
httpClient
.
Do
(
req
)
client
:=
e
.
httpClient
if
client
==
nil
{
client
=
&
http
.
Client
{
Timeout
:
easypayHTTPTimeout
}
}
resp
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
0
,
err
}
}
defer
func
()
{
_
=
resp
.
Body
.
Close
()
}()
defer
func
()
{
_
=
resp
.
Body
.
Close
()
}()
return
io
.
ReadAll
(
io
.
LimitReader
(
resp
.
Body
,
maxEasypayResponseSize
))
body
,
err
:=
io
.
ReadAll
(
io
.
LimitReader
(
resp
.
Body
,
maxEasypayResponseSize
))
if
err
!=
nil
{
return
nil
,
resp
.
StatusCode
,
err
}
return
body
,
resp
.
StatusCode
,
nil
}
}
func
easyPaySign
(
params
map
[
string
]
string
,
pkey
string
)
string
{
func
easyPaySign
(
params
map
[
string
]
string
,
pkey
string
)
string
{
...
...
backend/internal/payment/provider/easypay_refund_test.go
0 → 100644
View file @
a0b5e5bf
package
provider
import
(
"context"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/Wei-Shaw/sub2api/internal/payment"
)
func
TestNormalizeEasyPayAPIBase
(
t
*
testing
.
T
)
{
t
.
Parallel
()
tests
:=
[]
struct
{
input
string
want
string
}{
{
input
:
"https://zpayz.cn"
,
want
:
"https://zpayz.cn"
},
{
input
:
"https://zpayz.cn/"
,
want
:
"https://zpayz.cn"
},
{
input
:
"https://zpayz.cn/mapi.php"
,
want
:
"https://zpayz.cn"
},
{
input
:
"https://zpayz.cn/submit.php"
,
want
:
"https://zpayz.cn"
},
{
input
:
"https://zpayz.cn/api.php"
,
want
:
"https://zpayz.cn"
},
{
input
:
"https://zpayz.cn/api.php?act=refund"
,
want
:
"https://zpayz.cn"
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
input
,
func
(
t
*
testing
.
T
)
{
t
.
Parallel
()
if
got
:=
normalizeEasyPayAPIBase
(
tt
.
input
);
got
!=
tt
.
want
{
t
.
Fatalf
(
"normalizeEasyPayAPIBase(%q) = %q, want %q"
,
tt
.
input
,
got
,
tt
.
want
)
}
})
}
}
func
TestEasyPayRefundNormalizesAPIBaseAndSendsOutTradeNoOnly
(
t
*
testing
.
T
)
{
t
.
Parallel
()
var
gotPath
string
var
gotQuery
url
.
Values
var
gotForm
url
.
Values
server
:=
httptest
.
NewServer
(
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
gotPath
=
r
.
URL
.
Path
gotQuery
=
r
.
URL
.
Query
()
if
err
:=
r
.
ParseForm
();
err
!=
nil
{
t
.
Errorf
(
"ParseForm: %v"
,
err
)
}
gotForm
=
r
.
PostForm
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
_
,
_
=
w
.
Write
([]
byte
(
`{"code":1,"msg":"ok"}`
))
}))
defer
server
.
Close
()
provider
:=
newTestEasyPay
(
t
,
server
.
URL
+
"/mapi.php"
)
resp
,
err
:=
provider
.
Refund
(
context
.
Background
(),
payment
.
RefundRequest
{
TradeNo
:
"trade-123"
,
OrderID
:
"out-456"
,
Amount
:
"1.50"
,
})
if
err
!=
nil
{
t
.
Fatalf
(
"Refund returned error: %v"
,
err
)
}
if
resp
==
nil
||
resp
.
Status
!=
payment
.
ProviderStatusSuccess
{
t
.
Fatalf
(
"Refund response = %+v, want success"
,
resp
)
}
if
gotPath
!=
"/api.php"
{
t
.
Fatalf
(
"refund path = %q, want /api.php"
,
gotPath
)
}
if
gotQuery
.
Get
(
"act"
)
!=
"refund"
{
t
.
Fatalf
(
"refund act query = %q, want refund"
,
gotQuery
.
Get
(
"act"
))
}
for
key
,
want
:=
range
map
[
string
]
string
{
"pid"
:
"pid-1"
,
"key"
:
"pkey-1"
,
"out_trade_no"
:
"out-456"
,
"money"
:
"1.50"
,
}
{
if
got
:=
gotForm
.
Get
(
key
);
got
!=
want
{
t
.
Fatalf
(
"form[%s] = %q, want %q (form=%v)"
,
key
,
got
,
want
,
gotForm
)
}
}
if
got
:=
gotForm
.
Get
(
"trade_no"
);
got
!=
""
{
t
.
Fatalf
(
"form[trade_no] = %q, want empty (form=%v)"
,
got
,
gotForm
)
}
}
func
TestEasyPayRefundRetriesWithTradeNoWhenOutTradeNoNotFound
(
t
*
testing
.
T
)
{
t
.
Parallel
()
var
gotForms
[]
url
.
Values
server
:=
httptest
.
NewServer
(
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
r
.
URL
.
Path
!=
"/api.php"
{
t
.
Errorf
(
"refund path = %q, want /api.php"
,
r
.
URL
.
Path
)
}
if
r
.
URL
.
Query
()
.
Get
(
"act"
)
!=
"refund"
{
t
.
Errorf
(
"refund act query = %q, want refund"
,
r
.
URL
.
Query
()
.
Get
(
"act"
))
}
if
err
:=
r
.
ParseForm
();
err
!=
nil
{
t
.
Errorf
(
"ParseForm: %v"
,
err
)
}
gotForms
=
append
(
gotForms
,
r
.
PostForm
)
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
if
len
(
gotForms
)
==
1
{
_
,
_
=
w
.
Write
([]
byte
(
`{"code":0,"msg":"订单编号不存在!"}`
))
return
}
_
,
_
=
w
.
Write
([]
byte
(
`{"code":1,"msg":"ok"}`
))
}))
defer
server
.
Close
()
provider
:=
newTestEasyPay
(
t
,
server
.
URL
+
"/mapi.php"
)
resp
,
err
:=
provider
.
Refund
(
context
.
Background
(),
payment
.
RefundRequest
{
TradeNo
:
"trade-123"
,
OrderID
:
"out-456"
,
Amount
:
"1.50"
,
})
if
err
!=
nil
{
t
.
Fatalf
(
"Refund returned error: %v"
,
err
)
}
if
resp
==
nil
||
resp
.
Status
!=
payment
.
ProviderStatusSuccess
||
resp
.
RefundID
!=
"trade-123"
{
t
.
Fatalf
(
"Refund response = %+v, want success with trade refund id"
,
resp
)
}
if
len
(
gotForms
)
!=
2
{
t
.
Fatalf
(
"refund attempts = %d, want 2"
,
len
(
gotForms
))
}
if
got
:=
gotForms
[
0
]
.
Get
(
"out_trade_no"
);
got
!=
"out-456"
{
t
.
Fatalf
(
"first form[out_trade_no] = %q, want out-456 (form=%v)"
,
got
,
gotForms
[
0
])
}
if
got
:=
gotForms
[
0
]
.
Get
(
"trade_no"
);
got
!=
""
{
t
.
Fatalf
(
"first form[trade_no] = %q, want empty (form=%v)"
,
got
,
gotForms
[
0
])
}
if
got
:=
gotForms
[
1
]
.
Get
(
"trade_no"
);
got
!=
"trade-123"
{
t
.
Fatalf
(
"second form[trade_no] = %q, want trade-123 (form=%v)"
,
got
,
gotForms
[
1
])
}
if
got
:=
gotForms
[
1
]
.
Get
(
"out_trade_no"
);
got
!=
""
{
t
.
Fatalf
(
"second form[out_trade_no] = %q, want empty (form=%v)"
,
got
,
gotForms
[
1
])
}
}
func
TestEasyPayRefundResponseErrors
(
t
*
testing
.
T
)
{
t
.
Parallel
()
tests
:=
[]
struct
{
name
string
statusCode
int
body
string
want
string
}{
{
name
:
"html response"
,
statusCode
:
http
.
StatusOK
,
body
:
"<html>bad config</html>"
,
want
:
"non-JSON response (HTTP 200): <html>bad config</html>"
},
{
name
:
"non json response"
,
statusCode
:
http
.
StatusOK
,
body
:
"not json"
,
want
:
"non-JSON response (HTTP 200): not json"
},
{
name
:
"non 2xx response"
,
statusCode
:
http
.
StatusBadGateway
,
body
:
"bad gateway"
,
want
:
"HTTP 502: bad gateway"
},
{
name
:
"empty response"
,
statusCode
:
http
.
StatusOK
,
body
:
""
,
want
:
"empty response (HTTP 200): <empty>"
},
}
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Parallel
()
server
:=
httptest
.
NewServer
(
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
_
*
http
.
Request
)
{
w
.
WriteHeader
(
tt
.
statusCode
)
_
,
_
=
w
.
Write
([]
byte
(
tt
.
body
))
}))
defer
server
.
Close
()
provider
:=
newTestEasyPay
(
t
,
server
.
URL
)
_
,
err
:=
provider
.
Refund
(
context
.
Background
(),
payment
.
RefundRequest
{
OrderID
:
"out-456"
,
Amount
:
"1.50"
,
})
if
err
==
nil
{
t
.
Fatal
(
"Refund returned nil error"
)
}
if
!
strings
.
Contains
(
err
.
Error
(),
tt
.
want
)
{
t
.
Fatalf
(
"Refund error = %q, want substring %q"
,
err
.
Error
(),
tt
.
want
)
}
})
}
}
func
newTestEasyPay
(
t
*
testing
.
T
,
apiBase
string
)
*
EasyPay
{
t
.
Helper
()
provider
,
err
:=
NewEasyPay
(
"test-instance"
,
map
[
string
]
string
{
"pid"
:
"pid-1"
,
"pkey"
:
"pkey-1"
,
"apiBase"
:
apiBase
,
"notifyUrl"
:
"https://example.com/notify"
,
"returnUrl"
:
"https://example.com/return"
,
})
if
err
!=
nil
{
t
.
Fatalf
(
"NewEasyPay: %v"
,
err
)
}
return
provider
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment