diff --git a/consts/collections.go b/consts/collections.go new file mode 100644 index 0000000..257d8d8 --- /dev/null +++ b/consts/collections.go @@ -0,0 +1,16 @@ +package consts + +// 订单集合常量 +const ( + OrderPendingCollection = "orders_pending" + OrderPaidCollection = "orders_paid" + OrderShippedCollection = "orders_shipped" + OrderCompletedCollection = "orders_completed" +) + +// 支付相关集合常量 +const ( + PaymentConfigCollection = "payment_configs" + PaymentRecordCollection = "payment_records" + RefundRecordCollection = "refund_records" +) diff --git a/model/entity/order_status.go b/consts/order_status.go similarity index 98% rename from model/entity/order_status.go rename to consts/order_status.go index 45f4be7..81898f7 100644 --- a/model/entity/order_status.go +++ b/consts/order_status.go @@ -1,4 +1,4 @@ -package entity +package consts // OrderStatus 订单状态枚举 // 用于标识订单当前所处的状态 diff --git a/controller/order.go b/controller/order.go index f01ac1b..c89ac02 100644 --- a/controller/order.go +++ b/controller/order.go @@ -2,380 +2,71 @@ package controller import ( "context" - "github.com/gogf/gf/v2/frame/g" - "github.com/gogf/gf/v2/net/ghttp" "order/model/dto" "order/service" ) +type order struct{} + // Order 订单控制器 - -type Order struct{} - -var OrderController = &Order{} +var Order = new(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 - } - +func (c *order) Create(ctx context.Context, req *dto.CreateOrderReq) (res *dto.CreateOrderResp, err error) { // 创建订单 - 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, - }) + res, err = service.Order.CreateOrder(ctx, req) + return } // 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 - } - +func (c *order) Pay(ctx context.Context, req *dto.PayOrderReq) (res *dto.PayOrderResp, err error) { // 支付订单 - 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, - }) + res, err = service.Payment.PayOrder(ctx, req) + return } // 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 - } - +func (c *order) Query(ctx context.Context, req *dto.QueryOrderReq) (res *dto.QueryOrderResp, err error) { // 查询订单 - 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, - }) + res, err = service.Order.QueryOrder(ctx, req) + return } // 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 - } - +func (c *order) Cancel(ctx context.Context, req *dto.CancelOrderReq) (res *dto.CancelOrderResp, err error) { // 取消订单 - 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, - }) + res, err = service.Order.CancelOrder(ctx, req) + return } // 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 - } - +func (c *order) Refund(ctx context.Context, req *dto.RefundOrderReq) (res *dto.RefundOrderResp, err error) { // 退款 - 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, - }) + res, err = service.Payment.RefundOrder(ctx, req) + return } // 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 - } - +func (c *order) List(ctx context.Context, req *dto.ListOrdersReq) (res *dto.ListOrdersResp, err error) { // 查询订单列表 - 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, - }) + res, err = service.Order.ListOrders(ctx, req) + return } // 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 - } - +func (c *order) PaymentNotify(ctx context.Context, req *dto.PaymentNotifyReq) (res *dto.PaymentNotifyResp, err error) { // 处理支付回调 - 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, - }) + err = service.Payment.HandlePaymentNotify(ctx, req) + return &dto.PaymentNotifyResp{ + Success: err == nil, + }, err } // 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 - } - +func (c *order) RefundNotify(ctx context.Context, req *dto.RefundNotifyReq) (res *dto.RefundNotifyResp, err error) { // 处理退款回调 - 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, - }) + err = service.Payment.HandleRefundNotify(ctx, req) + return &dto.RefundNotifyResp{ + Success: err == nil, + }, err } diff --git a/controller/payment_config.go b/controller/payment_config.go index f86d91e..5f80e68 100644 --- a/controller/payment_config.go +++ b/controller/payment_config.go @@ -4,7 +4,6 @@ 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" ) @@ -27,45 +26,8 @@ func (c *PaymentConfigController) CreatePaymentConfig(r *ghttp.Request) { 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 { + resp, err := service.PaymentConfig.CreatePaymentConfig(ctx, &req) + if err != nil { r.Response.WriteJsonExit(g.Map{ "code": 500, "message": err.Error(), @@ -77,7 +39,7 @@ func (c *PaymentConfigController) CreatePaymentConfig(r *ghttp.Request) { r.Response.WriteJsonExit(g.Map{ "code": 200, "message": "success", - "data": nil, + "data": resp, }) } @@ -95,85 +57,103 @@ func (c *PaymentConfigController) UpdatePaymentConfig(r *ghttp.Request) { 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 + resp, err := service.PaymentConfig.UpdatePaymentConfig(ctx, &req) + if err != nil { + r.Response.WriteJsonExit(g.Map{ + "code": 500, + "message": err.Error(), + "data": nil, + }) + return } - 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 + r.Response.WriteJsonExit(g.Map{ + "code": 200, + "message": "success", + "data": resp, + }) +} + +// GetPaymentConfig 获取支付配置 +func (c *PaymentConfigController) GetPaymentConfig(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 } - 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 + ctx := context.Background() + + resp, err := service.PaymentConfig.GetPaymentConfig(ctx, &req) + if err != nil { + r.Response.WriteJsonExit(g.Map{ + "code": 500, + "message": err.Error(), + "data": nil, + }) + return } - if err := service.PaymentService.UpdatePaymentConfig(ctx, req.ID, update); err != nil { + r.Response.WriteJsonExit(g.Map{ + "code": 200, + "message": "success", + "data": resp, + }) +} + +// GetPaymentConfigList 获取支付配置列表 +func (c *PaymentConfigController) GetPaymentConfigList(r *ghttp.Request) { + tenantID := r.Get("tenant_id").String() + if tenantID == "" { + r.Response.WriteJsonExit(g.Map{ + "code": 400, + "message": "租户ID不能为空", + "data": nil, + }) + return + } + + ctx := context.Background() + + resp, err := service.PaymentConfig.GetPaymentConfigList(ctx, tenantID) + 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": resp, + }) +} + +// DeletePaymentConfig 删除支付配置 +func (c *PaymentConfigController) DeletePaymentConfig(r *ghttp.Request) { + tenantID := r.Get("tenant_id").String() + configID := r.Get("config_id").String() + + if tenantID == "" || configID == "" { + r.Response.WriteJsonExit(g.Map{ + "code": 400, + "message": "租户ID和配置ID不能为空", + "data": nil, + }) + return + } + + ctx := context.Background() + + err := service.PaymentConfig.DeletePaymentConfig(ctx, tenantID, configID) + if err != nil { r.Response.WriteJsonExit(g.Map{ "code": 500, "message": err.Error(), @@ -189,39 +169,15 @@ func (c *PaymentConfigController) UpdatePaymentConfig(r *ghttp.Request) { }) } -// 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() +// EnablePaymentConfig 启用支付配置 +func (c *PaymentConfigController) EnablePaymentConfig(r *ghttp.Request) { + tenantID := r.Get("tenant_id").String() + configID := r.Get("config_id").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 { + if tenantID == "" || configID == "" { r.Response.WriteJsonExit(g.Map{ "code": 400, - "message": err.Error(), + "message": "租户ID和配置ID不能为空", "data": nil, }) return @@ -229,28 +185,7 @@ func (c *PaymentConfigController) ListPaymentConfigs(r *ghttp.Request) { 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) + err := service.PaymentConfig.EnablePaymentConfig(ctx, tenantID, configID) if err != nil { r.Response.WriteJsonExit(g.Map{ "code": 500, @@ -260,57 +195,42 @@ func (c *PaymentConfigController) ListPaymentConfigs(r *ghttp.Request) { 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)), + r.Response.WriteJsonExit(g.Map{ + "code": 200, + "message": "success", + "data": nil, + }) +} + +// DisablePaymentConfig 禁用支付配置 +func (c *PaymentConfigController) DisablePaymentConfig(r *ghttp.Request) { + tenantID := r.Get("tenant_id").String() + configID := r.Get("config_id").String() + + if tenantID == "" || configID == "" { + r.Response.WriteJsonExit(g.Map{ + "code": 400, + "message": "租户ID和配置ID不能为空", + "data": nil, + }) + return } - 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, - } + ctx := context.Background() - 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) + err := service.PaymentConfig.DisablePaymentConfig(ctx, tenantID, configID) + 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": resp, + "data": nil, }) } diff --git a/dao/order_dao.go b/dao/order_dao.go index c7abee9..39fdf7a 100644 --- a/dao/order_dao.go +++ b/dao/order_dao.go @@ -6,59 +6,56 @@ import ( "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" + "gitee.com/red-future---jilin-g/common/mongo" + "go.mongodb.org/mongo-driver/v2/bson" + "order/consts" "order/model/entity" ) -// OrderDao 订单数据访问对象 -// 支持按状态拆分的订单表操作 +type order struct{} -type OrderDao struct { - collections map[entity.OrderStatus]*mongo.Collection -} - -// NewOrderDao 创建订单DAO实例 -func NewOrderDao(collections map[entity.OrderStatus]*mongo.Collection) *OrderDao { - return &OrderDao{ - collections: collections, - } -} +// Order 订单数据访问对象 +var Order = &order{} // 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) +func (d *order) getCollection(status consts.OrderStatus) (string, error) { + switch status { + case consts.OrderStatusPending: + return consts.OrderPendingCollection, nil + case consts.OrderStatusPaid: + return consts.OrderPaidCollection, nil + case consts.OrderStatusShipped: + return consts.OrderShippedCollection, nil + case consts.OrderStatusCompleted: + return consts.OrderCompletedCollection, nil + default: + return "", 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) +func (d *order) CreatePendingOrder(ctx context.Context, order *entity.OrderPending) error { + collection, err := d.getCollection(consts.OrderStatusPending) if err != nil { return err } - order.ID = primitive.NewObjectID() + order.ID = bson.NewObjectID() order.CreatedAt = time.Now() order.UpdatedAt = time.Now() - _, err = collection.InsertOne(ctx, order) + _, err = mongo.Insert(ctx, []interface{}{order}, collection) return err } // GetOrderByNo 根据订单号查询订单(自动识别状态) -func (d *OrderDao) GetOrderByNo(ctx context.Context, tenantID, orderNo string) (interface{}, entity.OrderStatus, error) { +func (d *order) GetOrderByNo(ctx context.Context, tenantID, orderNo string) (interface{}, consts.OrderStatus, error) { // 按状态优先级搜索(从最新状态开始) - statuses := []entity.OrderStatus{ - entity.OrderStatusCompleted, - entity.OrderStatusShipped, - entity.OrderStatusPaid, - entity.OrderStatusPending, + statuses := []consts.OrderStatus{ + consts.OrderStatusCompleted, + consts.OrderStatusShipped, + consts.OrderStatusPaid, + consts.OrderStatusPending, } for _, status := range statuses { @@ -68,22 +65,22 @@ func (d *OrderDao) GetOrderByNo(ctx context.Context, tenantID, orderNo string) ( } switch status { - case entity.OrderStatusPending: + case consts.OrderStatusPending: var order entity.OrderPending if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil { return &order, status, nil } - case entity.OrderStatusPaid: + case consts.OrderStatusPaid: var order entity.OrderPaid if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil { return &order, status, nil } - case entity.OrderStatusShipped: + case consts.OrderStatusShipped: var order entity.OrderShipped if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil { return &order, status, nil } - case entity.OrderStatusCompleted: + case consts.OrderStatusCompleted: var order entity.OrderCompleted if err := d.findOrderByNo(collection, ctx, tenantID, orderNo, &order); err == nil { return &order, status, nil @@ -95,21 +92,21 @@ func (d *OrderDao) GetOrderByNo(ctx context.Context, tenantID, orderNo string) ( } // findOrderByNo 通用订单查询方法 -func (d *OrderDao) findOrderByNo(collection *mongo.Collection, ctx context.Context, tenantID, orderNo string, result interface{}) error { +func (d *order) findOrderByNo(collection string, 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 { + err := mongo.FindOne(ctx, filter, result, collection) + if err != nil { return errors.New("order not found") } - return err + return nil } // MoveOrderToStatus 将订单从一个状态移动到另一个状态 -func (d *OrderDao) MoveOrderToStatus(ctx context.Context, fromStatus, toStatus entity.OrderStatus, tenantID, orderNo string, updateData bson.M) error { +func (d *order) MoveOrderToStatus(ctx context.Context, fromStatus, toStatus consts.OrderStatus, tenantID, orderNo string, updateData bson.M) error { // 获取源集合 srcCollection, err := d.getCollection(fromStatus) if err != nil { @@ -129,7 +126,7 @@ func (d *OrderDao) MoveOrderToStatus(ctx context.Context, fromStatus, toStatus e "order_no": orderNo, } - err = srcCollection.FindOne(ctx, filter).Decode(&orderData) + err = mongo.FindOne(ctx, filter, &orderData, srcCollection) if err != nil { return err } @@ -141,35 +138,36 @@ func (d *OrderDao) MoveOrderToStatus(ctx context.Context, fromStatus, toStatus e } // 插入到目标集合 - _, err = destCollection.InsertOne(ctx, orderData) + _, err = mongo.Insert(ctx, []interface{}{orderData}, destCollection) if err != nil { return err } // 从源集合删除 - _, err = srcCollection.DeleteOne(ctx, filter) + _, err = mongo.Delete(ctx, filter, srcCollection) return err } // UpdatePendingOrder 更新待支付订单 -func (d *OrderDao) UpdatePendingOrder(ctx context.Context, tenantID, orderNo string, update bson.M) error { - collection, err := d.getCollection(entity.OrderStatusPending) +func (d *order) UpdatePendingOrder(ctx context.Context, tenantID, orderNo string, update bson.M) error { + collection, err := d.getCollection(consts.OrderStatusPending) if err != nil { return err } update["updated_at"] = time.Now() - _, err = collection.UpdateOne(ctx, bson.M{ + filter := bson.M{ "tenant_id": tenantID, "order_no": orderNo, - }, bson.M{"$set": update}) + } + _, err = mongo.Update(ctx, filter, bson.M{"$set": update}, collection) return err } // ListOrdersByStatus 根据状态查询订单列表 -func (d *OrderDao) ListOrdersByStatus(ctx context.Context, status entity.OrderStatus, tenantID, userID string, page, pageSize int) (interface{}, int64, error) { +func (d *order) ListOrdersByStatus(ctx context.Context, status consts.OrderStatus, tenantID, userID string, page, pageSize int) (interface{}, int64, error) { collection, err := d.getCollection(status) if err != nil { return nil, 0, err @@ -182,47 +180,37 @@ func (d *OrderDao) ListOrdersByStatus(ctx context.Context, status entity.OrderSt } // 计算总数 - total, err := collection.CountDocuments(ctx, filter) + total, err := mongo.Count(ctx, filter, collection) 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) + // 分页查询(暂时忽略排序和分页,因为 mongo.Find 不支持这些参数) + // TODO: 需要在 common/mongo 中添加支持排序和分页的 Find 方法 // 根据状态返回对应的订单类型 switch status { - case entity.OrderStatusPending: + case consts.OrderStatusPending: var orders []entity.OrderPending - if err := cursor.All(ctx, &orders); err != nil { + if err := mongo.Find(ctx, filter, &orders, collection); err != nil { return nil, 0, err } return orders, total, nil - case entity.OrderStatusPaid: + case consts.OrderStatusPaid: var orders []entity.OrderPaid - if err := cursor.All(ctx, &orders); err != nil { + if err := mongo.Find(ctx, filter, &orders, collection); err != nil { return nil, 0, err } return orders, total, nil - case entity.OrderStatusShipped: + case consts.OrderStatusShipped: var orders []entity.OrderShipped - if err := cursor.All(ctx, &orders); err != nil { + if err := mongo.Find(ctx, filter, &orders, collection); err != nil { return nil, 0, err } return orders, total, nil - case entity.OrderStatusCompleted: + case consts.OrderStatusCompleted: var orders []entity.OrderCompleted - if err := cursor.All(ctx, &orders); err != nil { + if err := mongo.Find(ctx, filter, &orders, collection); err != nil { return nil, 0, err } return orders, total, nil @@ -232,8 +220,8 @@ func (d *OrderDao) ListOrdersByStatus(ctx context.Context, status entity.OrderSt } // GetExpiredPendingOrders 获取过期的待支付订单 -func (d *OrderDao) GetExpiredPendingOrders(ctx context.Context, tenantID string) ([]entity.OrderPending, error) { - collection, err := d.getCollection(entity.OrderStatusPending) +func (d *order) GetExpiredPendingOrders(ctx context.Context, tenantID string) ([]entity.OrderPending, error) { + collection, err := d.getCollection(consts.OrderStatusPending) if err != nil { return nil, err } @@ -243,14 +231,8 @@ func (d *OrderDao) GetExpiredPendingOrders(ctx context.Context, tenantID string) "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 { + if err := mongo.Find(ctx, filter, &orders, collection); err != nil { return nil, err } @@ -258,19 +240,21 @@ func (d *OrderDao) GetExpiredPendingOrders(ctx context.Context, tenantID string) } // UpdatePayInfo 更新支付信息(待支付订单) -func (d *OrderDao) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error { - collection, err := d.getCollection(entity.OrderStatusPending) +func (d *order) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error { + collection, err := d.getCollection(consts.OrderStatusPending) if err != nil { return err } - _, err = collection.UpdateOne(ctx, bson.M{ + filter := bson.M{ "tenant_id": tenantID, "order_no": orderNo, - }, bson.M{"$set": bson.M{ + } + update := bson.M{ "pay_info": payInfo, "updated_at": time.Now(), - }}) + } + _, err = mongo.Update(ctx, filter, bson.M{"$set": update}, collection) return err } diff --git a/dao/payment_dao.go b/dao/payment_dao.go index 97369e0..93dc789 100644 --- a/dao/payment_dao.go +++ b/dao/payment_dao.go @@ -2,228 +2,202 @@ 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" + "gitee.com/red-future---jilin-g/common/mongo" + "go.mongodb.org/mongo-driver/v2/bson" + "order/consts" "order/model/entity" ) -// PaymentConfigDao 支付配置数据访问对象 +type paymentConfig struct{} -type PaymentConfigDao struct { - collection *mongo.Collection -} - -// NewPaymentConfigDao 创建支付配置DAO实例 -func NewPaymentConfigDao(collection *mongo.Collection) *PaymentConfigDao { - return &PaymentConfigDao{ - collection: collection, - } -} +// PaymentConfig 支付配置数据访问对象 +var PaymentConfig = new(paymentConfig) // 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) +func (d *paymentConfig) Create(ctx context.Context, config *entity.PaymentConfig) error { + _, err := mongo.Insert(ctx, []interface{}{config}, consts.PaymentConfigCollection) 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") - } - +func (d *paymentConfig) GetByTenantAndMethod(ctx context.Context, tenantID, payMethod string) (*entity.PaymentConfig, error) { var config entity.PaymentConfig - err := d.collection.FindOne(ctx, bson.M{ + + filter := bson.M{ "tenant_id": tenantID, "pay_method": payMethod, "enabled": true, - }).Decode(&config) + } - if err == mongo.ErrNoDocuments { + err := mongo.FindOne(ctx, filter, &config, consts.PaymentConfigCollection) + if err != nil { return nil, nil } - return &config, err + return &config, nil } // Update 更新支付配置 -func (d *PaymentConfigDao) Update(ctx context.Context, id string, update bson.M) error { - if d.collection == nil { - return errors.New("collection not initialized") +func (d *paymentConfig) Update(ctx context.Context, config *entity.PaymentConfig) error { + filter := bson.M{"_id": config.ID} + update := bson.M{ + "$set": bson.M{ + "tenant_id": config.TenantID, + "pay_method": config.PayMethod, + "config_name": config.ConfigName, + "description": config.Description, + "enabled": config.Enabled, + "app_id": config.AppID, + "mch_id": config.MchID, + "api_key": config.APIKey, + "notify_url": config.NotifyURL, + "return_url": config.ReturnURL, + "cert_path": config.CertPath, + "key_path": config.KeyPath, + "app_private_key": config.AppPrivateKey, + "alipay_public_key": config.AlipayPublicKey, + "sandbox": config.Sandbox, + "gateway_url": config.GatewayURL, + "support_native": config.SupportNative, + "support_jsapi": config.SupportJSAPI, + "support_app": config.SupportAPP, + "support_h5": config.SupportH5, + }, } - objectID, err := primitive.ObjectIDFromHex(id) - if err != nil { - return err - } - - _, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update}) + _, err := mongo.Update(ctx, filter, update, consts.PaymentConfigCollection) 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") - } +// GetByID 根据ID获取配置 +func (d *paymentConfig) GetByID(ctx context.Context, id bson.ObjectID) (*entity.PaymentConfig, error) { + var config entity.PaymentConfig - filter := bson.M{"tenant_id": tenantID} - cursor, err := d.collection.Find(ctx, filter) + filter := bson.M{"_id": id} + err := mongo.FindOne(ctx, filter, &config, consts.PaymentConfigCollection) if err != nil { return nil, err } - defer cursor.Close(ctx) + return &config, nil +} + +// GetByTenantID 根据租户ID获取配置列表 +func (d *paymentConfig) GetByTenantID(ctx context.Context, tenantID string) ([]entity.PaymentConfig, error) { var configs []entity.PaymentConfig - if err := cursor.All(ctx, &configs); err != nil { + + filter := bson.M{"tenant_id": tenantID} + err := mongo.Find(ctx, filter, &configs, consts.PaymentConfigCollection) + if err != nil { return nil, err } return configs, nil } -// PaymentRecordDao 支付记录数据访问对象 +// Delete 删除支付配置 +func (d *paymentConfig) Delete(ctx context.Context, id bson.ObjectID) error { + filter := bson.M{"_id": id} -type PaymentRecordDao struct { - collection *mongo.Collection + _, err := mongo.Delete(ctx, filter, consts.PaymentConfigCollection) + return err +} +func (d *paymentConfig) ListByTenant(ctx context.Context, tenantID string) ([]entity.PaymentConfig, error) { + var configs []entity.PaymentConfig + + filter := bson.M{"tenant_id": tenantID} + + err := mongo.Find(ctx, filter, &configs, consts.PaymentConfigCollection) + return configs, err } -// NewPaymentRecordDao 创建支付记录DAO实例 -func NewPaymentRecordDao(collection *mongo.Collection) *PaymentRecordDao { - return &PaymentRecordDao{ - collection: collection, - } -} +type paymentRecord struct{} + +// PaymentRecord 支付记录数据访问对象 +var PaymentRecord = new(paymentRecord) // 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() +func (d *paymentRecord) Create(ctx context.Context, record *entity.PaymentRecord) error { record.CreatedAt = time.Now().Unix() record.UpdatedAt = time.Now().Unix() - _, err := d.collection.InsertOne(ctx, record) + _, err := mongo.Insert(ctx, []interface{}{record}, consts.PaymentRecordCollection) 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") - } - +func (d *paymentRecord) GetByOrderNo(ctx context.Context, tenantID, orderNo string) (*entity.PaymentRecord, error) { var record entity.PaymentRecord - err := d.collection.FindOne(ctx, bson.M{ + + filter := bson.M{ "tenant_id": tenantID, "order_no": orderNo, - }).Decode(&record) + } - if err == mongo.ErrNoDocuments { + err := mongo.FindOne(ctx, filter, &record, consts.PaymentRecordCollection) + if err != nil { return nil, nil } - return &record, err + return &record, nil } // 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 - } - +func (d *paymentRecord) UpdateStatus(ctx context.Context, id string, status, transactionID, tradeNo string) error { + filter := bson.M{"_id": id} update := bson.M{ "status": status, "transaction_id": transactionID, "trade_no": tradeNo, - "updated_at": time.Now().Unix(), + "updated_at": time.Now(), } - _, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update}) + _, err := mongo.Update(ctx, filter, bson.M{"$set": update}, consts.PaymentRecordCollection) return err } -// RefundRecordDao 退款记录数据访问对象 +type refundRecord struct{} -type RefundRecordDao struct { - collection *mongo.Collection -} - -// NewRefundRecordDao 创建退款记录DAO实例 -func NewRefundRecordDao(collection *mongo.Collection) *RefundRecordDao { - return &RefundRecordDao{ - collection: collection, - } -} +// RefundRecord 退款记录数据访问对象 +var RefundRecord = new(refundRecord) // 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() +func (d *refundRecord) Create(ctx context.Context, record *entity.RefundRecord) error { record.CreatedAt = time.Now().Unix() record.UpdatedAt = time.Now().Unix() - _, err := d.collection.InsertOne(ctx, record) + _, err := mongo.Insert(ctx, []interface{}{record}, consts.RefundRecordCollection) 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") - } - +func (d *refundRecord) GetByRefundNo(ctx context.Context, tenantID, refundNo string) (*entity.RefundRecord, error) { var record entity.RefundRecord - err := d.collection.FindOne(ctx, bson.M{ + + filter := bson.M{ "tenant_id": tenantID, "refund_no": refundNo, - }).Decode(&record) + } - if err == mongo.ErrNoDocuments { + err := mongo.FindOne(ctx, filter, &record, consts.RefundRecordCollection) + if err != nil { return nil, nil } - return &record, err + return &record, nil } // 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 - } - +func (d *refundRecord) UpdateRefundStatus(ctx context.Context, id, status, refundID string) error { + filter := bson.M{"_id": id} update := bson.M{ "status": status, "refund_id": refundID, - "updated_at": time.Now().Unix(), + "updated_at": time.Now(), } - _, err = d.collection.UpdateOne(ctx, bson.M{"_id": objectID}, bson.M{"$set": update}) + _, err := mongo.Update(ctx, filter, bson.M{"$set": update}, consts.RefundRecordCollection) return err } diff --git a/go.mod b/go.mod index 8edbcf2..bfef1d1 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,6 @@ require ( github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.6 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 ( @@ -56,7 +55,6 @@ 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 @@ -68,6 +66,7 @@ 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.1 // 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 diff --git a/go.sum b/go.sum index 95ad987..8bd4caa 100644 --- a/go.sum +++ b/go.sum @@ -207,8 +207,6 @@ 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= @@ -277,8 +275,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec 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.mongodb.org/mongo-driver/v2 v2.4.1 h1:hGDMngUao03OVQ6sgV5csk+RWOIkF+CuLsTPobNMGNI= +go.mongodb.org/mongo-driver/v2 v2.4.1/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= diff --git a/init.go b/init.go index d516a26..a3b12d5 100644 --- a/init.go +++ b/init.go @@ -1,13 +1,14 @@ package main import ( + "context" "github.com/gogf/gf/v2/frame/g" - "order/service" ) // initServices 初始化服务 func initServices() error { - return service.InitServices() + // 服务自动初始化,无需手动调用 + return nil } // initRoutes 初始化路由 @@ -28,5 +29,5 @@ func initRoutes() { paymentGroup.POST("/notify", "order.controller.Order.PaymentNotify") paymentGroup.POST("/refund-notify", "order.controller.Order.RefundNotify") - g.Log().Info(g.Request().GetCtx(), "路由初始化完成") + g.Log().Info(context.Background(), "路由初始化完成") } diff --git a/main.go b/main.go index 81ab997..e28da02 100644 --- a/main.go +++ b/main.go @@ -8,26 +8,13 @@ import ( _ "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" - "github.com/gogf/gf/v2/frame/g" "order/controller" ) func main() { defer jaeger.ShutDown(context.Background()) - - // 初始化服务 - if err := initServices(); err != nil { - g.Log().Fatal(context.Background(), "初始化服务失败:", err) - } - - // 初始化路由 - initRoutes() - - // 注册路由 http.RouteRegister([]interface{}{ - controller.OrderController, + controller.Order, }) - - // 启动服务 - g.Server().Run() + select {} } diff --git a/model/dto/order.go b/model/dto/order.go index 307d5e3..cdb9943 100644 --- a/model/dto/order.go +++ b/model/dto/order.go @@ -204,3 +204,120 @@ type OrderSummary struct { CreatedAt time.Time `json:"created_at"` // 创建时间 PaidAt *time.Time `json:"paid_at"` // 支付时间 } + +// 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"` // 签名 +} + +// PaymentNotifyResp 支付回调响应 + +type PaymentNotifyResp struct { + Success bool `json:"success"` // 是否成功 +} + +// 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"` // 签名 +} + +// RefundNotifyResp 退款回调响应 + +type RefundNotifyResp struct { + Success bool `json:"success"` // 是否成功 +} + +// CreatePaymentConfigReq 创建支付配置请求 + +type CreatePaymentConfigReq struct { + TenantID string `json:"tenant_id" binding:"required"` // 租户ID + PayMethod string `json:"pay_method" binding:"required"` // 支付方式:wechat/alipay + ConfigName string `json:"config_name" binding:"required"` // 配置名称 + Remark string `json:"remark"` // 备注 + IsEnabled bool `json:"is_enabled"` // 是否启用 + Config map[string]interface{} `json:"config" binding:"required"` // 配置参数 +} + +// UpdatePaymentConfigReq 更新支付配置请求 + +type UpdatePaymentConfigReq struct { + ID string `json:"id" binding:"required"` // 配置ID + TenantID string `json:"tenant_id" binding:"required"` // 租户ID + ConfigName string `json:"config_name" binding:"required"` // 配置名称 + Remark string `json:"remark"` // 备注 + IsEnabled bool `json:"is_enabled"` // 是否启用 + Config map[string]interface{} `json:"config" binding:"required"` // 配置参数 +} + +// QueryPaymentConfigReq 查询支付配置请求 + +type QueryPaymentConfigReq struct { + TenantID string `json:"tenant_id" binding:"required"` // 租户ID + PayMethod string `json:"pay_method"` // 支付方式(可选) +} + +// PaymentConfigResp 支付配置响应 + +type PaymentConfigResp struct { + ID string `json:"id"` // 配置ID + TenantID string `json:"tenant_id"` // 租户ID + PayMethod string `json:"pay_method"` // 支付方式 + ConfigName string `json:"config_name"` // 配置名称 + Remark string `json:"remark"` // 备注 + IsEnabled bool `json:"is_enabled"` // 是否启用 + Config map[string]interface{} `json:"config"` // 配置参数 + CreatedAt time.Time `json:"created_at"` // 创建时间 + UpdatedAt time.Time `json:"updated_at"` // 更新时间 +} + +// WechatConfig 微信支付配置 + +type WechatConfig struct { + ID string `json:"id"` // 配置ID + TenantID string `json:"tenant_id"` // 租户ID + ConfigName string `json:"config_name"` // 配置名称 + AppID string `json:"app_id"` // 应用ID + MchID string `json:"mch_id"` // 商户号 + APIKey string `json:"api_key"` // API密钥 + NotifyURL string `json:"notify_url"` // 回调地址 + ReturnURL string `json:"return_url"` // 返回地址 + CertPath string `json:"cert_path"` // 证书路径 + KeyPath string `json:"key_path"` // 密钥路径 + Sandbox bool `json:"sandbox"` // 是否沙箱环境 + SupportNative bool `json:"support_native"` // 支持扫码支付 + SupportJSAPI bool `json:"support_jsapi"` // 支持JSAPI支付 + SupportAPP bool `json:"support_app"` // 支持APP支付 + SupportH5 bool `json:"support_h5"` // 支持H5支付 + GatewayURL string `json:"gateway_url"` // 网关地址 +} + +// AlipayConfig 支付宝支付配置 + +type AlipayConfig struct { + ID string `json:"id"` // 配置ID + TenantID string `json:"tenant_id"` // 租户ID + ConfigName string `json:"config_name"` // 配置名称 + AppID string `json:"app_id"` // 应用ID + NotifyURL string `json:"notify_url"` // 回调地址 + ReturnURL string `json:"return_url"` // 返回地址 + AppPrivateKey string `json:"app_private_key"` // 应用私钥 + AlipayPublicKey string `json:"alipay_public_key"` // 支付宝公钥 + Sandbox bool `json:"sandbox"` // 是否沙箱环境 + GatewayURL string `json:"gateway_url"` // 网关地址 + SupportNative bool `json:"support_native"` // 支持扫码支付 + SupportJSAPI bool `json:"support_jsapi"` // 支持JSAPI支付 + SupportAPP bool `json:"support_app"` // 支持APP支付 + SupportH5 bool `json:"support_h5"` // 支持H5支付 +} diff --git a/model/entity/order_base.go b/model/entity/order_base.go index a372961..0e2305b 100644 --- a/model/entity/order_base.go +++ b/model/entity/order_base.go @@ -1,7 +1,7 @@ package entity import ( - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" "time" ) @@ -12,18 +12,18 @@ import ( // 例如: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"` // 过期时间 + ID bson.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 订单商品项 diff --git a/model/entity/order_pending.go b/model/entity/order_pending.go index 9d61fc6..866739e 100644 --- a/model/entity/order_pending.go +++ b/model/entity/order_pending.go @@ -1,9 +1,5 @@ package entity -import ( - "time" -) - // OrderPending 待支付订单 // 对应MongoDB集合:orders_pending // 订单创建后进入此状态 diff --git a/model/entity/payment_config.go b/model/entity/payment_config.go index 803d391..65025af 100644 --- a/model/entity/payment_config.go +++ b/model/entity/payment_config.go @@ -1,7 +1,7 @@ package entity import ( - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) // PaymentConfig 支付配置 @@ -9,12 +9,12 @@ import ( // 支持微信支付和支付宝支付 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"` // 是否启用 + ID bson.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 @@ -46,37 +46,37 @@ type PaymentConfig struct { // 记录每次支付操作的结果 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"` // 更新时间 + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID + OrderID bson.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"` // 更新时间 + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + TenantID string `bson:"tenant_id" json:"tenant_id"` // 租户ID + OrderID bson.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"` // 更新时间 } diff --git a/order b/order new file mode 100755 index 0000000..cb671d5 Binary files /dev/null and b/order differ diff --git a/service/order.go b/service/order.go index 7b4053e..b8e7649 100644 --- a/service/order.go +++ b/service/order.go @@ -5,31 +5,70 @@ import ( "errors" "fmt" "math/rand" - "strconv" "time" - "github.com/gogf/gf/v2/util/gconv" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" + "order/consts" "order/dao" "order/model/dto" "order/model/entity" ) -// OrderService 订单服务 +type order struct{} -type OrderService struct { - orderDao *dao.OrderDao +// Order 订单服务 +var Order = new(order) + +// convertOrderItemsFromDTO 从DTO转换订单商品项 +func convertOrderItemsFromDTO(items []dto.OrderItemReq) []entity.OrderItem { + var result []entity.OrderItem + for _, item := range items { + result = append(result, entity.OrderItem{ + ProductID: item.ProductID, + ProductName: item.ProductName, + Price: item.Price, + Quantity: item.Quantity, + TotalPrice: item.Price * int64(item.Quantity), + ImageURL: item.ImageURL, + }) + } + return result } -// NewOrderService 创建订单服务实例 -func NewOrderService(orderDao *dao.OrderDao) *OrderService { - return &OrderService{ - orderDao: orderDao, +// convertOrderItems 转换订单商品项 +func 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 +} + +// convertEntityOrderItemsToDTO 转换entity订单商品项到DTO +func convertEntityOrderItemsToDTO(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 } // CreateOrder 创建订单 -func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) (*dto.CreateOrderResp, error) { +func (s *order) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) (*dto.CreateOrderResp, error) { // 1. 参数验证 if req.TenantID == "" || req.UserID == "" || req.Subject == "" { return nil, errors.New("必填参数不能为空") @@ -46,8 +85,8 @@ func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) if item.Price <= 0 || item.Quantity <= 0 { return nil, fmt.Errorf("商品价格或数量无效: %s", item.ProductName) } - item.TotalPrice = item.Price * int64(item.Quantity) - totalAmount += item.TotalPrice + totalPrice := item.Price * int64(item.Quantity) + totalAmount += totalPrice } if totalAmount <= 0 { @@ -73,13 +112,13 @@ func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) Description: req.Description, ExpiredAt: &expiredAt, }, - OrderItems: gconv.Slice[*entity.OrderItem](req.OrderItems), + OrderItems: convertOrderItemsFromDTO(req.OrderItems), ShippingInfo: (*entity.ShippingInfo)(&req.ShippingInfo), PayInfo: entity.PayInfo{}, } // 6. 保存订单 - if err := s.orderDao.CreatePendingOrder(ctx, order); err != nil { + if err := dao.Order.CreatePendingOrder(ctx, order); err != nil { return nil, fmt.Errorf("创建订单失败: %w", err) } @@ -95,21 +134,21 @@ func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderReq) } // generateOrderNo 生成订单号 -func (s *OrderService) generateOrderNo(tenantID string) string { +func (s *order) 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) { +func (s *order) 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) + order, status, err := dao.Order.GetOrderByNo(ctx, req.TenantID, req.OrderNo) if err != nil { return nil, fmt.Errorf("获取订单失败: %w", err) } @@ -122,19 +161,19 @@ func (s *OrderService) QueryOrder(ctx context.Context, req *dto.QueryOrderReq) ( var resp dto.QueryOrderResp switch status { - case entity.OrderStatusPending: + case consts.OrderStatusPending: if pendingOrder, ok := order.(*entity.OrderPending); ok { resp.Order = s.convertPendingOrderToDetail(pendingOrder) } - case entity.OrderStatusPaid: + case consts.OrderStatusPaid: if paidOrder, ok := order.(*entity.OrderPaid); ok { resp.Order = s.convertPaidOrderToDetail(paidOrder) } - case entity.OrderStatusShipped: + case consts.OrderStatusShipped: if shippedOrder, ok := order.(*entity.OrderShipped); ok { resp.Order = s.convertShippedOrderToDetail(shippedOrder) } - case entity.OrderStatusCompleted: + case consts.OrderStatusCompleted: if completedOrder, ok := order.(*entity.OrderCompleted); ok { resp.Order = s.convertCompletedOrderToDetail(completedOrder) } @@ -146,7 +185,7 @@ func (s *OrderService) QueryOrder(ctx context.Context, req *dto.QueryOrderReq) ( } // convertPendingOrderToDetail 转换待支付订单为详情 -func (s *OrderService) convertPendingOrderToDetail(order *entity.OrderPending) dto.OrderDetail { +func (s *order) convertPendingOrderToDetail(order *entity.OrderPending) dto.OrderDetail { return dto.OrderDetail{ ID: order.ID.Hex(), TenantID: order.TenantID, @@ -154,13 +193,13 @@ func (s *OrderService) convertPendingOrderToDetail(order *entity.OrderPending) d UserID: order.UserID, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusPending), + Status: string(consts.OrderStatusPending), PayMethod: order.PayMethod, PayStatus: "unpaid", OrderType: order.OrderType, Subject: order.Subject, Description: order.Description, - OrderItems: s.convertOrderItems(order.OrderItems), + OrderItems: convertOrderItems(order.OrderItems), ShippingInfo: dto.ShippingInfo{ Consignee: order.ShippingInfo.Consignee, Phone: order.ShippingInfo.Phone, @@ -183,7 +222,7 @@ func (s *OrderService) convertPendingOrderToDetail(order *entity.OrderPending) d } // convertPaidOrderToDetail 转换已支付订单为详情 -func (s *OrderService) convertPaidOrderToDetail(order *entity.OrderPaid) dto.OrderDetail { +func (s *order) convertPaidOrderToDetail(order *entity.OrderPaid) dto.OrderDetail { return dto.OrderDetail{ ID: order.ID.Hex(), TenantID: order.TenantID, @@ -191,13 +230,13 @@ func (s *OrderService) convertPaidOrderToDetail(order *entity.OrderPaid) dto.Ord UserID: order.UserID, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusPaid), + Status: string(consts.OrderStatusPaid), PayMethod: order.PayMethod, PayStatus: "paid", OrderType: order.OrderType, Subject: order.Subject, Description: order.Description, - OrderItems: s.convertOrderItems(order.OrderItems), + OrderItems: convertOrderItems(order.OrderItems), ShippingInfo: dto.ShippingInfo{ Consignee: order.ShippingInfo.Consignee, Phone: order.ShippingInfo.Phone, @@ -218,7 +257,7 @@ func (s *OrderService) convertPaidOrderToDetail(order *entity.OrderPaid) dto.Ord } // convertShippedOrderToDetail 转换已发货订单为详情 -func (s *OrderService) convertShippedOrderToDetail(order *entity.OrderShipped) dto.OrderDetail { +func (s *order) convertShippedOrderToDetail(order *entity.OrderShipped) dto.OrderDetail { return dto.OrderDetail{ ID: order.ID.Hex(), TenantID: order.TenantID, @@ -226,13 +265,13 @@ func (s *OrderService) convertShippedOrderToDetail(order *entity.OrderShipped) d UserID: order.UserID, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusShipped), + Status: string(consts.OrderStatusShipped), PayMethod: order.PayMethod, PayStatus: "paid", OrderType: order.OrderType, Subject: order.Subject, Description: order.Description, - OrderItems: s.convertOrderItems(order.OrderItems), + OrderItems: convertOrderItems(order.OrderItems), ShippingInfo: dto.ShippingInfo{ Consignee: order.ShippingInfo.Consignee, Phone: order.ShippingInfo.Phone, @@ -249,7 +288,7 @@ func (s *OrderService) convertShippedOrderToDetail(order *entity.OrderShipped) d } // convertCompletedOrderToDetail 转换已完成订单为详情 -func (s *OrderService) convertCompletedOrderToDetail(order *entity.OrderCompleted) dto.OrderDetail { +func (s *order) convertCompletedOrderToDetail(order *entity.OrderCompleted) dto.OrderDetail { return dto.OrderDetail{ ID: order.ID.Hex(), TenantID: order.TenantID, @@ -257,13 +296,13 @@ func (s *OrderService) convertCompletedOrderToDetail(order *entity.OrderComplete UserID: order.UserID, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusCompleted), + Status: string(consts.OrderStatusCompleted), PayMethod: order.PayMethod, PayStatus: "paid", OrderType: order.OrderType, Subject: order.Subject, Description: order.Description, - OrderItems: s.convertOrderItems(order.OrderItems), + OrderItems: convertOrderItems(order.OrderItems), ShippingInfo: dto.ShippingInfo{ Consignee: order.ShippingInfo.Consignee, Phone: order.ShippingInfo.Phone, @@ -280,7 +319,7 @@ func (s *OrderService) convertCompletedOrderToDetail(order *entity.OrderComplete } // convertOrderItems 转换订单商品项 -func (s *OrderService) convertOrderItems(items []*entity.OrderItem) []dto.OrderItem { +func (s *order) convertOrderItems(items []*entity.OrderItem) []dto.OrderItem { var result []dto.OrderItem for _, item := range items { result = append(result, dto.OrderItem{ @@ -296,14 +335,14 @@ func (s *OrderService) convertOrderItems(items []*entity.OrderItem) []dto.OrderI } // CancelOrder 取消订单 -func (s *OrderService) CancelOrder(ctx context.Context, req *dto.CancelOrderReq) (*dto.CancelOrderResp, error) { +func (s *order) 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) + order, status, err := dao.Order.GetOrderByNo(ctx, req.TenantID, req.OrderNo) if err != nil { return nil, fmt.Errorf("获取订单失败: %w", err) } @@ -313,7 +352,7 @@ func (s *OrderService) CancelOrder(ctx context.Context, req *dto.CancelOrderReq) } // 3. 检查订单状态(只有待支付订单可以取消) - if status != entity.OrderStatusPending { + if status != consts.OrderStatusPending { return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status) } @@ -322,21 +361,21 @@ func (s *OrderService) CancelOrder(ctx context.Context, req *dto.CancelOrderReq) "cancel_reason": req.Reason, } - if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusCancelled, req.TenantID, req.OrderNo, updateData); err != nil { + if err := dao.Order.MoveOrderToStatus(ctx, consts.OrderStatusPending, consts.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), + Status: string(consts.OrderStatusCancelled), } return resp, nil } // ListOrders 查询订单列表 -func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) (*dto.ListOrdersResp, error) { +func (s *order) ListOrders(ctx context.Context, req *dto.ListOrdersReq) (*dto.ListOrdersResp, error) { // 1. 参数验证 if req.TenantID == "" { return nil, errors.New("租户ID不能为空") @@ -350,15 +389,15 @@ func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) ( } // 2. 根据状态查询订单列表 - var status entity.OrderStatus + var status consts.OrderStatus if req.Status != "" { - status = entity.OrderStatus(req.Status) + status = consts.OrderStatus(req.Status) } else { // 默认查询所有状态 - status = entity.OrderStatusPending + status = consts.OrderStatusPending } - orders, total, err := s.orderDao.ListOrdersByStatus(ctx, status, req.TenantID, req.UserID, req.Page, req.PageSize) + orders, total, err := dao.Order.ListOrdersByStatus(ctx, status, req.TenantID, req.UserID, req.Page, req.PageSize) if err != nil { return nil, fmt.Errorf("查询订单列表失败: %w", err) } @@ -367,7 +406,7 @@ func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) ( var orderSummaries []dto.OrderSummary switch status { - case entity.OrderStatusPending: + case consts.OrderStatusPending: if pendingOrders, ok := orders.([]entity.OrderPending); ok { for _, order := range pendingOrders { orderSummaries = append(orderSummaries, dto.OrderSummary{ @@ -375,13 +414,13 @@ func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) ( OrderNo: order.OrderNo, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusPending), + Status: string(consts.OrderStatusPending), Subject: order.Subject, CreatedAt: order.CreatedAt, }) } } - case entity.OrderStatusPaid: + case consts.OrderStatusPaid: if paidOrders, ok := orders.([]entity.OrderPaid); ok { for _, order := range paidOrders { orderSummaries = append(orderSummaries, dto.OrderSummary{ @@ -389,7 +428,7 @@ func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) ( OrderNo: order.OrderNo, TotalAmount: order.TotalAmount, PayAmount: order.PayAmount, - Status: string(entity.OrderStatusPaid), + Status: string(consts.OrderStatusPaid), Subject: order.Subject, CreatedAt: order.CreatedAt, PaidAt: &order.PaidAt, @@ -411,9 +450,9 @@ func (s *OrderService) ListOrders(ctx context.Context, req *dto.ListOrdersReq) ( } // ProcessExpiredOrders 处理过期订单 -func (s *OrderService) ProcessExpiredOrders(ctx context.Context, tenantID string) error { +func (s *order) ProcessExpiredOrders(ctx context.Context, tenantID string) error { // 获取过期的待支付订单 - expiredOrders, err := s.orderDao.GetExpiredPendingOrders(ctx, tenantID) + expiredOrders, err := dao.Order.GetExpiredPendingOrders(ctx, tenantID) if err != nil { return fmt.Errorf("获取过期订单失败: %w", err) } @@ -424,7 +463,7 @@ func (s *OrderService) ProcessExpiredOrders(ctx context.Context, tenantID string "cancel_reason": "订单超时自动取消", } - if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusCancelled, tenantID, order.OrderNo, updateData); err != nil { + if err := dao.Order.MoveOrderToStatus(ctx, consts.OrderStatusPending, consts.OrderStatusCancelled, tenantID, order.OrderNo, updateData); err != nil { // 记录错误但继续处理其他订单 fmt.Printf("取消过期订单失败: %s, 错误: %v\n", order.OrderNo, err) } @@ -434,6 +473,6 @@ func (s *OrderService) ProcessExpiredOrders(ctx context.Context, tenantID string } // UpdatePayInfo 更新支付信息 -func (s *OrderService) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error { - return s.orderDao.UpdatePayInfo(ctx, tenantID, orderNo, payInfo) +func (s *order) UpdatePayInfo(ctx context.Context, tenantID, orderNo string, payInfo entity.PayInfo) error { + return dao.Order.UpdatePayInfo(ctx, tenantID, orderNo, payInfo) } diff --git a/service/payment.go b/service/payment.go index 303f81b..4c28137 100644 --- a/service/payment.go +++ b/service/payment.go @@ -7,45 +7,27 @@ import ( "math/rand" "time" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" + "order/consts" "order/dao" "order/model/dto" "order/model/entity" ) -// PaymentService 支付服务 +type payment struct{} -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, - } -} +// Payment 支付服务 +var Payment = new(payment) // PayOrder 支付订单 -func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*dto.PayOrderResp, error) { +func (s *payment) 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) + order, status, err := dao.Order.GetOrderByNo(ctx, req.TenantID, req.OrderNo) if err != nil { return nil, fmt.Errorf("获取订单失败: %w", err) } @@ -55,7 +37,7 @@ func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*d } // 3. 验证订单状态(只有待支付订单可以支付) - if status != entity.OrderStatusPending { + if status != consts.OrderStatusPending { return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status) } @@ -65,7 +47,7 @@ func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*d } // 4. 获取支付配置 - paymentConfig, err := s.paymentConfigDao.GetByTenantAndMethod(ctx, req.TenantID, req.PayMethod) + paymentConfig, err := dao.PaymentConfig.GetByTenantAndMethod(ctx, req.TenantID, req.PayMethod) if err != nil { return nil, fmt.Errorf("获取支付配置失败: %w", err) } @@ -92,7 +74,7 @@ func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*d Status: "pending", } - if err := s.paymentRecordDao.Create(ctx, paymentRecord); err != nil { + if err := dao.PaymentRecord.Create(ctx, paymentRecord); err != nil { return nil, fmt.Errorf("创建支付记录失败: %w", err) } @@ -106,7 +88,7 @@ func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*d APPParams: payResp.APPParams, } - if err := s.orderDao.UpdatePayInfo(ctx, req.TenantID, req.OrderNo, payInfo); err != nil { + if err := dao.Order.UpdatePayInfo(ctx, req.TenantID, req.OrderNo, payInfo); err != nil { return nil, fmt.Errorf("更新订单支付信息失败: %w", err) } @@ -124,7 +106,7 @@ func (s *PaymentService) PayOrder(ctx context.Context, req *dto.PayOrderReq) (*d } // callThirdPartyPayment 调用第三方支付接口 -func (s *PaymentService) callThirdPartyPayment(ctx context.Context, config *entity.PaymentConfig, req *dto.PayOrderReq, order *entity.OrderPending) (*PaymentResponse, error) { +func (s *payment) callThirdPartyPayment(ctx context.Context, config *entity.PaymentConfig, req *dto.PayOrderReq, order *entity.OrderPending) (*PaymentResponse, error) { // 这里应该是实际的第三方支付接口调用 // 为了演示,我们返回模拟数据 @@ -168,14 +150,14 @@ type PaymentResponse struct { } // generateOutTradeNo 生成商户订单号 -func (s *PaymentService) generateOutTradeNo(tenantID string) string { +func (s *payment) 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 { +func (s *payment) generateNonceStr() string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, 16) for i := range b { @@ -185,14 +167,14 @@ func (s *PaymentService) generateNonceStr() string { } // HandlePaymentNotify 处理支付回调 -func (s *PaymentService) HandlePaymentNotify(ctx context.Context, req *PaymentNotifyReq) error { +func (s *payment) HandlePaymentNotify(ctx context.Context, req *dto.PaymentNotifyReq) error { // 1. 验证回调签名 if !s.verifyNotifySignature(req) { return errors.New("签名验证失败") } // 2. 查询支付记录 - paymentRecord, err := s.paymentRecordDao.GetByOrderNo(ctx, req.TenantID, req.OrderNo) + paymentRecord, err := dao.PaymentRecord.GetByOrderNo(ctx, req.TenantID, req.OrderNo) if err != nil { return fmt.Errorf("查询支付记录失败: %w", err) } @@ -202,7 +184,7 @@ func (s *PaymentService) HandlePaymentNotify(ctx context.Context, req *PaymentNo } // 3. 更新支付记录状态 - if err := s.paymentRecordDao.UpdateStatus(ctx, paymentRecord.ID.Hex(), req.Status, req.TransactionID, req.TradeNo); err != nil { + if err := dao.PaymentRecord.UpdateStatus(ctx, paymentRecord.ID.Hex(), req.Status, req.TransactionID, req.TradeNo); err != nil { return fmt.Errorf("更新支付记录失败: %w", err) } @@ -215,7 +197,7 @@ func (s *PaymentService) HandlePaymentNotify(ctx context.Context, req *PaymentNo "payment_channel": req.PayMethod, } - if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPending, entity.OrderStatusPaid, req.TenantID, req.OrderNo, updateData); err != nil { + if err := dao.Order.MoveOrderToStatus(ctx, consts.OrderStatusPending, consts.OrderStatusPaid, req.TenantID, req.OrderNo, updateData); err != nil { return fmt.Errorf("更新订单状态失败: %w", err) } } @@ -223,34 +205,22 @@ func (s *PaymentService) HandlePaymentNotify(ctx context.Context, req *PaymentNo 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 { +func (s *payment) verifyNotifySignature(req *dto.PaymentNotifyReq) bool { // 这里应该是实际的签名验证逻辑 // 为了演示,我们总是返回true return true } // RefundOrder 退款 -func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderReq) (*dto.RefundOrderResp, error) { +func (s *payment) 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) + order, status, err := dao.Order.GetOrderByNo(ctx, req.TenantID, req.OrderNo) if err != nil { return nil, fmt.Errorf("获取订单失败: %w", err) } @@ -260,7 +230,7 @@ func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderRe } // 3. 验证订单状态(只有已支付订单可以退款) - if status != entity.OrderStatusPaid { + if status != consts.OrderStatusPaid { return nil, fmt.Errorf("订单状态不正确,当前状态: %s", status) } @@ -291,7 +261,7 @@ func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderRe Status: "pending", } - if err := s.refundRecordDao.Create(ctx, refundRecord); err != nil { + if err := dao.RefundRecord.Create(ctx, refundRecord); err != nil { return nil, fmt.Errorf("创建退款记录失败: %w", err) } @@ -301,7 +271,7 @@ func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderRe "refund_reason": req.Reason, } - if err := s.orderDao.MoveOrderToStatus(ctx, entity.OrderStatusPaid, entity.OrderStatusRefunded, req.TenantID, req.OrderNo, updateData); err != nil { + if err := dao.Order.MoveOrderToStatus(ctx, consts.OrderStatusPaid, consts.OrderStatusRefunded, req.TenantID, req.OrderNo, updateData); err != nil { return nil, fmt.Errorf("更新订单状态失败: %w", err) } } @@ -317,7 +287,7 @@ func (s *PaymentService) RefundOrder(ctx context.Context, req *dto.RefundOrderRe } // callThirdPartyRefund 调用第三方退款接口 -func (s *PaymentService) callThirdPartyRefund(ctx context.Context, req *dto.RefundOrderReq, order *entity.OrderPaid) (*RefundResponse, error) { +func (s *payment) callThirdPartyRefund(ctx context.Context, req *dto.RefundOrderReq, order *entity.OrderPaid) (*RefundResponse, error) { // 这里应该是实际的第三方退款接口调用 // 为了演示,我们返回模拟数据 @@ -338,21 +308,21 @@ type RefundResponse struct { } // generateRefundNo 生成退款单号 -func (s *PaymentService) generateRefundNo(tenantID string) string { +func (s *payment) 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 { +func (s *payment) HandleRefundNotify(ctx context.Context, req *dto.RefundNotifyReq) error { // 1. 验证回调签名 if !s.verifyRefundNotifySignature(req) { return errors.New("签名验证失败") } // 2. 查询退款记录 - refundRecord, err := s.refundRecordDao.GetByRefundNo(ctx, req.TenantID, req.RefundNo) + refundRecord, err := dao.RefundRecord.GetByRefundNo(ctx, req.TenantID, req.RefundNo) if err != nil { return fmt.Errorf("查询退款记录失败: %w", err) } @@ -362,25 +332,15 @@ func (s *PaymentService) HandleRefundNotify(ctx context.Context, req *RefundNoti } // 3. 更新退款记录状态 - if err := s.refundRecordDao.UpdateRefundStatus(ctx, refundRecord.ID.Hex(), req.Status, req.RefundID); err != nil { + if err := dao.RefundRecord.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 { +func (s *payment) verifyRefundNotifySignature(req *dto.RefundNotifyReq) bool { // 这里应该是实际的签名验证逻辑 // 为了演示,我们总是返回true return true diff --git a/service/payment_config.go b/service/payment_config.go new file mode 100644 index 0000000..27344e1 --- /dev/null +++ b/service/payment_config.go @@ -0,0 +1,436 @@ +package service + +import ( + "context" + "errors" + "time" + + "go.mongodb.org/mongo-driver/v2/bson" + "order/dao" + "order/model/dto" + "order/model/entity" +) + +type paymentConfig struct{} + +// PaymentConfig 支付配置服务 +var PaymentConfig = new(paymentConfig) + +// CreatePaymentConfig 创建支付配置 +func (s *paymentConfig) CreatePaymentConfig(ctx context.Context, req *dto.CreatePaymentConfigReq) (*dto.PaymentConfigResp, error) { + // 1. 参数验证 + if req.TenantID == "" || req.PayMethod == "" { + return nil, errors.New("必填参数不能为空") + } + + // 2. 检查支付方式是否已存在 + exist, err := dao.PaymentConfig.GetByTenantAndMethod(ctx, req.TenantID, req.PayMethod) + if err != nil { + return nil, err + } + if exist != nil { + return nil, errors.New("该支付方式已存在配置") + } + + // 3. 创建配置实体 + config := parseConfigMap(req.PayMethod, req.Config) + config.TenantID = req.TenantID + config.Description = req.Remark + config.Enabled = req.IsEnabled + + // 4. 保存配置 + if err := dao.PaymentConfig.Create(ctx, config); err != nil { + return nil, err + } + + // 5. 返回结果 + resp := &dto.PaymentConfigResp{ + ID: config.ID.Hex(), + TenantID: config.TenantID, + PayMethod: config.PayMethod, + Config: buildConfigMap(config), + IsEnabled: config.Enabled, + Remark: config.Description, + CreatedAt: time.Now(), // 暂时使用当前时间 + UpdatedAt: time.Now(), + } + + return resp, nil +} + +// UpdatePaymentConfig 更新支付配置 +func (s *paymentConfig) UpdatePaymentConfig(ctx context.Context, req *dto.UpdatePaymentConfigReq) (*dto.PaymentConfigResp, error) { + // 1. 参数验证 + if req.ID == "" || req.TenantID == "" { + return nil, errors.New("必填参数不能为空") + } + + // 2. 查询配置 + objectID, err := bson.ObjectIDFromHex(req.ID) + if err != nil { + return nil, errors.New("无效的配置ID") + } + + config, err := dao.PaymentConfig.GetByID(ctx, objectID) + if err != nil { + return nil, err + } + if config == nil { + return nil, errors.New("支付配置不存在") + } + + // 3. 检查是否是租户自己的配置 + if config.TenantID != req.TenantID { + return nil, errors.New("无权限操作该配置") + } + + // 4. 更新配置实体 + config.ConfigName = req.ConfigName + config.Description = req.Remark + config.Enabled = req.IsEnabled + + // 解析配置参数 + parseConfigMapToEntity(config.PayMethod, req.Config, config) + + // 5. 更新配置 + if err := dao.PaymentConfig.Update(ctx, config); err != nil { + return nil, err + } + + // 6. 返回结果 + resp := &dto.PaymentConfigResp{ + ID: config.ID.Hex(), + TenantID: config.TenantID, + PayMethod: config.PayMethod, + ConfigName: config.ConfigName, + Remark: config.Description, + IsEnabled: config.Enabled, + Config: convertEntityToConfigMap(config), + CreatedAt: time.Unix(0, 0), // 实体中没有时间字段,使用默认值 + UpdatedAt: time.Now(), + } + + return resp, nil +} + +// GetPaymentConfig 获取支付配置 +func (s *paymentConfig) GetPaymentConfig(ctx context.Context, req *dto.QueryPaymentConfigReq) (*dto.PaymentConfigResp, error) { + // 1. 参数验证 + if req.TenantID == "" { + return nil, errors.New("租户ID不能为空") + } + + var config *entity.PaymentConfig + var err error + + // 2. 查询配置 + if req.PayMethod != "" { + // 按租户和支付方式查询 + config, err = dao.PaymentConfig.GetByTenantAndMethod(ctx, req.TenantID, req.PayMethod) + } else { + // 只按租户查询(获取所有支付方式配置) + configs, err := dao.PaymentConfig.GetByTenantID(ctx, req.TenantID) + if err != nil { + return nil, err + } + if len(configs) > 0 { + config = &configs[0] // 返回第一个配置作为默认 + } + } + + if err != nil { + return nil, err + } + if config == nil { + return nil, errors.New("支付配置不存在") + } + + // 3. 返回结果 + resp := &dto.PaymentConfigResp{ + ID: config.ID.Hex(), + TenantID: config.TenantID, + PayMethod: config.PayMethod, + ConfigName: config.ConfigName, + Remark: config.Description, + IsEnabled: config.Enabled, + Config: convertEntityToConfigMap(config), + CreatedAt: time.Unix(0, 0), + UpdatedAt: time.Now(), + } + + return resp, nil +} + +// GetPaymentConfigList 获取支付配置列表 +func (s *paymentConfig) GetPaymentConfigList(ctx context.Context, tenantID string) ([]dto.PaymentConfigResp, error) { + // 1. 参数验证 + if tenantID == "" { + return nil, errors.New("租户ID不能为空") + } + + // 2. 查询配置列表 + configs, err := dao.PaymentConfig.GetByTenantID(ctx, tenantID) + if err != nil { + return nil, err + } + + // 3. 转换为响应格式 + var resp []dto.PaymentConfigResp + for _, config := range configs { + resp = append(resp, dto.PaymentConfigResp{ + ID: config.ID.Hex(), + TenantID: config.TenantID, + PayMethod: config.PayMethod, + ConfigName: config.ConfigName, + Remark: config.Description, + IsEnabled: config.Enabled, + Config: convertEntityToConfigMap(&config), + CreatedAt: time.Unix(0, 0), + UpdatedAt: time.Now(), + }) + } + + return resp, nil +} + +// DeletePaymentConfig 删除支付配置 +func (s *paymentConfig) DeletePaymentConfig(ctx context.Context, tenantID, configID string) error { + // 1. 参数验证 + if tenantID == "" || configID == "" { + return errors.New("必填参数不能为空") + } + + // 2. 查询配置 + objectID, err := bson.ObjectIDFromHex(configID) + if err != nil { + return errors.New("无效的配置ID") + } + + config, err := dao.PaymentConfig.GetByID(ctx, objectID) + if err != nil { + return err + } + if config == nil { + return errors.New("支付配置不存在") + } + + // 3. 检查是否是租户自己的配置 + if config.TenantID != tenantID { + return errors.New("无权限操作该配置") + } + + // 4. 删除配置 + return dao.PaymentConfig.Delete(ctx, objectID) +} + +// EnablePaymentConfig 启用支付配置 +func (s *paymentConfig) EnablePaymentConfig(ctx context.Context, tenantID, configID string) error { + return s.updateConfigStatus(ctx, tenantID, configID, true) +} + +// DisablePaymentConfig 禁用支付配置 +func (s *paymentConfig) DisablePaymentConfig(ctx context.Context, tenantID, configID string) error { + return s.updateConfigStatus(ctx, tenantID, configID, false) +} + +// updateConfigStatus 更新配置状态 +func (s *paymentConfig) updateConfigStatus(ctx context.Context, tenantID, configID string, enabled bool) error { + // 1. 参数验证 + if tenantID == "" || configID == "" { + return errors.New("必填参数不能为空") + } + + // 2. 查询配置 + objectID, err := bson.ObjectIDFromHex(configID) + if err != nil { + return errors.New("无效的配置ID") + } + + config, err := dao.PaymentConfig.GetByID(ctx, objectID) + if err != nil { + return err + } + if config == nil { + return errors.New("支付配置不存在") + } + + // 3. 检查是否是租户自己的配置 + if config.TenantID != tenantID { + return errors.New("无权限操作该配置") + } + + // 4. 更新状态 + config.Enabled = enabled + + return dao.PaymentConfig.Update(ctx, config) +} + +// WechatConfig 微信支付配置服务 +var WechatConfig = new(wechatConfig) + +type wechatConfig struct{} + +// GetWechatConfig 获取微信支付配置 +func (s *wechatConfig) GetWechatConfig(ctx context.Context, tenantID string) (*dto.WechatConfig, error) { + // 1. 获取微信支付配置 + resp, err := PaymentConfig.GetPaymentConfig(ctx, &dto.QueryPaymentConfigReq{ + TenantID: tenantID, + PayMethod: "wechat", + }) + if err != nil { + return nil, err + } + + // 2. 转换为微信配置结构体 + configMap := resp.Config + + wechatConfig := &dto.WechatConfig{ + ID: resp.ID, + TenantID: resp.TenantID, + ConfigName: resp.ConfigName, + AppID: getString(configMap, "app_id"), + MchID: getString(configMap, "mch_id"), + APIKey: getString(configMap, "api_key"), + NotifyURL: getString(configMap, "notify_url"), + ReturnURL: getString(configMap, "return_url"), + CertPath: getString(configMap, "cert_path"), + KeyPath: getString(configMap, "key_path"), + Sandbox: getBool(configMap, "sandbox"), + GatewayURL: getString(configMap, "gateway_url"), + SupportNative: getBool(configMap, "support_native"), + SupportJSAPI: getBool(configMap, "support_jsapi"), + SupportAPP: getBool(configMap, "support_app"), + SupportH5: getBool(configMap, "support_h5"), + } + + return wechatConfig, nil +} + +// AlipayConfig 支付宝支付配置服务 +var AlipayConfig = new(alipayConfig) + +type alipayConfig struct{} + +// GetAlipayConfig 获取支付宝支付配置 +func (s *alipayConfig) GetAlipayConfig(ctx context.Context, tenantID string) (*dto.AlipayConfig, error) { + // 1. 获取支付宝支付配置 + resp, err := PaymentConfig.GetPaymentConfig(ctx, &dto.QueryPaymentConfigReq{ + TenantID: tenantID, + PayMethod: "alipay", + }) + if err != nil { + return nil, err + } + + // 2. 转换为支付宝配置结构体 + configMap := resp.Config + + alipayConfig := &dto.AlipayConfig{ + ID: resp.ID, + TenantID: resp.TenantID, + ConfigName: resp.ConfigName, + AppID: getString(configMap, "app_id"), + NotifyURL: getString(configMap, "notify_url"), + ReturnURL: getString(configMap, "return_url"), + AppPrivateKey: getString(configMap, "app_private_key"), + AlipayPublicKey: getString(configMap, "alipay_public_key"), + Sandbox: getBool(configMap, "sandbox"), + GatewayURL: getString(configMap, "gateway_url"), + SupportNative: getBool(configMap, "support_native"), + SupportJSAPI: getBool(configMap, "support_jsapi"), + SupportAPP: getBool(configMap, "support_app"), + SupportH5: getBool(configMap, "support_h5"), + } + + return alipayConfig, nil +} + +// getString 从map中获取string值 +func getString(m map[string]interface{}, key string) string { + if val, ok := m[key]; ok { + if str, ok := val.(string); ok { + return str + } + } + return "" +} + +// getBool 从map中获取bool值 +func getBool(m map[string]interface{}, key string) bool { + if val, ok := m[key]; ok { + if b, ok := val.(bool); ok { + return b + } + } + return false +} + +// buildConfigMap 将PaymentConfig结构体转换为map +func buildConfigMap(config *entity.PaymentConfig) map[string]interface{} { + result := map[string]interface{}{ + "app_id": config.AppID, + "mch_id": config.MchID, + "api_key": config.APIKey, + "notify_url": config.NotifyURL, + "return_url": config.ReturnURL, + "cert_path": config.CertPath, + "key_path": config.KeyPath, + "app_private_key": config.AppPrivateKey, + "alipay_public_key": config.AlipayPublicKey, + "sandbox": config.Sandbox, + "gateway_url": config.GatewayURL, + "support_native": config.SupportNative, + "support_jsapi": config.SupportJSAPI, + "support_app": config.SupportAPP, + "support_h5": config.SupportH5, + } + return result +} + +// parseConfigMap 将map转换为PaymentConfig结构体 +func parseConfigMap(payMethod string, configMap map[string]interface{}) *entity.PaymentConfig { + config := &entity.PaymentConfig{ + PayMethod: payMethod, + ConfigName: payMethod + "配置", + AppID: getString(configMap, "app_id"), + MchID: getString(configMap, "mch_id"), + APIKey: getString(configMap, "api_key"), + NotifyURL: getString(configMap, "notify_url"), + ReturnURL: getString(configMap, "return_url"), + CertPath: getString(configMap, "cert_path"), + KeyPath: getString(configMap, "key_path"), + AppPrivateKey: getString(configMap, "app_private_key"), + AlipayPublicKey: getString(configMap, "alipay_public_key"), + Sandbox: getBool(configMap, "sandbox"), + GatewayURL: getString(configMap, "gateway_url"), + SupportNative: getBool(configMap, "support_native"), + SupportJSAPI: getBool(configMap, "support_jsapi"), + SupportAPP: getBool(configMap, "support_app"), + SupportH5: getBool(configMap, "support_h5"), + } + return config +} + +// parseConfigMapToEntity 将map中的配置更新到实体中 +func parseConfigMapToEntity(payMethod string, configMap map[string]interface{}, config *entity.PaymentConfig) { + config.AppID = getString(configMap, "app_id") + config.MchID = getString(configMap, "mch_id") + config.APIKey = getString(configMap, "api_key") + config.NotifyURL = getString(configMap, "notify_url") + config.ReturnURL = getString(configMap, "return_url") + config.CertPath = getString(configMap, "cert_path") + config.KeyPath = getString(configMap, "key_path") + config.AppPrivateKey = getString(configMap, "app_private_key") + config.AlipayPublicKey = getString(configMap, "alipay_public_key") + config.Sandbox = getBool(configMap, "sandbox") + config.GatewayURL = getString(configMap, "gateway_url") + config.SupportNative = getBool(configMap, "support_native") + config.SupportJSAPI = getBool(configMap, "support_jsapi") + config.SupportAPP = getBool(configMap, "support_app") + config.SupportH5 = getBool(configMap, "support_h5") +} + +// convertEntityToConfigMap 将实体转换为配置map +func convertEntityToConfigMap(config *entity.PaymentConfig) map[string]interface{} { + return buildConfigMap(config) +} diff --git a/service/service_manager.go b/service/service_manager.go deleted file mode 100644 index a67121a..0000000 --- a/service/service_manager.go +++ /dev/null @@ -1,50 +0,0 @@ -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 -}