62 lines
2.6 KiB
Go
62 lines
2.6 KiB
Go
package payment
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/config"
|
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
|
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const (
|
|
StatusPending = 10
|
|
StatusPaid = 23
|
|
StatusClosed = 30
|
|
)
|
|
|
|
type CreateInput struct {
|
|
RequestNo, BusinessType, BusinessIdentity, UserIdentity string
|
|
Channel, PayType, Subject, OpenID string
|
|
Amount int64
|
|
}
|
|
|
|
// Create 创建幂等支付单并向渠道请求客户端调起参数。
|
|
func Create(ctx context.Context, input CreateInput) (models.PaymentOrder, error) {
|
|
if input.Amount <= 0 || input.RequestNo == "" || input.BusinessIdentity == "" || input.UserIdentity == "" {
|
|
return models.PaymentOrder{}, gorm.ErrInvalidData
|
|
}
|
|
var existing models.PaymentOrder
|
|
if err := impl.DBService.Where("business_type = ? AND request_no = ?", input.BusinessType, input.RequestNo).First(&existing).Error; err == nil {
|
|
if existing.BusinessIdentity != input.BusinessIdentity || existing.Amount != input.Amount || existing.Channel != input.Channel || existing.PayType != input.PayType {
|
|
return existing, errors.New("idempotency conflict")
|
|
}
|
|
return existing, nil
|
|
}
|
|
order := models.PaymentOrder{Entity: models.Entity{Identity: models.NewIdentity(), Status: 1}, PaymentStatus: StatusPending,
|
|
PaymentNo: "PAY" + time.Now().Format("20060102150405.000000"), RequestNo: input.RequestNo, BusinessType: input.BusinessType,
|
|
BusinessIdentity: input.BusinessIdentity, UserIdentity: input.UserIdentity, MerchantIdentity: "platform", Channel: input.Channel,
|
|
PayType: input.PayType, Amount: input.Amount, Subject: input.Subject, ExpiresAt: time.Now().Add(time.Duration(config.Spec.Payment.ExpireMinutes) * time.Minute)}
|
|
args, err := createChannelOrder(ctx, order, input.OpenID)
|
|
if err != nil {
|
|
return order, err
|
|
}
|
|
order.ClientArgs = args
|
|
if err = impl.DBService.Create(&order).Error; err != nil {
|
|
return order, err
|
|
}
|
|
return order, nil
|
|
}
|
|
|
|
// PublicResponse 仅返回客户端调起支付所需的非密钥参数。
|
|
func PublicResponse(order models.PaymentOrder) map[string]any {
|
|
response := map[string]any{"identity": order.Identity, "payment_no": order.PaymentNo, "payment_status": order.PaymentStatus,
|
|
"channel": order.Channel, "pay_type": order.PayType, "amount": order.Amount, "client_args": order.ClientArgs, "expires_at": order.ExpiresAt}
|
|
if order.Channel == "wechat" && order.PayType == "app" {
|
|
response["app_id"] = config.Spec.Payment.Wechat.AppAppID
|
|
}
|
|
return response
|
|
}
|