feat(quality-owner): 增加优质号主、极品专区与无忧租号保险
- 支持保证金余额支付、在线支付开通及后台手动设置审计 - 新增极品专区发布权限、赔付方案与保险结算费率快照 - 优化首页、商品卡和个人中心的优质号主身份展示
This commit is contained in:
@@ -48,30 +48,45 @@ func (r *Repository) confirmPaid(ctx context.Context, payment *model.PaymentOrde
|
||||
var newConvID uint64
|
||||
var notifyFn func(uint64)
|
||||
err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if payment.OrderID != 0 {
|
||||
switch payment.BizType {
|
||||
case "mohong_pay":
|
||||
if r.mohongRepo == nil {
|
||||
return ErrDependencyUnavailable
|
||||
}
|
||||
convID, err := r.mohongRepo.ConfirmPaidFromChannelTx(tx, payment.OrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newConvID = convID
|
||||
notifyFn = r.mohongRepo.NotifyNewConversation
|
||||
default:
|
||||
if r.orderRepo == nil {
|
||||
return ErrDependencyUnavailable
|
||||
}
|
||||
convID, err := r.orderRepo.ConfirmPaidFromChannelTx(tx, payment.OrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newConvID = convID
|
||||
notifyFn = r.orderRepo.NotifyNewConversation
|
||||
if err := distribution.SnapshotPaidOrderTx(tx, payment.OrderID, payment.AmountCent); err != nil {
|
||||
return err
|
||||
switch payment.BizType {
|
||||
case qualityOwnerPayBizType:
|
||||
if r.qualityOwnerRepo == nil {
|
||||
return ErrDependencyUnavailable
|
||||
}
|
||||
if err := r.qualityOwnerRepo.ConfirmQualityOwnerDepositPaidTx(
|
||||
tx,
|
||||
payment.UserID,
|
||||
payment.AmountCent,
|
||||
payment.PaymentNo,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if payment.OrderID != 0 {
|
||||
switch payment.BizType {
|
||||
case "mohong_pay":
|
||||
if r.mohongRepo == nil {
|
||||
return ErrDependencyUnavailable
|
||||
}
|
||||
convID, err := r.mohongRepo.ConfirmPaidFromChannelTx(tx, payment.OrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newConvID = convID
|
||||
notifyFn = r.mohongRepo.NotifyNewConversation
|
||||
default:
|
||||
if r.orderRepo == nil {
|
||||
return ErrDependencyUnavailable
|
||||
}
|
||||
convID, err := r.orderRepo.ConfirmPaidFromChannelTx(tx, payment.OrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newConvID = convID
|
||||
notifyFn = r.orderRepo.NotifyNewConversation
|
||||
if err := distribution.SnapshotPaidOrderTx(tx, payment.OrderID, payment.AmountCent); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ type PaymentDTO struct {
|
||||
PaymentNo string `json:"payment_no"`
|
||||
OrderID uint64 `json:"order_id"`
|
||||
OrderNo string `json:"order_no"`
|
||||
BizID uint64 `json:"biz_id"`
|
||||
PaymentConfigID uint64 `json:"payment_config_id"`
|
||||
Provider string `json:"provider"`
|
||||
ThirdOrderID string `json:"third_order_id"`
|
||||
@@ -28,6 +29,7 @@ type PaymentDTO struct {
|
||||
PayWay string `json:"pay_way"`
|
||||
JSPayFlag string `json:"jspay_flag"`
|
||||
AmountCent int64 `json:"amount_cent"`
|
||||
BizType string `json:"biz_type"`
|
||||
Status string `json:"status"`
|
||||
TDCode string `json:"td_code,omitempty"`
|
||||
JSPayURL string `json:"jspay_url,omitempty"`
|
||||
@@ -80,6 +82,7 @@ type AdminPaymentDTO struct {
|
||||
PaymentNo string `json:"payment_no"`
|
||||
OrderID uint64 `json:"order_id"`
|
||||
OrderNo string `json:"order_no"`
|
||||
BizID uint64 `json:"biz_id"`
|
||||
UserID uint64 `json:"user_id"`
|
||||
PaymentConfigID uint64 `json:"payment_config_id"`
|
||||
UserPhone string `json:"user_phone"`
|
||||
|
||||
@@ -111,6 +111,22 @@ func (h *Handler) StartMohong(c *gin.Context) {
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) StartQualityOwner(c *gin.Context) {
|
||||
userID, ok := currentUserID(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "缺少用户上下文")
|
||||
return
|
||||
}
|
||||
var req StartPaymentRequest
|
||||
_ = c.ShouldBindJSON(&req)
|
||||
item, err := h.service.StartQualityOwner(c.Request.Context(), userID, req, c.ClientIP())
|
||||
if err != nil {
|
||||
writePaymentError(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) Query(c *gin.Context) {
|
||||
userID, ok := currentUserID(c)
|
||||
if !ok {
|
||||
@@ -147,6 +163,20 @@ func (h *Handler) QueryMohong(c *gin.Context) {
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) QueryQualityOwner(c *gin.Context) {
|
||||
userID, ok := currentUserID(c)
|
||||
if !ok {
|
||||
response.Unauthorized(c, "缺少用户上下文")
|
||||
return
|
||||
}
|
||||
item, err := h.service.QueryQualityOwner(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
writePaymentError(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) AdminRefundMohong(c *gin.Context) {
|
||||
orderID, ok := parseID(c)
|
||||
if !ok {
|
||||
|
||||
@@ -20,6 +20,11 @@ func (r *Repository) Start(ctx context.Context, userID uint64, orderID uint64, r
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.startPreparedPayment(ctx, payment, "租号订单 "+orderRow.OrderNo, orderRow.OrderNo, clientIP)
|
||||
}
|
||||
|
||||
// startPreparedPayment 对已经创建或复用的支付单执行渠道下单、收银台复用或模拟支付。
|
||||
func (r *Repository) startPreparedPayment(ctx context.Context, payment *model.PaymentOrder, body string, attach string, clientIP string) (*PaymentDTO, error) {
|
||||
runtimeConfig, err := r.runtimeConfigForPayment(ctx, payment)
|
||||
if err != nil {
|
||||
return nil, ErrPaymentUnavailable
|
||||
@@ -64,8 +69,8 @@ func (r *Repository) Start(ctx context.Context, userID uint64, orderID uint64, r
|
||||
NotifyURL: runtimeConfig.NotifyURL,
|
||||
JumpURL: runtimeConfig.JumpURL,
|
||||
ClientIP: clientIP,
|
||||
Body: "租号订单 " + orderRow.OrderNo,
|
||||
Attach: orderRow.OrderNo,
|
||||
Body: body,
|
||||
Attach: attach,
|
||||
})
|
||||
if err != nil {
|
||||
_ = r.markPaymentFailed(ctx, payment.ID, nil, err.Error())
|
||||
|
||||
@@ -19,6 +19,7 @@ func toDTO(payment model.PaymentOrder) PaymentDTO {
|
||||
PaymentNo: payment.PaymentNo,
|
||||
OrderID: payment.OrderID,
|
||||
OrderNo: payment.OrderNo,
|
||||
BizID: payment.BizID,
|
||||
PaymentConfigID: payment.PaymentConfigID,
|
||||
Provider: payment.Provider,
|
||||
ThirdOrderID: payment.ThirdOrderID,
|
||||
@@ -26,6 +27,7 @@ func toDTO(payment model.PaymentOrder) PaymentDTO {
|
||||
PayWay: payment.PayWay,
|
||||
JSPayFlag: payment.JSPayFlag,
|
||||
AmountCent: payment.AmountCent,
|
||||
BizType: payment.BizType,
|
||||
Status: payment.Status,
|
||||
TDCode: payment.TDCode,
|
||||
JSPayURL: payment.JSPayURL,
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"hfb_sys/backend/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
const qualityOwnerPayBizType = "quality_owner_pay"
|
||||
|
||||
// StartQualityOwner 创建优质号主保证金在线支付单,支付成功后自动开通资格并冻结保证金。
|
||||
func (r *Repository) StartQualityOwner(ctx context.Context, userID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||
if r.qualityOwnerRepo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
req.PayWay = normalizePayWay(req.PayWay)
|
||||
payment, err := r.prepareQualityOwnerPayment(ctx, userID, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.startPreparedPayment(ctx, payment, "优质号主保证金", payment.OrderNo, clientIP)
|
||||
}
|
||||
|
||||
func (r *Repository) prepareQualityOwnerPayment(ctx context.Context, userID uint64, req StartPaymentRequest) (*model.PaymentOrder, error) {
|
||||
amountCent, active, err := r.qualityOwnerRepo.PaymentAmount(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if active || amountCent <= 0 {
|
||||
return nil, ErrPaymentCannotStart
|
||||
}
|
||||
runtimeConfig, err := r.defaultRuntimeConfig(ctx, req.PayWay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var paymentID uint64
|
||||
err = r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
var user model.User
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
Select("id").
|
||||
First(&user, userID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
var existing model.PaymentOrder
|
||||
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
|
||||
Where("user_id = ? AND biz_type = ? AND biz_id = ?", userID, qualityOwnerPayBizType, userID).
|
||||
Order("id DESC").
|
||||
First(&existing).Error
|
||||
if err == nil {
|
||||
if canReuseOrderPayment(existing, *runtimeConfig) {
|
||||
existing.PayWay = firstNonEmpty(req.PayWay, existing.PayWay, runtimeConfig.PayWay, "ZFBZF")
|
||||
existing.JSPayFlag = firstNonEmpty(req.JSPayFlag, existing.JSPayFlag, runtimeConfig.JSPayFlag, "2")
|
||||
existing.AmountCent = amountCent
|
||||
existing.PaymentConfigID = firstNonZero(existing.PaymentConfigID, runtimeConfig.ID)
|
||||
existing.Provider = firstNonEmpty(existing.Provider, runtimeConfig.Provider)
|
||||
existing.MerchantID = firstNonEmpty(existing.MerchantID, runtimeConfig.MerchantID)
|
||||
if existing.Provider == "mock" && existing.ProviderOrderID == "" {
|
||||
existing.ProviderOrderID = "MOCK" + existing.ThirdOrderID
|
||||
}
|
||||
if err := tx.Save(&existing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
paymentID = existing.ID
|
||||
return nil
|
||||
}
|
||||
} else if err != gorm.ErrRecordNotFound {
|
||||
return err
|
||||
}
|
||||
payment, err := newQualityOwnerPayment(userID, amountCent, req, *runtimeConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&payment).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
paymentID = payment.ID
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.findPaymentByID(ctx, paymentID)
|
||||
}
|
||||
|
||||
func newQualityOwnerPayment(userID uint64, amountCent int64, req StartPaymentRequest, runtimeConfig runtimePaymentConfig) (model.PaymentOrder, error) {
|
||||
paymentNo, err := newPaymentNo()
|
||||
if err != nil {
|
||||
return model.PaymentOrder{}, err
|
||||
}
|
||||
orderNo := fmt.Sprintf("QO%d", userID)
|
||||
payment := model.PaymentOrder{
|
||||
PaymentNo: paymentNo,
|
||||
OrderID: 0,
|
||||
OrderNo: orderNo,
|
||||
BizID: userID,
|
||||
UserID: userID,
|
||||
PaymentConfigID: runtimeConfig.ID,
|
||||
Provider: runtimeConfig.Provider,
|
||||
MerchantID: runtimeConfig.MerchantID,
|
||||
ThirdOrderID: paymentNo,
|
||||
PayWay: firstNonEmpty(req.PayWay, runtimeConfig.PayWay, "ZFBZF"),
|
||||
JSPayFlag: firstNonEmpty(req.JSPayFlag, runtimeConfig.JSPayFlag, "2"),
|
||||
AmountCent: amountCent,
|
||||
BizType: qualityOwnerPayBizType,
|
||||
Status: "created",
|
||||
}
|
||||
if runtimeConfig.isMockMode() {
|
||||
payment.ProviderOrderID = "MOCK" + paymentNo
|
||||
payment.TDCode = "mock://payment/pay/" + paymentNo
|
||||
}
|
||||
return payment, nil
|
||||
}
|
||||
|
||||
func (r *Repository) QueryQualityOwner(ctx context.Context, userID uint64) (*PaymentDTO, error) {
|
||||
var payment model.PaymentOrder
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("user_id = ? AND biz_type = ? AND biz_id = ?", userID, qualityOwnerPayBizType, userID).
|
||||
Order("id DESC").
|
||||
First(&payment).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, ErrPaymentNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if isOrderPaymentTerminalStatus(payment.Status) {
|
||||
dto := toDTO(payment)
|
||||
return &dto, nil
|
||||
}
|
||||
runtimeConfig, err := r.runtimeConfigForPayment(ctx, &payment)
|
||||
if err != nil {
|
||||
return nil, ErrPaymentUnavailable
|
||||
}
|
||||
if runtimeConfig.isMockMode() {
|
||||
dto := toDTO(payment)
|
||||
return &dto, nil
|
||||
}
|
||||
if runtimeConfig.Channel == nil {
|
||||
return nil, ErrPaymentUnavailable
|
||||
}
|
||||
resp, err := runtimeConfig.Channel.QueryPayment(ctx, payment.ThirdOrderID, payment.ProviderOrderID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.applyChannelStatus(ctx, &payment, resp.Status, resp.PayTime, resp.Raw, channelSourceQuery); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
latest, err := r.findPaymentByID(ctx, payment.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dto := toDTO(*latest)
|
||||
return &dto, nil
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"hfb_sys/backend/internal/database"
|
||||
"hfb_sys/backend/internal/model"
|
||||
"hfb_sys/backend/internal/modules/qualityowner"
|
||||
)
|
||||
|
||||
func TestConfirmQualityOwnerPaymentFreezesDepositAndIsIdempotent(t *testing.T) {
|
||||
db := database.NewTestDB()
|
||||
user := model.User{
|
||||
Phone: "13900009401",
|
||||
RealnameStatus: "verified",
|
||||
Status: "active",
|
||||
}
|
||||
if err := db.Create(&user).Error; err != nil {
|
||||
t.Fatalf("创建用户失败: %v", err)
|
||||
}
|
||||
if err := db.Create(&model.WalletAccount{
|
||||
UserID: user.ID,
|
||||
AvailableBalanceCent: 0,
|
||||
Status: "active",
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("创建钱包失败: %v", err)
|
||||
}
|
||||
payment := model.PaymentOrder{
|
||||
PaymentNo: "PAYQUALITYOWNER01",
|
||||
OrderID: 0,
|
||||
OrderNo: "QOQUALITY",
|
||||
BizID: user.ID,
|
||||
UserID: user.ID,
|
||||
Provider: "mock",
|
||||
ThirdOrderID: "PAYQUALITYOWNER01",
|
||||
AmountCent: 20_000,
|
||||
BizType: qualityOwnerPayBizType,
|
||||
Status: "paying",
|
||||
}
|
||||
if err := db.Create(&payment).Error; err != nil {
|
||||
t.Fatalf("创建支付单失败: %v", err)
|
||||
}
|
||||
repo := NewRepository(db, nil, nil, WithQualityOwnerRepo(qualityowner.NewRepository(db)))
|
||||
raw := map[string]string{"status": "2", "third_order_id": payment.ThirdOrderID}
|
||||
if err := repo.confirmPaid(t.Context(), &payment, "2", time.Now(), raw, channelSourceMock); err != nil {
|
||||
t.Fatalf("确认保证金支付失败: %v", err)
|
||||
}
|
||||
if err := repo.confirmPaid(t.Context(), &payment, "2", time.Now(), raw, channelSourceMock); err != nil {
|
||||
t.Fatalf("重复确认保证金支付失败: %v", err)
|
||||
}
|
||||
|
||||
var gotUser model.User
|
||||
if err := db.First(&gotUser, user.ID).Error; err != nil {
|
||||
t.Fatalf("读取用户失败: %v", err)
|
||||
}
|
||||
if gotUser.QualityOwnerStatus != qualityowner.StatusActive || gotUser.QualityOwnerDepositCent != 20_000 {
|
||||
t.Fatalf("用户未开通优质号主: %+v", gotUser)
|
||||
}
|
||||
var account model.WalletAccount
|
||||
if err := db.Where("user_id = ? AND distribution_site_id = 0", user.ID).First(&account).Error; err != nil {
|
||||
t.Fatalf("读取钱包失败: %v", err)
|
||||
}
|
||||
if account.AvailableBalanceCent != 0 || account.FrozenBalanceCent != 20_000 {
|
||||
t.Fatalf("保证金钱包余额不正确: %+v", account)
|
||||
}
|
||||
var ledgerCount int64
|
||||
if err := db.Model(&model.WalletLedger{}).
|
||||
Where("user_id = ? AND biz_type = ?", user.ID, "quality_owner_deposit").
|
||||
Count(&ledgerCount).Error; err != nil {
|
||||
t.Fatalf("统计保证金流水失败: %v", err)
|
||||
}
|
||||
if ledgerCount != 1 {
|
||||
t.Fatalf("保证金流水条数 = %d, want 1", ledgerCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewQualityOwnerPaymentUsesBizIDAndMockCashier(t *testing.T) {
|
||||
payment, err := newQualityOwnerPayment(88, 20_000, StartPaymentRequest{PayWay: "WXZF"}, runtimePaymentConfig{
|
||||
Provider: "mock",
|
||||
MerchantID: "mock-merchant",
|
||||
PayWay: "WXZF",
|
||||
JSPayFlag: "2",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("newQualityOwnerPayment() error = %v", err)
|
||||
}
|
||||
if payment.BizType != qualityOwnerPayBizType || payment.BizID != 88 || payment.UserID != 88 {
|
||||
t.Fatalf("保证金支付单业务字段不正确: %+v", payment)
|
||||
}
|
||||
if payment.OrderID != 0 || payment.AmountCent != 20_000 {
|
||||
t.Fatalf("保证金支付单订单/金额不正确: %+v", payment)
|
||||
}
|
||||
if payment.TDCode == "" || payment.ProviderOrderID == "" {
|
||||
t.Fatalf("mock 支付单未生成收银台: %+v", payment)
|
||||
}
|
||||
}
|
||||
@@ -107,6 +107,7 @@ func (row adminPaymentRow) toDTO() AdminPaymentDTO {
|
||||
PaymentNo: row.PaymentNo,
|
||||
OrderID: row.OrderID,
|
||||
OrderNo: row.OrderNo,
|
||||
BizID: row.BizID,
|
||||
UserID: row.UserID,
|
||||
PaymentConfigID: row.PaymentConfigID,
|
||||
UserPhone: row.UserPhone,
|
||||
|
||||
@@ -19,12 +19,19 @@ type MohongOrderConfirmer interface {
|
||||
NotifyNewConversation(conversationID uint64)
|
||||
}
|
||||
|
||||
// QualityOwnerPaymentAdapter 由优质号主模块实现,避免 payment 与 qualityowner 直接耦合。
|
||||
type QualityOwnerPaymentAdapter interface {
|
||||
PaymentAmount(ctx context.Context, userID uint64) (amountCent int64, active bool, err error)
|
||||
ConfirmQualityOwnerDepositPaidTx(tx *gorm.DB, userID uint64, amountCent int64, paymentNo string) error
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
db *gorm.DB
|
||||
configRepo *paymentconfig.Repository
|
||||
orderRepo *order.Repository
|
||||
mohongRepo MohongOrderConfirmer
|
||||
logger *zap.Logger
|
||||
db *gorm.DB
|
||||
configRepo *paymentconfig.Repository
|
||||
orderRepo *order.Repository
|
||||
mohongRepo MohongOrderConfirmer
|
||||
qualityOwnerRepo QualityOwnerPaymentAdapter
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
type runtimePaymentConfig struct {
|
||||
@@ -96,6 +103,13 @@ func WithMohongRepo(repo MohongOrderConfirmer) RepositoryOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithQualityOwnerRepo 注入优质号主保证金支付适配器。
|
||||
func WithQualityOwnerRepo(repo QualityOwnerPaymentAdapter) RepositoryOption {
|
||||
return func(r *Repository) {
|
||||
r.qualityOwnerRepo = repo
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) log() *zap.Logger {
|
||||
if r == nil || r.logger == nil {
|
||||
return zap.NewNop()
|
||||
|
||||
@@ -42,6 +42,16 @@ func (s *Service) StartMohong(ctx context.Context, userID uint64, orderID uint64
|
||||
return s.repo.StartMohong(ctx, userID, orderID, req, clientIP)
|
||||
}
|
||||
|
||||
func (s *Service) StartQualityOwner(ctx context.Context, userID uint64, req StartPaymentRequest, clientIP string) (*PaymentDTO, error) {
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
if userID == 0 {
|
||||
return nil, ErrPaymentCannotStart
|
||||
}
|
||||
return s.repo.StartQualityOwner(ctx, userID, req, clientIP)
|
||||
}
|
||||
|
||||
func (s *Service) Query(ctx context.Context, userID uint64, orderID uint64) (*PaymentDTO, error) {
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
@@ -62,6 +72,16 @@ func (s *Service) QueryMohong(ctx context.Context, userID uint64, orderID uint64
|
||||
return s.repo.QueryMohong(ctx, userID, orderID)
|
||||
}
|
||||
|
||||
func (s *Service) QueryQualityOwner(ctx context.Context, userID uint64) (*PaymentDTO, error) {
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
}
|
||||
if userID == 0 {
|
||||
return nil, ErrPaymentNotFound
|
||||
}
|
||||
return s.repo.QueryQualityOwner(ctx, userID)
|
||||
}
|
||||
|
||||
func (s *Service) HandleLeshuaNotify(ctx context.Context, params map[string]string, rawPayload string, contentType string) (*NotifyResult, error) {
|
||||
if s.repo == nil {
|
||||
return nil, ErrDependencyUnavailable
|
||||
|
||||
Reference in New Issue
Block a user