kra-new/internal/server/handler/payment.go

237 lines
6.2 KiB
Go

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)
}
}