修复 Context 改造后的编译问题
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package e2e
|
package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@@ -45,7 +46,7 @@ func TestRentalFullFlowWithMockPayment(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
orderDTO := mustCreateOrder(t, services.order, renter.ID, adjusted.ID)
|
orderDTO := mustCreateOrder(t, services.order, renter.ID, adjusted.ID)
|
||||||
paymentDTO, err := services.payment.Start(renter.ID, orderDTO.ID, payment.StartPaymentRequest{}, "127.0.0.1")
|
paymentDTO, err := services.payment.Start(t.Context(), renter.ID, orderDTO.ID, payment.StartPaymentRequest{}, "127.0.0.1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("启动 mock 支付失败: %v", err)
|
t.Fatalf("启动 mock 支付失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -115,7 +116,7 @@ func TestArbitrationReleaseDepositDoesNotRepublishListing(t *testing.T) {
|
|||||||
listingDTO := createListingUnderReview(t, services.listing, owner.ID)
|
listingDTO := createListingUnderReview(t, services.listing, owner.ID)
|
||||||
approved := adjustAndApproveListing(t, services.listing, adminID, listingDTO.ID)
|
approved := adjustAndApproveListing(t, services.listing, adminID, listingDTO.ID)
|
||||||
orderDTO := mustCreateOrder(t, services.order, renter.ID, approved.ID)
|
orderDTO := mustCreateOrder(t, services.order, renter.ID, approved.ID)
|
||||||
if _, err := services.payment.Start(renter.ID, orderDTO.ID, payment.StartPaymentRequest{}, "127.0.0.1"); err != nil {
|
if _, err := services.payment.Start(t.Context(), renter.ID, orderDTO.ID, payment.StartPaymentRequest{}, "127.0.0.1"); err != nil {
|
||||||
t.Fatalf("启动 mock 支付失败: %v", err)
|
t.Fatalf("启动 mock 支付失败: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := services.order.SubmitHandoff(owner.ID, orderDTO.ID, order.SubmitHandoffRequest{Content: "账号:demo,密码:demo-pass"}); err != nil {
|
if _, err := services.order.SubmitHandoff(owner.ID, orderDTO.ID, order.SubmitHandoffRequest{Content: "账号:demo,密码:demo-pass"}); err != nil {
|
||||||
@@ -171,7 +172,7 @@ func TestArbitrationReleaseDepositDoesNotRepublishListing(t *testing.T) {
|
|||||||
assertEqual(t, "仲裁退款状态", orderRow.RefundStatus, "refunded")
|
assertEqual(t, "仲裁退款状态", orderRow.RefundStatus, "refunded")
|
||||||
assertEqual(t, "仲裁退款金额", orderRow.RefundAmountCent, int64(15000))
|
assertEqual(t, "仲裁退款金额", orderRow.RefundAmountCent, int64(15000))
|
||||||
|
|
||||||
walletAccount, err := services.wallet.Account(owner.ID)
|
walletAccount, err := services.wallet.Account(t.Context(), owner.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("读取号主钱包失败: %v", err)
|
t.Fatalf("读取号主钱包失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -209,14 +210,14 @@ func newFlowServices(db *gorm.DB) flowServices {
|
|||||||
paymentRepo := payment.NewRepository(db, configRepo, orderRepo, walletRepo)
|
paymentRepo := payment.NewRepository(db, configRepo, orderRepo, walletRepo)
|
||||||
disputeRepo := dispute.NewRepository(db)
|
disputeRepo := dispute.NewRepository(db)
|
||||||
orderRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
orderRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
||||||
refund, err := paymentRepo.StartRefund(orderID, refundAmountCent, bizType, remark)
|
refund, err := paymentRepo.StartRefund(context.Background(), orderID, refundAmountCent, bizType, remark)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return refund.Status, nil
|
return refund.Status, nil
|
||||||
})
|
})
|
||||||
disputeRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
disputeRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
||||||
refund, err := paymentRepo.StartRefund(orderID, refundAmountCent, bizType, remark)
|
refund, err := paymentRepo.StartRefund(context.Background(), orderID, refundAmountCent, bizType, remark)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -238,7 +239,7 @@ func newFlowServices(db *gorm.DB) flowServices {
|
|||||||
|
|
||||||
type fixedConfig map[string]string
|
type fixedConfig map[string]string
|
||||||
|
|
||||||
func (c fixedConfig) FindValue(key string) (string, error) {
|
func (c fixedConfig) FindValue(ctx context.Context, key string) (string, error) {
|
||||||
return c[key], nil
|
return c[key], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +393,7 @@ func createOwnerPaymentAccount(t *testing.T, service *paymentaccount.Service, ow
|
|||||||
|
|
||||||
func createListingUnderReview(t *testing.T, service *listing.Service, ownerID uint64) *listing.ListingDTO {
|
func createListingUnderReview(t *testing.T, service *listing.Service, ownerID uint64) *listing.ListingDTO {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dto, err := service.Create(ownerID, listing.CreateRequest{
|
dto, err := service.Create(t.Context(), ownerID, listing.CreateRequest{
|
||||||
Title: "E2E 烽火地带账号",
|
Title: "E2E 烽火地带账号",
|
||||||
Description: "用于完整链路测试",
|
Description: "用于完整链路测试",
|
||||||
ServerRegion: "烽火地带",
|
ServerRegion: "烽火地带",
|
||||||
@@ -490,7 +491,7 @@ func assertFinanceDashboard(t *testing.T, service *adminfinance.Service, orderNo
|
|||||||
|
|
||||||
func assertWalletAndWithdrawal(t *testing.T, walletService *wallet.Service, withdrawalService *withdrawal.Service, ownerID uint64, adminID uint64, paymentAccountID uint64) {
|
func assertWalletAndWithdrawal(t *testing.T, walletService *wallet.Service, withdrawalService *withdrawal.Service, ownerID uint64, adminID uint64, paymentAccountID uint64) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
accountBefore, err := walletService.Account(ownerID)
|
accountBefore, err := walletService.Account(t.Context(), ownerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("读取号主钱包失败: %v", err)
|
t.Fatalf("读取号主钱包失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -525,7 +526,7 @@ func assertWalletAndWithdrawal(t *testing.T, walletService *wallet.Service, with
|
|||||||
assertEqual(t, "提现完成状态", paid.Status, "completed")
|
assertEqual(t, "提现完成状态", paid.Status, "completed")
|
||||||
assertEqual(t, "提现到账金额", paid.ActualAmountCent, int64(10000))
|
assertEqual(t, "提现到账金额", paid.ActualAmountCent, int64(10000))
|
||||||
|
|
||||||
accountAfter, err := walletService.Account(ownerID)
|
accountAfter, err := walletService.Account(t.Context(), ownerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("读取提现后钱包失败: %v", err)
|
t.Fatalf("读取提现后钱包失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func NewHandler(service *Service) *Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Captcha(c *gin.Context) {
|
func (h *Handler) Captcha(c *gin.Context) {
|
||||||
item, err := h.service.Captcha(c.Request.Context(), )
|
item, err := h.service.Captcha(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeAdminAuthError(c, err)
|
writeAdminAuthError(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ func (s *Service) Refresh(ctx context.Context, refreshToken string) (*auth.Token
|
|||||||
return &pair, nil
|
return &pair, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Captcha(ctx context.Context, ) (*CaptchaDTO, error) {
|
func (s *Service) Captcha(ctx context.Context) (*CaptchaDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
return s.repo.Captcha(ctx, )
|
return s.repo.Captcha(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Login(ctx context.Context, username string, password string, captchaID string, captchaCode string) (LoginResult, error) {
|
func (s *Service) Login(ctx context.Context, username string, password string, captchaID string, captchaCode string) (LoginResult, error) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func (h *Handler) Create(c *gin.Context) {
|
|||||||
response.BadRequest(c, "发布信息不完整")
|
response.BadRequest(c, "发布信息不完整")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.Create(ownerID, req)
|
item, err := h.service.Create(c.Request.Context(), ownerID, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeListingError(c, err)
|
writeListingError(c, err)
|
||||||
return
|
return
|
||||||
@@ -57,7 +57,7 @@ func (h *Handler) ImportExternalUpload(c *gin.Context) {
|
|||||||
response.BadRequest(c, "上传 JSON 格式不正确")
|
response.BadRequest(c, "上传 JSON 格式不正确")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result, err := h.service.ImportExternalUpload(req, ExternalUploadMeta{
|
result, err := h.service.ImportExternalUpload(c.Request.Context(), req, ExternalUploadMeta{
|
||||||
IP: c.ClientIP(),
|
IP: c.ClientIP(),
|
||||||
UserAgent: c.GetHeader("User-Agent"),
|
UserAgent: c.GetHeader("User-Agent"),
|
||||||
RawPayload: raw,
|
RawPayload: raw,
|
||||||
@@ -90,7 +90,7 @@ func (h *Handler) Update(c *gin.Context) {
|
|||||||
response.BadRequest(c, "发布信息不完整")
|
response.BadRequest(c, "发布信息不完整")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.Update(ownerID, id, req)
|
item, err := h.service.Update(c.Request.Context(), ownerID, id, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeListingError(c, err)
|
writeListingError(c, err)
|
||||||
return
|
return
|
||||||
@@ -108,7 +108,7 @@ func (h *Handler) SubmitReview(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.SubmitReview(ownerID, id)
|
item, err := h.service.SubmitReview(c.Request.Context(), ownerID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeListingError(c, err)
|
writeListingError(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package listing
|
package listing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -36,7 +37,7 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigReader interface {
|
type ConfigReader interface {
|
||||||
FindValue(key string) (string, error)
|
FindValue(ctx context.Context, key string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -77,28 +78,28 @@ func NewService(repo *Repository, config ConfigReader) *Service {
|
|||||||
return &Service{repo: repo, config: config}
|
return &Service{repo: repo, config: config}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Create(ownerID uint64, req CreateRequest) (*ListingDTO, error) {
|
func (s *Service) Create(ctx context.Context, ownerID uint64, req CreateRequest) (*ListingDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if !req.AgreedVirtualAssetSale || !req.AgreedSellerAgreement {
|
if !req.AgreedVirtualAssetSale || !req.AgreedSellerAgreement {
|
||||||
return nil, ErrAgreementRequired
|
return nil, ErrAgreementRequired
|
||||||
}
|
}
|
||||||
rules, err := s.publishRules()
|
rules, err := s.publishRules(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validateRequest(req, rules); err != nil {
|
if err := validateRequest(req, rules); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reviewRequired, err := s.reviewRequired()
|
reviewRequired, err := s.reviewRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.repo.Create(ownerID, req, reviewRequired)
|
return s.repo.Create(ownerID, req, reviewRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ImportExternalUpload(req ExternalUploadRequest, meta ExternalUploadMeta) (*ExternalUploadResponse, error) {
|
func (s *Service) ImportExternalUpload(ctx context.Context, req ExternalUploadRequest, meta ExternalUploadMeta) (*ExternalUploadResponse, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
@@ -113,7 +114,7 @@ func (s *Service) ImportExternalUpload(req ExternalUploadRequest, meta ExternalU
|
|||||||
if len(items) > maxExternalUploadItems {
|
if len(items) > maxExternalUploadItems {
|
||||||
return nil, ErrTooManyUploadItems
|
return nil, ErrTooManyUploadItems
|
||||||
}
|
}
|
||||||
rules, err := s.publishRules()
|
rules, err := s.publishRules(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -171,29 +172,29 @@ func (s *Service) ImportExternalUpload(req ExternalUploadRequest, meta ExternalU
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Update(ownerID uint64, id uint64, req UpdateRequest) (*ListingDTO, error) {
|
func (s *Service) Update(ctx context.Context, ownerID uint64, id uint64, req UpdateRequest) (*ListingDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
rules, err := s.publishRules()
|
rules, err := s.publishRules(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validateRequest(req, rules); err != nil {
|
if err := validateRequest(req, rules); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reviewRequired, err := s.reviewRequired()
|
reviewRequired, err := s.reviewRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return s.repo.Update(ownerID, id, req, reviewRequired)
|
return s.repo.Update(ownerID, id, req, reviewRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SubmitReview(ownerID uint64, id uint64) (*ListingDTO, error) {
|
func (s *Service) SubmitReview(ctx context.Context, ownerID uint64, id uint64) (*ListingDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
reviewRequired, err := s.reviewRequired()
|
reviewRequired, err := s.reviewRequired(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -753,11 +754,11 @@ func hasScreenshotURL(urls []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) reviewRequired() (bool, error) {
|
func (s *Service) reviewRequired(ctx context.Context) (bool, error) {
|
||||||
if s.config == nil {
|
if s.config == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
value, err := s.config.FindValue(reviewRequiredConfigKey)
|
value, err := s.config.FindValue(ctx, reviewRequiredConfigKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -768,12 +769,12 @@ func (s *Service) reviewRequired() (bool, error) {
|
|||||||
return required, nil
|
return required, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) publishRules() (publishRules, error) {
|
func (s *Service) publishRules(ctx context.Context) (publishRules, error) {
|
||||||
rules := publishRules{FireLevelMin: defaultFireLevelMin}
|
rules := publishRules{FireLevelMin: defaultFireLevelMin}
|
||||||
if s.config == nil {
|
if s.config == nil {
|
||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
value, err := s.config.FindValue(publishOptionsConfigKey)
|
value, err := s.config.FindValue(ctx, publishOptionsConfigKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rules, err
|
return rules, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func TestValidateRequestRequiresDepositAboveConsumables(t *testing.T) {
|
|||||||
func TestCreateRequiresPublishAgreements(t *testing.T) {
|
func TestCreateRequiresPublishAgreements(t *testing.T) {
|
||||||
service := NewService(&Repository{}, nil)
|
service := NewService(&Repository{}, nil)
|
||||||
|
|
||||||
_, err := service.Create(1, CreateRequest{})
|
_, err := service.Create(t.Context(), 1, CreateRequest{})
|
||||||
if err != ErrAgreementRequired {
|
if err != ErrAgreementRequired {
|
||||||
t.Fatalf("expected ErrAgreementRequired, got %v", err)
|
t.Fatalf("expected ErrAgreementRequired, got %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func (h *Handler) Start(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
var req StartPaymentRequest
|
var req StartPaymentRequest
|
||||||
_ = c.ShouldBindJSON(&req)
|
_ = c.ShouldBindJSON(&req)
|
||||||
item, err := h.service.Start(userID, orderID, req, c.ClientIP())
|
item, err := h.service.Start(c.Request.Context(), userID, orderID, req, c.ClientIP())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -55,7 +55,7 @@ func (h *Handler) Query(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.Query(userID, orderID)
|
item, err := h.service.Query(c.Request.Context(), userID, orderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -74,7 +74,7 @@ func (h *Handler) WalletRecharge(c *gin.Context) {
|
|||||||
response.BadRequest(c, "充值金额不正确")
|
response.BadRequest(c, "充值金额不正确")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.StartWalletRecharge(userID, req, c.ClientIP())
|
item, err := h.service.StartWalletRecharge(c.Request.Context(), userID, req, c.ClientIP())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -92,7 +92,7 @@ func (h *Handler) WalletRechargeQuery(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.QueryWalletRecharge(userID, paymentID)
|
item, err := h.service.QueryWalletRecharge(c.Request.Context(), userID, paymentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -105,7 +105,7 @@ func (h *Handler) QueryRefundStatus(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
item, err := h.service.QueryRefundStatus(orderID)
|
item, err := h.service.QueryRefundStatus(c.Request.Context(), orderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -118,7 +118,7 @@ func (h *Handler) AdminList(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result, err := h.service.AdminList(query)
|
result, err := h.service.AdminList(c.Request.Context(), query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePaymentError(c, err)
|
writePaymentError(c, err)
|
||||||
return
|
return
|
||||||
@@ -148,7 +148,7 @@ func (h *Handler) LeshuaNotify(c *gin.Context) {
|
|||||||
contentType,
|
contentType,
|
||||||
rawPayload,
|
rawPayload,
|
||||||
)
|
)
|
||||||
result, err := h.service.HandleLeshuaNotify(params, rawPayload, contentType)
|
result, err := h.service.HandleLeshuaNotify(c.Request.Context(), params, rawPayload, contentType)
|
||||||
if err != nil || result == nil || !result.OK {
|
if err != nil || result == nil || !result.OK {
|
||||||
log.Printf("[payment] leshua notify failed third_order_id=%s err=%v", params["third_order_id"], err)
|
log.Printf("[payment] leshua notify failed third_order_id=%s err=%v", params["third_order_id"], err)
|
||||||
c.String(http.StatusOK, "FAIL")
|
c.String(http.StatusOK, "FAIL")
|
||||||
@@ -181,7 +181,7 @@ func (h *Handler) LakalaNotify(c *gin.Context) {
|
|||||||
contentType,
|
contentType,
|
||||||
rawPayload,
|
rawPayload,
|
||||||
)
|
)
|
||||||
result, err := h.service.HandleNotify("lakala", params, rawPayload, contentType, authorization)
|
result, err := h.service.HandleNotify(c.Request.Context(), "lakala", params, rawPayload, contentType, authorization)
|
||||||
if err != nil || result == nil || !result.OK {
|
if err != nil || result == nil || !result.OK {
|
||||||
log.Printf("[payment] lakala notify failed third_order_id=%s err=%v", params["third_order_id"], err)
|
log.Printf("[payment] lakala notify failed third_order_id=%s err=%v", params["third_order_id"], err)
|
||||||
c.JSON(http.StatusOK, gin.H{"code": "FAIL", "message": "失败"})
|
c.JSON(http.StatusOK, gin.H{"code": "FAIL", "message": "失败"})
|
||||||
|
|||||||
@@ -135,12 +135,12 @@ func runtimeConfigFromDTO(dto *paymentconfig.ConfigDTO) *runtimePaymentConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
func (r *Repository) Start(ctx context.Context, userID uint64, orderID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||||
defaultConfig, err := r.defaultRuntimeConfig()
|
defaultConfig, err := r.defaultRuntimeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
payment, orderRow, err := r.preparePayment(userID, orderID, req, *defaultConfig)
|
payment, orderRow, err := r.preparePayment(ctx, userID, orderID, req, *defaultConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
if runtimeConfig.isMockMode() {
|
if runtimeConfig.isMockMode() {
|
||||||
if err := r.confirmPaid(payment, "2", time.Now(), map[string]string{
|
if err := r.confirmPaid(ctx, payment, "2", time.Now(), map[string]string{
|
||||||
"mock": "true",
|
"mock": "true",
|
||||||
"third_order_id": payment.ThirdOrderID,
|
"third_order_id": payment.ThirdOrderID,
|
||||||
"leshua_order_id": payment.ProviderOrderID,
|
"leshua_order_id": payment.ProviderOrderID,
|
||||||
@@ -162,7 +162,7 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
}, channelSourceMock); err != nil {
|
}, channelSourceMock); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -176,13 +176,13 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
_ = r.markPaymentFailed(payment.ID, nil, "payment channel unavailable")
|
_ = r.markPaymentFailed(ctx, payment.ID, nil, "payment channel unavailable")
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[payment] payment start order_id=%d order_no=%s payment_id=%d provider=%s amount_cent=%d third_order_id=%s",
|
log.Printf("[payment] payment start order_id=%d order_no=%s payment_id=%d provider=%s amount_cent=%d third_order_id=%s",
|
||||||
orderID, orderRow.OrderNo, payment.ID, runtimeConfig.Provider, payment.AmountCent, payment.ThirdOrderID)
|
orderID, orderRow.OrderNo, payment.ID, runtimeConfig.Provider, payment.AmountCent, payment.ThirdOrderID)
|
||||||
resp, err := runtimeConfig.Channel.CreatePayment(context.Background(), channelCreatePaymentRequest{
|
resp, err := runtimeConfig.Channel.CreatePayment(ctx, channelCreatePaymentRequest{
|
||||||
ThirdOrderID: payment.ThirdOrderID,
|
ThirdOrderID: payment.ThirdOrderID,
|
||||||
AmountCent: payment.AmountCent,
|
AmountCent: payment.AmountCent,
|
||||||
PayWay: payment.PayWay,
|
PayWay: payment.PayWay,
|
||||||
@@ -194,18 +194,18 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
Attach: orderRow.OrderNo,
|
Attach: orderRow.OrderNo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = r.markPaymentFailed(payment.ID, nil, err.Error())
|
_ = r.markPaymentFailed(ctx, payment.ID, nil, err.Error())
|
||||||
log.Printf("[payment] payment request failed order_id=%d payment_id=%d provider=%s amount_cent=%d err=%v",
|
log.Printf("[payment] payment request failed order_id=%d payment_id=%d provider=%s amount_cent=%d err=%v",
|
||||||
orderID, payment.ID, runtimeConfig.Provider, payment.AmountCent, err)
|
orderID, payment.ID, runtimeConfig.Provider, payment.AmountCent, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !resp.OK {
|
if !resp.OK {
|
||||||
_ = r.markPaymentFailed(payment.ID, resp.Raw, resp.ErrorMessage)
|
_ = r.markPaymentFailed(ctx, payment.ID, resp.Raw, resp.ErrorMessage)
|
||||||
log.Printf("[payment] payment rejected order_id=%d payment_id=%d provider=%s amount_cent=%d code=%s message=%s",
|
log.Printf("[payment] payment rejected order_id=%d payment_id=%d provider=%s amount_cent=%d code=%s message=%s",
|
||||||
orderID, payment.ID, runtimeConfig.Provider, payment.AmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
orderID, payment.ID, runtimeConfig.Provider, payment.AmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "paying",
|
"status": "paying",
|
||||||
"provider_order_id": resp.ProviderOrderID,
|
"provider_order_id": resp.ProviderOrderID,
|
||||||
"pay_way": firstNonEmpty(resp.PayWay, payment.PayWay),
|
"pay_way": firstNonEmpty(resp.PayWay, payment.PayWay),
|
||||||
@@ -217,7 +217,7 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ func (r *Repository) Start(userID uint64, orderID uint64, req StartPaymentReques
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymentRequest, clientIP string) (*PaymentDTO, error) {
|
func (r *Repository) StartWalletRecharge(ctx context.Context, userID uint64, req WalletRechargePaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||||
amountCent := req.AmountCent
|
amountCent := req.AmountCent
|
||||||
if userID == 0 || amountCent < moneyCent(MinWalletRechargeAmount) {
|
if userID == 0 || amountCent < moneyCent(MinWalletRechargeAmount) {
|
||||||
return nil, ErrPaymentCannotStart
|
return nil, ErrPaymentCannotStart
|
||||||
@@ -237,12 +237,12 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
payment, err := r.createWalletRechargePayment(userID, amountCent, req, *runtimeConfig)
|
payment, err := r.createWalletRechargePayment(ctx, userID, amountCent, req, *runtimeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if runtimeConfig.isMockMode() {
|
if runtimeConfig.isMockMode() {
|
||||||
if err := r.confirmPaid(payment, "2", time.Now(), map[string]string{
|
if err := r.confirmPaid(ctx, payment, "2", time.Now(), map[string]string{
|
||||||
"mock": "true",
|
"mock": "true",
|
||||||
"third_order_id": payment.ThirdOrderID,
|
"third_order_id": payment.ThirdOrderID,
|
||||||
"leshua_order_id": payment.ProviderOrderID,
|
"leshua_order_id": payment.ProviderOrderID,
|
||||||
@@ -250,7 +250,7 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
}, channelSourceMock); err != nil {
|
}, channelSourceMock); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -259,12 +259,12 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
_ = r.markPaymentFailed(payment.ID, nil, "payment channel unavailable")
|
_ = r.markPaymentFailed(ctx, payment.ID, nil, "payment channel unavailable")
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
log.Printf("[payment] wallet recharge start user_id=%d payment_id=%d provider=%s amount_cent=%d third_order_id=%s",
|
log.Printf("[payment] wallet recharge start user_id=%d payment_id=%d provider=%s amount_cent=%d third_order_id=%s",
|
||||||
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, payment.ThirdOrderID)
|
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, payment.ThirdOrderID)
|
||||||
resp, err := runtimeConfig.Channel.CreatePayment(context.Background(), channelCreatePaymentRequest{
|
resp, err := runtimeConfig.Channel.CreatePayment(ctx, channelCreatePaymentRequest{
|
||||||
ThirdOrderID: payment.ThirdOrderID,
|
ThirdOrderID: payment.ThirdOrderID,
|
||||||
AmountCent: payment.AmountCent,
|
AmountCent: payment.AmountCent,
|
||||||
PayWay: payment.PayWay,
|
PayWay: payment.PayWay,
|
||||||
@@ -276,18 +276,18 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
Attach: payment.PaymentNo,
|
Attach: payment.PaymentNo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = r.markPaymentFailed(payment.ID, nil, err.Error())
|
_ = r.markPaymentFailed(ctx, payment.ID, nil, err.Error())
|
||||||
log.Printf("[payment] wallet recharge request failed user_id=%d payment_id=%d provider=%s amount_cent=%d err=%v",
|
log.Printf("[payment] wallet recharge request failed user_id=%d payment_id=%d provider=%s amount_cent=%d err=%v",
|
||||||
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, err)
|
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !resp.OK {
|
if !resp.OK {
|
||||||
_ = r.markPaymentFailed(payment.ID, resp.Raw, resp.ErrorMessage)
|
_ = r.markPaymentFailed(ctx, payment.ID, resp.Raw, resp.ErrorMessage)
|
||||||
log.Printf("[payment] wallet recharge rejected user_id=%d payment_id=%d provider=%s amount_cent=%d code=%s message=%s",
|
log.Printf("[payment] wallet recharge rejected user_id=%d payment_id=%d provider=%s amount_cent=%d code=%s message=%s",
|
||||||
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
userID, payment.ID, runtimeConfig.Provider, payment.AmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "paying",
|
"status": "paying",
|
||||||
"provider_order_id": resp.ProviderOrderID,
|
"provider_order_id": resp.ProviderOrderID,
|
||||||
"pay_way": firstNonEmpty(resp.PayWay, payment.PayWay),
|
"pay_way": firstNonEmpty(resp.PayWay, payment.PayWay),
|
||||||
@@ -299,7 +299,7 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -310,9 +310,9 @@ func (r *Repository) StartWalletRecharge(userID uint64, req WalletRechargePaymen
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) QueryWalletRecharge(userID uint64, paymentID uint64) (*PaymentDTO, error) {
|
func (r *Repository) QueryWalletRecharge(ctx context.Context, userID uint64, paymentID uint64) (*PaymentDTO, error) {
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.Where("id = ? AND user_id = ? AND order_id = 0", paymentID, userID).First(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("id = ? AND user_id = ? AND order_id = 0", paymentID, userID).First(&payment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -329,14 +329,14 @@ func (r *Repository) QueryWalletRecharge(userID uint64, paymentID uint64) (*Paym
|
|||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
resp, err := runtimeConfig.Channel.QueryPayment(context.Background(), payment.ThirdOrderID, payment.ProviderOrderID)
|
resp, err := runtimeConfig.Channel.QueryPayment(ctx, payment.ThirdOrderID, payment.ProviderOrderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := r.applyChannelStatus(&payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil {
|
if err := r.applyChannelStatus(ctx, &payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -344,9 +344,9 @@ func (r *Repository) QueryWalletRecharge(userID uint64, paymentID uint64) (*Paym
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Query(userID uint64, orderID uint64) (*PaymentDTO, error) {
|
func (r *Repository) Query(ctx context.Context, userID uint64, orderID uint64) (*PaymentDTO, error) {
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.Where("order_id = ? AND user_id = ? AND biz_type = ?", orderID, userID, "order_pay").Order("id DESC").First(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("order_id = ? AND user_id = ? AND biz_type = ?", orderID, userID, "order_pay").Order("id DESC").First(&payment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -363,14 +363,14 @@ func (r *Repository) Query(userID uint64, orderID uint64) (*PaymentDTO, error) {
|
|||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
resp, err := runtimeConfig.Channel.QueryPayment(context.Background(), payment.ThirdOrderID, payment.ProviderOrderID)
|
resp, err := runtimeConfig.Channel.QueryPayment(ctx, payment.ThirdOrderID, payment.ProviderOrderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := r.applyChannelStatus(&payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil {
|
if err := r.applyChannelStatus(ctx, &payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
latest, err := r.findPaymentByID(payment.ID)
|
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -378,17 +378,17 @@ func (r *Repository) Query(userID uint64, orderID uint64) (*PaymentDTO, error) {
|
|||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) HandleLeshuaNotify(params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
|
func (r *Repository) HandleLeshuaNotify(ctx context.Context, params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
|
||||||
return r.HandleNotify("leshua", params, rawPayload, contentType, "")
|
return r.HandleNotify(ctx, "leshua", params, rawPayload, contentType, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) HandleNotify(provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
func (r *Repository) HandleNotify(ctx context.Context, provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
||||||
// 退款通知会携带 merchant_refund_id 或 leshua_refund_id。
|
// 退款通知会携带 merchant_refund_id 或 leshua_refund_id。
|
||||||
if params["merchant_refund_id"] != "" || params["leshua_refund_id"] != "" || params["provider_refund_id"] != "" {
|
if params["merchant_refund_id"] != "" || params["leshua_refund_id"] != "" || params["provider_refund_id"] != "" {
|
||||||
return r.HandleRefundNotify(provider, params, rawPayload, contentType, authorization)
|
return r.HandleRefundNotify(ctx, provider, params, rawPayload, contentType, authorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
payment, err := r.findPaymentForNotify(params)
|
payment, err := r.findPaymentForNotify(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -396,28 +396,28 @@ func (r *Repository) HandleNotify(provider string, params map[string]string, raw
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
verify, err := r.verifyNotify(payment, runtimeConfig, params, rawPayload, contentType, authorization)
|
verify, err := r.verifyNotify(ctx, payment, runtimeConfig, params, rawPayload, contentType, authorization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if amount := parseCent(params["amount"]); amount > 0 && amount != payment.AmountCent {
|
if amount := parseCent(params["amount"]); amount > 0 && amount != payment.AmountCent {
|
||||||
if err := r.recordNotifyDiagnostic(payment.ID, params, rawPayload, contentType, verify, "amount_mismatch"); err != nil {
|
if err := r.recordNotifyDiagnostic(ctx, payment.ID, params, rawPayload, contentType, verify, "amount_mismatch"); err != nil {
|
||||||
log.Printf("[payment] %s notify diagnostic save failed third_order_id=%s err=%v", runtimeConfig.Provider, params["third_order_id"], err)
|
log.Printf("[payment] %s notify diagnostic save failed third_order_id=%s err=%v", runtimeConfig.Provider, params["third_order_id"], err)
|
||||||
}
|
}
|
||||||
return nil, ErrPaymentVerifyFailed
|
return nil, ErrPaymentVerifyFailed
|
||||||
}
|
}
|
||||||
raw := withNotifyDiagnostic(params, rawPayload, contentType, verify, "verified")
|
raw := withNotifyDiagnostic(params, rawPayload, contentType, verify, "verified")
|
||||||
if err := r.applyChannelStatus(payment, normalizeNotifyPaymentStatus(runtimeConfig.Provider, params["status"]), params["pay_time"], raw, channelSourceNotify); err != nil {
|
if err := r.applyChannelStatus(ctx, payment, normalizeNotifyPaymentStatus(runtimeConfig.Provider, params["status"]), params["pay_time"], raw, channelSourceNotify); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &NotifyResult{OK: true, Message: "000000"}, nil
|
return &NotifyResult{OK: true, Message: "000000"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartRefund 创建退款单,并在本地落库后调用乐刷退款接口。
|
// StartRefund 创建退款单,并在本地落库后调用乐刷退款接口。
|
||||||
func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType string, remark string) (*RefundDTO, error) {
|
func (r *Repository) StartRefund(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (*RefundDTO, error) {
|
||||||
var originalPayment model.PaymentOrder
|
var originalPayment model.PaymentOrder
|
||||||
if err := r.db.Where("order_id = ? AND status = 'paid' AND biz_type = 'order_pay'", orderID).Order("id DESC").First(&originalPayment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("order_id = ? AND status = 'paid' AND biz_type = 'order_pay'", orderID).Order("id DESC").First(&originalPayment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -429,7 +429,7 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
}
|
}
|
||||||
|
|
||||||
var existingRefund model.PaymentOrder
|
var existingRefund model.PaymentOrder
|
||||||
err = r.db.Where("order_id = ? AND biz_type = ? AND status NOT IN ('failed')", orderID, bizType).Order("id DESC").First(&existingRefund).Error
|
err = r.db.WithContext(ctx).Where("order_id = ? AND biz_type = ? AND status NOT IN ('failed')", orderID, bizType).Order("id DESC").First(&existingRefund).Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
dto := toRefundDTO(existingRefund)
|
dto := toRefundDTO(existingRefund)
|
||||||
return &dto, nil
|
return &dto, nil
|
||||||
@@ -468,32 +468,32 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
if remark != "" {
|
if remark != "" {
|
||||||
refundOrder.RawResponse = datatypes.JSON([]byte(fmt.Sprintf(`{"mock":"true","remark":"%s"}`, remark)))
|
refundOrder.RawResponse = datatypes.JSON([]byte(fmt.Sprintf(`{"mock":"true","remark":"%s"}`, remark)))
|
||||||
}
|
}
|
||||||
if err := r.db.Create(&refundOrder).Error; err != nil {
|
if err := r.db.WithContext(ctx).Create(&refundOrder).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r.recordConfigUsage(runtimeConfig, &refundOrder)
|
r.recordConfigUsage(runtimeConfig, &refundOrder)
|
||||||
if err := r.updateOrderRefundStatus(orderID, refundAmountCent); err != nil {
|
if err := r.updateOrderRefundStatus(ctx, orderID, refundAmountCent); err != nil {
|
||||||
log.Printf("[payment] mock update order refund status failed order_id=%d err=%v", orderID, err)
|
log.Printf("[payment] mock update order refund status failed order_id=%d err=%v", orderID, err)
|
||||||
}
|
}
|
||||||
dto := toRefundDTO(refundOrder)
|
dto := toRefundDTO(refundOrder)
|
||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.db.Create(&refundOrder).Error; err != nil {
|
if err := r.db.WithContext(ctx).Create(&refundOrder).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Printf("[payment] refund start order_id=%d order_no=%s payment_id=%d biz_type=%s provider=%s amount_cent=%d merchant_refund_id=%s origin_third_order_id=%s origin_provider_order_id=%s",
|
log.Printf("[payment] refund start order_id=%d order_no=%s payment_id=%d biz_type=%s provider=%s amount_cent=%d merchant_refund_id=%s origin_third_order_id=%s origin_provider_order_id=%s",
|
||||||
orderID, originalPayment.OrderNo, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, merchantRefundID, originalPayment.ThirdOrderID, refundOriginProviderOrderID(originalPayment))
|
orderID, originalPayment.OrderNo, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, merchantRefundID, originalPayment.ThirdOrderID, refundOriginProviderOrderID(originalPayment))
|
||||||
r.recordConfigUsage(runtimeConfig, &refundOrder)
|
r.recordConfigUsage(runtimeConfig, &refundOrder)
|
||||||
if err := r.markOrderRefunding(orderID, refundAmountCent); err != nil {
|
if err := r.markOrderRefunding(ctx, orderID, refundAmountCent); err != nil {
|
||||||
log.Printf("[payment] mark order refunding failed order_id=%d err=%v", orderID, err)
|
log.Printf("[payment] mark order refunding failed order_id=%d err=%v", orderID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
_ = r.markRefundFailed(refundOrder.ID, orderID, refundAmountCent, map[string]string{"error": "payment channel unavailable"})
|
_ = r.markRefundFailed(ctx, refundOrder.ID, orderID, refundAmountCent, map[string]string{"error": "payment channel unavailable"})
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
resp, err := runtimeConfig.Channel.CreateRefund(context.Background(), channelCreateRefundRequest{
|
resp, err := runtimeConfig.Channel.CreateRefund(ctx, channelCreateRefundRequest{
|
||||||
ThirdOrderID: originalPayment.ThirdOrderID,
|
ThirdOrderID: originalPayment.ThirdOrderID,
|
||||||
ProviderOrderID: refundOriginProviderOrderID(originalPayment),
|
ProviderOrderID: refundOriginProviderOrderID(originalPayment),
|
||||||
MerchantRefundID: merchantRefundID,
|
MerchantRefundID: merchantRefundID,
|
||||||
@@ -503,13 +503,13 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
Remark: remark,
|
Remark: remark,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = r.markRefundFailed(refundOrder.ID, orderID, refundAmountCent, map[string]string{"error": err.Error()})
|
_ = r.markRefundFailed(ctx, refundOrder.ID, orderID, refundAmountCent, map[string]string{"error": err.Error()})
|
||||||
log.Printf("[payment] refund request failed order_id=%d payment_id=%d biz_type=%s provider=%s amount_cent=%d err=%v",
|
log.Printf("[payment] refund request failed order_id=%d payment_id=%d biz_type=%s provider=%s amount_cent=%d err=%v",
|
||||||
orderID, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, err)
|
orderID, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !resp.OK {
|
if !resp.OK {
|
||||||
_ = r.markRefundFailed(refundOrder.ID, orderID, refundAmountCent, resp.Raw)
|
_ = r.markRefundFailed(ctx, refundOrder.ID, orderID, refundAmountCent, resp.Raw)
|
||||||
log.Printf("[payment] refund rejected order_id=%d payment_id=%d biz_type=%s provider=%s amount_cent=%d code=%s message=%s",
|
log.Printf("[payment] refund rejected order_id=%d payment_id=%d biz_type=%s provider=%s amount_cent=%d code=%s message=%s",
|
||||||
orderID, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
orderID, refundOrder.ID, bizType, runtimeConfig.Provider, refundAmountCent, firstNonEmpty(resp.Raw["code"], resp.Raw["resp_code"], resp.Raw["result_code"]), resp.ErrorMessage)
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
@@ -524,7 +524,7 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
} else if resp.Status == "failed" {
|
} else if resp.Status == "failed" {
|
||||||
refundStatus = "failed"
|
refundStatus = "failed"
|
||||||
}
|
}
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", refundOrder.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", refundOrder.ID).Updates(map[string]any{
|
||||||
"status": refundStatus,
|
"status": refundStatus,
|
||||||
"provider_order_id": resp.ProviderRefundID,
|
"provider_order_id": resp.ProviderRefundID,
|
||||||
"raw_request": jsonMap(resp.RawRequest),
|
"raw_request": jsonMap(resp.RawRequest),
|
||||||
@@ -535,12 +535,12 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
}
|
}
|
||||||
|
|
||||||
if refundStatus == "refunded" {
|
if refundStatus == "refunded" {
|
||||||
_ = r.updateOrderRefundStatus(orderID, refundAmountCent)
|
_ = r.updateOrderRefundStatus(ctx, orderID, refundAmountCent)
|
||||||
refundOrder.PaidAt = paidAt
|
refundOrder.PaidAt = paidAt
|
||||||
} else if refundStatus == "failed" {
|
} else if refundStatus == "failed" {
|
||||||
_ = r.markOrderRefundFailed(orderID, refundAmountCent)
|
_ = r.markOrderRefundFailed(ctx, orderID, refundAmountCent)
|
||||||
} else {
|
} else {
|
||||||
_ = r.markOrderRefunding(orderID, refundAmountCent)
|
_ = r.markOrderRefunding(ctx, orderID, refundAmountCent)
|
||||||
}
|
}
|
||||||
refundOrder.Status = refundStatus
|
refundOrder.Status = refundStatus
|
||||||
refundOrder.ProviderOrderID = resp.ProviderRefundID
|
refundOrder.ProviderOrderID = resp.ProviderRefundID
|
||||||
@@ -552,9 +552,9 @@ func (r *Repository) StartRefund(orderID uint64, refundAmountCent int64, bizType
|
|||||||
}
|
}
|
||||||
|
|
||||||
// QueryRefundStatus 查询订单最近一笔退款状态。
|
// QueryRefundStatus 查询订单最近一笔退款状态。
|
||||||
func (r *Repository) QueryRefundStatus(orderID uint64) (*RefundDTO, error) {
|
func (r *Repository) QueryRefundStatus(ctx context.Context, orderID uint64) (*RefundDTO, error) {
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.Where("order_id = ? AND biz_type IN ?", orderID, refundBizTypes).Order("id DESC").First(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("order_id = ? AND biz_type IN ?", orderID, refundBizTypes).Order("id DESC").First(&payment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -571,7 +571,7 @@ func (r *Repository) QueryRefundStatus(orderID uint64) (*RefundDTO, error) {
|
|||||||
if runtimeConfig.Channel == nil {
|
if runtimeConfig.Channel == nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
resp, err := runtimeConfig.Channel.QueryRefund(context.Background(), channelQueryRefundRequest{
|
resp, err := runtimeConfig.Channel.QueryRefund(ctx, channelQueryRefundRequest{
|
||||||
ThirdOrderID: payment.ThirdOrderID,
|
ThirdOrderID: payment.ThirdOrderID,
|
||||||
MerchantRefundID: payment.ThirdOrderID,
|
MerchantRefundID: payment.ThirdOrderID,
|
||||||
ProviderRefundID: payment.ProviderOrderID,
|
ProviderRefundID: payment.ProviderOrderID,
|
||||||
@@ -581,7 +581,7 @@ func (r *Repository) QueryRefundStatus(orderID uint64) (*RefundDTO, error) {
|
|||||||
}
|
}
|
||||||
if resp.Status == "refunded" {
|
if resp.Status == "refunded" {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "refunded",
|
"status": "refunded",
|
||||||
"paid_at": now,
|
"paid_at": now,
|
||||||
"raw_response": jsonMap(withRawSource(resp.Raw, channelSourceQuery)),
|
"raw_response": jsonMap(withRawSource(resp.Raw, channelSourceQuery)),
|
||||||
@@ -590,26 +590,26 @@ func (r *Repository) QueryRefundStatus(orderID uint64) (*RefundDTO, error) {
|
|||||||
}
|
}
|
||||||
payment.Status = "refunded"
|
payment.Status = "refunded"
|
||||||
payment.PaidAt = &now
|
payment.PaidAt = &now
|
||||||
_ = r.updateOrderRefundStatus(orderID, payment.AmountCent)
|
_ = r.updateOrderRefundStatus(ctx, orderID, payment.AmountCent)
|
||||||
} else if resp.Status == "failed" {
|
} else if resp.Status == "failed" {
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
"raw_response": jsonMap(withRawSource(resp.Raw, channelSourceQuery)),
|
"raw_response": jsonMap(withRawSource(resp.Raw, channelSourceQuery)),
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
payment.Status = "failed"
|
payment.Status = "failed"
|
||||||
_ = r.markOrderRefundFailed(orderID, payment.AmountCent)
|
_ = r.markOrderRefundFailed(ctx, orderID, payment.AmountCent)
|
||||||
}
|
}
|
||||||
dto := toRefundDTO(payment)
|
dto := toRefundDTO(payment)
|
||||||
return &dto, nil
|
return &dto, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) AdminList(query AdminPaymentQuery) (*PaginatedResult, error) {
|
func (r *Repository) AdminList(ctx context.Context, query AdminPaymentQuery) (*PaginatedResult, error) {
|
||||||
db := r.db.Table("payment_orders AS p").
|
db := r.db.WithContext(ctx).Table("payment_orders AS p").
|
||||||
Select("p.*, COALESCE(u.phone, '') AS user_phone").
|
Select("p.*, COALESCE(u.phone, '') AS user_phone").
|
||||||
Joins("LEFT JOIN users AS u ON u.id = p.user_id")
|
Joins("LEFT JOIN users AS u ON u.id = p.user_id")
|
||||||
countDB := r.db.Model(&model.PaymentOrder{})
|
countDB := r.db.WithContext(ctx).Model(&model.PaymentOrder{})
|
||||||
if query.UserID > 0 {
|
if query.UserID > 0 {
|
||||||
db = db.Where("p.user_id = ?", query.UserID)
|
db = db.Where("p.user_id = ?", query.UserID)
|
||||||
countDB = countDB.Where("user_id = ?", query.UserID)
|
countDB = countDB.Where("user_id = ?", query.UserID)
|
||||||
@@ -651,8 +651,8 @@ func (r *Repository) AdminList(query AdminPaymentQuery) (*PaginatedResult, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HandleRefundNotify 处理渠道退款通知。
|
// HandleRefundNotify 处理渠道退款通知。
|
||||||
func (r *Repository) HandleRefundNotify(provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
func (r *Repository) HandleRefundNotify(ctx context.Context, provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
||||||
payment, err := r.findRefundPaymentForNotify(params)
|
payment, err := r.findRefundPaymentForNotify(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -660,7 +660,7 @@ func (r *Repository) HandleRefundNotify(provider string, params map[string]strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrPaymentUnavailable
|
return nil, ErrPaymentUnavailable
|
||||||
}
|
}
|
||||||
verify, err := r.verifyNotify(payment, runtimeConfig, params, rawPayload, contentType, authorization)
|
verify, err := r.verifyNotify(ctx, payment, runtimeConfig, params, rawPayload, contentType, authorization)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ func (r *Repository) HandleRefundNotify(provider string, params map[string]strin
|
|||||||
switch status {
|
switch status {
|
||||||
case "refunded":
|
case "refunded":
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "refunded",
|
"status": "refunded",
|
||||||
"paid_at": now,
|
"paid_at": now,
|
||||||
"notified_at": now,
|
"notified_at": now,
|
||||||
@@ -678,16 +678,16 @@ func (r *Repository) HandleRefundNotify(provider string, params map[string]strin
|
|||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = r.updateOrderRefundStatus(payment.OrderID, payment.AmountCent)
|
_ = r.updateOrderRefundStatus(ctx, payment.OrderID, payment.AmountCent)
|
||||||
case "failed":
|
case "failed":
|
||||||
r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
"notified_at": time.Now(),
|
"notified_at": time.Now(),
|
||||||
"raw_response": jsonMap(raw),
|
"raw_response": jsonMap(raw),
|
||||||
})
|
})
|
||||||
_ = r.markOrderRefundFailed(payment.OrderID, payment.AmountCent)
|
_ = r.markOrderRefundFailed(ctx, payment.OrderID, payment.AmountCent)
|
||||||
default:
|
default:
|
||||||
r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(map[string]any{
|
||||||
"status": "refunding",
|
"status": "refunding",
|
||||||
"raw_response": jsonMap(raw),
|
"raw_response": jsonMap(raw),
|
||||||
})
|
})
|
||||||
@@ -696,42 +696,42 @@ func (r *Repository) HandleRefundNotify(provider string, params map[string]strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateOrderRefundStatus 更新订单退款成功状态。
|
// updateOrderRefundStatus 更新订单退款成功状态。
|
||||||
func (r *Repository) updateOrderRefundStatus(orderID uint64, refundAmountCent int64) error {
|
func (r *Repository) updateOrderRefundStatus(ctx context.Context, orderID uint64, refundAmountCent int64) error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
return r.db.Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
return r.db.WithContext(ctx).Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
||||||
"refund_status": "refunded",
|
"refund_status": "refunded",
|
||||||
"refund_amount_cent": refundAmountCent,
|
"refund_amount_cent": refundAmountCent,
|
||||||
"refunded_at": now,
|
"refunded_at": now,
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) markOrderRefunding(orderID uint64, refundAmountCent int64) error {
|
func (r *Repository) markOrderRefunding(ctx context.Context, orderID uint64, refundAmountCent int64) error {
|
||||||
return r.db.Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
return r.db.WithContext(ctx).Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
||||||
"refund_status": "refunding",
|
"refund_status": "refunding",
|
||||||
"refund_amount_cent": refundAmountCent,
|
"refund_amount_cent": refundAmountCent,
|
||||||
"refunded_at": nil,
|
"refunded_at": nil,
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) markOrderRefundFailed(orderID uint64, refundAmountCent int64) error {
|
func (r *Repository) markOrderRefundFailed(ctx context.Context, orderID uint64, refundAmountCent int64) error {
|
||||||
return r.db.Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
return r.db.WithContext(ctx).Model(&model.RentalOrder{}).Where("id = ?", orderID).Updates(map[string]any{
|
||||||
"refund_status": "failed",
|
"refund_status": "failed",
|
||||||
"refund_amount_cent": refundAmountCent,
|
"refund_amount_cent": refundAmountCent,
|
||||||
"refunded_at": nil,
|
"refunded_at": nil,
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) markRefundFailed(paymentID uint64, orderID uint64, refundAmountCent int64, raw map[string]string) error {
|
func (r *Repository) markRefundFailed(ctx context.Context, paymentID uint64, orderID uint64, refundAmountCent int64, raw map[string]string) error {
|
||||||
if raw == nil {
|
if raw == nil {
|
||||||
raw = map[string]string{"error": "refund failed"}
|
raw = map[string]string{"error": "refund failed"}
|
||||||
}
|
}
|
||||||
if err := r.db.Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(map[string]any{
|
if err := r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(map[string]any{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
"raw_response": jsonMap(raw),
|
"raw_response": jsonMap(raw),
|
||||||
}).Error; err != nil {
|
}).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return r.markOrderRefundFailed(orderID, refundAmountCent)
|
return r.markOrderRefundFailed(ctx, orderID, refundAmountCent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// toRefundDTO 将支付表里的退款单转换为接口 DTO。
|
// toRefundDTO 将支付表里的退款单转换为接口 DTO。
|
||||||
@@ -751,10 +751,10 @@ func toRefundDTO(payment model.PaymentOrder) RefundDTO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) preparePayment(userID uint64, orderID uint64, req StartPaymentRequest, runtimeConfig runtimePaymentConfig) (*model.PaymentOrder, *model.RentalOrder, error) {
|
func (r *Repository) preparePayment(ctx context.Context, userID uint64, orderID uint64, req StartPaymentRequest, runtimeConfig runtimePaymentConfig) (*model.PaymentOrder, *model.RentalOrder, error) {
|
||||||
var paymentID uint64
|
var paymentID uint64
|
||||||
var orderRow model.RentalOrder
|
var orderRow model.RentalOrder
|
||||||
err := r.db.Transaction(func(tx *gorm.DB) error {
|
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
var row model.RentalOrder
|
var row model.RentalOrder
|
||||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||||
Where("id = ? AND renter_id = ?", orderID, userID).
|
Where("id = ? AND renter_id = ?", orderID, userID).
|
||||||
@@ -807,7 +807,7 @@ func (r *Repository) preparePayment(userID uint64, orderID uint64, req StartPaym
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
payment, err := r.findPaymentByID(paymentID)
|
payment, err := r.findPaymentByID(ctx, paymentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -875,7 +875,7 @@ func newOrderPayment(row model.RentalOrder, amountCent int64, req StartPaymentRe
|
|||||||
return payment, nil
|
return payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) createWalletRechargePayment(userID uint64, amountCent int64, req WalletRechargePaymentRequest, runtimeConfig runtimePaymentConfig) (*model.PaymentOrder, error) {
|
func (r *Repository) createWalletRechargePayment(ctx context.Context, userID uint64, amountCent int64, req WalletRechargePaymentRequest, runtimeConfig runtimePaymentConfig) (*model.PaymentOrder, error) {
|
||||||
paymentNo, err := newPaymentNo()
|
paymentNo, err := newPaymentNo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -899,13 +899,13 @@ func (r *Repository) createWalletRechargePayment(userID uint64, amountCent int64
|
|||||||
payment.ProviderOrderID = "MOCK" + paymentNo
|
payment.ProviderOrderID = "MOCK" + paymentNo
|
||||||
payment.TDCode = "mock://payment/recharge/" + paymentNo
|
payment.TDCode = "mock://payment/recharge/" + paymentNo
|
||||||
}
|
}
|
||||||
if err := r.db.Create(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Create(&payment).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &payment, nil
|
return &payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) applyChannelStatus(payment *model.PaymentOrder, status string, payTime string, raw map[string]string, source string) error {
|
func (r *Repository) applyChannelStatus(ctx context.Context, payment *model.PaymentOrder, status string, payTime string, raw map[string]string, source string) error {
|
||||||
switch status {
|
switch status {
|
||||||
case "paid":
|
case "paid":
|
||||||
paidAt := parseChannelTime(payTime)
|
paidAt := parseChannelTime(payTime)
|
||||||
@@ -913,17 +913,17 @@ func (r *Repository) applyChannelStatus(payment *model.PaymentOrder, status stri
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
paidAt = &now
|
paidAt = &now
|
||||||
}
|
}
|
||||||
return r.confirmPaid(payment, status, *paidAt, raw, source)
|
return r.confirmPaid(ctx, payment, status, *paidAt, raw, source)
|
||||||
case "closed":
|
case "closed":
|
||||||
return r.updateChannelStatus(payment.ID, "closed", raw, source)
|
return r.updateChannelStatus(ctx, payment.ID, "closed", raw, source)
|
||||||
case "failed":
|
case "failed":
|
||||||
return r.updateChannelStatus(payment.ID, "failed", raw, source)
|
return r.updateChannelStatus(ctx, payment.ID, "failed", raw, source)
|
||||||
default:
|
default:
|
||||||
return r.updateChannelStatus(payment.ID, "paying", raw, source)
|
return r.updateChannelStatus(ctx, payment.ID, "paying", raw, source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) updateChannelStatus(paymentID uint64, status string, raw map[string]string, source string) error {
|
func (r *Repository) updateChannelStatus(ctx context.Context, paymentID uint64, status string, raw map[string]string, source string) error {
|
||||||
updates := map[string]any{
|
updates := map[string]any{
|
||||||
"status": status,
|
"status": status,
|
||||||
"raw_response": jsonMap(withRawSource(raw, source)),
|
"raw_response": jsonMap(withRawSource(raw, source)),
|
||||||
@@ -931,16 +931,16 @@ func (r *Repository) updateChannelStatus(paymentID uint64, status string, raw ma
|
|||||||
if source == channelSourceNotify {
|
if source == channelSourceNotify {
|
||||||
updates["notified_at"] = time.Now()
|
updates["notified_at"] = time.Now()
|
||||||
}
|
}
|
||||||
return r.db.Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(updates).Error
|
return r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(updates).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) confirmPaid(payment *model.PaymentOrder, status string, paidAt time.Time, raw map[string]string, source string) error {
|
func (r *Repository) confirmPaid(ctx context.Context, payment *model.PaymentOrder, status string, paidAt time.Time, raw map[string]string, source string) error {
|
||||||
if payment.Status != "paid" {
|
if payment.Status != "paid" {
|
||||||
if payment.OrderID == 0 {
|
if payment.OrderID == 0 {
|
||||||
if r.walletRepo == nil {
|
if r.walletRepo == nil {
|
||||||
return ErrDependencyUnavailable
|
return ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if err := r.walletRepo.ConfirmRechargeFromChannel(context.Background(), payment.UserID, firstNonEmpty(payment.ProviderOrderID, payment.PaymentNo), payment.AmountCent); err != nil {
|
if err := r.walletRepo.ConfirmRechargeFromChannel(ctx, payment.UserID, firstNonEmpty(payment.ProviderOrderID, payment.PaymentNo), payment.AmountCent); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -961,34 +961,34 @@ func (r *Repository) confirmPaid(payment *model.PaymentOrder, status string, pai
|
|||||||
if source == channelSourceNotify {
|
if source == channelSourceNotify {
|
||||||
updates["notified_at"] = time.Now()
|
updates["notified_at"] = time.Now()
|
||||||
}
|
}
|
||||||
return r.db.Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(updates).Error
|
return r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", payment.ID).Updates(updates).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) markPaymentFailed(paymentID uint64, raw map[string]string, message string) error {
|
func (r *Repository) markPaymentFailed(ctx context.Context, paymentID uint64, raw map[string]string, message string) error {
|
||||||
if raw == nil {
|
if raw == nil {
|
||||||
raw = map[string]string{"error": message}
|
raw = map[string]string{"error": message}
|
||||||
}
|
}
|
||||||
return r.db.Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(map[string]any{
|
return r.db.WithContext(ctx).Model(&model.PaymentOrder{}).Where("id = ?", paymentID).Updates(map[string]any{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
"raw_response": jsonMap(raw),
|
"raw_response": jsonMap(raw),
|
||||||
}).Error
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) findPaymentByID(paymentID uint64) (*model.PaymentOrder, error) {
|
func (r *Repository) findPaymentByID(ctx context.Context, paymentID uint64) (*model.PaymentOrder, error) {
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.First(&payment, paymentID).Error; err != nil {
|
if err := r.db.WithContext(ctx).First(&payment, paymentID).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &payment, nil
|
return &payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) findPaymentForNotify(params map[string]string) (*model.PaymentOrder, error) {
|
func (r *Repository) findPaymentForNotify(ctx context.Context, params map[string]string) (*model.PaymentOrder, error) {
|
||||||
thirdOrderID := params["third_order_id"]
|
thirdOrderID := params["third_order_id"]
|
||||||
if thirdOrderID == "" {
|
if thirdOrderID == "" {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.Where("third_order_id = ?", thirdOrderID).First(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("third_order_id = ?", thirdOrderID).First(&payment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -997,13 +997,13 @@ func (r *Repository) findPaymentForNotify(params map[string]string) (*model.Paym
|
|||||||
return &payment, nil
|
return &payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) findRefundPaymentForNotify(params map[string]string) (*model.PaymentOrder, error) {
|
func (r *Repository) findRefundPaymentForNotify(ctx context.Context, params map[string]string) (*model.PaymentOrder, error) {
|
||||||
merchantRefundID := params["merchant_refund_id"]
|
merchantRefundID := params["merchant_refund_id"]
|
||||||
if merchantRefundID == "" {
|
if merchantRefundID == "" {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
var payment model.PaymentOrder
|
var payment model.PaymentOrder
|
||||||
if err := r.db.Where("third_order_id = ?", merchantRefundID).First(&payment).Error; err != nil {
|
if err := r.db.WithContext(ctx).Where("third_order_id = ?", merchantRefundID).First(&payment).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
@@ -1012,7 +1012,7 @@ func (r *Repository) findRefundPaymentForNotify(params map[string]string) (*mode
|
|||||||
return &payment, nil
|
return &payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) verifyNotify(payment *model.PaymentOrder, runtimeConfig *runtimePaymentConfig, params map[string]string, rawPayload string, contentType string, authorization string) (channelVerifyNotifyResult, error) {
|
func (r *Repository) verifyNotify(ctx context.Context, payment *model.PaymentOrder, runtimeConfig *runtimePaymentConfig, params map[string]string, rawPayload string, contentType string, authorization string) (channelVerifyNotifyResult, error) {
|
||||||
var verify channelVerifyNotifyResult
|
var verify channelVerifyNotifyResult
|
||||||
if runtimeConfig.isMockMode() {
|
if runtimeConfig.isMockMode() {
|
||||||
return verify, nil
|
return verify, nil
|
||||||
@@ -1032,7 +1032,7 @@ func (r *Repository) verifyNotify(payment *model.PaymentOrder, runtimeConfig *ru
|
|||||||
verify.ParamKeys,
|
verify.ParamKeys,
|
||||||
firstNonEmpty(verify.BaseString["notify_key"], verify.BaseString["notify_cert"]),
|
firstNonEmpty(verify.BaseString["notify_key"], verify.BaseString["notify_cert"]),
|
||||||
)
|
)
|
||||||
if err := r.recordNotifyDiagnostic(payment.ID, params, rawPayload, contentType, verify, "verify_failed"); err != nil {
|
if err := r.recordNotifyDiagnostic(ctx, payment.ID, params, rawPayload, contentType, verify, "verify_failed"); err != nil {
|
||||||
log.Printf("[payment] %s notify diagnostic save failed payment_id=%d err=%v", runtimeConfig.Provider, payment.ID, err)
|
log.Printf("[payment] %s notify diagnostic save failed payment_id=%d err=%v", runtimeConfig.Provider, payment.ID, err)
|
||||||
}
|
}
|
||||||
return verify, ErrPaymentVerifyFailed
|
return verify, ErrPaymentVerifyFailed
|
||||||
@@ -1231,12 +1231,12 @@ func withRawSource(raw map[string]string, source string) map[string]string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) recordNotifyDiagnostic(paymentID uint64, params map[string]string, rawPayload string, contentType string, verify channelVerifyNotifyResult, status string) error {
|
func (r *Repository) recordNotifyDiagnostic(ctx context.Context, paymentID uint64, params map[string]string, rawPayload string, contentType string, verify channelVerifyNotifyResult, status string) error {
|
||||||
if paymentID == 0 {
|
if paymentID == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
raw := withNotifyDiagnostic(params, rawPayload, contentType, verify, status)
|
raw := withNotifyDiagnostic(params, rawPayload, contentType, verify, status)
|
||||||
return r.db.Model(&model.PaymentOrder{}).
|
return r.db.WithContext(ctx).Model(&model.PaymentOrder{}).
|
||||||
Where("id = ?", paymentID).
|
Where("id = ?", paymentID).
|
||||||
Update("raw_response", jsonMap(raw)).Error
|
Update("raw_response", jsonMap(raw)).Error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ func TestRuntimePaymentConfigRequiredFields(t *testing.T) {
|
|||||||
func TestServiceStartRequiresNonZeroOrderID(t *testing.T) {
|
func TestServiceStartRequiresNonZeroOrderID(t *testing.T) {
|
||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
_, err := svc.Start(1, 0, StartPaymentRequest{}, "127.0.0.1")
|
_, err := svc.Start(t.Context(), 1, 0, StartPaymentRequest{}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrPaymentCannotStart) {
|
if !errors.Is(err, ErrPaymentCannotStart) {
|
||||||
t.Fatalf("error = %v, want ErrPaymentCannotStart", err)
|
t.Fatalf("error = %v, want ErrPaymentCannotStart", err)
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ func TestServiceStartRequiresNonZeroOrderID(t *testing.T) {
|
|||||||
func TestServiceStartRequiresNonZeroUserID(t *testing.T) {
|
func TestServiceStartRequiresNonZeroUserID(t *testing.T) {
|
||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
_, err := svc.Start(0, 100, StartPaymentRequest{}, "127.0.0.1")
|
_, err := svc.Start(t.Context(), 0, 100, StartPaymentRequest{}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrPaymentCannotStart) {
|
if !errors.Is(err, ErrPaymentCannotStart) {
|
||||||
t.Fatalf("error = %v, want ErrPaymentCannotStart", err)
|
t.Fatalf("error = %v, want ErrPaymentCannotStart", err)
|
||||||
}
|
}
|
||||||
@@ -264,12 +264,12 @@ func TestServiceStartRequiresNonZeroUserID(t *testing.T) {
|
|||||||
func TestServiceStartRefundRequiresPositiveAmount(t *testing.T) {
|
func TestServiceStartRefundRequiresPositiveAmount(t *testing.T) {
|
||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
_, err := svc.StartRefund(100, 0, "cancel_refund", "test")
|
_, err := svc.StartRefund(t.Context(), 100, 0, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrRefundCannotStart) {
|
if !errors.Is(err, ErrRefundCannotStart) {
|
||||||
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = svc.StartRefund(100, -1000, "cancel_refund", "test")
|
_, err = svc.StartRefund(t.Context(), 100, -1000, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrRefundCannotStart) {
|
if !errors.Is(err, ErrRefundCannotStart) {
|
||||||
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
||||||
}
|
}
|
||||||
@@ -278,7 +278,7 @@ func TestServiceStartRefundRequiresPositiveAmount(t *testing.T) {
|
|||||||
func TestServiceStartRefundRequiresNonZeroOrderID(t *testing.T) {
|
func TestServiceStartRefundRequiresNonZeroOrderID(t *testing.T) {
|
||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
_, err := svc.StartRefund(0, 1000, "cancel_refund", "test")
|
_, err := svc.StartRefund(t.Context(), 0, 1000, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrRefundCannotStart) {
|
if !errors.Is(err, ErrRefundCannotStart) {
|
||||||
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
t.Fatalf("error = %v, want ErrRefundCannotStart", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package payment
|
package payment
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -33,81 +34,81 @@ func NewService(repo *Repository, appEnv ...string) *Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Start(userID uint64, orderID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
func (s *Service) Start(ctx context.Context, userID uint64, orderID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if userID == 0 || orderID == 0 {
|
if userID == 0 || orderID == 0 {
|
||||||
return nil, ErrPaymentCannotStart
|
return nil, ErrPaymentCannotStart
|
||||||
}
|
}
|
||||||
return s.repo.Start(userID, orderID, req, clientIP)
|
return s.repo.Start(ctx, userID, orderID, req, clientIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Query(userID uint64, orderID uint64) (*PaymentDTO, error) {
|
func (s *Service) Query(ctx context.Context, userID uint64, orderID uint64) (*PaymentDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if userID == 0 || orderID == 0 {
|
if userID == 0 || orderID == 0 {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
return s.repo.Query(userID, orderID)
|
return s.repo.Query(ctx, userID, orderID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) StartWalletRecharge(userID uint64, req WalletRechargePaymentRequest, clientIP string) (*PaymentDTO, error) {
|
func (s *Service) StartWalletRecharge(ctx context.Context, userID uint64, req WalletRechargePaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if !s.walletRechargeEnabled {
|
if !s.walletRechargeEnabled {
|
||||||
return nil, ErrWalletRechargeDisabled
|
return nil, ErrWalletRechargeDisabled
|
||||||
}
|
}
|
||||||
return s.repo.StartWalletRecharge(userID, req, clientIP)
|
return s.repo.StartWalletRecharge(ctx, userID, req, clientIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) QueryWalletRecharge(userID uint64, paymentID uint64) (*PaymentDTO, error) {
|
func (s *Service) QueryWalletRecharge(ctx context.Context, userID uint64, paymentID uint64) (*PaymentDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if userID == 0 || paymentID == 0 {
|
if userID == 0 || paymentID == 0 {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
return s.repo.QueryWalletRecharge(userID, paymentID)
|
return s.repo.QueryWalletRecharge(ctx, userID, paymentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) HandleLeshuaNotify(params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
|
func (s *Service) HandleLeshuaNotify(ctx context.Context, params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
return s.repo.HandleLeshuaNotify(params, rawPayload, contentType)
|
return s.repo.HandleLeshuaNotify(ctx, params, rawPayload, contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) HandleNotify(provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
func (s *Service) HandleNotify(ctx context.Context, provider string, params map[string]string, rawPayload string, contentType string, authorization string) (*NotifyResult, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
return s.repo.HandleNotify(provider, params, rawPayload, contentType, authorization)
|
return s.repo.HandleNotify(ctx, provider, params, rawPayload, contentType, authorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) StartRefund(orderID uint64, refundAmountCent int64, bizType string, remark string) (*RefundDTO, error) {
|
func (s *Service) StartRefund(ctx context.Context, orderID uint64, refundAmountCent int64, bizType string, remark string) (*RefundDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if orderID == 0 || refundAmountCent <= 0 {
|
if orderID == 0 || refundAmountCent <= 0 {
|
||||||
return nil, ErrRefundCannotStart
|
return nil, ErrRefundCannotStart
|
||||||
}
|
}
|
||||||
return s.repo.StartRefund(orderID, refundAmountCent, bizType, remark)
|
return s.repo.StartRefund(ctx, orderID, refundAmountCent, bizType, remark)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) QueryRefundStatus(orderID uint64) (*RefundDTO, error) {
|
func (s *Service) QueryRefundStatus(ctx context.Context, orderID uint64) (*RefundDTO, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
if orderID == 0 {
|
if orderID == 0 {
|
||||||
return nil, ErrPaymentNotFound
|
return nil, ErrPaymentNotFound
|
||||||
}
|
}
|
||||||
return s.repo.QueryRefundStatus(orderID)
|
return s.repo.QueryRefundStatus(ctx, orderID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) AdminList(query AdminPaymentQuery) (*PaginatedResult, error) {
|
func (s *Service) AdminList(ctx context.Context, query AdminPaymentQuery) (*PaginatedResult, error) {
|
||||||
if s.repo == nil {
|
if s.repo == nil {
|
||||||
return nil, ErrDependencyUnavailable
|
return nil, ErrDependencyUnavailable
|
||||||
}
|
}
|
||||||
@@ -120,5 +121,5 @@ func (s *Service) AdminList(query AdminPaymentQuery) (*PaginatedResult, error) {
|
|||||||
if query.PageSize > 100 {
|
if query.PageSize > 100 {
|
||||||
query.PageSize = 100
|
query.PageSize = 100
|
||||||
}
|
}
|
||||||
return s.repo.AdminList(query)
|
return s.repo.AdminList(ctx, query)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
// TestServiceDependencyChecks 测试 Service 依赖检查
|
// TestServiceDependencyChecks 测试 Service 依赖检查
|
||||||
func TestServiceStartWithNilRepo(t *testing.T) {
|
func TestServiceStartWithNilRepo(t *testing.T) {
|
||||||
svc := &Service{repo: nil}
|
svc := &Service{repo: nil}
|
||||||
_, err := svc.Start(1, 100, StartPaymentRequest{}, "127.0.0.1")
|
_, err := svc.Start(t.Context(), 1, 100, StartPaymentRequest{}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrDependencyUnavailable) {
|
if !errors.Is(err, ErrDependencyUnavailable) {
|
||||||
t.Fatalf("Start() error = %v, want ErrDependencyUnavailable", err)
|
t.Fatalf("Start() error = %v, want ErrDependencyUnavailable", err)
|
||||||
}
|
}
|
||||||
@@ -18,13 +18,13 @@ func TestServiceStartWithInvalidParams(t *testing.T) {
|
|||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
// 测试 userID 为 0
|
// 测试 userID 为 0
|
||||||
_, err := svc.Start(0, 100, StartPaymentRequest{}, "127.0.0.1")
|
_, err := svc.Start(t.Context(), 0, 100, StartPaymentRequest{}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrPaymentCannotStart) {
|
if !errors.Is(err, ErrPaymentCannotStart) {
|
||||||
t.Fatalf("Start() error = %v, want ErrPaymentCannotStart", err)
|
t.Fatalf("Start() error = %v, want ErrPaymentCannotStart", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试 orderID 为 0
|
// 测试 orderID 为 0
|
||||||
_, err = svc.Start(1, 0, StartPaymentRequest{}, "127.0.0.1")
|
_, err = svc.Start(t.Context(), 1, 0, StartPaymentRequest{}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrPaymentCannotStart) {
|
if !errors.Is(err, ErrPaymentCannotStart) {
|
||||||
t.Fatalf("Start() error = %v, want ErrPaymentCannotStart", err)
|
t.Fatalf("Start() error = %v, want ErrPaymentCannotStart", err)
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ func TestServiceStartWithInvalidParams(t *testing.T) {
|
|||||||
|
|
||||||
func TestServiceQueryWithNilRepo(t *testing.T) {
|
func TestServiceQueryWithNilRepo(t *testing.T) {
|
||||||
svc := &Service{repo: nil}
|
svc := &Service{repo: nil}
|
||||||
_, err := svc.Query(1, 100)
|
_, err := svc.Query(t.Context(), 1, 100)
|
||||||
if !errors.Is(err, ErrDependencyUnavailable) {
|
if !errors.Is(err, ErrDependencyUnavailable) {
|
||||||
t.Fatalf("Query() error = %v, want ErrDependencyUnavailable", err)
|
t.Fatalf("Query() error = %v, want ErrDependencyUnavailable", err)
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func TestServiceQueryWithNilRepo(t *testing.T) {
|
|||||||
func TestServiceQueryWithInvalidParams(t *testing.T) {
|
func TestServiceQueryWithInvalidParams(t *testing.T) {
|
||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
_, err := svc.Query(0, 100)
|
_, err := svc.Query(t.Context(), 0, 100)
|
||||||
if !errors.Is(err, ErrPaymentNotFound) {
|
if !errors.Is(err, ErrPaymentNotFound) {
|
||||||
t.Fatalf("Query() error = %v, want ErrPaymentNotFound", err)
|
t.Fatalf("Query() error = %v, want ErrPaymentNotFound", err)
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ func TestServiceQueryWithInvalidParams(t *testing.T) {
|
|||||||
|
|
||||||
func TestServiceStartRefundWithNilRepo(t *testing.T) {
|
func TestServiceStartRefundWithNilRepo(t *testing.T) {
|
||||||
svc := &Service{repo: nil}
|
svc := &Service{repo: nil}
|
||||||
_, err := svc.StartRefund(100, 1000, "cancel_refund", "test")
|
_, err := svc.StartRefund(t.Context(), 100, 1000, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrDependencyUnavailable) {
|
if !errors.Is(err, ErrDependencyUnavailable) {
|
||||||
t.Fatalf("StartRefund() error = %v, want ErrDependencyUnavailable", err)
|
t.Fatalf("StartRefund() error = %v, want ErrDependencyUnavailable", err)
|
||||||
}
|
}
|
||||||
@@ -59,13 +59,13 @@ func TestServiceStartRefundWithInvalidParams(t *testing.T) {
|
|||||||
svc := &Service{repo: &Repository{}}
|
svc := &Service{repo: &Repository{}}
|
||||||
|
|
||||||
// 测试 orderID 为 0
|
// 测试 orderID 为 0
|
||||||
_, err := svc.StartRefund(0, 1000, "cancel_refund", "test")
|
_, err := svc.StartRefund(t.Context(), 0, 1000, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrRefundCannotStart) {
|
if !errors.Is(err, ErrRefundCannotStart) {
|
||||||
t.Fatalf("StartRefund() error = %v, want ErrRefundCannotStart", err)
|
t.Fatalf("StartRefund() error = %v, want ErrRefundCannotStart", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试金额为 0
|
// 测试金额为 0
|
||||||
_, err = svc.StartRefund(100, 0, "cancel_refund", "test")
|
_, err = svc.StartRefund(t.Context(), 100, 0, "cancel_refund", "test")
|
||||||
if !errors.Is(err, ErrRefundCannotStart) {
|
if !errors.Is(err, ErrRefundCannotStart) {
|
||||||
t.Fatalf("StartRefund() error = %v, want ErrRefundCannotStart", err)
|
t.Fatalf("StartRefund() error = %v, want ErrRefundCannotStart", err)
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ func TestServiceStartRefundWithInvalidParams(t *testing.T) {
|
|||||||
|
|
||||||
func TestServiceWalletRechargeDisabledInProduction(t *testing.T) {
|
func TestServiceWalletRechargeDisabledInProduction(t *testing.T) {
|
||||||
svc := NewService(&Repository{}, "production")
|
svc := NewService(&Repository{}, "production")
|
||||||
_, err := svc.StartWalletRecharge(1, WalletRechargePaymentRequest{AmountCent: 1000}, "127.0.0.1")
|
_, err := svc.StartWalletRecharge(t.Context(), 1, WalletRechargePaymentRequest{AmountCent: 1000}, "127.0.0.1")
|
||||||
if !errors.Is(err, ErrWalletRechargeDisabled) {
|
if !errors.Is(err, ErrWalletRechargeDisabled) {
|
||||||
t.Fatalf("StartWalletRecharge() error = %v, want ErrWalletRechargeDisabled", err)
|
t.Fatalf("StartWalletRecharge() error = %v, want ErrWalletRechargeDisabled", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func NewHandler(service *Service) *Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) List(c *gin.Context) {
|
func (h *Handler) List(c *gin.Context) {
|
||||||
items, err := h.service.List(c.Request.Context(), )
|
items, err := h.service.List(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -28,7 +28,7 @@ func (h *Handler) List(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) PublishOptions(c *gin.Context) {
|
func (h *Handler) PublishOptions(c *gin.Context) {
|
||||||
options, err := h.service.PublishOptions(c.Request.Context(), )
|
options, err := h.service.PublishOptions(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -37,7 +37,7 @@ func (h *Handler) PublishOptions(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) SalePriceConfig(c *gin.Context) {
|
func (h *Handler) SalePriceConfig(c *gin.Context) {
|
||||||
config, err := h.service.SalePriceConfig(c.Request.Context(), )
|
config, err := h.service.SalePriceConfig(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -46,7 +46,7 @@ func (h *Handler) SalePriceConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) OrderAgreements(c *gin.Context) {
|
func (h *Handler) OrderAgreements(c *gin.Context) {
|
||||||
agreements, err := h.service.OrderAgreements(c.Request.Context(), )
|
agreements, err := h.service.OrderAgreements(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -55,7 +55,7 @@ func (h *Handler) OrderAgreements(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) ListingPublishAgreements(c *gin.Context) {
|
func (h *Handler) ListingPublishAgreements(c *gin.Context) {
|
||||||
agreements, err := h.service.ListingPublishAgreements(c.Request.Context(), )
|
agreements, err := h.service.ListingPublishAgreements(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -64,7 +64,7 @@ func (h *Handler) ListingPublishAgreements(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) PostRentalNotice(c *gin.Context) {
|
func (h *Handler) PostRentalNotice(c *gin.Context) {
|
||||||
notice, err := h.service.PostRentalNotice(c.Request.Context(), )
|
notice, err := h.service.PostRentalNotice(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -73,7 +73,7 @@ func (h *Handler) PostRentalNotice(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) HomeAnnouncements(c *gin.Context) {
|
func (h *Handler) HomeAnnouncements(c *gin.Context) {
|
||||||
announcements, err := h.service.HomeAnnouncements(c.Request.Context(), )
|
announcements, err := h.service.HomeAnnouncements(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
@@ -82,7 +82,7 @@ func (h *Handler) HomeAnnouncements(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) HomeConfig(c *gin.Context) {
|
func (h *Handler) HomeConfig(c *gin.Context) {
|
||||||
config, err := h.service.HomeConfig(c.Request.Context(), )
|
config, err := h.service.HomeConfig(c.Request.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeConfigError(c, err)
|
writeConfigError(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
|
|||||||
// Inject refund function into order repo to avoid circular dependency
|
// Inject refund function into order repo to avoid circular dependency
|
||||||
if orderRepo != nil && paymentRepo != nil {
|
if orderRepo != nil && paymentRepo != nil {
|
||||||
orderRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
orderRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
||||||
dto, err := paymentRepo.StartRefund(orderID, refundAmountCent, bizType, remark)
|
dto, err := paymentRepo.StartRefund(context.Background(), orderID, refundAmountCent, bizType, remark)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -200,7 +201,7 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
|
|||||||
}
|
}
|
||||||
if disputeRepo != nil && paymentRepo != nil {
|
if disputeRepo != nil && paymentRepo != nil {
|
||||||
disputeRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
disputeRepo.SetRefundFunc(func(orderID uint64, refundAmountCent int64, bizType string, remark string) (string, error) {
|
||||||
dto, err := paymentRepo.StartRefund(orderID, refundAmountCent, bizType, remark)
|
dto, err := paymentRepo.StartRefund(context.Background(), orderID, refundAmountCent, bizType, remark)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user