feat: 为订单表添加 app_account_token 字段并增强 Apple IAP 对账逻辑,支持通过交易历史记录查找。
Build docker and publish / build (20.15.1) (push) Successful in 7m25s
Build docker and publish / build (20.15.1) (push) Successful in 7m25s
This commit is contained in:
@@ -129,3 +129,78 @@ func GetTransactionInfo(cfg ServerAPIConfig, transactionId string) (string, erro
|
||||
}
|
||||
return "", fmt.Errorf("apple api error, primary[%d:%s], secondary[%d:%s]", code, body, code2, body2)
|
||||
}
|
||||
|
||||
// GetTransactionHistory 获取指定交易 ID 的完整交易历史(该用户的所有交易)
|
||||
// Apple API: GET /inApps/v2/history/{transactionId}
|
||||
// 返回所有交易的 JWS 列表
|
||||
func GetTransactionHistory(cfg ServerAPIConfig, transactionId string) ([]string, error) {
|
||||
token, err := buildAPIToken(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fetchPage := func(host, revision string) ([]string, string, bool, int, error) {
|
||||
url := fmt.Sprintf("%s/inApps/v2/history/%s?sort=DESCENDING", host, transactionId)
|
||||
if revision != "" {
|
||||
url += "&revision=" + revision
|
||||
}
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, "", false, 0, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(resp.Body)
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, "", false, resp.StatusCode, fmt.Errorf("apple api error: %d %s", resp.StatusCode, buf.String())
|
||||
}
|
||||
var result struct {
|
||||
SignedTransactions []string `json:"signedTransactions"`
|
||||
Revision string `json:"revision"`
|
||||
HasMore bool `json:"hasMore"`
|
||||
}
|
||||
if err := json.Unmarshal(buf.Bytes(), &result); err != nil {
|
||||
return nil, "", false, resp.StatusCode, err
|
||||
}
|
||||
return result.SignedTransactions, result.Revision, result.HasMore, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
primary := "https://api.storekit.itunes.apple.com"
|
||||
secondary := "https://api.storekit-sandbox.itunes.apple.com"
|
||||
if cfg.Sandbox {
|
||||
primary, secondary = secondary, primary
|
||||
}
|
||||
|
||||
// 尝试 primary 环境
|
||||
var allTx []string
|
||||
revision := ""
|
||||
for {
|
||||
txs, rev, hasMore, _, err := fetchPage(primary, revision)
|
||||
if err != nil {
|
||||
break // primary 失败,尝试 secondary
|
||||
}
|
||||
allTx = append(allTx, txs...)
|
||||
if !hasMore || rev == "" {
|
||||
return allTx, nil
|
||||
}
|
||||
revision = rev
|
||||
}
|
||||
|
||||
// Fallback: secondary 环境
|
||||
allTx = nil
|
||||
revision = ""
|
||||
for {
|
||||
txs, rev, hasMore, code, err := fetchPage(secondary, revision)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("both environments failed, secondary[%d]: %v", code, err)
|
||||
}
|
||||
allTx = append(allTx, txs...)
|
||||
if !hasMore || rev == "" {
|
||||
return allTx, nil
|
||||
}
|
||||
revision = rev
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user