初始化项目
This commit is contained in:
381
controller/order.go
Normal file
381
controller/order.go
Normal file
@@ -0,0 +1,381 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"order/model/dto"
|
||||
"order/service"
|
||||
)
|
||||
|
||||
// Order 订单控制器
|
||||
|
||||
type Order struct{}
|
||||
|
||||
var OrderController = &Order{}
|
||||
|
||||
// Create 创建订单
|
||||
func (c *Order) Create(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.CreateOrderReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取订单服务实例
|
||||
orderService := service.GetOrderService()
|
||||
if orderService == nil {
|
||||
g.Log().Error(ctx, "订单服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
resp, err := orderService.CreateOrder(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "创建订单失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// Pay 支付订单
|
||||
func (c *Order) Pay(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.PayOrderReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取支付服务实例
|
||||
paymentService := service.GetPaymentService()
|
||||
if paymentService == nil {
|
||||
g.Log().Error(ctx, "支付服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 支付订单
|
||||
resp, err := paymentService.PayOrder(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "支付订单失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// Query 查询订单详情
|
||||
func (c *Order) Query(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.QueryOrderReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取订单服务实例
|
||||
orderService := service.GetOrderService()
|
||||
if orderService == nil {
|
||||
g.Log().Error(ctx, "订单服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 查询订单
|
||||
resp, err := orderService.QueryOrder(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询订单失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// Cancel 取消订单
|
||||
func (c *Order) Cancel(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.CancelOrderReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取订单服务实例
|
||||
orderService := service.GetOrderService()
|
||||
if orderService == nil {
|
||||
g.Log().Error(ctx, "订单服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 取消订单
|
||||
resp, err := orderService.CancelOrder(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "取消订单失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// Refund 退款
|
||||
func (c *Order) Refund(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.RefundOrderReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取支付服务实例
|
||||
paymentService := service.GetPaymentService()
|
||||
if paymentService == nil {
|
||||
g.Log().Error(ctx, "支付服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 退款
|
||||
resp, err := paymentService.RefundOrder(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "退款失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// List 查询订单列表
|
||||
func (c *Order) List(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req dto.ListOrdersReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析请求参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取订单服务实例
|
||||
orderService := service.GetOrderService()
|
||||
if orderService == nil {
|
||||
g.Log().Error(ctx, "订单服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 查询订单列表
|
||||
resp, err := orderService.ListOrders(ctx, &req)
|
||||
if err != nil {
|
||||
g.Log().Error(ctx, "查询订单列表失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
|
||||
// PaymentNotify 支付回调
|
||||
func (c *Order) PaymentNotify(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req service.PaymentNotifyReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析支付回调参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取支付服务实例
|
||||
paymentService := service.GetPaymentService()
|
||||
if paymentService == nil {
|
||||
g.Log().Error(ctx, "支付服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 处理支付回调
|
||||
if err := paymentService.HandlePaymentNotify(ctx, &req); err != nil {
|
||||
g.Log().Error(ctx, "处理支付回调失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// RefundNotify 退款回调
|
||||
func (c *Order) RefundNotify(r *ghttp.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req service.RefundNotifyReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
g.Log().Error(ctx, "解析退款回调参数失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取支付服务实例
|
||||
paymentService := service.GetPaymentService()
|
||||
if paymentService == nil {
|
||||
g.Log().Error(ctx, "支付服务未初始化")
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": "服务内部错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 处理退款回调
|
||||
if err := paymentService.HandleRefundNotify(ctx, &req); err != nil {
|
||||
g.Log().Error(ctx, "处理退款回调失败:", err)
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
316
controller/payment_config.go
Normal file
316
controller/payment_config.go
Normal file
@@ -0,0 +1,316 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"order/model/dto"
|
||||
"order/service"
|
||||
)
|
||||
|
||||
type PaymentConfigController struct{}
|
||||
|
||||
var PaymentConfig = &PaymentConfigController{}
|
||||
|
||||
// CreatePaymentConfig 创建支付配置
|
||||
func (c *PaymentConfigController) CreatePaymentConfig(r *ghttp.Request) {
|
||||
var req dto.CreatePaymentConfigReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 构建支付配置实体
|
||||
config := &service.PaymentConfig{
|
||||
TenantID: req.TenantID,
|
||||
PayMethod: req.PayMethod,
|
||||
ConfigType: req.ConfigType,
|
||||
Environment: req.Environment,
|
||||
IsEnabled: req.IsEnabled,
|
||||
}
|
||||
|
||||
if req.WechatConfig != nil {
|
||||
config.WechatConfig = &service.WechatConfig{
|
||||
AppID: req.WechatConfig.AppID,
|
||||
MchID: req.WechatConfig.MchID,
|
||||
APIKey: req.WechatConfig.APIKey,
|
||||
APIClientCert: req.WechatConfig.APIClientCert,
|
||||
APIClientKey: req.WechatConfig.APIClientKey,
|
||||
NotifyURL: req.WechatConfig.NotifyURL,
|
||||
RefundNotifyURL: req.WechatConfig.RefundNotifyURL,
|
||||
SubAppID: req.WechatConfig.SubAppID,
|
||||
SubMchID: req.WechatConfig.SubMchID,
|
||||
}
|
||||
}
|
||||
|
||||
if req.AlipayConfig != nil {
|
||||
config.AlipayConfig = &service.AlipayConfig{
|
||||
AppID: req.AlipayConfig.AppID,
|
||||
PrivateKey: req.AlipayConfig.PrivateKey,
|
||||
PublicKey: req.AlipayConfig.PublicKey,
|
||||
AlipayPublicKey: req.AlipayConfig.AlipayPublicKey,
|
||||
NotifyURL: req.AlipayConfig.NotifyURL,
|
||||
RefundNotifyURL: req.AlipayConfig.RefundNotifyURL,
|
||||
Format: req.AlipayConfig.Format,
|
||||
Charset: req.AlipayConfig.Charset,
|
||||
SignType: req.AlipayConfig.SignType,
|
||||
IsSandbox: req.AlipayConfig.IsSandbox,
|
||||
}
|
||||
}
|
||||
|
||||
if err := service.PaymentService.CreatePaymentConfig(ctx, config); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdatePaymentConfig 更新支付配置
|
||||
func (c *PaymentConfigController) UpdatePaymentConfig(r *ghttp.Request) {
|
||||
var req dto.UpdatePaymentConfigReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
update := bson.M{}
|
||||
if req.ConfigType != "" {
|
||||
update["config_type"] = req.ConfigType
|
||||
}
|
||||
if req.Environment != "" {
|
||||
update["environment"] = req.Environment
|
||||
}
|
||||
if req.IsEnabled != nil {
|
||||
update["is_enabled"] = *req.IsEnabled
|
||||
}
|
||||
|
||||
if req.WechatConfig != nil {
|
||||
wechatConfig := bson.M{}
|
||||
if req.WechatConfig.AppID != "" {
|
||||
wechatConfig["app_id"] = req.WechatConfig.AppID
|
||||
}
|
||||
if req.WechatConfig.MchID != "" {
|
||||
wechatConfig["mch_id"] = req.WechatConfig.MchID
|
||||
}
|
||||
if req.WechatConfig.APIKey != "" {
|
||||
wechatConfig["api_key"] = req.WechatConfig.APIKey
|
||||
}
|
||||
if req.WechatConfig.APIClientCert != "" {
|
||||
wechatConfig["api_client_cert"] = req.WechatConfig.APIClientCert
|
||||
}
|
||||
if req.WechatConfig.APIClientKey != "" {
|
||||
wechatConfig["api_client_key"] = req.WechatConfig.APIClientKey
|
||||
}
|
||||
if req.WechatConfig.NotifyURL != "" {
|
||||
wechatConfig["notify_url"] = req.WechatConfig.NotifyURL
|
||||
}
|
||||
if req.WechatConfig.RefundNotifyURL != "" {
|
||||
wechatConfig["refund_notify_url"] = req.WechatConfig.RefundNotifyURL
|
||||
}
|
||||
if req.WechatConfig.SubAppID != "" {
|
||||
wechatConfig["sub_app_id"] = req.WechatConfig.SubAppID
|
||||
}
|
||||
if req.WechatConfig.SubMchID != "" {
|
||||
wechatConfig["sub_mch_id"] = req.WechatConfig.SubMchID
|
||||
}
|
||||
update["wechat_config"] = wechatConfig
|
||||
}
|
||||
|
||||
if req.AlipayConfig != nil {
|
||||
alipayConfig := bson.M{}
|
||||
if req.AlipayConfig.AppID != "" {
|
||||
alipayConfig["app_id"] = req.AlipayConfig.AppID
|
||||
}
|
||||
if req.AlipayConfig.PrivateKey != "" {
|
||||
alipayConfig["private_key"] = req.AlipayConfig.PrivateKey
|
||||
}
|
||||
if req.AlipayConfig.PublicKey != "" {
|
||||
alipayConfig["public_key"] = req.AlipayConfig.PublicKey
|
||||
}
|
||||
if req.AlipayConfig.AlipayPublicKey != "" {
|
||||
alipayConfig["alipay_public_key"] = req.AlipayConfig.AlipayPublicKey
|
||||
}
|
||||
if req.AlipayConfig.NotifyURL != "" {
|
||||
alipayConfig["notify_url"] = req.AlipayConfig.NotifyURL
|
||||
}
|
||||
if req.AlipayConfig.RefundNotifyURL != "" {
|
||||
alipayConfig["refund_notify_url"] = req.AlipayConfig.RefundNotifyURL
|
||||
}
|
||||
if req.AlipayConfig.Format != "" {
|
||||
alipayConfig["format"] = req.AlipayConfig.Format
|
||||
}
|
||||
if req.AlipayConfig.Charset != "" {
|
||||
alipayConfig["charset"] = req.AlipayConfig.Charset
|
||||
}
|
||||
if req.AlipayConfig.SignType != "" {
|
||||
alipayConfig["sign_type"] = req.AlipayConfig.SignType
|
||||
}
|
||||
if req.AlipayConfig.IsSandbox != false {
|
||||
alipayConfig["is_sandbox"] = req.AlipayConfig.IsSandbox
|
||||
}
|
||||
update["alipay_config"] = alipayConfig
|
||||
}
|
||||
|
||||
if err := service.PaymentService.UpdatePaymentConfig(ctx, req.ID, update); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// QueryPaymentConfig 查询支付配置
|
||||
func (c *PaymentConfigController) QueryPaymentConfig(r *ghttp.Request) {
|
||||
tentID := r.Get("tenant_id").String()
|
||||
payMethod := r.Get("pay_method").String()
|
||||
configType := r.Get("config_type").String()
|
||||
environment := r.Get("environment").String()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
config, err := service.PaymentService.QueryPaymentConfig(ctx, tentID, payMethod, configType, environment)
|
||||
if err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": config,
|
||||
})
|
||||
}
|
||||
|
||||
// ListPaymentConfigs 查询支付配置列表
|
||||
func (c *PaymentConfigController) ListPaymentConfigs(r *ghttp.Request) {
|
||||
var req dto.QueryPaymentConfigReq
|
||||
if err := r.Parse(&req); err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
filter := bson.M{"tenant_id": req.TenantID}
|
||||
if req.PayMethod != "" {
|
||||
filter["pay_method"] = req.PayMethod
|
||||
}
|
||||
if req.ConfigType != "" {
|
||||
filter["config_type"] = req.ConfigType
|
||||
}
|
||||
if req.Environment != "" {
|
||||
filter["environment"] = req.Environment
|
||||
}
|
||||
if req.IsEnabled != nil {
|
||||
filter["is_enabled"] = *req.IsEnabled
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
configs, total, err := service.PaymentService.ListPaymentConfigs(ctx, filter, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
resp := dto.PaymentConfigListResp{
|
||||
List: make([]dto.PaymentConfigResp, 0, len(configs)),
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
TotalPage: int((total + int64(req.PageSize) - 1) / int64(req.PageSize)),
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
configResp := dto.PaymentConfigResp{
|
||||
ID: config.ID.Hex(),
|
||||
TenantID: config.TenantID,
|
||||
PayMethod: config.PayMethod,
|
||||
ConfigType: config.ConfigType,
|
||||
Environment: config.Environment,
|
||||
IsEnabled: config.IsEnabled,
|
||||
CreatedAt: config.CreatedAt,
|
||||
UpdatedAt: config.UpdatedAt,
|
||||
CreatedBy: config.CreatedBy,
|
||||
UpdatedBy: config.UpdatedBy,
|
||||
}
|
||||
|
||||
if config.WechatConfig != nil {
|
||||
configResp.WechatConfig = &dto.WechatConfigResp{
|
||||
AppID: config.WechatConfig.AppID,
|
||||
MchID: config.WechatConfig.MchID,
|
||||
NotifyURL: config.WechatConfig.NotifyURL,
|
||||
RefundNotifyURL: config.WechatConfig.RefundNotifyURL,
|
||||
SubAppID: config.WechatConfig.SubAppID,
|
||||
SubMchID: config.WechatConfig.SubMchID,
|
||||
}
|
||||
}
|
||||
|
||||
if config.AlipayConfig != nil {
|
||||
configResp.AlipayConfig = &dto.AlipayConfigResp{
|
||||
AppID: config.AlipayConfig.AppID,
|
||||
NotifyURL: config.AlipayConfig.NotifyURL,
|
||||
RefundNotifyURL: config.AlipayConfig.RefundNotifyURL,
|
||||
Format: config.AlipayConfig.Format,
|
||||
Charset: config.AlipayConfig.Charset,
|
||||
SignType: config.AlipayConfig.SignType,
|
||||
IsSandbox: config.AlipayConfig.IsSandbox,
|
||||
}
|
||||
}
|
||||
|
||||
resp.List = append(resp.List, configResp)
|
||||
}
|
||||
|
||||
r.Response.WriteJsonExit(g.Map{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": resp,
|
||||
})
|
||||
}
|
||||
276
dao/order_dao.go
Normal file
276
dao/order_dao.go
Normal file
@@ -0,0 +1,276 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"order/model/entity"
|
||||
)
|
||||
|
||||
// OrderDao 订单数据访问对象
|
||||
// 支持按状态拆分的订单表操作
|
||||
|
||||
type OrderDao struct {
|
||||
collections map[entity.OrderStatus]*mongo.Collection
|
||||
}
|
||||
|
||||
// NewOrderDao 创建订单DAO实例
|
||||
func NewOrderDao(collections map[entity.OrderStatus]*mongo.Collection) *OrderDao {
|
||||
return &OrderDao{
|
||||
collections: collections,
|
||||
}
|
||||
}
|
||||
|
||||
// getCollection 根据订单状态获取对应的集合
|
||||
func (d *OrderDao) getCollection(status entity.OrderStatus) (*mongo.Collection, error) {
|
||||
collection, exists := d.collections[status]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("collection for status %s not found", status)
|
||||
}
|
||||
return collection, nil
|
||||
}
|
||||
|
||||
// CreatePendingOrder 创建待支付订单
|
||||
func (d *OrderDao) CreatePendingOrder(ctx context.Context, order *entity.OrderPending) error {
|
||||
collection, err := d.getCollection(entity.OrderStatusPending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
order.ID = primitive.NewObjectID()
|
||||
order.CreatedAt = time.Now()
|
||||
order.UpdatedAt = time.Now()
|
||||
|
||||
_, err = collection.InsertOne(ctx, order)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetOrderByNo 根据订单号查询订单(自动识别状态)
|
||||
func (d *OrderDao) GetOrderByNo(ctx context.Context, tenantID, orderNo string) (interface{}, entity.OrderStatus, error) {
|
||||
// 按状态优先级搜索(从最新状态开始)
|
||||
statuses := []entity.OrderStatus{
|
||||
entity.OrderStatusCompleted,
|
||||
entity.OrderStatusShipped,
|
||||
entity.OrderStatusPaid,
|
||||
entity.OrderStatusPending,
|
||||
}
|
||||
|
||||
for _, status := range statuses {
|
||||
collection, err := d.getCollection(status)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch status {
|
||||
case entity.OrderStatusPending:
|
||||
var order entity.OrderPending
|
||||
if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil {
|
||||
return &order, status, nil
|
||||
}
|
||||
case entity.OrderStatusPaid:
|
||||
var order entity.OrderPaid
|
||||
if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil {
|
||||
return &order, status, nil
|
||||
}
|
||||
case entity.OrderStatusShipped:
|
||||
var order entity.OrderShipped
|
||||
if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil {
|
||||
return &order, status, nil
|
||||
}
|
||||
case entity.OrderStatusCompleted:
|
||||
var order entity.OrderCompleted
|
||||
if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil {
|
||||
return &order, status, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, "", errors.New("order not found")
|
||||
}
|
||||
|
||||
// findOrderByNo 通用订单查询方法
|
||||
func (d *OrderDao) findOrderByNo(collection *mongo.Collection, ctx context.Context, tenantID, orderNo string, result interface{}) error {
|
||||
filter := bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"order_no": orderNo,
|
||||
}
|
||||
|
||||
err := collection.FindOne(ctx, filter).Decode(result)
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return errors.New("order not found")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MoveOrderToStatus 将订单从一个状态移动到另一个状态
|
||||
func (d *OrderDao) MoveOrderToStatus(ctx context.Context, fromStatus, toStatus entity.OrderStatus, tenantID, orderNo string, updateData bson.M) error {
|
||||
// 获取源集合
|
||||
srcCollection, err := d.getCollection(fromStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取目标集合
|
||||
destCollection, err := d.getCollection(toStatus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找源订单
|
||||
var orderData bson.M
|
||||
filter := bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"order_no": orderNo,
|
||||
}
|
||||
|
||||
err = srcCollection.FindOne(ctx, filter).Decode(&orderData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新数据
|
||||
orderData["updated_at"] = time.Now()
|
||||
for key, value := range updateData {
|
||||
orderData[key] = value
|
||||
}
|
||||
|
||||
// 插入到目标集合
|
||||
_, err = destCollection.InsertOne(ctx, orderData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 从源集合删除
|
||||
_, err = srcCollection.DeleteOne(ctx, filter)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdatePendingOrder 更新待支付订单
|
||||
func (d *OrderDao) UpdatePendingOrder(ctx context.Context, tenantID, orderNo string, update bson.M) error {
|
||||
collection, err := d.getCollection(entity.OrderStatusPending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
update["updated_at"] = time.Now()
|
||||
|
||||
_, err = collection.UpdateOne(ctx, bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"order_no": orderNo,
|
||||
}, bson.M{"$set": update})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ListOrdersByStatus 根据状态查询订单列表
|
||||
func (d *OrderDao) ListOrdersByStatus(ctx context.Context, status entity.OrderStatus, tenantID, userID string, page, pageSize int) (interface{}, int64, error) {
|
||||
collection, err := d.getCollection(status)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
filter := bson.M{"tenant_id": tenantID}
|
||||
if userID != "" {
|
||||
filter["user_id"] = userID
|
||||
}
|
||||
|
||||
// 计算总数
|
||||
total, err := collection.CountDocuments(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
skip := int64((page - 1) * pageSize)
|
||||
opt := options.Find().
|
||||
SetSort(bson.D{{Key: "created_at", Value: -1}}).
|
||||
SetSkip(skip).
|
||||
SetLimit(int64(pageSize))
|
||||
|
||||
cursor, err := collection.Find(ctx, filter, opt)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
// 根据状态返回对应的订单类型
|
||||
switch status {
|
||||
case entity.OrderStatusPending:
|
||||
var orders []entity.OrderPending
|
||||
if err := cursor.All(ctx, &orders); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return orders, total, nil
|
||||
case entity.OrderStatusPaid:
|
||||
var orders []entity.OrderPaid
|
||||
if err := cursor.All(ctx, &orders); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return orders, total, nil
|
||||
case entity.OrderStatusShipped:
|
||||
var orders []entity.OrderShipped
|
||||
if err := cursor.All(ctx, &orders); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return orders, total, nil
|
||||
case entity.OrderStatusCompleted:
|
||||
var orders []entity.OrderCompleted
|
||||
if err := cursor.All(ctx, &orders); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return orders, total, nil
|
||||
default:
|
||||
return nil, 0, errors.New("unsupported order status")
|
||||
}
|
||||
}
|
||||
|
||||
// GetExpiredPendingOrders 获取过期的待支付订单
|
||||
func (d *OrderDao) GetExpiredPendingOrders(ctx context.Context, tenantID string) ([]entity.OrderPending, error) {
|
||||
collection, err := d.getCollection(entity.OrderStatusPending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter := bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"expired_at": bson.M{"$lte": time.Now()},
|
||||
}
|
||||
|
||||
cursor, err := collection.Find(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var orders []entity.OrderPending
|
||||
if err := cursor.All(ctx, &orders); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// UpdatePayInfo 更新支付信息(待支付订单)
|
||||
func (d *OrderDao) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error {
|
||||
collection, err := d.getCollection(entity.OrderStatusPending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = collection.UpdateOne(ctx, bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"order_no": orderNo,
|
||||
}, bson.M{"$set": bson.M{
|
||||
"pay_info": payInfo,
|
||||
"updated_at": time.Now(),
|
||||
}})
|
||||
|
||||
return err
|
||||
}
|
||||
229
dao/payment_dao.go
Normal file
229
dao/payment_dao.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"order/model/entity"
|
||||
)
|
||||
|
||||
// PaymentConfigDao 支付配置数据访问对象
|
||||
|
||||
type PaymentConfigDao struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewPaymentConfigDao 创建支付配置DAO实例
|
||||
func NewPaymentConfigDao(collection *mongo.Collection) *PaymentConfigDao {
|
||||
return &PaymentConfigDao{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建支付配置
|
||||
func (d *PaymentConfigDao) Create(ctx context.Context, config *entity.PaymentConfig) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
config.ID = primitive.NewObjectID()
|
||||
|
||||
_, err := d.collection.InsertOne(ctx, config)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetByTenantAndMethod 根据租户和支付方式获取配置
|
||||
func (d *PaymentConfigDao) GetByTenantAndMethod(ctx context.Context, tenantID, payMethod string) (*entity.PaymentConfig, error) {
|
||||
if d.collection == nil {
|
||||
return nil, errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
var config entity.PaymentConfig
|
||||
err := d.collection.FindOne(ctx, bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"pay_method": payMethod,
|
||||
"enabled": true,
|
||||
}).Decode(&config)
|
||||
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &config, err
|
||||
}
|
||||
|
||||
// Update 更新支付配置
|
||||
func (d *PaymentConfigDao) Update(ctx context.Context, id string, update bson.M) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
objectID, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update})
|
||||
return err
|
||||
}
|
||||
|
||||
// ListByTenant 查询租户的支付配置列表
|
||||
func (d *PaymentConfigDao) ListByTenant(ctx context.Context, tenantID string) ([]entity.PaymentConfig, error) {
|
||||
if d.collection == nil {
|
||||
return nil, errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
filter := bson.M{"tenant_id": tenantID}
|
||||
cursor, err := d.collection.Find(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var configs []entity.PaymentConfig
|
||||
if err := cursor.All(ctx, &configs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// PaymentRecordDao 支付记录数据访问对象
|
||||
|
||||
type PaymentRecordDao struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewPaymentRecordDao 创建支付记录DAO实例
|
||||
func NewPaymentRecordDao(collection *mongo.Collection) *PaymentRecordDao {
|
||||
return &PaymentRecordDao{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建支付记录
|
||||
func (d *PaymentRecordDao) Create(ctx context.Context, record *entity.PaymentRecord) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
record.ID = primitive.NewObjectID()
|
||||
record.CreatedAt = time.Now().Unix()
|
||||
record.UpdatedAt = time.Now().Unix()
|
||||
|
||||
_, err := d.collection.InsertOne(ctx, record)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetByOrderNo 根据订单号获取支付记录
|
||||
func (d *PaymentRecordDao) GetByOrderNo(ctx context.Context, tenantID, orderNo string) (*entity.PaymentRecord, error) {
|
||||
if d.collection == nil {
|
||||
return nil, errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
var record entity.PaymentRecord
|
||||
err := d.collection.FindOne(ctx, bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"order_no": orderNo,
|
||||
}).Decode(&record)
|
||||
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &record, err
|
||||
}
|
||||
|
||||
// UpdateStatus 更新支付记录状态
|
||||
func (d *PaymentRecordDao) UpdateStatus(ctx context.Context, id string, status, transactionID, tradeNo string) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
objectID, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
update := bson.M{
|
||||
"status": status,
|
||||
"transaction_id": transactionID,
|
||||
"trade_no": tradeNo,
|
||||
"updated_at": time.Now().Unix(),
|
||||
}
|
||||
|
||||
_, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update})
|
||||
return err
|
||||
}
|
||||
|
||||
// RefundRecordDao 退款记录数据访问对象
|
||||
|
||||
type RefundRecordDao struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewRefundRecordDao 创建退款记录DAO实例
|
||||
func NewRefundRecordDao(collection *mongo.Collection) *RefundRecordDao {
|
||||
return &RefundRecordDao{
|
||||
collection: collection,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建退款记录
|
||||
func (d *RefundRecordDao) Create(ctx context.Context, record *entity.RefundRecord) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
record.ID = primitive.NewObjectID()
|
||||
record.CreatedAt = time.Now().Unix()
|
||||
record.UpdatedAt = time.Now().Unix()
|
||||
|
||||
_, err := d.collection.InsertOne(ctx, record)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetByRefundNo 根据退款单号获取退款记录
|
||||
func (d *RefundRecordDao) GetByRefundNo(ctx context.Context, tenantID, refundNo string) (*entity.RefundRecord, error) {
|
||||
if d.collection == nil {
|
||||
return nil, errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
var record entity.RefundRecord
|
||||
err := d.collection.FindOne(ctx, bson.M{
|
||||
"tenant_id": tenantID,
|
||||
"refund_no": refundNo,
|
||||
}).Decode(&record)
|
||||
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &record, err
|
||||
}
|
||||
|
||||
// UpdateRefundStatus 更新退款记录状态
|
||||
func (d *RefundRecordDao) UpdateRefundStatus(ctx context.Context, id, status, refundID string) error {
|
||||
if d.collection == nil {
|
||||
return errors.New("collection not initialized")
|
||||
}
|
||||
|
||||
objectID, err := primitive.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
update := bson.M{
|
||||
"status": status,
|
||||
"refund_id": refundID,
|
||||
"updated_at": time.Now().Unix(),
|
||||
}
|
||||
|
||||
_, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update})
|
||||
return err
|
||||
}
|
||||
8
go.mod
8
go.mod
@@ -6,7 +6,9 @@ require (
|
||||
gitee.com/red-future---jilin-g/common v0.1.9
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.6
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.6
|
||||
golang.org/x/net v0.48.0
|
||||
github.com/gogf/gf/v2 v2.9.6
|
||||
go.mongodb.org/mongo-driver v1.17.6
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -27,7 +29,6 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect
|
||||
github.com/gogf/gf/v2 v2.9.6 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
|
||||
github.com/golang/glog v1.2.5 // indirect
|
||||
@@ -55,6 +56,7 @@ require (
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
||||
@@ -66,7 +68,6 @@ require (
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
||||
go.opencensus.io v0.22.5 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
@@ -78,6 +79,7 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -207,6 +207,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
@@ -273,6 +275,8 @@ github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfS
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
||||
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
||||
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
|
||||
|
||||
32
init.go
Normal file
32
init.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"order/service"
|
||||
)
|
||||
|
||||
// initServices 初始化服务
|
||||
func initServices() error {
|
||||
return service.InitServices()
|
||||
}
|
||||
|
||||
// initRoutes 初始化路由
|
||||
func initRoutes() {
|
||||
s := g.Server()
|
||||
|
||||
// 订单相关路由
|
||||
orderGroup := s.Group("/api/order")
|
||||
orderGroup.POST("/create", "order.controller.Order.Create")
|
||||
orderGroup.POST("/pay", "order.controller.Order.Pay")
|
||||
orderGroup.GET("/query", "order.controller.Order.Query")
|
||||
orderGroup.POST("/cancel", "order.controller.Order.Cancel")
|
||||
orderGroup.POST("/refund", "order.controller.Order.Refund")
|
||||
orderGroup.GET("/list", "order.controller.Order.List")
|
||||
|
||||
// 支付回调路由
|
||||
paymentGroup := s.Group("/api/payment")
|
||||
paymentGroup.POST("/notify", "order.controller.Order.PaymentNotify")
|
||||
paymentGroup.POST("/refund-notify", "order.controller.Order.RefundNotify")
|
||||
|
||||
g.Log().Info(g.Request().GetCtx(), "路由初始化完成")
|
||||
}
|
||||
26
main.go
26
main.go
@@ -1,21 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
// "order/controller"
|
||||
|
||||
"context"
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"gitee.com/red-future---jilin-g/common/jaeger"
|
||||
_ "gitee.com/red-future---jilin-g/common/mongo"
|
||||
_ "gitee.com/red-future---jilin-g/common/ragflow" // RAGFlow 客户端自动初始化
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
||||
"golang.org/x/net/context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"order/controller"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer jaeger.ShutDown(context.Background())
|
||||
//http.RouteRegister([]interface{}{
|
||||
// controller.Order,
|
||||
//})
|
||||
select {}
|
||||
|
||||
// 初始化服务
|
||||
if err := initServices(); err != nil {
|
||||
g.Log().Fatal(context.Background(), "初始化服务失败:", err)
|
||||
}
|
||||
|
||||
// 初始化路由
|
||||
initRoutes()
|
||||
|
||||
// 注册路由
|
||||
http.RouteRegister([]interface{}{
|
||||
controller.OrderController,
|
||||
})
|
||||
|
||||
// 启动服务
|
||||
g.Server().Run()
|
||||
}
|
||||
|
||||
206
model/dto/order.go
Normal file
206
model/dto/order.go
Normal file
@@ -0,0 +1,206 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateOrderReq 创建订单请求
|
||||
|
||||
type CreateOrderReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
UserID string `json:"user_id" binding:"required"` // 用户ID
|
||||
OrderType string `json:"order_type" binding:"required"` // 订单类型
|
||||
Subject string `json:"subject" binding:"required"` // 订单标题
|
||||
Description string `json:"description"` // 订单描述
|
||||
OrderItems []OrderItemReq `json:"order_items" binding:"required"` // 订单商品
|
||||
ShippingInfo ShippingInfoReq `json:"shipping_info"` // 收货信息
|
||||
}
|
||||
|
||||
// OrderItemReq 创建订单商品项请求
|
||||
|
||||
type OrderItemReq struct {
|
||||
ProductID string `json:"product_id" binding:"required"` // 商品ID
|
||||
ProductName string `json:"product_name" binding:"required"` // 商品名称
|
||||
Price int64 `json:"price" binding:"required,min=1"` // 单价(分)
|
||||
Quantity int `json:"quantity" binding:"required,min=1"` // 数量
|
||||
ImageURL string `json:"image_url"` // 商品图片
|
||||
}
|
||||
|
||||
// ShippingInfoReq 收货信息请求
|
||||
|
||||
type ShippingInfoReq struct {
|
||||
Consignee string `json:"consignee" binding:"required"` // 收货人
|
||||
Phone string `json:"phone" binding:"required"` // 手机号
|
||||
Province string `json:"province" binding:"required"` // 省份
|
||||
City string `json:"city" binding:"required"` // 城市
|
||||
District string `json:"district" binding:"required"` // 区县
|
||||
Address string `json:"address" binding:"required"` // 详细地址
|
||||
PostalCode string `json:"postal_code"` // 邮编
|
||||
}
|
||||
|
||||
// CreateOrderResp 创建订单响应
|
||||
|
||||
type CreateOrderResp struct {
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
TotalAmount int64 `json:"total_amount"` // 订单总金额
|
||||
PayAmount int64 `json:"pay_amount"` // 实付金额
|
||||
ExpiredAt string `json:"expired_at"` // 过期时间
|
||||
}
|
||||
|
||||
// PayOrderReq 支付订单请求
|
||||
|
||||
type PayOrderReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
OrderNo string `json:"order_no" binding:"required"` // 订单号
|
||||
PayMethod string `json:"pay_method" binding:"required"` // 支付方式:wechat/alipay
|
||||
PayType string `json:"pay_type" binding:"required"` // 支付类型:native/jsapi/app/h5
|
||||
ClientIP string `json:"client_ip"` // 客户端IP
|
||||
OpenID string `json:"openid"` // 用户OpenID(JSAPI支付)
|
||||
AuthCode string `json:"auth_code"` // 授权码(付款码支付)
|
||||
ReturnURL string `json:"return_url"` // 支付完成跳转URL
|
||||
}
|
||||
|
||||
// PayOrderResp 支付订单响应
|
||||
|
||||
type PayOrderResp struct {
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
QRCode string `json:"qrcode"` // 支付二维码(Native支付)
|
||||
PayURL string `json:"pay_url"` // 支付链接(H5支付)
|
||||
PrepayID string `json:"prepay_id"` // 预支付ID(微信)
|
||||
JSAPIParams string `json:"jsapi_params"` // JSAPI参数(微信)
|
||||
APPParams string `json:"app_params"` // APP参数
|
||||
}
|
||||
|
||||
// QueryOrderReq 查询订单请求
|
||||
|
||||
type QueryOrderReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
OrderNo string `json:"order_no" binding:"required"` // 订单号
|
||||
}
|
||||
|
||||
// QueryOrderResp 查询订单响应
|
||||
|
||||
type QueryOrderResp struct {
|
||||
Order OrderDetail `json:"order"` // 订单详情
|
||||
}
|
||||
|
||||
// OrderDetail 订单详情
|
||||
|
||||
type OrderDetail struct {
|
||||
ID string `json:"id"` // 订单ID
|
||||
TenantID string `json:"tenant_id"` // 租户ID
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
UserID string `json:"user_id"` // 用户ID
|
||||
TotalAmount int64 `json:"total_amount"` // 订单总金额
|
||||
PayAmount int64 `json:"pay_amount"` // 实付金额
|
||||
Status string `json:"status"` // 订单状态
|
||||
PayMethod string `json:"pay_method"` // 支付方式
|
||||
PayStatus string `json:"pay_status"` // 支付状态
|
||||
OrderType string `json:"order_type"` // 订单类型
|
||||
Subject string `json:"subject"` // 订单标题
|
||||
Description string `json:"description"` // 订单描述
|
||||
OrderItems []OrderItem `json:"order_items"` // 订单商品
|
||||
ShippingInfo ShippingInfo `json:"shipping_info"` // 收货信息
|
||||
PayInfo PayInfo `json:"pay_info"` // 支付信息
|
||||
CreatedAt time.Time `json:"created_at"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updated_at"` // 更新时间
|
||||
PaidAt *time.Time `json:"paid_at"` // 支付时间
|
||||
ExpiredAt *time.Time `json:"expired_at"` // 过期时间
|
||||
}
|
||||
|
||||
// OrderItem 订单商品项(响应)
|
||||
|
||||
type OrderItem struct {
|
||||
ProductID string `json:"product_id"` // 商品ID
|
||||
ProductName string `json:"product_name"` // 商品名称
|
||||
Price int64 `json:"price"` // 单价(分)
|
||||
Quantity int `json:"quantity"` // 数量
|
||||
TotalPrice int64 `json:"total_price"` // 小计(分)
|
||||
ImageURL string `json:"image_url"` // 商品图片
|
||||
}
|
||||
|
||||
// ShippingInfo 收货信息(响应)
|
||||
|
||||
type ShippingInfo struct {
|
||||
Consignee string `json:"consignee"` // 收货人
|
||||
Phone string `json:"phone"` // 手机号
|
||||
Province string `json:"province"` // 省份
|
||||
City string `json:"city"` // 城市
|
||||
District string `json:"district"` // 区县
|
||||
Address string `json:"address"` // 详细地址
|
||||
PostalCode string `json:"postal_code"` // 邮编
|
||||
}
|
||||
|
||||
// PayInfo 支付信息(响应)
|
||||
|
||||
type PayInfo struct {
|
||||
TransactionID string `json:"transaction_id"` // 支付平台交易号
|
||||
OutTradeNo string `json:"out_trade_no"` // 商户订单号
|
||||
PrepayID string `json:"prepay_id"` // 预支付ID
|
||||
QRCode string `json:"qrcode"` // 支付二维码
|
||||
PayURL string `json:"pay_url"` // 支付链接
|
||||
}
|
||||
|
||||
// CancelOrderReq 取消订单请求
|
||||
|
||||
type CancelOrderReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
OrderNo string `json:"order_no" binding:"required"` // 订单号
|
||||
Reason string `json:"reason"` // 取消原因
|
||||
}
|
||||
|
||||
// CancelOrderResp 取消订单响应
|
||||
|
||||
type CancelOrderResp struct {
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
Status string `json:"status"` // 新状态
|
||||
}
|
||||
|
||||
// RefundOrderReq 退款请求
|
||||
|
||||
type RefundOrderReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
OrderNo string `json:"order_no" binding:"required"` // 订单号
|
||||
RefundAmount int64 `json:"refund_amount" binding:"required"` // 退款金额(分)
|
||||
Reason string `json:"reason"` // 退款原因
|
||||
}
|
||||
|
||||
// RefundOrderResp 退款响应
|
||||
|
||||
type RefundOrderResp struct {
|
||||
RefundNo string `json:"refund_no"` // 退款单号
|
||||
RefundID string `json:"refund_id"` // 退款ID
|
||||
RefundAmount int64 `json:"refund_amount"` // 退款金额
|
||||
}
|
||||
|
||||
// ListOrdersReq 订单列表请求
|
||||
|
||||
type ListOrdersReq struct {
|
||||
TenantID string `json:"tenant_id" binding:"required"` // 租户ID
|
||||
UserID string `json:"user_id"` // 用户ID(可选)
|
||||
Status string `json:"status"` // 订单状态(可选)
|
||||
Page int `json:"page"` // 页码
|
||||
PageSize int `json:"page_size"` // 每页大小
|
||||
}
|
||||
|
||||
// ListOrdersResp 订单列表响应
|
||||
|
||||
type ListOrdersResp struct {
|
||||
Orders []OrderSummary `json:"orders"` // 订单列表
|
||||
Total int64 `json:"total"` // 总记录数
|
||||
Page int `json:"page"` // 当前页码
|
||||
PageSize int `json:"page_size"` // 每页大小
|
||||
}
|
||||
|
||||
// OrderSummary 订单摘要(用于列表)
|
||||
|
||||
type OrderSummary struct {
|
||||
ID string `json:"id"` // 订单ID
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
TotalAmount int64 `json:"total_amount"` // 订单总金额
|
||||
PayAmount int64 `json:"pay_amount"` // 实付金额
|
||||
Status string `json:"status"` // 订单状态
|
||||
Subject string `json:"subject"` // 订单标题
|
||||
CreatedAt time.Time `json:"created_at"` // 创建时间
|
||||
PaidAt *time.Time `json:"paid_at"` // 支付时间
|
||||
}
|
||||
54
model/entity/order_base.go
Normal file
54
model/entity/order_base.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderBase 订单基础信息
|
||||
// 所有订单状态共有的字段
|
||||
// 按状态拆分的订单表会继承这个基础结构
|
||||
// 每个状态对应一个独立的MongoDB集合
|
||||
// 例如:orders_pending, orders_paid, orders_shipped, orders_completed, orders_cancelled
|
||||
|
||||
type OrderBase struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
|
||||
TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID
|
||||
OrderNo string `bson:"order_no" json:"order_no"` // 订单号
|
||||
UserID string `bson:"user_id" json:"user_id"` // 用户ID
|
||||
TotalAmount int64 `bson:"total_amount" json:"total_amount"` // 订单总金额(分)
|
||||
PayAmount int64 `bson:"pay_amount" json:"pay_amount"` // 实付金额(分)
|
||||
OrderType string `bson:"order_type" json:"order_type"` // 订单类型:normal-普通订单
|
||||
Subject string `bson:"subject" json:"subject"` // 订单标题
|
||||
Description string `bson:"description" json:"description"` // 订单描述
|
||||
CreatedAt time.Time `bson:"created_at" json:"created_at"` // 创建时间
|
||||
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"` // 更新时间
|
||||
ExpiredAt *time.Time `bson:"expired_at,omitempty" json:"expired_at"` // 过期时间
|
||||
}
|
||||
|
||||
// OrderItem 订单商品项
|
||||
// 所有订单状态共有的商品信息
|
||||
// 按状态拆分的订单表会包含这个结构
|
||||
|
||||
type OrderItem struct {
|
||||
ProductID string `bson:"product_id" json:"product_id"` // 商品ID
|
||||
ProductName string `bson:"product_name" json:"product_name"` // 商品名称
|
||||
Price int64 `bson:"price" json:"price"` // 单价(分)
|
||||
Quantity int `bson:"quantity" json:"quantity"` // 数量
|
||||
TotalPrice int64 `bson:"total_price" json:"total_price"` // 小计(分)
|
||||
ImageURL string `bson:"image_url,omitempty" json:"image_url"` // 商品图片
|
||||
}
|
||||
|
||||
// ShippingInfo 收货信息
|
||||
// 所有订单状态共有的收货信息
|
||||
// 按状态拆分的订单表会包含这个结构
|
||||
|
||||
type ShippingInfo struct {
|
||||
Consignee string `bson:"consignee" json:"consignee"` // 收货人
|
||||
Phone string `bson:"phone" json:"phone"` // 手机号
|
||||
Province string `bson:"province" json:"province"` // 省份
|
||||
City string `bson:"city" json:"city"` // 城市
|
||||
District string `bson:"district" json:"district"` // 区县
|
||||
Address string `bson:"address" json:"address"` // 详细地址
|
||||
PostalCode string `bson:"postal_code,omitempty" json:"postal_code"` // 邮编
|
||||
}
|
||||
36
model/entity/order_completed.go
Normal file
36
model/entity/order_completed.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderCompleted 已完成订单
|
||||
// 对应MongoDB集合:orders_completed
|
||||
// 用户确认收货后订单进入此状态
|
||||
|
||||
type OrderCompleted struct {
|
||||
OrderBase // 基础订单信息
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式:wechat/alipay
|
||||
OrderItems []OrderItem `bson:"order_items" json:"order_items"` // 订单商品列表
|
||||
ShippingInfo *ShippingInfo `bson:"shipping_info,omitempty" json:"shipping_info"` // 收货信息
|
||||
|
||||
// 支付成功信息
|
||||
PaidAt time.Time `bson:"paid_at" json:"paid_at"` // 支付时间
|
||||
TransactionID string `bson:"transaction_id" json:"transaction_id"` // 支付平台交易号
|
||||
TradeNo string `bson:"trade_no" json:"trade_no"` // 交易号
|
||||
PaymentChannel string `bson:"payment_channel" json:"payment_channel"` // 支付渠道:wechat/alipay
|
||||
|
||||
// 发货信息
|
||||
ShippedAt time.Time `bson:"shipped_at" json:"shipped_at"` // 发货时间
|
||||
ExpressCompany string `bson:"express_company" json:"express_company"` // 快递公司
|
||||
ExpressNo string `bson:"express_no" json:"express_no"` // 快递单号
|
||||
ShippingCost int64 `bson:"shipping_cost" json:"shipping_cost"` // 运费(分)
|
||||
|
||||
// 完成特有字段
|
||||
CompletedAt time.Time `bson:"completed_at" json:"completed_at"` // 完成时间
|
||||
ReceivedAt time.Time `bson:"received_at" json:"received_at"` // 收货时间
|
||||
|
||||
// 评价相关字段
|
||||
Rating int `bson:"rating,omitempty" json:"rating"` // 评分(1-5)
|
||||
Comment string `bson:"comment,omitempty" json:"comment"` // 评价内容
|
||||
}
|
||||
26
model/entity/order_paid.go
Normal file
26
model/entity/order_paid.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderPaid 已支付订单
|
||||
// 对应MongoDB集合:orders_paid
|
||||
// 支付成功后订单进入此状态
|
||||
|
||||
type OrderPaid struct {
|
||||
OrderBase // 基础订单信息
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式:wechat/alipay
|
||||
PayType string `bson:"pay_type" json:"pay_type"` // 支付类型:native/jsapi/app/h5
|
||||
OrderItems []OrderItem `bson:"order_items" json:"order_items"` // 订单商品列表
|
||||
ShippingInfo *ShippingInfo `bson:"shipping_info,omitempty" json:"shipping_info"` // 收货信息
|
||||
|
||||
// 支付成功特有字段
|
||||
PaidAt time.Time `bson:"paid_at" json:"paid_at"` // 支付时间
|
||||
TransactionID string `bson:"transaction_id" json:"transaction_id"` // 支付平台交易号
|
||||
TradeNo string `bson:"trade_no" json:"trade_no"` // 交易号
|
||||
PaymentChannel string `bson:"payment_channel" json:"payment_channel"` // 支付渠道:wechat/alipay
|
||||
|
||||
// 发货准备相关字段
|
||||
ReadyToShip bool `bson:"ready_to_ship" json:"ready_to_ship"` // 是否准备发货
|
||||
}
|
||||
32
model/entity/order_pending.go
Normal file
32
model/entity/order_pending.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderPending 待支付订单
|
||||
// 对应MongoDB集合:orders_pending
|
||||
// 订单创建后进入此状态
|
||||
|
||||
type OrderPending struct {
|
||||
OrderBase // 基础订单信息
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式:wechat/alipay
|
||||
PayType string `bson:"pay_type" json:"pay_type"` // 支付类型:native/jsapi/app/h5
|
||||
OrderItems []OrderItem `bson:"order_items" json:"order_items"` // 订单商品列表
|
||||
ShippingInfo *ShippingInfo `bson:"shipping_info,omitempty" json:"shipping_info"` // 收货信息
|
||||
|
||||
// 支付相关字段
|
||||
PayInfo PayInfo `bson:"pay_info" json:"pay_info"` // 支付信息
|
||||
}
|
||||
|
||||
// PayInfo 支付信息(待支付订单特有)
|
||||
// 包含支付二维码、支付链接等
|
||||
|
||||
type PayInfo struct {
|
||||
OutTradeNo string `bson:"out_trade_no" json:"out_trade_no"` // 商户订单号
|
||||
QRCode string `bson:"qrcode,omitempty" json:"qrcode"` // 支付二维码
|
||||
PayURL string `bson:"pay_url,omitempty" json:"pay_url"` // 支付链接
|
||||
PrepayID string `bson:"prepay_id,omitempty" json:"prepay_id"` // 预支付ID(微信)
|
||||
JSAPIParams string `bson:"jsapi_params,omitempty" json:"jsapi_params"` // JSAPI参数
|
||||
APPParams string `bson:"app_params,omitempty" json:"app_params"` // APP参数
|
||||
}
|
||||
31
model/entity/order_shipped.go
Normal file
31
model/entity/order_shipped.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderShipped 已发货订单
|
||||
// 对应MongoDB集合:orders_shipped
|
||||
// 发货后订单进入此状态
|
||||
|
||||
type OrderShipped struct {
|
||||
OrderBase // 基础订单信息
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式:wechat/alipay
|
||||
OrderItems []OrderItem `bson:"order_items" json:"order_items"` // 订单商品列表
|
||||
ShippingInfo *ShippingInfo `bson:"shipping_info,omitempty" json:"shipping_info"` // 收货信息
|
||||
|
||||
// 支付成功信息
|
||||
PaidAt time.Time `bson:"paid_at" json:"paid_at"` // 支付时间
|
||||
TransactionID string `bson:"transaction_id" json:"transaction_id"` // 支付平台交易号
|
||||
TradeNo string `bson:"trade_no" json:"trade_no"` // 交易号
|
||||
PaymentChannel string `bson:"payment_channel" json:"payment_channel"` // 支付渠道:wechat/alipay
|
||||
|
||||
// 发货特有字段
|
||||
ShippedAt time.Time `bson:"shipped_at" json:"shipped_at"` // 发货时间
|
||||
ExpressCompany string `bson:"express_company" json:"express_company"` // 快递公司
|
||||
ExpressNo string `bson:"express_no" json:"express_no"` // 快递单号
|
||||
ShippingCost int64 `bson:"shipping_cost" json:"shipping_cost"` // 运费(分)
|
||||
|
||||
// 收货相关字段
|
||||
ExpectedArrival time.Time `bson:"expected_arrival,omitempty" json:"expected_arrival"` // 预计到达时间
|
||||
}
|
||||
48
model/entity/order_status.go
Normal file
48
model/entity/order_status.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package entity
|
||||
|
||||
// OrderStatus 订单状态枚举
|
||||
// 用于标识订单当前所处的状态
|
||||
// 每个状态对应一个独立的MongoDB集合
|
||||
|
||||
type OrderStatus string
|
||||
|
||||
const (
|
||||
OrderStatusPending OrderStatus = "pending" // 待支付 - orders_pending
|
||||
OrderStatusPaid OrderStatus = "paid" // 已支付 - orders_paid
|
||||
OrderStatusShipped OrderStatus = "shipped" // 已发货 - orders_shipped
|
||||
OrderStatusCompleted OrderStatus = "completed" // 已完成 - orders_completed
|
||||
OrderStatusCancelled OrderStatus = "cancelled" // 已取消 - orders_cancelled
|
||||
OrderStatusRefunded OrderStatus = "refunded" // 已退款 - orders_refunded
|
||||
)
|
||||
|
||||
// PayStatus 支付状态枚举
|
||||
// 用于标识订单的支付状态
|
||||
|
||||
type PayStatus string
|
||||
|
||||
const (
|
||||
PayStatusUnpaid PayStatus = "unpaid" // 未支付
|
||||
PayStatusPaid PayStatus = "paid" // 已支付
|
||||
PayStatusFailed PayStatus = "failed" // 支付失败
|
||||
PayStatusRefunded PayStatus = "refunded" // 已退款
|
||||
)
|
||||
|
||||
// PayMethod 支付方式枚举
|
||||
|
||||
type PayMethod string
|
||||
|
||||
const (
|
||||
PayMethodWechat PayMethod = "wechat" // 微信支付
|
||||
PayMethodAlipay PayMethod = "alipay" // 支付宝支付
|
||||
)
|
||||
|
||||
// PayType 支付类型枚举
|
||||
|
||||
type PayType string
|
||||
|
||||
const (
|
||||
PayTypeNative PayType = "native" // 扫码支付
|
||||
PayTypeJSAPI PayType = "jsapi" // JSAPI支付
|
||||
PayTypeAPP PayType = "app" // APP支付
|
||||
PayTypeH5 PayType = "h5" // H5支付
|
||||
)
|
||||
82
model/entity/payment_config.go
Normal file
82
model/entity/payment_config.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
// PaymentConfig 支付配置
|
||||
// 每个租户有独立的支付配置
|
||||
// 支持微信支付和支付宝支付
|
||||
|
||||
type PaymentConfig struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
|
||||
TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式:wechat/alipay
|
||||
ConfigName string `bson:"config_name" json:"config_name"` // 配置名称
|
||||
Description string `bson:"description" json:"description"` // 配置描述
|
||||
Enabled bool `bson:"enabled" json:"enabled"` // 是否启用
|
||||
|
||||
// 通用配置
|
||||
AppID string `bson:"app_id" json:"app_id"` // 应用ID
|
||||
MchID string `bson:"mch_id" json:"mch_id"` // 商户号
|
||||
APIKey string `bson:"api_key" json:"api_key"` // API密钥
|
||||
NotifyURL string `bson:"notify_url" json:"notify_url"` // 回调地址
|
||||
ReturnURL string `bson:"return_url" json:"return_url"` // 返回地址
|
||||
|
||||
// 证书配置(微信支付)
|
||||
CertPath string `bson:"cert_path,omitempty" json:"cert_path"` // 证书路径
|
||||
KeyPath string `bson:"key_path,omitempty" json:"key_path"` // 密钥路径
|
||||
|
||||
// 支付宝特有配置
|
||||
AppPrivateKey string `bson:"app_private_key,omitempty" json:"app_private_key"` // 应用私钥
|
||||
AlipayPublicKey string `bson:"alipay_public_key,omitempty" json:"alipay_public_key"` // 支付宝公钥
|
||||
|
||||
// 环境配置
|
||||
Sandbox bool `bson:"sandbox" json:"sandbox"` // 是否沙箱环境
|
||||
GatewayURL string `bson:"gateway_url" json:"gateway_url"` // 网关地址
|
||||
|
||||
// 支持的支付类型
|
||||
SupportNative bool `bson:"support_native" json:"support_native"` // 支持扫码支付
|
||||
SupportJSAPI bool `bson:"support_jsapi" json:"support_jsapi"` // 支持JSAPI支付
|
||||
SupportAPP bool `bson:"support_app" json:"support_app"` // 支持APP支付
|
||||
SupportH5 bool `bson:"support_h5" json:"support_h5"` // 支持H5支付
|
||||
}
|
||||
|
||||
// PaymentRecord 支付记录
|
||||
// 记录每次支付操作的结果
|
||||
|
||||
type PaymentRecord struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
|
||||
TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID
|
||||
OrderID primitive.ObjectID `bson:"order_id" json:"order_id"` // 订单ID
|
||||
OrderNo string `bson:"order_no" json:"order_no"` // 订单号
|
||||
PayMethod string `bson:"pay_method" json:"pay_method"` // 支付方式
|
||||
PayType string `bson:"pay_type" json:"pay_type"` // 支付类型
|
||||
Amount int64 `bson:"amount" json:"amount"` // 支付金额(分)
|
||||
TransactionID string `bson:"transaction_id" json:"transaction_id"` // 支付平台交易号
|
||||
OutTradeNo string `bson:"out_trade_no" json:"out_trade_no"` // 商户订单号
|
||||
TradeNo string `bson:"trade_no" json:"trade_no"` // 交易号
|
||||
PrepayID string `bson:"prepay_id,omitempty" json:"prepay_id"` // 预支付ID
|
||||
Status string `bson:"status" json:"status"` // 支付状态:success/failed
|
||||
ErrorMsg string `bson:"error_msg,omitempty" json:"error_msg"` // 错误信息
|
||||
CreatedAt int64 `bson:"created_at" json:"created_at"` // 创建时间
|
||||
UpdatedAt int64 `bson:"updated_at" json:"updated_at"` // 更新时间
|
||||
}
|
||||
|
||||
// RefundRecord 退款记录
|
||||
// 记录每次退款操作的结果
|
||||
|
||||
type RefundRecord struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
|
||||
TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID
|
||||
OrderID primitive.ObjectID `bson:"order_id" json:"order_id"` // 订单ID
|
||||
OrderNo string `bson:"order_no" json:"order_no"` // 订单号
|
||||
RefundNo string `bson:"refund_no" json:"refund_no"` // 退款单号
|
||||
RefundID string `bson:"refund_id" json:"refund_id"` // 退款ID
|
||||
RefundAmount int64 `bson:"refund_amount" json:"refund_amount"` // 退款金额(分)
|
||||
Reason string `bson:"reason" json:"reason"` // 退款原因
|
||||
Status string `bson:"status" json:"status"` // 退款状态:success/failed
|
||||
ErrorMsg string `bson:"error_msg,omitempty" json:"error_msg"` // 错误信息
|
||||
CreatedAt int64 `bson:"created_at" json:"created_at"` // 创建时间
|
||||
UpdatedAt int64 `bson:"updated_at" json:"updated_at"` // 更新时间
|
||||
}
|
||||
439
service/order.go
Normal file
439
service/order.go
Normal file
@@ -0,0 +1,439 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"order/dao"
|
||||
"order/model/dto"
|
||||
"order/model/entity"
|
||||
)
|
||||
|
||||
// OrderService 订单服务
|
||||
|
||||
type OrderService struct {
|
||||
orderDao *dao.OrderDao
|
||||
}
|
||||
|
||||
// NewOrderService 创建订单服务实例
|
||||
func NewOrderService(orderDao *dao.OrderDao) *OrderService {
|
||||
return &OrderService{
|
||||
orderDao: orderDao,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) (*dto.CreateOrderResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" || req.UserID == "" || req.Subject == "" {
|
||||
return nil, errors.New("必填参数不能为空")
|
||||
}
|
||||
|
||||
if len(req.OrderItems) == 0 {
|
||||
return nil, errors.New("订单商品不能为空")
|
||||
}
|
||||
|
||||
// 2. 计算订单金额
|
||||
totalAmount := int64(0)
|
||||
for i := range req.OrderItems {
|
||||
item := &req.OrderItems[i]
|
||||
if item.Price <= 0 || item.Quantity <= 0 {
|
||||
return nil, fmt.Errorf("商品价格或数量无效: %s", item.ProductName)
|
||||
}
|
||||
item.TotalPrice = item.Price * int64(item.Quantity)
|
||||
totalAmount += item.TotalPrice
|
||||
}
|
||||
|
||||
if totalAmount <= 0 {
|
||||
return nil, errors.New("订单总金额必须大于0")
|
||||
}
|
||||
|
||||
// 3. 生成订单号
|
||||
orderNo := s.generateOrderNo(req.TenantID)
|
||||
|
||||
// 4. 设置订单过期时间(30分钟后)
|
||||
expiredAt := time.Now().Add(30 * time.Minute)
|
||||
|
||||
// 5. 创建待支付订单
|
||||
order := &entity.OrderPending{
|
||||
OrderBase: entity.OrderBase{
|
||||
TenantID: req.TenantID,
|
||||
OrderNo: orderNo,
|
||||
UserID: req.UserID,
|
||||
TotalAmount: totalAmount,
|
||||
PayAmount: totalAmount, // 暂时没有优惠,实付金额等于总金额
|
||||
OrderType: req.OrderType,
|
||||
Subject: req.Subject,
|
||||
Description: req.Description,
|
||||
ExpiredAt: &expiredAt,
|
||||
},
|
||||
OrderItems: gconv.Slice[*entity.OrderItem](req.OrderItems),
|
||||
ShippingInfo: (*entity.ShippingInfo)(&req.ShippingInfo),
|
||||
PayInfo: entity.PayInfo{},
|
||||
}
|
||||
|
||||
// 6. 保存订单
|
||||
if err := s.orderDao.CreatePendingOrder(ctx, order); err != nil {
|
||||
return nil, fmt.Errorf("创建订单失败: %w", err)
|
||||
}
|
||||
|
||||
// 7. 返回结果
|
||||
resp := &dto.CreateOrderResp{
|
||||
OrderNo: orderNo,
|
||||
TotalAmount: totalAmount,
|
||||
PayAmount: totalAmount,
|
||||
ExpiredAt: expiredAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// generateOrderNo 生成订单号
|
||||
func (s *OrderService) generateOrderNo(tenantID string) string {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
random := rand.Intn(10000)
|
||||
return fmt.Sprintf("%s%s%04d", tenantID, timestamp, random)
|
||||
}
|
||||
|
||||
// QueryOrder 查询订单详情
|
||||
func (s *OrderService) QueryOrder(ctx context.Context, req *dto.QueryOrderReq) (*dto.QueryOrderResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" || req.OrderNo == "" {
|
||||
return nil, errors.New("必填参数不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询订单
|
||||
order, status, err := s.orderDao.GetOrderByNo(ctx, req.TenantID, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取订单失败: %w", err)
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return nil, errors.New("订单不存在")
|
||||
}
|
||||
|
||||
// 3. 构建响应
|
||||
var resp dto.QueryOrderResp
|
||||
|
||||
switch status {
|
||||
case entity.OrderStatusPending:
|
||||
if pendingOrder, ok := order.(*entity.OrderPending); ok {
|
||||
resp.Order = s.convertPendingOrderToDetail(pendingOrder)
|
||||
}
|
||||
case entity.OrderStatusPaid:
|
||||
if paidOrder, ok := order.(*entity.OrderPaid); ok {
|
||||
resp.Order = s.convertPaidOrderToDetail(paidOrder)
|
||||
}
|
||||
case entity.OrderStatusShipped:
|
||||
if shippedOrder, ok := order.(*entity.OrderShipped); ok {
|
||||
resp.Order = s.convertShippedOrderToDetail(shippedOrder)
|
||||
}
|
||||
case entity.OrderStatusCompleted:
|
||||
if completedOrder, ok := order.(*entity.OrderCompleted); ok {
|
||||
resp.Order = s.convertCompletedOrderToDetail(completedOrder)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("不支持的订单状态: %s", status)
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// convertPendingOrderToDetail 转换待支付订单为详情
|
||||
func (s *OrderService) convertPendingOrderToDetail(order *entity.OrderPending) dto.OrderDetail {
|
||||
return dto.OrderDetail{
|
||||
ID: order.ID.Hex(),
|
||||
TenantID: order.TenantID,
|
||||
OrderNo: order.OrderNo,
|
||||
UserID: order.UserID,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusPending),
|
||||
PayMethod: order.PayMethod,
|
||||
PayStatus: "unpaid",
|
||||
OrderType: order.OrderType,
|
||||
Subject: order.Subject,
|
||||
Description: order.Description,
|
||||
OrderItems: s.convertOrderItems(order.OrderItems),
|
||||
ShippingInfo: dto.ShippingInfo{
|
||||
Consignee: order.ShippingInfo.Consignee,
|
||||
Phone: order.ShippingInfo.Phone,
|
||||
Province: order.ShippingInfo.Province,
|
||||
City: order.ShippingInfo.City,
|
||||
District: order.ShippingInfo.District,
|
||||
Address: order.ShippingInfo.Address,
|
||||
PostalCode: order.ShippingInfo.PostalCode,
|
||||
},
|
||||
PayInfo: dto.PayInfo{
|
||||
OutTradeNo: order.PayInfo.OutTradeNo,
|
||||
PrepayID: order.PayInfo.PrepayID,
|
||||
QRCode: order.PayInfo.QRCode,
|
||||
PayURL: order.PayInfo.PayURL,
|
||||
},
|
||||
CreatedAt: order.CreatedAt,
|
||||
UpdatedAt: order.UpdatedAt,
|
||||
ExpiredAt: order.ExpiredAt,
|
||||
}
|
||||
}
|
||||
|
||||
// convertPaidOrderToDetail 转换已支付订单为详情
|
||||
func (s *OrderService) convertPaidOrderToDetail(order *entity.OrderPaid) dto.OrderDetail {
|
||||
return dto.OrderDetail{
|
||||
ID: order.ID.Hex(),
|
||||
TenantID: order.TenantID,
|
||||
OrderNo: order.OrderNo,
|
||||
UserID: order.UserID,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusPaid),
|
||||
PayMethod: order.PayMethod,
|
||||
PayStatus: "paid",
|
||||
OrderType: order.OrderType,
|
||||
Subject: order.Subject,
|
||||
Description: order.Description,
|
||||
OrderItems: s.convertOrderItems(order.OrderItems),
|
||||
ShippingInfo: dto.ShippingInfo{
|
||||
Consignee: order.ShippingInfo.Consignee,
|
||||
Phone: order.ShippingInfo.Phone,
|
||||
Province: order.ShippingInfo.Province,
|
||||
City: order.ShippingInfo.City,
|
||||
District: order.ShippingInfo.District,
|
||||
Address: order.ShippingInfo.Address,
|
||||
PostalCode: order.ShippingInfo.PostalCode,
|
||||
},
|
||||
PayInfo: dto.PayInfo{
|
||||
TransactionID: order.TransactionID,
|
||||
OutTradeNo: order.OrderNo,
|
||||
},
|
||||
CreatedAt: order.CreatedAt,
|
||||
UpdatedAt: order.UpdatedAt,
|
||||
PaidAt: &order.PaidAt,
|
||||
}
|
||||
}
|
||||
|
||||
// convertShippedOrderToDetail 转换已发货订单为详情
|
||||
func (s *OrderService) convertShippedOrderToDetail(order *entity.OrderShipped) dto.OrderDetail {
|
||||
return dto.OrderDetail{
|
||||
ID: order.ID.Hex(),
|
||||
TenantID: order.TenantID,
|
||||
OrderNo: order.OrderNo,
|
||||
UserID: order.UserID,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusShipped),
|
||||
PayMethod: order.PayMethod,
|
||||
PayStatus: "paid",
|
||||
OrderType: order.OrderType,
|
||||
Subject: order.Subject,
|
||||
Description: order.Description,
|
||||
OrderItems: s.convertOrderItems(order.OrderItems),
|
||||
ShippingInfo: dto.ShippingInfo{
|
||||
Consignee: order.ShippingInfo.Consignee,
|
||||
Phone: order.ShippingInfo.Phone,
|
||||
Province: order.ShippingInfo.Province,
|
||||
City: order.ShippingInfo.City,
|
||||
District: order.ShippingInfo.District,
|
||||
Address: order.ShippingInfo.Address,
|
||||
PostalCode: order.ShippingInfo.PostalCode,
|
||||
},
|
||||
CreatedAt: order.CreatedAt,
|
||||
UpdatedAt: order.UpdatedAt,
|
||||
PaidAt: &order.PaidAt,
|
||||
}
|
||||
}
|
||||
|
||||
// convertCompletedOrderToDetail 转换已完成订单为详情
|
||||
func (s *OrderService) convertCompletedOrderToDetail(order *entity.OrderCompleted) dto.OrderDetail {
|
||||
return dto.OrderDetail{
|
||||
ID: order.ID.Hex(),
|
||||
TenantID: order.TenantID,
|
||||
OrderNo: order.OrderNo,
|
||||
UserID: order.UserID,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusCompleted),
|
||||
PayMethod: order.PayMethod,
|
||||
PayStatus: "paid",
|
||||
OrderType: order.OrderType,
|
||||
Subject: order.Subject,
|
||||
Description: order.Description,
|
||||
OrderItems: s.convertOrderItems(order.OrderItems),
|
||||
ShippingInfo: dto.ShippingInfo{
|
||||
Consignee: order.ShippingInfo.Consignee,
|
||||
Phone: order.ShippingInfo.Phone,
|
||||
Province: order.ShippingInfo.Province,
|
||||
City: order.ShippingInfo.City,
|
||||
District: order.ShippingInfo.District,
|
||||
Address: order.ShippingInfo.Address,
|
||||
PostalCode: order.ShippingInfo.PostalCode,
|
||||
},
|
||||
CreatedAt: order.CreatedAt,
|
||||
UpdatedAt: order.UpdatedAt,
|
||||
PaidAt: &order.PaidAt,
|
||||
}
|
||||
}
|
||||
|
||||
// convertOrderItems 转换订单商品项
|
||||
func (s *OrderService) convertOrderItems(items []*entity.OrderItem) []dto.OrderItem {
|
||||
var result []dto.OrderItem
|
||||
for _, item := range items {
|
||||
result = append(result, dto.OrderItem{
|
||||
ProductID: item.ProductID,
|
||||
ProductName: item.ProductName,
|
||||
Price: item.Price,
|
||||
Quantity: item.Quantity,
|
||||
TotalPrice: item.TotalPrice,
|
||||
ImageURL: item.ImageURL,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CancelOrder 取消订单
|
||||
func (s *OrderService) CancelOrder(ctx context.Context, req *dto.CancelOrderReq) (*dto.CancelOrderResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" || req.OrderNo == "" {
|
||||
return nil, errors.New("必填参数不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询订单
|
||||
order, status, err := s.orderDao.GetOrderByNo(ctx, req.TenantID, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取订单失败: %w", err)
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return nil, errors.New("订单不存在")
|
||||
}
|
||||
|
||||
// 3. 检查订单状态(只有待支付订单可以取消)
|
||||
if status != entity.OrderStatusPending {
|
||||
return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status)
|
||||
}
|
||||
|
||||
// 4. 将订单移动到已取消状态
|
||||
updateData := bson.M{
|
||||
"cancel_reason": req.Reason,
|
||||
}
|
||||
|
||||
if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusCancelled, req.TenantID, req.OrderNo, updateData); err != nil {
|
||||
return nil, fmt.Errorf("取消订单失败: %w", err)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
resp := &dto.CancelOrderResp{
|
||||
OrderNo: req.OrderNo,
|
||||
Status: string(entity.OrderStatusCancelled),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListOrders 查询订单列表
|
||||
func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) (*dto.ListOrdersResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" {
|
||||
return nil, errors.New("租户ID不能为空")
|
||||
}
|
||||
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
// 2. 根据状态查询订单列表
|
||||
var status entity.OrderStatus
|
||||
if req.Status != "" {
|
||||
status = entity.OrderStatus(req.Status)
|
||||
} else {
|
||||
// 默认查询所有状态
|
||||
status = entity.OrderStatusPending
|
||||
}
|
||||
|
||||
orders, total, err := s.orderDao.ListOrdersByStatus(ctx, status, req.TenantID, req.UserID, req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("查询订单列表失败: %w", err)
|
||||
}
|
||||
|
||||
// 3. 转换订单列表
|
||||
var orderSummaries []dto.OrderSummary
|
||||
|
||||
switch status {
|
||||
case entity.OrderStatusPending:
|
||||
if pendingOrders, ok := orders.([]entity.OrderPending); ok {
|
||||
for _, order := range pendingOrders {
|
||||
orderSummaries = append(orderSummaries, dto.OrderSummary{
|
||||
ID: order.ID.Hex(),
|
||||
OrderNo: order.OrderNo,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusPending),
|
||||
Subject: order.Subject,
|
||||
CreatedAt: order.CreatedAt,
|
||||
})
|
||||
}
|
||||
}
|
||||
case entity.OrderStatusPaid:
|
||||
if paidOrders, ok := orders.([]entity.OrderPaid); ok {
|
||||
for _, order := range paidOrders {
|
||||
orderSummaries = append(orderSummaries, dto.OrderSummary{
|
||||
ID: order.ID.Hex(),
|
||||
OrderNo: order.OrderNo,
|
||||
TotalAmount: order.TotalAmount,
|
||||
PayAmount: order.PayAmount,
|
||||
Status: string(entity.OrderStatusPaid),
|
||||
Subject: order.Subject,
|
||||
CreatedAt: order.CreatedAt,
|
||||
PaidAt: &order.PaidAt,
|
||||
})
|
||||
}
|
||||
}
|
||||
// 其他状态类似处理...
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
resp := &dto.ListOrdersResp{
|
||||
Orders: orderSummaries,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ProcessExpiredOrders 处理过期订单
|
||||
func (s *OrderService) ProcessExpiredOrders(ctx context.Context, tenantID string) error {
|
||||
// 获取过期的待支付订单
|
||||
expiredOrders, err := s.orderDao.GetExpiredPendingOrders(ctx, tenantID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取过期订单失败: %w", err)
|
||||
}
|
||||
|
||||
// 批量取消过期订单
|
||||
for _, order := range expiredOrders {
|
||||
updateData := bson.M{
|
||||
"cancel_reason": "订单超时自动取消",
|
||||
}
|
||||
|
||||
if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusCancelled, tenantID, order.OrderNo, updateData); err != nil {
|
||||
// 记录错误但继续处理其他订单
|
||||
fmt.Printf("取消过期订单失败: %s, 错误: %v\n", order.OrderNo, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePayInfo 更新支付信息
|
||||
func (s *OrderService) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error {
|
||||
return s.orderDao.UpdatePayInfo(ctx, tenantID, orderNo, payInfo)
|
||||
}
|
||||
387
service/payment.go
Normal file
387
service/payment.go
Normal file
@@ -0,0 +1,387 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"order/dao"
|
||||
"order/model/dto"
|
||||
"order/model/entity"
|
||||
)
|
||||
|
||||
// PaymentService 支付服务
|
||||
|
||||
type PaymentService struct {
|
||||
orderDao *dao.OrderDao
|
||||
paymentConfigDao *dao.PaymentConfigDao
|
||||
paymentRecordDao *dao.PaymentRecordDao
|
||||
refundRecordDao *dao.RefundRecordDao
|
||||
}
|
||||
|
||||
// NewPaymentService 创建支付服务实例
|
||||
func NewPaymentService(
|
||||
orderDao *dao.OrderDao,
|
||||
paymentConfigDao *dao.PaymentConfigDao,
|
||||
paymentRecordDao *dao.PaymentRecordDao,
|
||||
refundRecordDao *dao.RefundRecordDao,
|
||||
) *PaymentService {
|
||||
return &PaymentService{
|
||||
orderDao: orderDao,
|
||||
paymentConfigDao: paymentConfigDao,
|
||||
paymentRecordDao: paymentRecordDao,
|
||||
refundRecordDao: refundRecordDao,
|
||||
}
|
||||
}
|
||||
|
||||
// PayOrder 支付订单
|
||||
func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*dto.PayOrderResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" || req.OrderNo == "" || req.PayMethod == "" || req.PayType == "" {
|
||||
return nil, errors.New("必填参数不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询订单
|
||||
order, status, err := s.orderDao.GetOrderByNo(ctx, req.TenantID, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取订单失败: %w", err)
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return nil, errors.New("订单不存在")
|
||||
}
|
||||
|
||||
// 3. 验证订单状态(只有待支付订单可以支付)
|
||||
if status != entity.OrderStatusPending {
|
||||
return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status)
|
||||
}
|
||||
|
||||
pendingOrder, ok := order.(*entity.OrderPending)
|
||||
if !ok {
|
||||
return nil, errors.New("订单类型错误")
|
||||
}
|
||||
|
||||
// 4. 获取支付配置
|
||||
paymentConfig, err := s.paymentConfigDao.GetByTenantAndMethod(ctx, req.TenantID, req.PayMethod)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取支付配置失败: %w", err)
|
||||
}
|
||||
|
||||
if paymentConfig == nil {
|
||||
return nil, errors.New("支付配置不存在")
|
||||
}
|
||||
|
||||
// 5. 调用第三方支付接口
|
||||
payResp, err := s.callThirdPartyPayment(ctx, paymentConfig, req, pendingOrder)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("调用支付接口失败: %w", err)
|
||||
}
|
||||
|
||||
// 6. 创建支付记录
|
||||
paymentRecord := &entity.PaymentRecord{
|
||||
TenantID: req.TenantID,
|
||||
OrderID: pendingOrder.ID,
|
||||
OrderNo: req.OrderNo,
|
||||
PayMethod: req.PayMethod,
|
||||
PayType: req.PayType,
|
||||
Amount: pendingOrder.PayAmount,
|
||||
OutTradeNo: payResp.OutTradeNo,
|
||||
Status: "pending",
|
||||
}
|
||||
|
||||
if err := s.paymentRecordDao.Create(ctx, paymentRecord); err != nil {
|
||||
return nil, fmt.Errorf("创建支付记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 7. 更新订单支付信息
|
||||
payInfo := entity.PayInfo{
|
||||
OutTradeNo: payResp.OutTradeNo,
|
||||
QRCode: payResp.QRCode,
|
||||
PayURL: payResp.PayURL,
|
||||
PrepayID: payResp.PrepayID,
|
||||
JSAPIParams: payResp.JSAPIParams,
|
||||
APPParams: payResp.APPParams,
|
||||
}
|
||||
|
||||
if err := s.orderDao.UpdatePayInfo(ctx, req.TenantID, req.OrderNo, payInfo); err != nil {
|
||||
return nil, fmt.Errorf("更新订单支付信息失败: %w", err)
|
||||
}
|
||||
|
||||
// 8. 返回支付信息
|
||||
resp := &dto.PayOrderResp{
|
||||
OrderNo: req.OrderNo,
|
||||
QRCode: payResp.QRCode,
|
||||
PayURL: payResp.PayURL,
|
||||
PrepayID: payResp.PrepayID,
|
||||
JSAPIParams: payResp.JSAPIParams,
|
||||
APPParams: payResp.APPParams,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// callThirdPartyPayment 调用第三方支付接口
|
||||
func (s *PaymentService) callThirdPartyPayment(ctx context.Context, config *entity.PaymentConfig, req *dto.PayOrderReq, order *entity.OrderPending) (*PaymentResponse, error) {
|
||||
// 这里应该是实际的第三方支付接口调用
|
||||
// 为了演示,我们返回模拟数据
|
||||
|
||||
outTradeNo := s.generateOutTradeNo(req.TenantID)
|
||||
|
||||
payResp := &PaymentResponse{
|
||||
OutTradeNo: outTradeNo,
|
||||
}
|
||||
|
||||
// 根据支付类型返回不同的支付参数
|
||||
switch req.PayType {
|
||||
case "native":
|
||||
// 扫码支付
|
||||
payResp.QRCode = fmt.Sprintf("https://api.example.com/qrcode/%s", outTradeNo)
|
||||
case "jsapi":
|
||||
// JSAPI支付
|
||||
payResp.PrepayID = fmt.Sprintf("wxprepay_%s", outTradeNo)
|
||||
payResp.JSAPIParams = fmt.Sprintf(`{"appId":"%s","timeStamp":"%d","nonceStr":"%s","package":"prepay_id=%s","signType":"MD5","paySign":"signature"}`,
|
||||
config.AppID, time.Now().Unix(), s.generateNonceStr(), payResp.PrepayID)
|
||||
case "app":
|
||||
// APP支付
|
||||
payResp.APPParams = fmt.Sprintf(`{"appid":"%s","partnerid":"%s","prepayid":"%s","package":"Sign=WXPay","noncestr":"%s","timestamp":"%d","sign":"signature"}`,
|
||||
config.AppID, config.MchID, payResp.PrepayID, s.generateNonceStr(), time.Now().Unix())
|
||||
case "h5":
|
||||
// H5支付
|
||||
payResp.PayURL = fmt.Sprintf("https://api.example.com/h5pay/%s", outTradeNo)
|
||||
}
|
||||
|
||||
return payResp, nil
|
||||
}
|
||||
|
||||
// PaymentResponse 支付响应
|
||||
|
||||
type PaymentResponse struct {
|
||||
OutTradeNo string `json:"out_trade_no"` // 商户订单号
|
||||
QRCode string `json:"qrcode"` // 支付二维码
|
||||
PayURL string `json:"pay_url"` // 支付链接
|
||||
PrepayID string `json:"prepay_id"` // 预支付ID
|
||||
JSAPIParams string `json:"jsapi_params"` // JSAPI参数
|
||||
APPParams string `json:"app_params"` // APP参数
|
||||
}
|
||||
|
||||
// generateOutTradeNo 生成商户订单号
|
||||
func (s *PaymentService) generateOutTradeNo(tenantID string) string {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
random := rand.Intn(10000)
|
||||
return fmt.Sprintf("%s%s%04d", tenantID, timestamp, random)
|
||||
}
|
||||
|
||||
// generateNonceStr 生成随机字符串
|
||||
func (s *PaymentService) generateNonceStr() string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, 16)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// HandlePaymentNotify 处理支付回调
|
||||
func (s *PaymentService) HandlePaymentNotify(ctx context.Context, req *PaymentNotifyReq) error {
|
||||
// 1. 验证回调签名
|
||||
if !s.verifyNotifySignature(req) {
|
||||
return errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
// 2. 查询支付记录
|
||||
paymentRecord, err := s.paymentRecordDao.GetByOrderNo(ctx, req.TenantID, req.OrderNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询支付记录失败: %w", err)
|
||||
}
|
||||
|
||||
if paymentRecord == nil {
|
||||
return errors.New("支付记录不存在")
|
||||
}
|
||||
|
||||
// 3. 更新支付记录状态
|
||||
if err := s.paymentRecordDao.UpdateStatus(ctx, paymentRecord.ID.Hex(), req.Status, req.TransactionID, req.TradeNo); err != nil {
|
||||
return fmt.Errorf("更新支付记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 4. 如果支付成功,更新订单状态
|
||||
if req.Status == "success" {
|
||||
updateData := bson.M{
|
||||
"paid_at": time.Now(),
|
||||
"transaction_id": req.TransactionID,
|
||||
"trade_no": req.TradeNo,
|
||||
"payment_channel": req.PayMethod,
|
||||
}
|
||||
|
||||
if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusPaid, req.TenantID, req.OrderNo, updateData); err != nil {
|
||||
return fmt.Errorf("更新订单状态失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PaymentNotifyReq 支付回调请求
|
||||
|
||||
type PaymentNotifyReq struct {
|
||||
TenantID string `json:"tenant_id"` // 租户ID
|
||||
OrderNo string `json:"order_no"` // 订单号
|
||||
PayMethod string `json:"pay_method"` // 支付方式
|
||||
Status string `json:"status"` // 支付状态
|
||||
TransactionID string `json:"transaction_id"` // 交易号
|
||||
TradeNo string `json:"trade_no"` // 交易号
|
||||
Sign string `json:"sign"` // 签名
|
||||
}
|
||||
|
||||
// verifyNotifySignature 验证回调签名
|
||||
func (s *PaymentService) verifyNotifySignature(req *PaymentNotifyReq) bool {
|
||||
// 这里应该是实际的签名验证逻辑
|
||||
// 为了演示,我们总是返回true
|
||||
return true
|
||||
}
|
||||
|
||||
// RefundOrder 退款
|
||||
func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderReq) (*dto.RefundOrderResp, error) {
|
||||
// 1. 参数验证
|
||||
if req.TenantID == "" || req.OrderNo == "" || req.RefundAmount <= 0 {
|
||||
return nil, errors.New("必填参数不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询订单
|
||||
order, status, err := s.orderDao.GetOrderByNo(ctx, req.TenantID, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取订单失败: %w", err)
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return nil, errors.New("订单不存在")
|
||||
}
|
||||
|
||||
// 3. 验证订单状态(只有已支付订单可以退款)
|
||||
if status != entity.OrderStatusPaid {
|
||||
return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status)
|
||||
}
|
||||
|
||||
paidOrder, ok := order.(*entity.OrderPaid)
|
||||
if !ok {
|
||||
return nil, errors.New("订单类型错误")
|
||||
}
|
||||
|
||||
// 4. 验证退款金额
|
||||
if req.RefundAmount > paidOrder.PayAmount {
|
||||
return nil, errors.New("退款金额不能超过支付金额")
|
||||
}
|
||||
|
||||
// 5. 调用第三方退款接口
|
||||
refundResp, err := s.callThirdPartyRefund(ctx, req, paidOrder)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("调用退款接口失败: %w", err)
|
||||
}
|
||||
|
||||
// 6. 创建退款记录
|
||||
refundRecord := &entity.RefundRecord{
|
||||
TenantID: req.TenantID,
|
||||
OrderID: paidOrder.ID,
|
||||
OrderNo: req.OrderNo,
|
||||
RefundNo: refundResp.RefundNo,
|
||||
RefundAmount: req.RefundAmount,
|
||||
Reason: req.Reason,
|
||||
Status: "pending",
|
||||
}
|
||||
|
||||
if err := s.refundRecordDao.Create(ctx, refundRecord); err != nil {
|
||||
return nil, fmt.Errorf("创建退款记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 7. 如果是全额退款,更新订单状态
|
||||
if req.RefundAmount == paidOrder.PayAmount {
|
||||
updateData := bson.M{
|
||||
"refund_reason": req.Reason,
|
||||
}
|
||||
|
||||
if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPaid, entity.OrderStatusRefunded, req.TenantID, req.OrderNo, updateData); err != nil {
|
||||
return nil, fmt.Errorf("更新订单状态失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 8. 返回退款结果
|
||||
resp := &dto.RefundOrderResp{
|
||||
RefundNo: refundResp.RefundNo,
|
||||
RefundID: refundResp.RefundID,
|
||||
RefundAmount: req.RefundAmount,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// callThirdPartyRefund 调用第三方退款接口
|
||||
func (s *PaymentService) callThirdPartyRefund(ctx context.Context, req *dto.RefundOrderReq, order *entity.OrderPaid) (*RefundResponse, error) {
|
||||
// 这里应该是实际的第三方退款接口调用
|
||||
// 为了演示,我们返回模拟数据
|
||||
|
||||
refundNo := s.generateRefundNo(req.TenantID)
|
||||
refundID := fmt.Sprintf("refund_%s", refundNo)
|
||||
|
||||
return &RefundResponse{
|
||||
RefundNo: refundNo,
|
||||
RefundID: refundID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RefundResponse 退款响应
|
||||
|
||||
type RefundResponse struct {
|
||||
RefundNo string `json:"refund_no"` // 退款单号
|
||||
RefundID string `json:"refund_id"` // 退款ID
|
||||
}
|
||||
|
||||
// generateRefundNo 生成退款单号
|
||||
func (s *PaymentService) generateRefundNo(tenantID string) string {
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
random := rand.Intn(10000)
|
||||
return fmt.Sprintf("R%s%s%04d", tenantID, timestamp, random)
|
||||
}
|
||||
|
||||
// HandleRefundNotify 处理退款回调
|
||||
func (s *PaymentService) HandleRefundNotify(ctx context.Context, req *RefundNotifyReq) error {
|
||||
// 1. 验证回调签名
|
||||
if !s.verifyRefundNotifySignature(req) {
|
||||
return errors.New("签名验证失败")
|
||||
}
|
||||
|
||||
// 2. 查询退款记录
|
||||
refundRecord, err := s.refundRecordDao.GetByRefundNo(ctx, req.TenantID, req.RefundNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询退款记录失败: %w", err)
|
||||
}
|
||||
|
||||
if refundRecord == nil {
|
||||
return errors.New("退款记录不存在")
|
||||
}
|
||||
|
||||
// 3. 更新退款记录状态
|
||||
if err := s.refundRecordDao.UpdateRefundStatus(ctx, refundRecord.ID.Hex(), req.Status, req.RefundID); err != nil {
|
||||
return fmt.Errorf("更新退款记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefundNotifyReq 退款回调请求
|
||||
|
||||
type RefundNotifyReq struct {
|
||||
TenantID string `json:"tenant_id"` // 租户ID
|
||||
RefundNo string `json:"refund_no"` // 退款单号
|
||||
Status string `json:"status"` // 退款状态
|
||||
RefundID string `json:"refund_id"` // 退款ID
|
||||
Sign string `json:"sign"` // 签名
|
||||
}
|
||||
|
||||
// verifyRefundNotifySignature 验证退款回调签名
|
||||
func (s *PaymentService) verifyRefundNotifySignature(req *RefundNotifyReq) bool {
|
||||
// 这里应该是实际的签名验证逻辑
|
||||
// 为了演示,我们总是返回true
|
||||
return true
|
||||
}
|
||||
50
service/service_manager.go
Normal file
50
service/service_manager.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"order/dao"
|
||||
"order/model/entity"
|
||||
)
|
||||
|
||||
var (
|
||||
orderService *OrderService
|
||||
paymentService *PaymentService
|
||||
)
|
||||
|
||||
// InitServices 初始化服务
|
||||
func InitServices() error {
|
||||
ctx := context.Background()
|
||||
|
||||
// 创建订单集合映射(模拟数据)
|
||||
orderCollections := make(map[entity.OrderStatus]*mongo.Collection)
|
||||
|
||||
// 创建DAO实例
|
||||
orderDao := dao.NewOrderDao(orderCollections)
|
||||
paymentConfigDao := dao.NewPaymentConfigDao(nil)
|
||||
paymentRecordDao := dao.NewPaymentRecordDao(nil)
|
||||
refundRecordDao := dao.NewRefundRecordDao(nil)
|
||||
|
||||
// 创建服务实例
|
||||
orderService = NewOrderService(orderDao)
|
||||
paymentService = NewPaymentService(
|
||||
orderDao,
|
||||
paymentConfigDao,
|
||||
paymentRecordDao,
|
||||
refundRecordDao,
|
||||
)
|
||||
|
||||
g.Log().Info(ctx, "服务初始化完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrderService 获取订单服务实例
|
||||
func GetOrderService() *OrderService {
|
||||
return orderService
|
||||
}
|
||||
|
||||
// GetPaymentService 获取支付服务实例
|
||||
func GetPaymentService() *PaymentService {
|
||||
return paymentService
|
||||
}
|
||||
Reference in New Issue
Block a user