微信相关能力
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||||
"github.com/break/junhong_cmp_fiber/internal/service/personal_customer"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
@@ -108,27 +109,49 @@ func (h *PersonalCustomerHandler) Login(c *fiber.Ctx) error {
|
||||
return response.Success(c, resp)
|
||||
}
|
||||
|
||||
// BindWechatRequest 绑定微信请求
|
||||
type BindWechatRequest struct {
|
||||
Code string `json:"code" validate:"required"` // 微信授权码
|
||||
}
|
||||
|
||||
// BindWechat 绑定微信
|
||||
// POST /api/c/v1/bind-wechat
|
||||
// TODO: 实现微信 OAuth 授权逻辑
|
||||
func (h *PersonalCustomerHandler) BindWechat(c *fiber.Ctx) error {
|
||||
var req BindWechatRequest
|
||||
// WechatOAuthLogin 微信 OAuth 登录
|
||||
// POST /api/c/v1/wechat/auth
|
||||
func (h *PersonalCustomerHandler) WechatOAuthLogin(c *fiber.Ctx) error {
|
||||
var req dto.WechatOAuthRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
|
||||
// TODO: 实现完整的微信绑定流程
|
||||
// 1. 从 context 中获取当前登录的客户 ID
|
||||
// 2. 使用微信授权码换取 OpenID 和 UnionID
|
||||
// 3. 调用 service 层的 BindWechat 方法绑定微信
|
||||
result, err := h.service.WechatOAuthLogin(c.Context(), req.Code)
|
||||
if err != nil {
|
||||
h.logger.Error("微信 OAuth 登录失败",
|
||||
zap.String("code", req.Code),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, result)
|
||||
}
|
||||
|
||||
// BindWechat 绑定微信
|
||||
// POST /api/c/v1/bind-wechat
|
||||
func (h *PersonalCustomerHandler) BindWechat(c *fiber.Ctx) error {
|
||||
var req dto.WechatOAuthRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
|
||||
customerID, ok := c.Locals("customer_id").(uint)
|
||||
if !ok {
|
||||
return errors.New(errors.CodeUnauthorized, "未找到客户信息")
|
||||
}
|
||||
|
||||
if err := h.service.BindWechatWithCode(c.Context(), customerID, req.Code); err != nil {
|
||||
h.logger.Error("绑定微信失败",
|
||||
zap.Uint("customer_id", customerID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, fiber.Map{
|
||||
"message": "微信绑定功能暂未实现,待微信 SDK 对接后启用",
|
||||
"message": "绑定成功",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,51 @@
|
||||
package callback
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
orderService "github.com/break/junhong_cmp_fiber/internal/service/order"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/wechat"
|
||||
)
|
||||
|
||||
type PaymentHandler struct {
|
||||
orderService *orderService.Service
|
||||
orderService *orderService.Service
|
||||
wechatPayment wechat.PaymentServiceInterface
|
||||
}
|
||||
|
||||
func NewPaymentHandler(orderService *orderService.Service) *PaymentHandler {
|
||||
return &PaymentHandler{orderService: orderService}
|
||||
}
|
||||
|
||||
type WechatPayCallbackRequest struct {
|
||||
OrderNo string `json:"order_no" xml:"out_trade_no"`
|
||||
func NewPaymentHandler(orderService *orderService.Service, wechatPayment wechat.PaymentServiceInterface) *PaymentHandler {
|
||||
return &PaymentHandler{
|
||||
orderService: orderService,
|
||||
wechatPayment: wechatPayment,
|
||||
}
|
||||
}
|
||||
|
||||
// WechatPayCallback 微信支付回调(带签名验证)
|
||||
// POST /api/callback/wechat-pay
|
||||
func (h *PaymentHandler) WechatPayCallback(c *fiber.Ctx) error {
|
||||
var req WechatPayCallbackRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
if h.wechatPayment == nil {
|
||||
return errors.New(errors.CodeWechatCallbackInvalid, "微信支付服务未配置")
|
||||
}
|
||||
|
||||
if req.OrderNo == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "订单号不能为空")
|
||||
}
|
||||
var httpReq http.Request
|
||||
fasthttpadaptor.ConvertRequest(c.Context(), &httpReq, true)
|
||||
|
||||
if err := h.orderService.HandlePaymentCallback(c.UserContext(), req.OrderNo, model.PaymentMethodWechat); err != nil {
|
||||
return err
|
||||
ctx := context.Background()
|
||||
_, err := h.wechatPayment.HandlePaymentNotify(&httpReq, func(result *wechat.PaymentNotifyResult) error {
|
||||
if result.TradeState != "SUCCESS" {
|
||||
return nil
|
||||
}
|
||||
return h.orderService.HandlePaymentCallback(ctx, result.OutTradeNo, model.PaymentMethodWechat)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CodeWechatCallbackInvalid, err, "处理微信支付回调失败")
|
||||
}
|
||||
|
||||
return response.Success(c, map[string]string{"return_code": "SUCCESS"})
|
||||
|
||||
@@ -129,3 +129,79 @@ func (h *OrderHandler) WalletPay(c *fiber.Ctx) error {
|
||||
|
||||
return response.Success(c, nil)
|
||||
}
|
||||
|
||||
// WechatPayJSAPI 微信 JSAPI 支付
|
||||
// POST /api/h5/orders/:id/wechat-pay/jsapi
|
||||
func (h *OrderHandler) WechatPayJSAPI(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的订单ID")
|
||||
}
|
||||
|
||||
var req dto.WechatPayJSAPIRequest
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
|
||||
ctx := c.UserContext()
|
||||
userType := middleware.GetUserTypeFromContext(ctx)
|
||||
|
||||
var buyerType string
|
||||
var buyerID uint
|
||||
|
||||
switch userType {
|
||||
case constants.UserTypeAgent:
|
||||
buyerType = model.BuyerTypeAgent
|
||||
buyerID = middleware.GetShopIDFromContext(ctx)
|
||||
case constants.UserTypePersonalCustomer:
|
||||
buyerType = model.BuyerTypePersonal
|
||||
buyerID = middleware.GetCustomerIDFromContext(ctx)
|
||||
default:
|
||||
return errors.New(errors.CodeForbidden, "不支持的用户类型")
|
||||
}
|
||||
|
||||
result, err := h.service.WechatPayJSAPI(ctx, uint(id), req.OpenID, buyerType, buyerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, result)
|
||||
}
|
||||
|
||||
// WechatPayH5 微信 H5 支付
|
||||
// POST /api/h5/orders/:id/wechat-pay/h5
|
||||
func (h *OrderHandler) WechatPayH5(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的订单ID")
|
||||
}
|
||||
|
||||
var req dto.WechatPayH5Request
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||||
}
|
||||
|
||||
ctx := c.UserContext()
|
||||
userType := middleware.GetUserTypeFromContext(ctx)
|
||||
|
||||
var buyerType string
|
||||
var buyerID uint
|
||||
|
||||
switch userType {
|
||||
case constants.UserTypeAgent:
|
||||
buyerType = model.BuyerTypeAgent
|
||||
buyerID = middleware.GetShopIDFromContext(ctx)
|
||||
case constants.UserTypePersonalCustomer:
|
||||
buyerType = model.BuyerTypePersonal
|
||||
buyerID = middleware.GetCustomerIDFromContext(ctx)
|
||||
default:
|
||||
return errors.New(errors.CodeForbidden, "不支持的用户类型")
|
||||
}
|
||||
|
||||
result, err := h.service.WechatPayH5(ctx, uint(id), &req.SceneInfo, buyerType, buyerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return response.Success(c, result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user