mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 09:46:37 +08:00
压缩历史至 95081aff
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
Copyright 2025 linux.do
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package order
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/linux-do/credit/internal/apps/oauth"
|
||||
"github.com/linux-do/credit/internal/db"
|
||||
"github.com/linux-do/credit/internal/model"
|
||||
"github.com/linux-do/credit/internal/util"
|
||||
)
|
||||
|
||||
type TransactionListRequest struct {
|
||||
Page int `json:"page" form:"page" binding:"min=1"`
|
||||
PageSize int `json:"page_size" form:"page_size" binding:"min=1,max=100"`
|
||||
Types []string `json:"types" form:"types" binding:"omitempty,dive,oneof=receive payment transfer community online test distribute red_envelope_send red_envelope_receive red_envelope_refund"`
|
||||
Statuses []string `json:"statuses" form:"statuses" binding:"omitempty,dive,oneof=success pending failed expired disputing refund refused"`
|
||||
ClientID string `json:"client_id" form:"client_id" binding:"omitempty"`
|
||||
StartTime *time.Time `json:"startTime" form:"startTime" binding:"omitempty"`
|
||||
EndTime *time.Time `json:"endTime" form:"endTime" binding:"omitempty,gtfield=StartTime"`
|
||||
ID *uint64 `json:"id,string" form:"id" binding:"omitempty"`
|
||||
OrderName string `json:"order_name" form:"order_name" binding:"omitempty"`
|
||||
PayerUsername string `json:"payer_username" form:"payer_username" binding:"omitempty"`
|
||||
PayeeUsername string `json:"payee_username" form:"payee_username" binding:"omitempty"`
|
||||
PayeeTransferStatus model.OrderTransferStatus `json:"payee_transfer_status" form:"payee_transfer_status" binding:"omitempty,oneof=pending completed"`
|
||||
}
|
||||
|
||||
type TransactionListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
Orders []struct {
|
||||
model.Order
|
||||
AppName string `json:"app_name"`
|
||||
AppHomepageURL string `json:"app_homepage_url"`
|
||||
AppDescription string `json:"app_description"`
|
||||
RedirectURI string `json:"redirect_uri"`
|
||||
DisputeID *uint64 `json:"dispute_id,string"`
|
||||
PayerUsername string `json:"payer_username"`
|
||||
PayeeUsername string `json:"payee_username"`
|
||||
PayerAvatarURL string `json:"payer_avatar_url"`
|
||||
PayeeAvatarURL string `json:"payee_avatar_url"`
|
||||
PayeeTransferStatus string `json:"payee_transfer_status"`
|
||||
PayeeTransferAt string `json:"payee_transfer_at"`
|
||||
} `json:"orders"`
|
||||
}
|
||||
|
||||
// ListTransactions 获取交易列表
|
||||
// @Tags order
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body TransactionListRequest false "request body"
|
||||
// @Success 200 {object} util.ResponseAny
|
||||
// @Router /api/v1/order/transactions [post]
|
||||
func ListTransactions(c *gin.Context) {
|
||||
var req TransactionListRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
user, _ := util.GetFromContext[*model.User](c, oauth.UserObjKey)
|
||||
|
||||
baseQuery := db.DB(c.Request.Context()).Model(&model.Order{}).
|
||||
Select("orders.*, merchant_api_keys.app_name, merchant_api_keys.app_homepage_url, merchant_api_keys.app_description, merchant_api_keys.redirect_uri, disputes.id as dispute_id, payer_user.username as payer_username, payee_user.username as payee_username, payer_user.avatar_url as payer_avatar_url, payee_user.avatar_url as payee_avatar_url, order_transfers.status as payee_transfer_status, order_transfers.transfer_at as payee_transfer_at").
|
||||
Joins("LEFT JOIN merchant_api_keys ON orders.client_id = merchant_api_keys.client_id").
|
||||
Joins("LEFT JOIN disputes ON orders.id = disputes.order_id").
|
||||
Joins("LEFT JOIN users as payer_user ON orders.payer_user_id = payer_user.id").
|
||||
Joins("LEFT JOIN users as payee_user ON orders.payee_user_id = payee_user.id").
|
||||
Joins("LEFT JOIN order_transfers ON orders.id = order_transfers.order_id")
|
||||
|
||||
clientIDHandled := false
|
||||
if len(req.Types) > 0 {
|
||||
// 使用 IN 查询支持多个类型
|
||||
var conditions []string
|
||||
var args []interface{}
|
||||
|
||||
for _, t := range req.Types {
|
||||
orderType := model.OrderType(t)
|
||||
|
||||
switch orderType {
|
||||
case model.OrderTypeReceive:
|
||||
// receive 类型:查询当前用户作为收款方的 payment 订单
|
||||
conditions = append(conditions, "(orders.type = ? AND orders.payee_user_id = ?)")
|
||||
args = append(args, model.OrderTypePayment, user.ID)
|
||||
case model.OrderTypeCommunity, model.OrderTypeRedEnvelopeRefund, model.OrderTypeRedEnvelopeReceive:
|
||||
// community、red_envelope_refund、red_envelope_receive 类型:查询当前用户作为收款方的订单
|
||||
conditions = append(conditions, "(orders.type = ? AND orders.payee_user_id = ?)")
|
||||
args = append(args, orderType, user.ID)
|
||||
case model.OrderTypeOnline:
|
||||
// online 类型:商家可查看自己 client_id 的所有订单,普通用户只能查看与自己相关的订单
|
||||
if req.ClientID != "" {
|
||||
clientIDHandled = true
|
||||
var count int64
|
||||
if err := db.DB(c.Request.Context()).Model(&model.MerchantAPIKey{}).
|
||||
Where("client_id = ? AND user_id = ?", req.ClientID, user.ID).
|
||||
Count(&count).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
conditions = append(conditions, "(orders.type = ? AND orders.client_id = ?)")
|
||||
args = append(args, orderType, req.ClientID)
|
||||
} else {
|
||||
conditions = append(conditions, "(orders.type = ? AND orders.client_id = ? AND (orders.payer_user_id = ? OR orders.payee_user_id = ?))")
|
||||
args = append(args, orderType, req.ClientID, user.ID, user.ID)
|
||||
}
|
||||
} else {
|
||||
conditions = append(conditions, "(orders.type = ? AND (orders.payer_user_id = ? OR orders.payee_user_id = ?))")
|
||||
args = append(args, orderType, user.ID, user.ID)
|
||||
}
|
||||
case model.OrderTypePayment, model.OrderTypeTransfer, model.OrderTypeTest, model.OrderTypeRedEnvelopeSend:
|
||||
// payment、transfer、test、red_envelope_send 类型:查询当前用户作为付款方的订单
|
||||
conditions = append(conditions, "(orders.type = ? AND orders.payer_user_id = ?)")
|
||||
args = append(args, orderType, user.ID)
|
||||
case model.OrderTypeDistribute:
|
||||
// distribute 类型:查询当前用户作为付款方或者收款方的订单
|
||||
conditions = append(conditions, "((orders.type = ? AND orders.payer_user_id = ?) OR (orders.type = ? AND orders.payee_user_id = ?))")
|
||||
args = append(args, orderType, user.ID, orderType, user.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(conditions) > 0 {
|
||||
combinedCondition := conditions[0]
|
||||
for i := 1; i < len(conditions); i++ {
|
||||
combinedCondition += " OR " + conditions[i]
|
||||
}
|
||||
baseQuery = baseQuery.Where(combinedCondition, args...)
|
||||
}
|
||||
} else {
|
||||
// 查询所有与当前用户相关的订单,但排除用户作为payer的red_envelope_receive订单
|
||||
baseQuery = baseQuery.Where(
|
||||
"orders.payee_user_id = ? OR (orders.payer_user_id = ? AND orders.type != ?)",
|
||||
user.ID, user.ID, model.OrderTypeRedEnvelopeReceive,
|
||||
)
|
||||
}
|
||||
|
||||
if len(req.Statuses) > 0 {
|
||||
baseQuery = baseQuery.Where("orders.status IN ?", req.Statuses)
|
||||
}
|
||||
|
||||
if req.ClientID != "" && !clientIDHandled {
|
||||
baseQuery = baseQuery.Where("orders.client_id = ?", req.ClientID)
|
||||
}
|
||||
if req.ID != nil {
|
||||
baseQuery = baseQuery.Where("orders.id = ?", req.ID)
|
||||
}
|
||||
if req.OrderName != "" {
|
||||
baseQuery = baseQuery.Where("orders.order_name LIKE ?", req.OrderName+"%")
|
||||
}
|
||||
if req.PayerUsername != "" {
|
||||
baseQuery = baseQuery.Where("payer_user.username LIKE ?", req.PayerUsername+"%")
|
||||
}
|
||||
if req.PayeeUsername != "" {
|
||||
baseQuery = baseQuery.Where("payee_user.username LIKE ?", req.PayeeUsername+"%")
|
||||
}
|
||||
if req.PayeeTransferStatus != "" {
|
||||
switch req.PayeeTransferStatus {
|
||||
case model.OrderTransferStatusPending:
|
||||
baseQuery = baseQuery.Where("order_transfers.status = ?", model.OrderTransferStatusPending)
|
||||
case model.OrderTransferStatusCompleted:
|
||||
baseQuery = baseQuery.Where("order_transfers.status = ? OR order_transfers.status IS NULL", model.OrderTransferStatusCompleted)
|
||||
}
|
||||
}
|
||||
if req.StartTime != nil {
|
||||
baseQuery = baseQuery.Where("orders.created_at >= ?", req.StartTime)
|
||||
}
|
||||
if req.EndTime != nil {
|
||||
baseQuery = baseQuery.Where("orders.created_at <= ?", req.EndTime)
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := baseQuery.Count(&total).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
response := &TransactionListResponse{
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}
|
||||
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
if err := baseQuery.Order("orders.created_at DESC").Offset(offset).Limit(req.PageSize).Find(&response.Orders).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 转换订单类型:从收款方视角看,payment 订单应该显示为 receive
|
||||
// 并更新 Payee_transfer_status,兼容为空的场景
|
||||
for i := range response.Orders {
|
||||
if response.Orders[i].PayeeTransferStatus == "" {
|
||||
response.Orders[i].PayeeTransferStatus = string(model.OrderTransferStatusCompleted)
|
||||
}
|
||||
if response.Orders[i].Type == model.OrderTypePayment && response.Orders[i].PayeeUserID == user.ID {
|
||||
response.Orders[i].Type = model.OrderTypeReceive
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, util.OK(response))
|
||||
}
|
||||
Reference in New Issue
Block a user