package handler import ( "io" "kra/internal/service/dto" paymentservice "kra/internal/service/payment" "net/http" "github.com/gin-gonic/gin" ) type Payment struct { service *paymentservice.PaymentService } func NewPayment(service *paymentservice.PaymentService) *Payment { return &Payment{service: service} } func (h *Payment) Order(c *gin.Context) { var req dto.PaymentQueryRequest if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } order, err := h.service.Order(c.Request.Context(), req.Provider, req.TradeNo) if err != nil { Fail(c, err.Error()) return } OKWithData(c, order) } func (h *Payment) OrderByPath(c *gin.Context) { order, err := h.service.Order(c.Request.Context(), c.Param("provider"), c.Param("tradeNo")) if err != nil { Fail(c, err.Error()) return } OKWithData(c, order) } func (h *Payment) RefundByPath(c *gin.Context) { var req struct { Amount int64 `json:"amount"` Reason string `json:"reason"` } if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } request := &dto.PaymentRefundRequest{Provider: c.Param("provider"), TradeNo: c.Param("tradeNo"), Amount: req.Amount, Reason: req.Reason} setPaymentRequestActor(c, &request.OperatorID, &request.OperatorName, &request.ClientIP, &request.UserAgent, &request.DeviceID) result, err := h.service.Refund(c.Request.Context(), request) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) FulfillByPath(c *gin.Context) { request := &dto.PaymentFulfillRequest{Provider: c.Param("provider"), TradeNo: c.Param("tradeNo")} setPaymentRequestActor(c, &request.OperatorID, &request.OperatorName, &request.ClientIP, &request.UserAgent, &request.DeviceID) result, err := h.service.Fulfill(c.Request.Context(), request) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Orders(c *gin.Context) { var req dto.PaymentOrderListRequest if err := c.ShouldBindQuery(&req); err != nil { Fail(c, err.Error()) return } items, total, page, pageSize, err := h.service.Orders(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } Write(c, CodeSuccess, PageResult{List: items, Total: total, Page: page, PageSize: pageSize}, "获取成功") } func (h *Payment) OrderSummary(c *gin.Context) { var req dto.PaymentOrderListRequest if err := c.ShouldBindQuery(&req); err != nil { Fail(c, err.Error()) return } result, err := h.service.OrderSummary(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) OrderEvents(c *gin.Context) { var req struct { Limit int `form:"limit"` } if err := c.ShouldBindQuery(&req); err != nil { Fail(c, err.Error()) return } items, err := h.service.OrderEvents(c.Request.Context(), c.Param("provider"), c.Param("tradeNo"), req.Limit) if err != nil { Fail(c, err.Error()) return } OKWithData(c, items) } func (h *Payment) TestProvider(c *gin.Context) { result, err := h.service.TestProvider(c.Request.Context(), c.Param("provider")) if err != nil { if result != nil { Write(c, CodeError, result, err.Error()) return } Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Create(c *gin.Context) { var req dto.PaymentRequest if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } req.ClientIP = c.ClientIP() req.UserAgent = c.Request.UserAgent() req.DeviceID = c.GetHeader("X-Device-Id") result, err := h.service.Create(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Query(c *gin.Context) { var req dto.PaymentQueryRequest if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } setPaymentRequestActor(c, &req.OperatorID, &req.OperatorName, &req.ClientIP, &req.UserAgent, &req.DeviceID) result, err := h.service.Query(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Refund(c *gin.Context) { var req dto.PaymentRefundRequest if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } setPaymentRequestActor(c, &req.OperatorID, &req.OperatorName, &req.ClientIP, &req.UserAgent, &req.DeviceID) result, err := h.service.Refund(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Fulfill(c *gin.Context) { var req dto.PaymentFulfillRequest if err := c.ShouldBindJSON(&req); err != nil { Fail(c, err.Error()) return } setPaymentRequestActor(c, &req.OperatorID, &req.OperatorName, &req.ClientIP, &req.UserAgent, &req.DeviceID) result, err := h.service.Fulfill(c.Request.Context(), &req) if err != nil { Fail(c, err.Error()) return } OKWithData(c, result) } func (h *Payment) Callback(c *gin.Context) { c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 8<<20) raw, err := io.ReadAll(c.Request.Body) if err != nil { _ = c.Error(err) writePaymentCallbackAck(c, paymentservice.DefaultPaymentCallbackAck(c.Param("provider"), false)) return } headers := map[string]string{} for k, v := range c.Request.Header { if len(v) > 0 { headers[k] = v[0] } } query := map[string]string{} for k, v := range c.Request.URL.Query() { if len(v) > 0 { query[k] = v[0] } } ack, err := h.service.Callback(c.Request.Context(), &dto.PaymentCallbackRequest{ Provider: c.Param("provider"), Headers: headers, Body: raw, Query: query, ClientIP: c.ClientIP(), UserAgent: c.Request.UserAgent(), }) writePaymentCallbackAck(c, ack) if err != nil { _ = c.Error(err) } } func setPaymentRequestActor(c *gin.Context, operatorID *uint, operatorName, clientIP, userAgent, deviceID *string) { if claims := Claims(c); claims != nil { *operatorID = claims.ID *operatorName = claims.Username } *clientIP = c.ClientIP() *userAgent = c.Request.UserAgent() *deviceID = c.GetHeader("X-Device-Id") } func writePaymentCallbackAck(c *gin.Context, ack dto.PaymentCallbackAck) { if ack.StatusCode == 0 { ack.StatusCode = http.StatusInternalServerError } if ack.ContentType != "" { c.Header("Content-Type", ack.ContentType) } c.Status(ack.StatusCode) if len(ack.Body) > 0 { _, _ = c.Writer.Write(ack.Body) } }