From a258c360c25fff90343b1920036bfc68c85bbfdf Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Fri, 24 Oct 2025 15:39:20 +0800 Subject: [PATCH] fix --- app/main/api/desc/admin/order.api | 156 +++++----- app/main/api/desc/front/agent.api | 164 ++++++----- app/main/api/desc/front/query.api | 38 ++- .../adminretryagentprocesshandler.go | 29 ++ .../handler/agent/getmembershipinfohandler.go | 17 ++ app/main/api/internal/handler/routes.go | 11 + .../admin_order/admingetorderdetaillogic.go | 56 +++- .../admin_order/admingetorderlistlogic.go | 66 +++++ .../admin_order/adminrefundorderlogic.go | 175 +++++++++--- .../adminretryagentprocesslogic.go | 55 ++++ .../logic/agent/agentwithdrawallogic.go | 9 + .../internal/logic/agent/getlinkdatalogic.go | 42 ++- .../logic/agent/getmembershipinfologic.go | 100 +++++++ .../internal/logic/pay/alipaycallbacklogic.go | 30 +- .../api/internal/logic/pay/paymentlogic.go | 11 + .../logic/pay/wechatpaycallbacklogic.go | 33 ++- .../logic/pay/wechatpayrefundcallbacklogic.go | 215 ++++++++++++-- .../logic/query/querydetailbyorderidlogic.go | 9 +- .../logic/query/querydetailbyordernologic.go | 5 +- .../internal/logic/query/queryexamplelogic.go | 1 + .../internal/logic/query/querylistlogic.go | 8 + .../logic/query/querysharedetaillogic.go | 1 + app/main/api/internal/service/agentService.go | 270 +++++++++++++++++- app/main/api/internal/svc/servicecontext.go | 2 +- app/main/api/internal/types/types.go | 93 ++++-- app/main/model/orderRefundModel_gen.go | 81 ++---- app/main/model/vars.go | 1 + deploy/script/gen_models.ps1 | 8 +- 28 files changed, 1335 insertions(+), 351 deletions(-) create mode 100644 app/main/api/internal/handler/admin_order/adminretryagentprocesshandler.go create mode 100644 app/main/api/internal/handler/agent/getmembershipinfohandler.go create mode 100644 app/main/api/internal/logic/admin_order/adminretryagentprocesslogic.go create mode 100644 app/main/api/internal/logic/agent/getmembershipinfologic.go diff --git a/app/main/api/desc/admin/order.api b/app/main/api/desc/admin/order.api index 426c456..84e606c 100644 --- a/app/main/api/desc/admin/order.api +++ b/app/main/api/desc/admin/order.api @@ -7,8 +7,8 @@ info ( ) @server ( - prefix: api/v1/admin/order - group: admin_order + prefix: api/v1/admin/order + group: admin_order middleware: AdminAuthInterceptor ) service main { @@ -35,133 +35,139 @@ service main { @doc "订单退款" @handler AdminRefundOrder post /refund/:id (AdminRefundOrderReq) returns (AdminRefundOrderResp) + + @doc "重新执行代理处理" + @handler AdminRetryAgentProcess + post /retry-agent-process/:id (AdminRetryAgentProcessReq) returns (AdminRetryAgentProcessResp) } type ( // 列表请求 AdminGetOrderListReq { - Page int64 `form:"page,default=1"` // 页码 - PageSize int64 `form:"pageSize,default=20"` // 每页数量 - OrderNo string `form:"order_no,optional"` // 商户订单号 - PlatformOrderId string `form:"platform_order_id,optional"` // 支付订单号 - ProductName string `form:"product_name,optional"` // 产品名称 - PaymentPlatform string `form:"payment_platform,optional"` // 支付方式 - PaymentScene string `form:"payment_scene,optional"` // 支付平台 - Amount float64 `form:"amount,optional"` // 金额 - Status string `form:"status,optional"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + Page int64 `form:"page,default=1"` // 页码 + PageSize int64 `form:"pageSize,default=20"` // 每页数量 + OrderNo string `form:"order_no,optional"` // 商户订单号 + PlatformOrderId string `form:"platform_order_id,optional"` // 支付订单号 + ProductName string `form:"product_name,optional"` // 产品名称 + PaymentPlatform string `form:"payment_platform,optional"` // 支付方式 + PaymentScene string `form:"payment_scene,optional"` // 支付平台 + Amount float64 `form:"amount,optional"` // 金额 + Status string `form:"status,optional"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 IsPromotion int64 `form:"is_promotion,optional,default=-1"` // 是否推广订单:0-否,1-是 - CreateTimeStart string `form:"create_time_start,optional"` // 创建时间开始 - CreateTimeEnd string `form:"create_time_end,optional"` // 创建时间结束 - PayTimeStart string `form:"pay_time_start,optional"` // 支付时间开始 - PayTimeEnd string `form:"pay_time_end,optional"` // 支付时间结束 - RefundTimeStart string `form:"refund_time_start,optional"` // 退款时间开始 - RefundTimeEnd string `form:"refund_time_end,optional"` // 退款时间结束 + CreateTimeStart string `form:"create_time_start,optional"` // 创建时间开始 + CreateTimeEnd string `form:"create_time_end,optional"` // 创建时间结束 + PayTimeStart string `form:"pay_time_start,optional"` // 支付时间开始 + PayTimeEnd string `form:"pay_time_end,optional"` // 支付时间结束 + RefundTimeStart string `form:"refund_time_start,optional"` // 退款时间开始 + RefundTimeEnd string `form:"refund_time_end,optional"` // 退款时间结束 } - // 列表响应 AdminGetOrderListResp { Total int64 `json:"total"` // 总数 Items []OrderListItem `json:"items"` // 列表 } - // 列表项 OrderListItem { - Id int64 `json:"id"` // 订单ID - OrderNo string `json:"order_no"` // 商户订单号 - PlatformOrderId string `json:"platform_order_id"` // 支付订单号 - ProductName string `json:"product_name"` // 产品名称 - PaymentPlatform string `json:"payment_platform"` // 支付方式 - PaymentScene string `json:"payment_scene"` // 支付平台 - Amount float64 `json:"amount"` // 金额 - Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 - QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 - CreateTime string `json:"create_time"` // 创建时间 - PayTime string `json:"pay_time"` // 支付时间 - RefundTime string `json:"refund_time"` // 退款时间 - IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + Id int64 `json:"id"` // 订单ID + OrderNo string `json:"order_no"` // 商户订单号 + PlatformOrderId string `json:"platform_order_id"` // 支付订单号 + ProductName string `json:"product_name"` // 产品名称 + PaymentPlatform string `json:"payment_platform"` // 支付方式 + PaymentScene string `json:"payment_scene"` // 支付平台 + Amount float64 `json:"amount"` // 金额 + Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 + CreateTime string `json:"create_time"` // 创建时间 + PayTime string `json:"pay_time"` // 支付时间 + RefundTime string `json:"refund_time"` // 退款时间 + IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + IsAgentOrder bool `json:"is_agent_order"` // 是否是代理订单 + AgentProcessStatus string `json:"agent_process_status"` // 代理事务处理状态:not_agent-非代理订单,success-处理成功,failed-处理失败,pending-待处理 } - // 详情请求 AdminGetOrderDetailReq { Id int64 `path:"id"` // 订单ID } - // 详情响应 AdminGetOrderDetailResp { - Id int64 `json:"id"` // 订单ID - OrderNo string `json:"order_no"` // 商户订单号 - PlatformOrderId string `json:"platform_order_id"` // 支付订单号 - ProductName string `json:"product_name"` // 产品名称 - PaymentPlatform string `json:"payment_platform"` // 支付方式 - PaymentScene string `json:"payment_scene"` // 支付平台 - Amount float64 `json:"amount"` // 金额 - Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 - QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 - CreateTime string `json:"create_time"` // 创建时间 - PayTime string `json:"pay_time"` // 支付时间 - RefundTime string `json:"refund_time"` // 退款时间 - IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 - UpdateTime string `json:"update_time"` // 更新时间 + Id int64 `json:"id"` // 订单ID + OrderNo string `json:"order_no"` // 商户订单号 + PlatformOrderId string `json:"platform_order_id"` // 支付订单号 + ProductName string `json:"product_name"` // 产品名称 + PaymentPlatform string `json:"payment_platform"` // 支付方式 + PaymentScene string `json:"payment_scene"` // 支付平台 + Amount float64 `json:"amount"` // 金额 + Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 + CreateTime string `json:"create_time"` // 创建时间 + PayTime string `json:"pay_time"` // 支付时间 + RefundTime string `json:"refund_time"` // 退款时间 + IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + UpdateTime string `json:"update_time"` // 更新时间 + IsAgentOrder bool `json:"is_agent_order"` // 是否是代理订单 + AgentProcessStatus string `json:"agent_process_status"` // 代理事务处理状态:not_agent-非代理订单,success-处理成功,failed-处理失败,pending-待处理 } - // 创建请求 AdminCreateOrderReq { - OrderNo string `json:"order_no"` // 商户订单号 - PlatformOrderId string `json:"platform_order_id"` // 支付订单号 - ProductName string `json:"product_name"` // 产品名称 - PaymentPlatform string `json:"payment_platform"` // 支付方式 - PaymentScene string `json:"payment_scene"` // 支付平台 - Amount float64 `json:"amount"` // 金额 + OrderNo string `json:"order_no"` // 商户订单号 + PlatformOrderId string `json:"platform_order_id"` // 支付订单号 + ProductName string `json:"product_name"` // 产品名称 + PaymentPlatform string `json:"payment_platform"` // 支付方式 + PaymentScene string `json:"payment_scene"` // 支付平台 + Amount float64 `json:"amount"` // 金额 Status string `json:"status,default=pending"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 IsPromotion int64 `json:"is_promotion,default=0"` // 是否推广订单:0-否,1-是 } - // 创建响应 AdminCreateOrderResp { Id int64 `json:"id"` // 订单ID } - // 更新请求 AdminUpdateOrderReq { - Id int64 `path:"id"` // 订单ID - OrderNo *string `json:"order_no,optional"` // 商户订单号 + Id int64 `path:"id"` // 订单ID + OrderNo *string `json:"order_no,optional"` // 商户订单号 PlatformOrderId *string `json:"platform_order_id,optional"` // 支付订单号 - ProductName *string `json:"product_name,optional"` // 产品名称 - PaymentPlatform *string `json:"payment_platform,optional"` // 支付方式 - PaymentScene *string `json:"payment_scene,optional"` // 支付平台 - Amount *float64 `json:"amount,optional"` // 金额 - Status *string `json:"status,optional"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 - PayTime *string `json:"pay_time,optional"` // 支付时间 - RefundTime *string `json:"refund_time,optional"` // 退款时间 - IsPromotion *int64 `json:"is_promotion,optional"` // 是否推广订单:0-否,1-是 + ProductName *string `json:"product_name,optional"` // 产品名称 + PaymentPlatform *string `json:"payment_platform,optional"` // 支付方式 + PaymentScene *string `json:"payment_scene,optional"` // 支付平台 + Amount *float64 `json:"amount,optional"` // 金额 + Status *string `json:"status,optional"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + PayTime *string `json:"pay_time,optional"` // 支付时间 + RefundTime *string `json:"refund_time,optional"` // 退款时间 + IsPromotion *int64 `json:"is_promotion,optional"` // 是否推广订单:0-否,1-是 } - // 更新响应 AdminUpdateOrderResp { Success bool `json:"success"` // 是否成功 } - // 删除请求 AdminDeleteOrderReq { Id int64 `path:"id"` // 订单ID } - // 删除响应 AdminDeleteOrderResp { Success bool `json:"success"` // 是否成功 } - // 退款请求 AdminRefundOrderReq { - Id int64 `path:"id"` // 订单ID + Id int64 `path:"id"` // 订单ID RefundAmount float64 `json:"refund_amount"` // 退款金额 RefundReason string `json:"refund_reason"` // 退款原因 } - // 退款响应 AdminRefundOrderResp { - Status string `json:"status"` // 退款状态 + Status string `json:"status"` // 退款状态 RefundNo string `json:"refund_no"` // 退款单号 - Amount float64 `json:"amount"` // 退款金额 + Amount float64 `json:"amount"` // 退款金额 + } + // 重新执行代理处理请求 + AdminRetryAgentProcessReq { + Id int64 `path:"id"` // 订单ID + } + // 重新执行代理处理响应 + AdminRetryAgentProcessResp { + Status string `json:"status"` // 执行状态:success-成功,already_processed-已处理,failed-失败 + Message string `json:"message"` // 执行结果消息 + ProcessedAt string `json:"processed_at"` // 处理时间 } ) \ No newline at end of file diff --git a/app/main/api/desc/front/agent.api b/app/main/api/desc/front/agent.api index 79a3a51..254ea2f 100644 --- a/app/main/api/desc/front/agent.api +++ b/app/main/api/desc/front/agent.api @@ -5,6 +5,7 @@ info ( desc: "代理服务接口" version: "v1" ) + @server ( prefix: api/v1/agent group: agent @@ -14,14 +15,42 @@ service main { @handler GetAgentPromotionQrcode get /promotion/qrcode (GetAgentPromotionQrcodeReq) + // 获取会员开通信息 + @handler GetMembershipInfo + get /membership/info returns (GetMembershipInfoResp) } type ( - GetAgentPromotionQrcodeReq{ + GetAgentPromotionQrcodeReq { QrcodeType string `form:"qrcode_type"` - QrcodeUrl string `form:"qrcode_url"` + QrcodeUrl string `form:"qrcode_url"` + } + // 会员配置信息 + MembershipConfigInfo { + Id int64 `json:"id"` // 主键 + LevelName string `json:"level_name"` // 会员级别名称 + Price float64 `json:"price"` // 会员年费 + ReportCommission float64 `json:"report_commission"` // 直推报告收益 + LowerActivityReward float64 `json:"lower_activity_reward"` // 下级活跃奖励金额 + NewActivityReward float64 `json:"new_activity_reward"` // 新增活跃奖励金额 + LowerStandardCount int64 `json:"lower_standard_count"` // 活跃下级达标个数 + NewLowerStandardCount int64 `json:"new_lower_standard_count"` // 新增活跃下级达标个数 + LowerWithdrawRewardRatio float64 `json:"lower_withdraw_reward_ratio"` // 下级提现奖励比例 + LowerConvertVipReward float64 `json:"lower_convert_vip_reward"` // 下级转化VIP奖励 + LowerConvertSvipReward float64 `json:"lower_convert_svip_reward"` // 下级转化SVIP奖励 + ExemptionAmount float64 `json:"exemption_amount"` // 免审核金额 + PriceIncreaseMax float64 `json:"price_increase_max"` // 提价最高金额 + PriceRatio float64 `json:"price_ratio"` // 提价区间收取比例 + PriceIncreaseAmount float64 `json:"price_increase_amount"` // 在原本成本上加价的金额 + } + // 获取会员开通信息响应 + GetMembershipInfoResp { + NormalConfig MembershipConfigInfo `json:"normal_config"` // 普通代理配置 + VipConfig MembershipConfigInfo `json:"vip_config"` // VIP会员配置 + SvipConfig MembershipConfigInfo `json:"svip_config"` // SVIP会员配置 } ) + // 代理服务基本类型定义 type AgentProductConfig { ProductID int64 `json:"product_id"` @@ -49,6 +78,7 @@ type ProductConfig { PriceRangeMin float64 `json:"price_range_min"` PriceRangeMax float64 `json:"price_range_max"` } + @server ( prefix: api/v1/agent group: agent @@ -62,10 +92,11 @@ service main { @handler GetAgentRevenueInfo get /revenue (GetAgentRevenueInfoReq) returns (GetAgentRevenueInfoResp) } + @server ( - prefix: api/v1/agent - group: agent - jwt: JwtAuth + prefix: api/v1/agent + group: agent + jwt: JwtAuth middleware: UserAuthInterceptor ) service main { @@ -88,21 +119,21 @@ service main { // 下级贡献详情 @handler GetAgentSubordinateContributionDetail get /subordinate/contribution/detail (GetAgentSubordinateContributionDetailReq) returns (GetAgentSubordinateContributionDetailResp) - + @handler AgentRealName post /real_name (AgentRealNameReq) returns (AgentRealNameResp) } type ( AgentInfoResp { - status int64 `json:"status"` // 0=待审核,1=审核通过,2=审核未通过,3=未申请 - isAgent bool `json:"is_agent"` - agentID int64 `json:"agent_id"` - level string `json:"level"` - region string `json:"region"` - mobile string `json:"mobile"` + status int64 `json:"status"` // 0=待审核,1=审核通过,2=审核未通过,3=未申请 + isAgent bool `json:"is_agent"` + agentID int64 `json:"agent_id"` + level string `json:"level"` + region string `json:"region"` + mobile string `json:"mobile"` expiryTime string `json:"expiry_time"` - isRealName bool `json:"is_real_name"` + isRealName bool `json:"is_real_name"` } // 查询代理申请状态响应 AgentAuditStatusResp { @@ -124,64 +155,63 @@ type ( PageSize int64 `form:"page_size"` // 每页数据量 } GetAgentSubordinateListResp { - Total int64 `json:"total"` // 总记录数 + Total int64 `json:"total"` // 总记录数 List []AgentSubordinateList `json:"list"` // 查询列表 } AgentSubordinateList { - ID int64 `json:"id"` - Mobile string `json:"mobile"` - CreateTime string `json:"create_time"` - LevelName string `json:"level_name"` - TotalOrders int64 `json:"total_orders"` // 总单量 - TotalEarnings float64 `json:"total_earnings"` // 总金额 + ID int64 `json:"id"` + Mobile string `json:"mobile"` + CreateTime string `json:"create_time"` + LevelName string `json:"level_name"` + TotalOrders int64 `json:"total_orders"` // 总单量 + TotalEarnings float64 `json:"total_earnings"` // 总金额 TotalContribution float64 `json:"total_contribution"` // 总贡献 } GetAgentSubordinateContributionDetailReq { - Page int64 `form:"page"` // 页码 - PageSize int64 `form:"page_size"` // 每页数据量 + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数据量 SubordinateID int64 `form:"subordinate_id"` // 下级ID } GetAgentSubordinateContributionDetailResp { - Mobile string `json:"mobile"` - Total int64 `json:"total"` // 总记录数 - CreateTime string `json:"create_time"` - TotalEarnings float64 `json:"total_earnings"` // 总金额 - TotalContribution float64 `json:"total_contribution"` // 总贡献 - TotalOrders int64 `json:"total_orders"` // 总单量 - LevelName string `json:"level_name"` // 等级名称 - List []AgentSubordinateContributionDetail `json:"list"` // 查询列表 - Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据 + Mobile string `json:"mobile"` + Total int64 `json:"total"` // 总记录数 + CreateTime string `json:"create_time"` + TotalEarnings float64 `json:"total_earnings"` // 总金额 + TotalContribution float64 `json:"total_contribution"` // 总贡献 + TotalOrders int64 `json:"total_orders"` // 总单量 + LevelName string `json:"level_name"` // 等级名称 + List []AgentSubordinateContributionDetail `json:"list"` // 查询列表 + Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据 } AgentSubordinateContributionDetail { ID int64 `json:"id"` - CreateTime string `json:"create_time"` - Amount float64 `json:"amount"` - Type string `json:"type"` + CreateTime string `json:"create_time"` + Amount float64 `json:"amount"` + Type string `json:"type"` } AgentSubordinateContributionStats { - CostCount int64 `json:"cost_count"` // 成本扣除次数 - CostAmount float64 `json:"cost_amount"` // 成本扣除总额 - PricingCount int64 `json:"pricing_count"` // 定价扣除次数 - PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额 - DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数 - DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额 - DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数 - DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额 - DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数 + CostCount int64 `json:"cost_count"` // 成本扣除次数 + CostAmount float64 `json:"cost_amount"` // 成本扣除总额 + PricingCount int64 `json:"pricing_count"` // 定价扣除次数 + PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额 + DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数 + DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额 + DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数 + DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额 + DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数 DescendantUpgradeSvipAmount float64 `json:"descendant_upgrade_svip_amount"` // 下级升级SVIP总额 - DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数 - DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额 - DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数 - DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额 - DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数 - DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额 + DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数 + DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额 + DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数 + DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额 + DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数 + DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额 } - AgentRealNameReq { - Name string `json:"name"` + Name string `json:"name"` IDCard string `json:"id_card"` Mobile string `json:"mobile"` - Code string `json:"code"` + Code string `json:"code"` } AgentRealNameResp { Status string `json:"status"` @@ -189,11 +219,10 @@ type ( ) @server ( - prefix: api/v1/agent - group: agent - jwt: JwtAuth + prefix: api/v1/agent + group: agent + jwt: JwtAuth middleware: UserAuthInterceptor - ) service main { @handler GetAgentMembershipProductConfig @@ -226,11 +255,10 @@ type ( ) @server ( - prefix: api/v1/agent - group: agent - jwt: JwtAuth + prefix: api/v1/agent + group: agent + jwt: JwtAuth middleware: UserAuthInterceptor - ) service main { @handler GetAgentCommission @@ -340,17 +368,15 @@ type ( Status int64 `json:"status"` // 1申请中 2成功 3失败 failMsg string `json:"fail_msg"` } - // 开通代理会员请求参数 AgentActivateMembershipReq { - Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip + Type string `json:"type,oneof=VIP SVIP"` // 会员类型:vip/svip } // 开通代理会员响应 AgentActivateMembershipResp { - Id string `json:"id"` - } - GetWithdrawalTaxExemptionReq { + Id string `json:"id"` } + GetWithdrawalTaxExemptionReq {} GetWithdrawalTaxExemptionResp { TotalExemptionAmount float64 `json:"total_exemption_amount"` UsedExemptionAmount float64 `json:"used_exemption_amount"` @@ -360,10 +386,9 @@ type ( ) @server ( - prefix: api/v1/agent - group: agent + prefix: api/v1/agent + group: agent middleware: AuthInterceptor - ) service main { // 提交代理申请 @@ -373,7 +398,6 @@ service main { // 获取推广标识数据 @handler GetLinkData get /link (GetLinkDataReq) returns (GetLinkDataResp) - } type ( @@ -384,7 +408,7 @@ type ( Code string `json:"code"` Ancestor string `json:"ancestor,optional"` } - AgentApplyResp{ + AgentApplyResp { AccessToken string `json:"accessToken"` AccessExpire int64 `json:"accessExpire"` RefreshAfter int64 `json:"refreshAfter"` diff --git a/app/main/api/desc/front/query.api b/app/main/api/desc/front/query.api index 3d3db3b..4bcd368 100644 --- a/app/main/api/desc/front/query.api +++ b/app/main/api/desc/front/query.api @@ -9,9 +9,10 @@ info ( //============================> query v1 <============================ // 查询基本类型定义 type Query { - Id int64 `json:"id"` // 主键ID - OrderId int64 `json:"order_id"` // 订单ID - UserId int64 `json:"user_id"` // 用户ID + Id int64 `json:"id"` // 主键ID + OrderId int64 `json:"order_id"` // 订单ID + UserId int64 `json:"user_id"` // 用户ID + Product string `json:"product"` // 产品ID ProductName string `json:"product_name"` // 产品ID QueryParams map[string]interface{} `json:"query_params"` QueryData []QueryItem `json:"query_data"` @@ -20,15 +21,14 @@ type Query { QueryState string `json:"query_state"` // 查询状态 } - type QueryItem { Feature interface{} `json:"feature"` Data interface{} `json:"data"` // 这里可以是 map 或 具体的 struct } @server ( - prefix: api/v1 - group: query + prefix: api/v1 + group: query middleware: AuthInterceptor ) service main { @@ -65,11 +65,10 @@ type ( ) @server ( - prefix: api/v1 - group: query - jwt: JwtAuth + prefix: api/v1 + group: query + jwt: JwtAuth middleware: UserAuthInterceptor - ) service main { @doc "query service" @@ -78,11 +77,10 @@ service main { } @server ( - prefix: api/v1 - group: query - jwt: JwtAuth + prefix: api/v1 + group: query + jwt: JwtAuth middleware: UserAuthInterceptor - ) service main { @doc "获取查询临时订单" @@ -116,7 +114,7 @@ service main { type ( QueryGenerateShareLinkReq { - OrderId *int64 `json:"order_id,optional"` + OrderId *int64 `json:"order_id,optional"` OrderNo *string `json:"order_no,optional"` } QueryGenerateShareLinkResp { @@ -139,12 +137,12 @@ type ( type ( QueryListReq { - Page int64 `form:"page"` // 页码 + Page int64 `form:"page"` // 页码 PageSize int64 `form:"page_size"` // 每页数据量 } QueryListResp { Total int64 `json:"total"` // 总记录数 - List []Query `json:"list"` // 查询列表 + List []Query `json:"list"` // 查询列表 } ) @@ -157,7 +155,6 @@ type ( } ) - type ( QueryDetailByOrderIdReq { OrderId int64 `path:"order_id"` @@ -185,10 +182,9 @@ type ( } ) - type ( UpdateQueryDataReq { - Id int64 `json:"id"` // 查询ID + Id int64 `json:"id"` // 查询ID QueryData string `json:"query_data"` // 查询数据(未加密的JSON) } UpdateQueryDataResp { @@ -212,8 +208,8 @@ service main { @doc "查询示例" @handler queryExample get /query/example (QueryExampleReq) returns (QueryExampleResp) - } + type ( QueryShareDetailReq { Id string `path:"id"` diff --git a/app/main/api/internal/handler/admin_order/adminretryagentprocesshandler.go b/app/main/api/internal/handler/admin_order/adminretryagentprocesshandler.go new file mode 100644 index 0000000..28f2377 --- /dev/null +++ b/app/main/api/internal/handler/admin_order/adminretryagentprocesshandler.go @@ -0,0 +1,29 @@ +package admin_order + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "tydata-server/app/main/api/internal/logic/admin_order" + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/api/internal/types" + "tydata-server/common/result" + "tydata-server/pkg/lzkit/validator" +) + +func AdminRetryAgentProcessHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.AdminRetryAgentProcessReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := admin_order.NewAdminRetryAgentProcessLogic(r.Context(), svcCtx) + resp, err := l.AdminRetryAgentProcess(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/getmembershipinfohandler.go b/app/main/api/internal/handler/agent/getmembershipinfohandler.go new file mode 100644 index 0000000..57b4b82 --- /dev/null +++ b/app/main/api/internal/handler/agent/getmembershipinfohandler.go @@ -0,0 +1,17 @@ +package agent + +import ( + "net/http" + + "tydata-server/app/main/api/internal/logic/agent" + "tydata-server/app/main/api/internal/svc" + "tydata-server/common/result" +) + +func GetMembershipInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + l := agent.NewGetMembershipInfoLogic(r.Context(), svcCtx) + resp, err := l.GetMembershipInfo() + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index d06bda7..97fcbd6 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -310,6 +310,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/refund/:id", Handler: admin_order.AdminRefundOrderHandler(serverCtx), }, + { + // 重新执行代理处理 + Method: http.MethodPost, + Path: "/retry-agent-process/:id", + Handler: admin_order.AdminRetryAgentProcessHandler(serverCtx), + }, { // 更新订单 Method: http.MethodPut, @@ -639,6 +645,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ + { + Method: http.MethodGet, + Path: "/membership/info", + Handler: agent.GetMembershipInfoHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/promotion/qrcode", diff --git a/app/main/api/internal/logic/admin_order/admingetorderdetaillogic.go b/app/main/api/internal/logic/admin_order/admingetorderdetaillogic.go index 41caf37..6969204 100644 --- a/app/main/api/internal/logic/admin_order/admingetorderdetaillogic.go +++ b/app/main/api/internal/logic/admin_order/admingetorderdetaillogic.go @@ -47,6 +47,36 @@ func (l *AdminGetOrderDetailLogic) AdminGetOrderDetail(req *types.AdminGetOrderD isPromotion = 1 } + // 判断是否为代理订单并获取代理处理状态 + var isAgentOrder bool + var agentProcessStatus string + + agentOrder, err := l.svcCtx.AgentOrderModel.FindOneByOrderId(l.ctx, order.Id) + if err == nil && agentOrder != nil { + isAgentOrder = true + + // 查询代理佣金记录 + commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, + l.svcCtx.AgentCommissionModel.SelectBuilder().Where("order_id = ?", order.Id), "") + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询代理佣金失败 err: %v", err) + } + + if len(commissions) > 0 { + agentProcessStatus = "success" + } else { + // 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败 + if order.Status == "paid" { + agentProcessStatus = "pending" + } else { + agentProcessStatus = "failed" + } + } + } else { + isAgentOrder = false + agentProcessStatus = "not_agent" + } + // 获取查询状态 var queryState string builder := l.svcCtx.QueryModel.SelectBuilder().Where("order_id = ?", order.Id).Columns("query_state") @@ -78,18 +108,20 @@ func (l *AdminGetOrderDetailLogic) AdminGetOrderDetail(req *types.AdminGetOrderD // 构建响应 resp = &types.AdminGetOrderDetailResp{ - Id: order.Id, - OrderNo: order.OrderNo, - PlatformOrderId: order.PlatformOrderId.String, - ProductName: product.ProductName, - PaymentPlatform: order.PaymentPlatform, - PaymentScene: order.PaymentScene, - Amount: order.Amount, - Status: order.Status, - CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"), - UpdateTime: order.UpdateTime.Format("2006-01-02 15:04:05"), - IsPromotion: isPromotion, - QueryState: queryState, + Id: order.Id, + OrderNo: order.OrderNo, + PlatformOrderId: order.PlatformOrderId.String, + ProductName: product.ProductName, + PaymentPlatform: order.PaymentPlatform, + PaymentScene: order.PaymentScene, + Amount: order.Amount, + Status: order.Status, + CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"), + UpdateTime: order.UpdateTime.Format("2006-01-02 15:04:05"), + IsPromotion: isPromotion, + QueryState: queryState, + IsAgentOrder: isAgentOrder, + AgentProcessStatus: agentProcessStatus, } // 处理可选字段 diff --git a/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go b/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go index 4026782..d166002 100644 --- a/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go +++ b/app/main/api/internal/logic/admin_order/admingetorderlistlogic.go @@ -102,6 +102,9 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR // 并发获取产品信息和查询状态 productMap := make(map[int64]string) queryStateMap := make(map[int64]string) + agentOrderMap := make(map[int64]bool) // 代理订单映射 + agentProcessStatusMap := make(map[int64]string) // 代理处理状态映射 + var mu sync.Mutex // 批量获取查询状态 @@ -160,6 +163,60 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR } } } + + // 批量获取代理订单状态 + agentOrders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx, + l.svcCtx.AgentOrderModel.SelectBuilder().Where(squirrel.Eq{"order_id": orderIds}), "") + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理订单失败 err: %v", err) + } + + // 记录代理订单 + for _, agentOrder := range agentOrders { + agentOrderMap[agentOrder.OrderId] = true + } + + // 对于代理订单,查询代理处理状态 + if len(agentOrders) > 0 { + agentOrderIds := make([]int64, 0, len(agentOrders)) + for _, agentOrder := range agentOrders { + agentOrderIds = append(agentOrderIds, agentOrder.OrderId) + } + + // 查询代理佣金记录 + commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, + l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.Eq{"order_id": agentOrderIds}), "") + if err != nil && !errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理佣金失败 err: %v", err) + } + + // 记录有佣金记录的订单为处理成功 + processedOrderIds := make(map[int64]bool) + for _, commission := range commissions { + processedOrderIds[commission.OrderId] = true + } + + // 创建订单状态映射,避免重复查找 + orderStatusMap := make(map[int64]string) + for _, order := range orders { + orderStatusMap[order.Id] = order.Status + } + + // 设置代理处理状态 + for _, agentOrder := range agentOrders { + orderId := agentOrder.OrderId + if processedOrderIds[orderId] { + agentProcessStatusMap[orderId] = "success" + } else { + // 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败 + if orderStatusMap[orderId] == "paid" { + agentProcessStatusMap[orderId] = "pending" + } else { + agentProcessStatusMap[orderId] = "failed" + } + } + } + } } // 并发获取产品信息 @@ -222,6 +279,15 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR if err == nil && promotionOrder != nil { item.IsPromotion = 1 } + + // 设置代理订单相关字段 + if agentOrderMap[order.Id] { + item.IsAgentOrder = true + item.AgentProcessStatus = agentProcessStatusMap[order.Id] + } else { + item.IsAgentOrder = false + item.AgentProcessStatus = "not_agent" + } resp.Items = append(resp.Items, item) } diff --git a/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go b/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go index 065c6b8..87c9506 100644 --- a/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go +++ b/app/main/api/internal/logic/admin_order/adminrefundorderlogic.go @@ -16,6 +16,13 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlx" ) +const ( + PaymentPlatformAlipay = "alipay" + PaymentPlatformWechat = "wechat" + OrderStatusPaid = "paid" + RefundNoPrefix = "refund-" +) + type AdminRefundOrderLogic struct { logx.Logger ctx context.Context @@ -29,64 +36,158 @@ func NewAdminRefundOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) * svcCtx: svcCtx, } } - func (l *AdminRefundOrderLogic) AdminRefundOrder(req *types.AdminRefundOrderReq) (resp *types.AdminRefundOrderResp, err error) { - // 获取订单信息 - order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id) + // 获取并验证订单 + order, err := l.getAndValidateOrder(req.Id, req.RefundAmount) + if err != nil { + return nil, err + } + + // 根据支付平台处理退款 + switch order.PaymentPlatform { + case PaymentPlatformAlipay: + return l.handleAlipayRefund(order, req) + case PaymentPlatformWechat: + return l.handleWechatRefund(order, req) + default: + return nil, errors.Wrapf(xerr.NewErrMsg("不支持的支付平台"), "AdminRefundOrder, 不支持的支付平台: %s", order.PaymentPlatform) + } +} + +// getAndValidateOrder 获取并验证订单信息 +func (l *AdminRefundOrderLogic) getAndValidateOrder(orderId int64, refundAmount float64) (*model.Order, error) { + order, err := l.svcCtx.OrderModel.FindOne(l.ctx, orderId) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminRefundOrder, 查询订单失败 err: %v", err) } // 检查订单状态 - if order.Status != "paid" { - return nil, errors.Wrapf(xerr.NewErrMsg("订单状态不正确,无法退款"), "AdminRefundOrder, 订单状态不正确,无法退款 err: %v", err) + if order.Status != OrderStatusPaid { + return nil, errors.Wrapf(xerr.NewErrMsg("订单状态不正确,无法退款"), "AdminRefundOrder, 订单状态: %s", order.Status) } // 检查退款金额 - if req.RefundAmount > order.Amount { - return nil, errors.Wrapf(xerr.NewErrMsg("退款金额不能大于订单金额"), "AdminRefundOrder, 退款金额不能大于订单金额 err: %v", err) + if refundAmount > order.Amount { + return nil, errors.Wrapf(xerr.NewErrMsg("退款金额不能大于订单金额"), "AdminRefundOrder, 退款金额: %f, 订单金额: %f", refundAmount, order.Amount) } + + return order, nil +} + +// handleAlipayRefund 处理支付宝退款 +func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) { + // 调用支付宝退款接口 refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.OrderNo, req.RefundAmount) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 退款失败 err: %v", err) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err) } + + refundNo := l.generateRefundNo(order.OrderNo) + if refundResp.IsSuccess() { - err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { - // 创建退款记录 - refund := &model.OrderRefund{ - RefundNo: fmt.Sprintf("refund-%s", order.OrderNo), - PlatformRefundId: sql.NullString{String: refundResp.TradeNo, Valid: true}, - OrderId: order.Id, - UserId: order.UserId, - ProductId: order.ProductId, - RefundAmount: req.RefundAmount, - RefundReason: sql.NullString{String: req.RefundReason, Valid: true}, - Status: model.OrderRefundStatusPending, - RefundTime: sql.NullTime{Time: time.Now(), Valid: true}, - } - - if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil { - return fmt.Errorf("创建退款记录失败: %v", err) - } - - // 更新订单状态 - order.Status = model.OrderStatusRefunded - order.RefundTime = sql.NullTime{Time: time.Now(), Valid: true} - if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil { - return fmt.Errorf("更新订单状态失败: %v", err) - } - return nil - }) + // 支付宝退款成功,创建成功记录 + err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, refundResp.TradeNo, model.OrderStatusRefunded, model.OrderRefundStatusSuccess) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 退款失败 err: %v", err) + return nil, err } + return &types.AdminRefundOrderResp{ Status: model.OrderStatusRefunded, - RefundNo: fmt.Sprintf("refund-%s", order.OrderNo), + RefundNo: refundNo, Amount: req.RefundAmount, }, nil } else { - return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("退款失败, : %v", refundResp.Msg)), "AdminRefundOrder, 退款失败 err: %v", err) + // 支付宝退款失败,创建失败记录但不更新订单状态 + err = l.createRefundRecordOnly(order, req, refundNo, refundResp.TradeNo, model.OrderRefundStatusFailed) + if err != nil { + logx.Errorf("创建退款失败记录时出错: %v", err) + } + return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("退款失败: %v", refundResp.Msg)), "AdminRefundOrder, 支付宝退款失败") + } +} + +// handleWechatRefund 处理微信退款 +func (l *AdminRefundOrderLogic) handleWechatRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) { + // 调用微信退款接口 + err := l.svcCtx.WechatPayService.WeChatRefund(l.ctx, order.OrderNo, req.RefundAmount, order.Amount) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 微信退款失败 err: %v", err) } + // 微信退款是异步的,创建pending状态的退款记录 + refundNo := l.generateRefundNo(order.OrderNo) + err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, "", model.OrderStatusRefunding, model.OrderRefundStatusPending) + if err != nil { + return nil, err + } + + return &types.AdminRefundOrderResp{ + Status: model.OrderRefundStatusPending, + RefundNo: refundNo, + Amount: req.RefundAmount, + }, nil +} + +// createRefundRecordAndUpdateOrder 创建退款记录并更新订单状态 +func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, orderStatus, refundStatus string) error { + return l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { + // 创建退款记录 + refund := &model.OrderRefund{ + RefundNo: refundNo, + PlatformRefundId: l.createNullString(platformRefundId), + OrderId: order.Id, + UserId: order.UserId, + ProductId: order.ProductId, + RefundAmount: req.RefundAmount, + RefundReason: l.createNullString(req.RefundReason), + Status: refundStatus, // 使用传入的状态,不再硬编码 + RefundTime: sql.NullTime{Time: time.Now(), Valid: true}, + } + + if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil { + return fmt.Errorf("创建退款记录失败: %v", err) + } + + // 更新订单状态 + order.Status = orderStatus + if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil { + return fmt.Errorf("更新订单状态失败: %v", err) + } + + return nil + }) +} + +// createRefundRecordOnly 仅创建退款记录,不更新订单状态(用于退款失败的情况) +func (l *AdminRefundOrderLogic) createRefundRecordOnly(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, refundStatus string) error { + refund := &model.OrderRefund{ + RefundNo: refundNo, + PlatformRefundId: l.createNullString(platformRefundId), + OrderId: order.Id, + UserId: order.UserId, + ProductId: order.ProductId, + RefundAmount: req.RefundAmount, + RefundReason: l.createNullString(req.RefundReason), + Status: refundStatus, + RefundTime: sql.NullTime{Time: time.Now(), Valid: true}, + } + + _, err := l.svcCtx.OrderRefundModel.Insert(l.ctx, nil, refund) + if err != nil { + return fmt.Errorf("创建退款记录失败: %v", err) + } + return nil +} + +// generateRefundNo 生成退款单号 +func (l *AdminRefundOrderLogic) generateRefundNo(orderNo string) string { + return fmt.Sprintf("%s%s", RefundNoPrefix, orderNo) +} + +// createNullString 创建 sql.NullString +func (l *AdminRefundOrderLogic) createNullString(value string) sql.NullString { + return sql.NullString{ + String: value, + Valid: value != "", + } } diff --git a/app/main/api/internal/logic/admin_order/adminretryagentprocesslogic.go b/app/main/api/internal/logic/admin_order/adminretryagentprocesslogic.go new file mode 100644 index 0000000..997a460 --- /dev/null +++ b/app/main/api/internal/logic/admin_order/adminretryagentprocesslogic.go @@ -0,0 +1,55 @@ +package admin_order + +import ( + "context" + "time" + + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type AdminRetryAgentProcessLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAdminRetryAgentProcessLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRetryAgentProcessLogic { + return &AdminRetryAgentProcessLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AdminRetryAgentProcessLogic) AdminRetryAgentProcess(req *types.AdminRetryAgentProcessReq) (resp *types.AdminRetryAgentProcessResp, err error) { + // 调用AgentService的重新执行代理处理方法 + err = l.svcCtx.AgentService.RetryAgentProcess(l.ctx, req.Id) + if err != nil { + // 检查是否是"已经处理"的错误 + if err.Error() == "代理处理已经成功,无需重新执行" { + return &types.AdminRetryAgentProcessResp{ + Status: "already_processed", + Message: "代理处理已经成功,无需重新执行", + ProcessedAt: time.Now().Format("2006-01-02 15:04:05"), + }, nil + } + + // 其他错误 + logx.Errorf("重新执行代理处理失败,订单ID: %d, 错误: %v", req.Id, err) + return &types.AdminRetryAgentProcessResp{ + Status: "failed", + Message: err.Error(), + ProcessedAt: time.Now().Format("2006-01-02 15:04:05"), + }, nil + } + + // 执行成功 + return &types.AdminRetryAgentProcessResp{ + Status: "success", + Message: "代理处理重新执行成功", + ProcessedAt: time.Now().Format("2006-01-02 15:04:05"), + }, nil +} diff --git a/app/main/api/internal/logic/agent/agentwithdrawallogic.go b/app/main/api/internal/logic/agent/agentwithdrawallogic.go index c84a437..c9b94f6 100644 --- a/app/main/api/internal/logic/agent/agentwithdrawallogic.go +++ b/app/main/api/internal/logic/agent/agentwithdrawallogic.go @@ -353,6 +353,15 @@ func (l *AgentWithdrawalLogic) updateWithdrawalStatus(outBizNo string, status in return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err) } } + + // 提现成功后,给上级代理发放提现奖励 + withdrawRewardErr := l.svcCtx.AgentService.GiveWithdrawReward(ctx, record.AgentId, record.Amount, session) + if withdrawRewardErr != nil { + l.Logger.Errorf("发放提现奖励失败,代理ID:%d,提现金额:%f,错误:%+v", record.AgentId, record.Amount, withdrawRewardErr) + // 提现奖励失败不影响主流程,只记录日志 + } else { + l.Logger.Infof("发放提现奖励成功,代理ID:%d,提现金额:%f", record.AgentId, record.Amount) + } } return nil }) diff --git a/app/main/api/internal/logic/agent/getlinkdatalogic.go b/app/main/api/internal/logic/agent/getlinkdatalogic.go index 8111b63..9780a6d 100644 --- a/app/main/api/internal/logic/agent/getlinkdatalogic.go +++ b/app/main/api/internal/logic/agent/getlinkdatalogic.go @@ -4,13 +4,16 @@ import ( "context" "tydata-server/common/xerr" + "github.com/Masterminds/squirrel" "github.com/jinzhu/copier" "github.com/pkg/errors" "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" + "tydata-server/app/main/model" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/mr" ) type GetLinkDataLogic struct { @@ -37,9 +40,46 @@ func (l *GetLinkDataLogic) GetLinkData(req *types.GetLinkDataReq) (resp *types.G if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理链接数据, %v", err) } + + // 查询产品关联的 feature + build := l.svcCtx.ProductFeatureModel.SelectBuilder().Where(squirrel.Eq{ + "product_id": productModel.Id, + }) + productFeatureAll, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, build, "") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理链接数据, 查找产品关联错误: %v", err) + } + var product types.Product - copier.Copy(&product, productModel) + err = copier.Copy(&product, productModel) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理链接数据, 产品信息结构体复制失败, %v", err) + } product.SellPrice = agentLinkModel.Price + + // 并发查询所有 feature 详情 + mr.MapReduceVoid(func(source chan<- interface{}) { + for _, productFeature := range productFeatureAll { + source <- productFeature.FeatureId + } + }, func(item interface{}, writer mr.Writer[*model.Feature], cancel func(error)) { + id := item.(int64) + + feature, findFeatureErr := l.svcCtx.FeatureModel.FindOne(l.ctx, id) + if findFeatureErr != nil { + logx.WithContext(l.ctx).Errorf("获取代理链接数据, 查找关联feature错误: %d, err:%v", id, findFeatureErr) + return + } + if feature != nil && feature.Id > 0 { + writer.Write(feature) + } + }, func(pipe <-chan *model.Feature, cancel func(error)) { + for item := range pipe { + var feature types.Feature + _ = copier.Copy(&feature, item) + product.Features = append(product.Features, feature) + } + }) return &types.GetLinkDataResp{ Product: product, }, nil diff --git a/app/main/api/internal/logic/agent/getmembershipinfologic.go b/app/main/api/internal/logic/agent/getmembershipinfologic.go new file mode 100644 index 0000000..b4a916f --- /dev/null +++ b/app/main/api/internal/logic/agent/getmembershipinfologic.go @@ -0,0 +1,100 @@ +package agent + +import ( + "context" + + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/api/internal/types" + "tydata-server/app/main/model" + "tydata-server/common/xerr" + "tydata-server/pkg/lzkit/lzUtils" + + "github.com/jinzhu/copier" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/logx" +) + +type GetMembershipInfoLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetMembershipInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMembershipInfoLogic { + return &GetMembershipInfoLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetMembershipInfoLogic) GetMembershipInfo() (resp *types.GetMembershipInfoResp, err error) { + // 获取普通代理配置 + normalConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameNormal) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取普通代理配置失败: %v", err) + } + + // 获取VIP会员配置 + vipConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameVIP) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取VIP会员配置失败: %v", err) + } + + // 获取SVIP会员配置 + svipConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameSVIP) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取SVIP会员配置失败: %v", err) + } + + // 转换配置的辅助函数 + convertConfig := func(config *model.AgentMembershipConfig) (types.MembershipConfigInfo, error) { + var configInfo types.MembershipConfigInfo + err := copier.Copy(&configInfo, config) + if err != nil { + return configInfo, err + } + // 转换Null类型字段 + configInfo.Price = lzUtils.NullFloat64ToFloat64(config.Price) + configInfo.ReportCommission = lzUtils.NullFloat64ToFloat64(config.ReportCommission) + configInfo.LowerActivityReward = lzUtils.NullFloat64ToFloat64(config.LowerActivityReward) + configInfo.NewActivityReward = lzUtils.NullFloat64ToFloat64(config.NewActivityReward) + configInfo.LowerStandardCount = lzUtils.NullInt64ToInt64(config.LowerStandardCount) + configInfo.NewLowerStandardCount = lzUtils.NullInt64ToInt64(config.NewLowerStandardCount) + configInfo.LowerWithdrawRewardRatio = lzUtils.NullFloat64ToFloat64(config.LowerWithdrawRewardRatio) + configInfo.LowerConvertVipReward = lzUtils.NullFloat64ToFloat64(config.LowerConvertVipReward) + configInfo.LowerConvertSvipReward = lzUtils.NullFloat64ToFloat64(config.LowerConvertSvipReward) + configInfo.ExemptionAmount = lzUtils.NullFloat64ToFloat64(config.ExemptionAmount) + configInfo.PriceIncreaseMax = lzUtils.NullFloat64ToFloat64(config.PriceIncreaseMax) + configInfo.PriceRatio = lzUtils.NullFloat64ToFloat64(config.PriceRatio) + configInfo.PriceIncreaseAmount = lzUtils.NullFloat64ToFloat64(config.PriceIncreaseAmount) + return configInfo, nil + } + + // 转换普通代理配置 + normalConfigInfo, err := convertConfig(normalConfig) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换普通代理配置失败: %v", err) + } + + // 转换VIP配置 + vipConfigInfo, err := convertConfig(vipConfig) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换VIP配置失败: %v", err) + } + + // 转换SVIP配置 + svipConfigInfo, err := convertConfig(svipConfig) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换SVIP配置失败: %v", err) + } + + // 构建响应数据 + resp = &types.GetMembershipInfoResp{ + NormalConfig: normalConfigInfo, + VipConfig: vipConfigInfo, + SvipConfig: svipConfigInfo, + } + + return resp, nil +} diff --git a/app/main/api/internal/logic/pay/alipaycallbacklogic.go b/app/main/api/internal/logic/pay/alipaycallbacklogic.go index 01e9857..b277497 100644 --- a/app/main/api/internal/logic/pay/alipaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/alipaycallbacklogic.go @@ -2,11 +2,11 @@ package pay import ( "context" - "tydata-server/pkg/lzkit/lzUtils" "fmt" "net/http" "strings" "time" + "tydata-server/pkg/lzkit/lzUtils" "github.com/smartwalle/alipay/v3" @@ -151,22 +151,40 @@ func (l *AlipayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter, return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr) } + // 记录旧等级,用于判断是否为升级 + oldLevel := agentModel.LevelName + // 设置会员等级 agentModel.LevelName = agentOrder.LevelName // 延长会员时间 - // 检查是否是同级续费并记录到日志 - isRenewal := agentModel.LevelName == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid - if isRenewal { - logx.Infof("代理会员续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) + // 检查是否是有效期内续费(不发放奖励)还是重新激活(发放奖励) + isValidRenewal := oldLevel == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid && agentModel.MembershipExpiryTime.Time.After(time.Now()) + if isValidRenewal { + logx.Infof("代理会员有效期内续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) } else { - logx.Infof("代理会员新购或升级成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) + logx.Infof("代理会员新购、升级或重新激活成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) } agentModel.MembershipExpiryTime = lzUtils.RenewMembership(agentModel.MembershipExpiryTime) if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil { return fmt.Errorf("修改代理信息失败: %+v", updateErr) } + + // 如果不是有效期内续费,给上级代理发放升级奖励 + if !isValidRenewal && (agentOrder.LevelName == model.AgentLeveNameVIP || agentOrder.LevelName == model.AgentLeveNameSVIP) { + // 验证升级路径的有效性 + if oldLevel != agentOrder.LevelName { + upgradeRewardErr := l.svcCtx.AgentService.GiveUpgradeReward(transCtx, agentModel.Id, oldLevel, agentOrder.LevelName, session) + if upgradeRewardErr != nil { + logx.Errorf("发放升级奖励失败,代理ID:%d,旧等级:%s,新等级:%s,错误:%+v", agentModel.Id, oldLevel, agentOrder.LevelName, upgradeRewardErr) + // 升级奖励失败不影响主流程,只记录日志 + } else { + logx.Infof("发放升级奖励成功,代理ID:%d,旧等级:%s,新等级:%s", agentModel.Id, oldLevel, agentOrder.LevelName) + } + } + } + return nil }) if err != nil { diff --git a/app/main/api/internal/logic/pay/paymentlogic.go b/app/main/api/internal/logic/pay/paymentlogic.go index 5d86422..66b184b 100644 --- a/app/main/api/internal/logic/pay/paymentlogic.go +++ b/app/main/api/internal/logic/pay/paymentlogic.go @@ -188,7 +188,18 @@ func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx. return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取代理会员配置失败, %+v", err) } + // 验证会员配置价格是否有效 + if !agentMembershipConfig.Price.Valid { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 会员等级%s的价格配置无效", agentVipCache.Type) + } + amount := agentMembershipConfig.Price.Float64 + // 验证价格是否合理 + if amount <= 0 { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 会员等级%s的价格配置无效: %f", agentVipCache.Type, amount) + } + + // 内部用户测试金额 if user.Inside == 1 { amount = 0.01 } diff --git a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go index 87c9a7e..5d46f6b 100644 --- a/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go +++ b/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go @@ -2,13 +2,13 @@ package pay import ( "context" - "tydata-server/app/main/api/internal/service" - "tydata-server/app/main/model" - "tydata-server/pkg/lzkit/lzUtils" "fmt" "net/http" "strings" "time" + "tydata-server/app/main/api/internal/service" + "tydata-server/app/main/model" + "tydata-server/pkg/lzkit/lzUtils" "tydata-server/app/main/api/internal/svc" @@ -150,21 +150,40 @@ func (l *WechatPayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWrite return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr) } + // 记录旧等级,用于判断是否为升级 + oldLevel := agentModel.LevelName + // 设置会员等级 agentModel.LevelName = agentOrder.LevelName // 延长会员时间 - isRenewal := agentModel.LevelName == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid - if isRenewal { - logx.Infof("代理会员续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) + // 检查是否是有效期内续费(不发放奖励)还是重新激活(发放奖励) + isValidRenewal := oldLevel == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid && agentModel.MembershipExpiryTime.Time.After(time.Now()) + if isValidRenewal { + logx.Infof("代理会员有效期内续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) } else { - logx.Infof("代理会员新购或升级成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) + logx.Infof("代理会员新购、升级或重新激活成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName) } agentModel.MembershipExpiryTime = lzUtils.RenewMembership(agentModel.MembershipExpiryTime) if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil { return fmt.Errorf("修改代理信息失败: %+v", updateErr) } + + // 如果不是有效期内续费,给上级代理发放升级奖励 + if !isValidRenewal && (agentOrder.LevelName == model.AgentLeveNameVIP || agentOrder.LevelName == model.AgentLeveNameSVIP) { + // 验证升级路径的有效性 + if oldLevel != agentOrder.LevelName { + upgradeRewardErr := l.svcCtx.AgentService.GiveUpgradeReward(transCtx, agentModel.Id, oldLevel, agentOrder.LevelName, session) + if upgradeRewardErr != nil { + logx.Errorf("发放升级奖励失败,代理ID:%d,旧等级:%s,新等级:%s,错误:%+v", agentModel.Id, oldLevel, agentOrder.LevelName, upgradeRewardErr) + // 升级奖励失败不影响主流程,只记录日志 + } else { + logx.Infof("发放升级奖励成功,代理ID:%d,旧等级:%s,新等级:%s", agentModel.Id, oldLevel, agentOrder.LevelName) + } + } + } + return nil }) diff --git a/app/main/api/internal/logic/pay/wechatpayrefundcallbacklogic.go b/app/main/api/internal/logic/pay/wechatpayrefundcallbacklogic.go index 027fb9f..7828191 100644 --- a/app/main/api/internal/logic/pay/wechatpayrefundcallbacklogic.go +++ b/app/main/api/internal/logic/pay/wechatpayrefundcallbacklogic.go @@ -2,11 +2,18 @@ package pay import ( "context" - "tydata-server/app/main/api/internal/svc" + "database/sql" "net/http" + "strings" + "time" + "tydata-server/app/main/api/internal/svc" + "tydata-server/app/main/model" + "tydata-server/common/globalkey" + "github.com/pkg/errors" "github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/stores/sqlx" ) type WechatPayRefundCallbackLogic struct { @@ -23,33 +30,207 @@ func NewWechatPayRefundCallbackLogic(ctx context.Context, svcCtx *svc.ServiceCon } } -func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error { - notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r) +// handleQueryOrderRefund 处理查询订单退款 +func (l *WechatPayRefundCallbackLogic) handleQueryOrderRefund(orderNo string, status refunddomestic.Status) error { + order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo) if err != nil { - logx.Errorf("微信退款回调,%v", err) - return nil + return errors.Wrapf(err, "查找查询订单信息失败: %s", orderNo) } - order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo) - if findOrderErr != nil { - logx.Errorf("微信退款回调,查找订单信息失败: %+v", findOrderErr) + + // 检查订单是否已经处理过退款 + if order.Status == model.OrderStatusRefunded { + logx.Infof("订单已经是退款状态,无需重复处理: orderNo=%s", orderNo) return nil } - switch *notification.Status { + // 只处理成功和失败状态 + var orderStatus, refundStatus string + switch status { case refunddomestic.STATUS_SUCCESS: - order.Status = "refunded" + orderStatus = model.OrderStatusRefunded + refundStatus = model.OrderRefundStatusSuccess + case refunddomestic.STATUS_CLOSED: + // 退款关闭,保持订单原状态,更新退款记录为失败 + refundStatus = model.OrderRefundStatusFailed case refunddomestic.STATUS_ABNORMAL: - // 异常 - return nil + // 退款异常,保持订单原状态,更新退款记录为失败 + refundStatus = model.OrderRefundStatusFailed default: + // 其他状态暂不处理 return nil } - if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil { - logx.Errorf("微信退款回调,更新订单失败%+v", updateErr) + + // 使用事务同时更新订单和退款记录 + err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { + // 更新订单状态(仅在退款成功时更新) + if status == refunddomestic.STATUS_SUCCESS { + order.Status = orderStatus + order.RefundTime = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + if err := l.svcCtx.OrderModel.UpdateWithVersion(ctx, session, order); err != nil { + return errors.Wrapf(err, "更新查询订单状态失败: %s", orderNo) + } + } + + // 查找最新的pending状态的退款记录 + refund, err := l.findLatestPendingRefund(ctx, order.Id) + if err != nil { + if err == model.ErrNotFound { + logx.Errorf("未找到订单对应的待处理退款记录: orderNo=%s, orderId=%d", orderNo, order.Id) + return nil // 没有退款记录时不报错,只记录警告 + } + return errors.Wrapf(err, "查找退款记录失败: orderNo=%s", orderNo) + } + + // 检查退款记录是否已经处理过 + if refund.Status == model.OrderRefundStatusSuccess { + logx.Infof("退款记录已经是成功状态,无需重复处理: orderNo=%s, refundId=%d", orderNo, refund.Id) + return nil + } + + refund.Status = refundStatus + if status == refunddomestic.STATUS_SUCCESS { + refund.RefundTime = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + } else if status == refunddomestic.STATUS_CLOSED { + refund.CloseTime = sql.NullTime{ + Time: time.Now(), + Valid: true, + } + } + + if _, err := l.svcCtx.OrderRefundModel.Update(ctx, session, refund); err != nil { + return errors.Wrapf(err, "更新退款记录状态失败: orderNo=%s", orderNo) + } + return nil + }) + + if err != nil { + return errors.Wrapf(err, "更新订单和退款记录失败: %s", orderNo) } - // 响应微信回调成功 - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("success")) // 确保只写入一次响应 + return nil } + +// handleAgentOrderRefund 处理代理会员订单退款 +func (l *WechatPayRefundCallbackLogic) handleAgentOrderRefund(orderNo string, status refunddomestic.Status) error { + order, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, orderNo) + if err != nil { + return errors.Wrapf(err, "查找代理会员订单信息失败: %s", orderNo) + } + + // 检查订单是否已经处理过退款 + if order.Status == "refunded" { + logx.Infof("代理会员订单已经是退款状态,无需重复处理: orderNo=%s", orderNo) + return nil + } + + if status == refunddomestic.STATUS_SUCCESS { + order.Status = "refunded" + } else if status == refunddomestic.STATUS_ABNORMAL { + return nil // 异常状态直接返回 + } else { + return nil // 其他状态直接返回 + } + + if err := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(l.ctx, nil, order); err != nil { + return errors.Wrapf(err, "更新代理会员订单状态失败: %s", orderNo) + } + + return nil +} + +// sendSuccessResponse 发送成功响应 +func (l *WechatPayRefundCallbackLogic) sendSuccessResponse(w http.ResponseWriter) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("success")) +} + +func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error { + // 1. 处理微信退款通知 + notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r) + if err != nil { + logx.Errorf("微信退款回调处理失败: %v", err) + l.sendSuccessResponse(w) + return nil + } + + // 2. 检查关键字段是否为空 + if notification.OutTradeNo == nil { + logx.Errorf("微信退款回调OutTradeNo字段为空") + l.sendSuccessResponse(w) + return nil + } + + orderNo := *notification.OutTradeNo + + // 3. 判断退款状态,优先使用Status,如果Status为nil则使用SuccessTime判断 + var status refunddomestic.Status + var statusDetermined bool = false + + if notification.Status != nil { + status = *notification.Status + statusDetermined = true + } else if notification.SuccessTime != nil && !notification.SuccessTime.IsZero() { + // 如果Status为空但SuccessTime有值,说明退款成功 + status = refunddomestic.STATUS_SUCCESS + statusDetermined = true + } else { + logx.Errorf("微信退款回调Status和SuccessTime都为空,无法确定退款状态: orderNo=%s", orderNo) + l.sendSuccessResponse(w) + return nil + } + + if !statusDetermined { + logx.Errorf("微信退款回调无法确定退款状态: orderNo=%s", orderNo) + l.sendSuccessResponse(w) + return nil + } + + var processErr error + + // 4. 根据订单号前缀处理不同类型的订单 + switch { + case strings.HasPrefix(orderNo, "Q_"): + processErr = l.handleQueryOrderRefund(orderNo, status) + case strings.HasPrefix(orderNo, "A_"): + processErr = l.handleAgentOrderRefund(orderNo, status) + default: + // 兼容旧订单,假设没有前缀的是查询订单 + processErr = l.handleQueryOrderRefund(orderNo, status) + } + + // 5. 处理错误并响应 + if processErr != nil { + logx.Errorf("处理退款订单失败: orderNo=%s, err=%v", orderNo, processErr) + } + + // 无论处理是否成功,都返回成功响应给微信 + l.sendSuccessResponse(w) + return nil +} + +// findLatestPendingRefund 查找订单最新的pending状态退款记录 +func (l *WechatPayRefundCallbackLogic) findLatestPendingRefund(ctx context.Context, orderId int64) (*model.OrderRefund, error) { + // 使用SelectBuilder查询最新的pending状态退款记录 + builder := l.svcCtx.OrderRefundModel.SelectBuilder(). + Where("order_id = ? AND status = ? AND del_state = ?", orderId, model.OrderRefundStatusPending, globalkey.DelStateNo). + OrderBy("id DESC"). + Limit(1) + + refunds, err := l.svcCtx.OrderRefundModel.FindAll(ctx, builder, "") + if err != nil { + return nil, err + } + + if len(refunds) == 0 { + return nil, model.ErrNotFound + } + + return refunds[0], nil +} diff --git a/app/main/api/internal/logic/query/querydetailbyorderidlogic.go b/app/main/api/internal/logic/query/querydetailbyorderidlogic.go index c1f7a06..1224f08 100644 --- a/app/main/api/internal/logic/query/querydetailbyorderidlogic.go +++ b/app/main/api/internal/logic/query/querydetailbyorderidlogic.go @@ -2,14 +2,14 @@ package query import ( "context" - "tydata-server/common/ctxdata" - "tydata-server/common/xerr" - "tydata-server/pkg/lzkit/crypto" - "tydata-server/pkg/lzkit/lzUtils" "database/sql" "encoding/hex" "encoding/json" "fmt" + "tydata-server/common/ctxdata" + "tydata-server/common/xerr" + "tydata-server/pkg/lzkit/crypto" + "tydata-server/pkg/lzkit/lzUtils" "github.com/jinzhu/copier" "github.com/pkg/errors" @@ -104,6 +104,7 @@ func (l *QueryDetailByOrderIdLogic) QueryDetailByOrderId(req *types.QueryDetailB return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err) } query.ProductName = product.ProductName + query.Product = product.ProductEn return &types.QueryDetailByOrderIdResp{ Query: query, }, nil diff --git a/app/main/api/internal/logic/query/querydetailbyordernologic.go b/app/main/api/internal/logic/query/querydetailbyordernologic.go index 0744903..dd61bcc 100644 --- a/app/main/api/internal/logic/query/querydetailbyordernologic.go +++ b/app/main/api/internal/logic/query/querydetailbyordernologic.go @@ -2,10 +2,10 @@ package query import ( "context" - "tydata-server/common/ctxdata" - "tydata-server/common/xerr" "encoding/hex" "fmt" + "tydata-server/common/ctxdata" + "tydata-server/common/xerr" "github.com/jinzhu/copier" "github.com/pkg/errors" @@ -94,6 +94,7 @@ func (l *QueryDetailByOrderNoLogic) QueryDetailByOrderNo(req *types.QueryDetailB if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err) } + query.Product = product.ProductEn query.ProductName = product.ProductName return &types.QueryDetailByOrderNoResp{ Query: query, diff --git a/app/main/api/internal/logic/query/queryexamplelogic.go b/app/main/api/internal/logic/query/queryexamplelogic.go index 5c1b720..e39bfd6 100644 --- a/app/main/api/internal/logic/query/queryexamplelogic.go +++ b/app/main/api/internal/logic/query/queryexamplelogic.go @@ -37,6 +37,7 @@ func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp *type // 创建一个空的Query结构体来存储结果 query := types.Query{ + Product: product.ProductEn, ProductName: product.ProductName, QueryData: make([]types.QueryItem, 0), QueryParams: make(map[string]interface{}), diff --git a/app/main/api/internal/logic/query/querylistlogic.go b/app/main/api/internal/logic/query/querylistlogic.go index b586c37..7fa82da 100644 --- a/app/main/api/internal/logic/query/querylistlogic.go +++ b/app/main/api/internal/logic/query/querylistlogic.go @@ -4,6 +4,7 @@ import ( "context" "tydata-server/app/main/api/internal/svc" "tydata-server/app/main/api/internal/types" + "tydata-server/app/main/model" "tydata-server/common/ctxdata" "tydata-server/common/xerr" @@ -58,7 +59,14 @@ func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryLi if findProductErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err) } + + // 检查订单状态,如果订单已退款,则设置查询状态为已退款 + order, findOrderErr := l.svcCtx.OrderModel.FindOne(l.ctx, queryModel.OrderId) + if findOrderErr == nil && order.Status == model.OrderStatusRefunded { + query.QueryState = model.QueryStateRefunded + } query.ProductName = product.ProductName + query.Product = product.ProductEn list = append(list, query) } } diff --git a/app/main/api/internal/logic/query/querysharedetaillogic.go b/app/main/api/internal/logic/query/querysharedetaillogic.go index 51811e3..5a12a08 100644 --- a/app/main/api/internal/logic/query/querysharedetaillogic.go +++ b/app/main/api/internal/logic/query/querysharedetaillogic.go @@ -103,6 +103,7 @@ func (l *QueryShareDetailLogic) QueryShareDetail(req *types.QueryShareDetailReq) return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err) } query.ProductName = product.ProductName + query.Product = product.ProductEn return &types.QueryShareDetailResp{ Status: "success", Query: query, diff --git a/app/main/api/internal/service/agentService.go b/app/main/api/internal/service/agentService.go index 45adb7b..d4f3ffa 100644 --- a/app/main/api/internal/service/agentService.go +++ b/app/main/api/internal/service/agentService.go @@ -12,6 +12,7 @@ import ( type AgentService struct { config config.Config + OrderModel model.OrderModel AgentModel model.AgentModel AgentAuditModel model.AgentAuditModel AgentClosureModel model.AgentClosureModel @@ -30,7 +31,7 @@ type AgentService struct { AgentWithdrawalModel model.AgentWithdrawalModel } -func NewAgentService(c config.Config, agentModel model.AgentModel, agentAuditModel model.AgentAuditModel, +func NewAgentService(c config.Config, orderModel model.OrderModel, agentModel model.AgentModel, agentAuditModel model.AgentAuditModel, agentClosureModel model.AgentClosureModel, agentCommissionModel model.AgentCommissionModel, agentCommissionDeductionModel model.AgentCommissionDeductionModel, agentWalletModel model.AgentWalletModel, agentLinkModel model.AgentLinkModel, agentOrderModel model.AgentOrderModel, agentRewardsModel model.AgentRewardsModel, agentMembershipConfigModel model.AgentMembershipConfigModel, @@ -41,6 +42,7 @@ func NewAgentService(c config.Config, agentModel model.AgentModel, agentAuditMod return &AgentService{ config: c, + OrderModel: orderModel, AgentModel: agentModel, AgentAuditModel: agentAuditModel, AgentClosureModel: agentClosureModel, @@ -99,10 +101,10 @@ func (l *AgentService) AgentProcess(ctx context.Context, order *model.Order) err if AgentClosureModel != nil { AncestorId := AgentClosureModel.AncestorId AncestorModel, findAgentModelErr := l.AgentModel.FindOne(transCtx, AncestorId) - if findAgentModelErr != nil != errors.Is(findAgentModelErr, model.ErrNotFound) { + if findAgentModelErr != nil && !errors.Is(findAgentModelErr, model.ErrNotFound) { return findAgentModelErr } - if AgentClosureModel != nil { + if AncestorModel != nil { if AncestorModel.LevelName == "" { AncestorModel.LevelName = model.AgentLeveNameNormal } @@ -271,6 +273,10 @@ func (l *AgentService) CommissionCost(ctx context.Context, descendantId int64, A // 拥有则查看该上级设定的成本 agentMembershipUserConfigModel, findAgentMembershipUserConfigModelErr := l.AgentMembershipUserConfigModel.FindOneByAgentIdProductId(ctx, AncestorId, productID) if findAgentMembershipUserConfigModelErr != nil { + // 如果上级没有配置该产品的定价规则,则跳过成本计算 + if errors.Is(findAgentMembershipUserConfigModelErr, model.ErrNotFound) { + return 0, nil + } return 0, findAgentMembershipUserConfigModelErr } @@ -301,6 +307,10 @@ func (l *AgentService) CommissionPricing(ctx context.Context, descendantId int64 // 拥有则查看该上级设定的成本 agentMembershipUserConfigModel, findAgentMembershipUserConfigModelErr := l.AgentMembershipUserConfigModel.FindOneByAgentIdProductId(ctx, AncestorId, productID) if findAgentMembershipUserConfigModelErr != nil { + // 如果上级没有配置该产品的定价规则,则跳过成本计算 + if errors.Is(findAgentMembershipUserConfigModelErr, model.ErrNotFound) { + return 0, nil + } return 0, findAgentMembershipUserConfigModelErr } @@ -332,13 +342,247 @@ func (l *AgentService) CommissionPricing(ctx context.Context, descendantId int64 return 0, nil } -//func (l *AgentService) UpgradeVip(ctx context.Context, agentID int64, leve string, session sqlx.Session) error { -// agentModel, err := l.AgentModel.FindOne(ctx, agentID) -// if err != nil { -// return err -// } -// if agentModel.LevelName != model.AgentLeveNameNormal { -// return fmt.Errorf("已经是会员") -// } -// return nil -//} +// GiveUpgradeReward 给上级代理发放下级升级奖励 +func (l *AgentService) GiveUpgradeReward(ctx context.Context, agentID int64, oldLevel, newLevel string, session sqlx.Session) error { + // 查找上级代理 + agentClosureModel, err := l.AgentClosureModel.FindOneByDescendantIdDepth(ctx, agentID, 1) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + // 没有上级代理,直接返回 + return nil + } + return err + } + + ancestorID := agentClosureModel.AncestorId + ancestorModel, err := l.AgentModel.FindOne(ctx, ancestorID) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + // 上级代理不存在,直接返回 + return nil + } + return err + } + if ancestorModel == nil { + // 上级代理不存在,直接返回 + return nil + } + + // 获取上级代理的等级配置 + if ancestorModel.LevelName == "" { + ancestorModel.LevelName = model.AgentLeveNameNormal + } + agentMembershipConfigModel, err := l.AgentMembershipConfigModel.FindOneByLevelName(ctx, ancestorModel.LevelName) + if err != nil { + return err + } + + // 根据升级路径计算奖励金额差额 + var rewardAmount float64 + var rewardType string + + // 获取各等级的奖励金额 + var vipRewardAmount float64 + var svipRewardAmount float64 + + if agentMembershipConfigModel.LowerConvertVipReward.Valid { + vipRewardAmount = agentMembershipConfigModel.LowerConvertVipReward.Float64 + } + if agentMembershipConfigModel.LowerConvertSvipReward.Valid { + svipRewardAmount = agentMembershipConfigModel.LowerConvertSvipReward.Float64 + } + + // 根据升级路径计算实际奖励金额 + switch { + case oldLevel == "" || oldLevel == model.AgentLeveNameNormal: + // 普通代理升级 + switch newLevel { + case model.AgentLeveNameVIP: + rewardAmount = vipRewardAmount + rewardType = model.AgentRewardsTypeDescendantUpgradeVip + case model.AgentLeveNameSVIP: + rewardAmount = svipRewardAmount + rewardType = model.AgentRewardsTypeDescendantUpgradeSvip + default: + // 无效的升级路径,直接返回 + return nil + } + case oldLevel == model.AgentLeveNameVIP && newLevel == model.AgentLeveNameSVIP: + // VIP升级到SVIP,发放差额奖励 + rewardAmount = svipRewardAmount - vipRewardAmount + rewardType = model.AgentRewardsTypeDescendantUpgradeSvip + // 如果差额为负数或零,不发放奖励 + if rewardAmount <= 0 { + return nil + } + default: + // 其他无效的升级路径(如SVIP降级等),直接返回 + return nil + } + + // 如果有奖励金额,则发放奖励 + if rewardAmount > 0 { + // 创建奖励记录 + agentRewards := model.AgentRewards{ + AgentId: ancestorID, + Amount: rewardAmount, + RelationAgentId: lzUtils.Int64ToNullInt64(agentID), + Type: rewardType, + } + + _, err = l.AgentRewardsModel.Insert(ctx, session, &agentRewards) + if err != nil { + return err + } + + // 更新上级代理钱包 + ancestorWallet, err := l.AgentWalletModel.FindOneByAgentId(ctx, ancestorID) + if err != nil { + return err + } + + ancestorWallet.Balance += rewardAmount + ancestorWallet.TotalEarnings += rewardAmount + err = l.AgentWalletModel.UpdateWithVersion(ctx, session, ancestorWallet) + if err != nil { + return err + } + } + + return nil +} + +// GiveWithdrawReward 给上级代理发放下级提现奖励 +func (l *AgentService) GiveWithdrawReward(ctx context.Context, agentID int64, withdrawAmount float64, session sqlx.Session) error { + // 验证提现金额 + if withdrawAmount <= 0 { + return nil + } + // 查找上级代理 + agentClosureModel, err := l.AgentClosureModel.FindOneByDescendantIdDepth(ctx, agentID, 1) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + // 没有上级代理,直接返回 + return nil + } + return err + } + + ancestorID := agentClosureModel.AncestorId + ancestorModel, err := l.AgentModel.FindOne(ctx, ancestorID) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + // 上级代理不存在,直接返回 + return nil + } + return err + } + if ancestorModel == nil { + // 上级代理不存在,直接返回 + return nil + } + + // 获取上级代理的等级配置 + if ancestorModel.LevelName == "" { + ancestorModel.LevelName = model.AgentLeveNameNormal + } + agentMembershipConfigModel, err := l.AgentMembershipConfigModel.FindOneByLevelName(ctx, ancestorModel.LevelName) + if err != nil { + return err + } + + // 计算提现奖励金额 + if agentMembershipConfigModel.LowerWithdrawRewardRatio.Valid { + rewardRatio := agentMembershipConfigModel.LowerWithdrawRewardRatio.Float64 + // 验证奖励比例的有效性(0-1之间) + if rewardRatio < 0 || rewardRatio > 1 { + // 无效的奖励比例,直接返回 + return nil + } + rewardAmount := withdrawAmount * rewardRatio + + if rewardAmount > 0 { + // 创建奖励记录 + agentRewards := model.AgentRewards{ + AgentId: ancestorID, + Amount: rewardAmount, + RelationAgentId: lzUtils.Int64ToNullInt64(agentID), + Type: model.AgentRewardsTypeDescendantWithdraw, + } + + _, err = l.AgentRewardsModel.Insert(ctx, session, &agentRewards) + if err != nil { + return err + } + + // 更新上级代理钱包 + ancestorWallet, err := l.AgentWalletModel.FindOneByAgentId(ctx, ancestorID) + if err != nil { + return err + } + + ancestorWallet.Balance += rewardAmount + ancestorWallet.TotalEarnings += rewardAmount + err = l.AgentWalletModel.UpdateWithVersion(ctx, session, ancestorWallet) + if err != nil { + return err + } + } + } + + return nil +} + +// CheckAgentProcessStatus 检查代理处理事务是否已成功 +func (l *AgentService) CheckAgentProcessStatus(ctx context.Context, orderID int64) (bool, error) { + // 检查是否存在代理订单记录 + _, err := l.AgentOrderModel.FindOneByOrderId(ctx, orderID) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + // 没有代理订单记录,说明不是代理推广订单 + return true, nil + } + return false, err + } + + // 检查是否存在代理佣金记录 + // 使用SelectBuilder查询该订单的佣金记录 + selectBuilder := l.AgentCommissionModel.SelectBuilder() + selectBuilder = selectBuilder.Where("order_id = ?", orderID) + selectBuilder = selectBuilder.Where("del_state = ?", 0) // 未删除 + + commissions, err := l.AgentCommissionModel.FindAll(ctx, selectBuilder, "") + if err != nil { + return false, err + } + + // 如果存在佣金记录,说明代理处理已成功 + return len(commissions) > 0, nil +} + +// RetryAgentProcess 重新执行代理处理事务 +func (l *AgentService) RetryAgentProcess(ctx context.Context, orderID int64) error { + // 首先检查订单是否存在 + order, err := l.OrderModel.FindOne(ctx, orderID) + if err != nil { + return err + } + + // 检查订单状态是否为已支付 + if order.Status != "paid" { + return errors.New("订单状态不是已支付,无法执行代理处理") + } + + // 检查代理处理是否已经成功 + alreadyProcessed, err := l.CheckAgentProcessStatus(ctx, orderID) + if err != nil { + return err + } + + if alreadyProcessed { + return errors.New("代理处理已经成功,无需重新执行") + } + + // 执行代理处理 + return l.AgentProcess(ctx, order) +} diff --git a/app/main/api/internal/svc/servicecontext.go b/app/main/api/internal/svc/servicecontext.go index cde2e40..4614792 100644 --- a/app/main/api/internal/svc/servicecontext.go +++ b/app/main/api/internal/svc/servicecontext.go @@ -192,7 +192,7 @@ func NewServiceContext(c config.Config) *ServiceContext { apiRequestService := service.NewApiRequestService(c, featureModel, productFeatureModel, tianyuanapi) verificationService := service.NewVerificationService(c, tianyuanapi, apiRequestService) asynqService := service.NewAsynqService(c) - agentService := service.NewAgentService(c, agentModel, agentAuditModel, agentClosureModel, + agentService := service.NewAgentService(c, orderModel, agentModel, agentAuditModel, agentClosureModel, agentCommissionModel, agentCommissionDeductionModel, agentWalletModel, agentLinkModel, agentOrderModel, agentRewardsModel, agentMembershipConfigModel, agentMembershipRechargeOrderModel, agentMembershipUserConfigModel, agentProductConfigModel, agentPlatformDeductionModel, diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index 33fae80..4ceb6a3 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -433,20 +433,22 @@ type AdminGetOrderDetailReq struct { } type AdminGetOrderDetailResp struct { - Id int64 `json:"id"` // 订单ID - OrderNo string `json:"order_no"` // 商户订单号 - PlatformOrderId string `json:"platform_order_id"` // 支付订单号 - ProductName string `json:"product_name"` // 产品名称 - PaymentPlatform string `json:"payment_platform"` // 支付方式 - PaymentScene string `json:"payment_scene"` // 支付平台 - Amount float64 `json:"amount"` // 金额 - Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 - QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 - CreateTime string `json:"create_time"` // 创建时间 - PayTime string `json:"pay_time"` // 支付时间 - RefundTime string `json:"refund_time"` // 退款时间 - IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 - UpdateTime string `json:"update_time"` // 更新时间 + Id int64 `json:"id"` // 订单ID + OrderNo string `json:"order_no"` // 商户订单号 + PlatformOrderId string `json:"platform_order_id"` // 支付订单号 + ProductName string `json:"product_name"` // 产品名称 + PaymentPlatform string `json:"payment_platform"` // 支付方式 + PaymentScene string `json:"payment_scene"` // 支付平台 + Amount float64 `json:"amount"` // 金额 + Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 + CreateTime string `json:"create_time"` // 创建时间 + PayTime string `json:"pay_time"` // 支付时间 + RefundTime string `json:"refund_time"` // 退款时间 + IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + UpdateTime string `json:"update_time"` // 更新时间 + IsAgentOrder bool `json:"is_agent_order"` // 是否是代理订单 + AgentProcessStatus string `json:"agent_process_status"` // 代理事务处理状态:not_agent-非代理订单,success-处理成功,failed-处理失败,pending-待处理 } type AdminGetOrderListReq struct { @@ -680,6 +682,16 @@ type AdminResetPasswordResp struct { Success bool `json:"success"` // 是否成功 } +type AdminRetryAgentProcessReq struct { + Id int64 `path:"id"` // 订单ID +} + +type AdminRetryAgentProcessResp struct { + Status string `json:"status"` // 执行状态:success-成功,already_processed-已处理,failed-失败 + Message string `json:"message"` // 执行结果消息 + ProcessedAt string `json:"processed_at"` // 处理时间 +} + type AdminRoleApiInfo struct { Id int64 `json:"id"` RoleId int64 `json:"role_id"` @@ -1329,6 +1341,12 @@ type GetLinkDataResp struct { Product } +type GetMembershipInfoResp struct { + NormalConfig MembershipConfigInfo `json:"normal_config"` // 普通代理配置 + VipConfig MembershipConfigInfo `json:"vip_config"` // VIP会员配置 + SvipConfig MembershipConfigInfo `json:"svip_config"` // SVIP会员配置 +} + type GetMenuAllReq struct { } @@ -1495,6 +1513,24 @@ type IapCallbackReq struct { TransactionReceipt string `json:"transaction_receipt" validate:"required"` } +type MembershipConfigInfo struct { + Id int64 `json:"id"` // 主键 + LevelName string `json:"level_name"` // 会员级别名称 + Price float64 `json:"price"` // 会员年费 + ReportCommission float64 `json:"report_commission"` // 直推报告收益 + LowerActivityReward float64 `json:"lower_activity_reward"` // 下级活跃奖励金额 + NewActivityReward float64 `json:"new_activity_reward"` // 新增活跃奖励金额 + LowerStandardCount int64 `json:"lower_standard_count"` // 活跃下级达标个数 + NewLowerStandardCount int64 `json:"new_lower_standard_count"` // 新增活跃下级达标个数 + LowerWithdrawRewardRatio float64 `json:"lower_withdraw_reward_ratio"` // 下级提现奖励比例 + LowerConvertVipReward float64 `json:"lower_convert_vip_reward"` // 下级转化VIP奖励 + LowerConvertSvipReward float64 `json:"lower_convert_svip_reward"` // 下级转化SVIP奖励 + ExemptionAmount float64 `json:"exemption_amount"` // 免审核金额 + PriceIncreaseMax float64 `json:"price_increase_max"` // 提价最高金额 + PriceRatio float64 `json:"price_ratio"` // 提价区间收取比例 + PriceIncreaseAmount float64 `json:"price_increase_amount"` // 在原本成本上加价的金额 +} + type MenuListItem struct { Id int64 `json:"id"` // 菜单ID Pid int64 `json:"pid"` // 父菜单ID @@ -1546,19 +1582,21 @@ type NotificationListItem struct { } type OrderListItem struct { - Id int64 `json:"id"` // 订单ID - OrderNo string `json:"order_no"` // 商户订单号 - PlatformOrderId string `json:"platform_order_id"` // 支付订单号 - ProductName string `json:"product_name"` // 产品名称 - PaymentPlatform string `json:"payment_platform"` // 支付方式 - PaymentScene string `json:"payment_scene"` // 支付平台 - Amount float64 `json:"amount"` // 金额 - Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 - QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 - CreateTime string `json:"create_time"` // 创建时间 - PayTime string `json:"pay_time"` // 支付时间 - RefundTime string `json:"refund_time"` // 退款时间 - IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + Id int64 `json:"id"` // 订单ID + OrderNo string `json:"order_no"` // 商户订单号 + PlatformOrderId string `json:"platform_order_id"` // 支付订单号 + ProductName string `json:"product_name"` // 产品名称 + PaymentPlatform string `json:"payment_platform"` // 支付方式 + PaymentScene string `json:"payment_scene"` // 支付平台 + Amount float64 `json:"amount"` // 金额 + Status string `json:"status"` // 支付状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 + QueryState string `json:"query_state"` // 查询状态:pending-待查询,success-查询成功,failed-查询失败 processing-查询中 + CreateTime string `json:"create_time"` // 创建时间 + PayTime string `json:"pay_time"` // 支付时间 + RefundTime string `json:"refund_time"` // 退款时间 + IsPromotion int64 `json:"is_promotion"` // 是否推广订单:0-否,1-是 + IsAgentOrder bool `json:"is_agent_order"` // 是否是代理订单 + AgentProcessStatus string `json:"agent_process_status"` // 代理事务处理状态:not_agent-非代理订单,success-处理成功,failed-处理失败,pending-待处理 } type PaymentCheckReq struct { @@ -1656,6 +1694,7 @@ type Query struct { Id int64 `json:"id"` // 主键ID OrderId int64 `json:"order_id"` // 订单ID UserId int64 `json:"user_id"` // 用户ID + Product string `json:"product"` // 产品ID ProductName string `json:"product_name"` // 产品ID QueryParams map[string]interface{} `json:"query_params"` QueryData []QueryItem `json:"query_data"` diff --git a/app/main/model/orderRefundModel_gen.go b/app/main/model/orderRefundModel_gen.go index 0e67b28..043c0d4 100644 --- a/app/main/model/orderRefundModel_gen.go +++ b/app/main/model/orderRefundModel_gen.go @@ -10,8 +10,6 @@ import ( "time" - "tydata-server/common/globalkey" - "github.com/Masterminds/squirrel" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/builder" @@ -19,6 +17,7 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stringx" + "tydata-server/common/globalkey" ) var ( @@ -27,17 +26,15 @@ var ( orderRefundRowsExpectAutoSet = strings.Join(stringx.Remove(orderRefundFieldNames, "`id`", "`create_time`", "`update_time`"), ",") orderRefundRowsWithPlaceHolder = strings.Join(stringx.Remove(orderRefundFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?" - cacheHmOrderRefundIdPrefix = "cache:tydata:orderRefund:id:" - cacheHmOrderRefundOrderIdPrefix = "cache:tydata:orderRefund:orderId:" - cacheHmOrderRefundPlatformRefundIdPrefix = "cache:tydata:orderRefund:platformRefundId:" - cacheHmOrderRefundRefundNoPrefix = "cache:tydata:orderRefund:refundNo:" + cacheTydataOrderRefundIdPrefix = "cache:tydata:orderRefund:id:" + cacheTydataOrderRefundPlatformRefundIdPrefix = "cache:tydata:orderRefund:platformRefundId:" + cacheTydataOrderRefundRefundNoPrefix = "cache:tydata:orderRefund:refundNo:" ) type ( orderRefundModel interface { Insert(ctx context.Context, session sqlx.Session, data *OrderRefund) (sql.Result, error) FindOne(ctx context.Context, id int64) (*OrderRefund, error) - FindOneByOrderId(ctx context.Context, orderId int64) (*OrderRefund, error) FindOneByPlatformRefundId(ctx context.Context, platformRefundId sql.NullString) (*OrderRefund, error) FindOneByRefundNo(ctx context.Context, refundNo string) (*OrderRefund, error) Update(ctx context.Context, session sqlx.Session, data *OrderRefund) (sql.Result, error) @@ -89,23 +86,22 @@ func newOrderRefundModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultOrderRefu func (m *defaultOrderRefundModel) Insert(ctx context.Context, session sqlx.Session, data *OrderRefund) (sql.Result, error) { data.DelState = globalkey.DelStateNo - hmOrderRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, data.Id) - hmOrderRefundOrderIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundOrderIdPrefix, data.OrderId) - hmOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) - hmOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheHmOrderRefundRefundNoPrefix, data.RefundNo) + tydataOrderRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, data.Id) + tydataOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) + tydataOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundRefundNoPrefix, data.RefundNo) return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRefundRowsExpectAutoSet) if session != nil { return session.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) } return conn.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime) - }, hmOrderRefundIdKey, hmOrderRefundOrderIdKey, hmOrderRefundPlatformRefundIdKey, hmOrderRefundRefundNoKey) + }, tydataOrderRefundIdKey, tydataOrderRefundPlatformRefundIdKey, tydataOrderRefundRefundNoKey) } func (m *defaultOrderRefundModel) FindOne(ctx context.Context, id int64) (*OrderRefund, error) { - hmOrderRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, id) + tydataOrderRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, id) var resp OrderRefund - err := m.QueryRowCtx(ctx, &resp, hmOrderRefundIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error { + err := m.QueryRowCtx(ctx, &resp, tydataOrderRefundIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error { query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", orderRefundRows, m.table) return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo) }) @@ -119,30 +115,10 @@ func (m *defaultOrderRefundModel) FindOne(ctx context.Context, id int64) (*Order } } -func (m *defaultOrderRefundModel) FindOneByOrderId(ctx context.Context, orderId int64) (*OrderRefund, error) { - hmOrderRefundOrderIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundOrderIdPrefix, orderId) - var resp OrderRefund - err := m.QueryRowIndexCtx(ctx, &resp, hmOrderRefundOrderIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { - query := fmt.Sprintf("select %s from %s where `order_id` = ? and del_state = ? limit 1", orderRefundRows, m.table) - if err := conn.QueryRowCtx(ctx, &resp, query, orderId, globalkey.DelStateNo); err != nil { - return nil, err - } - return resp.Id, nil - }, m.queryPrimary) - switch err { - case nil: - return &resp, nil - case sqlc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } -} - func (m *defaultOrderRefundModel) FindOneByPlatformRefundId(ctx context.Context, platformRefundId sql.NullString) (*OrderRefund, error) { - hmOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundPlatformRefundIdPrefix, platformRefundId) + tydataOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundPlatformRefundIdPrefix, platformRefundId) var resp OrderRefund - err := m.QueryRowIndexCtx(ctx, &resp, hmOrderRefundPlatformRefundIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { + err := m.QueryRowIndexCtx(ctx, &resp, tydataOrderRefundPlatformRefundIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { query := fmt.Sprintf("select %s from %s where `platform_refund_id` = ? and del_state = ? limit 1", orderRefundRows, m.table) if err := conn.QueryRowCtx(ctx, &resp, query, platformRefundId, globalkey.DelStateNo); err != nil { return nil, err @@ -160,9 +136,9 @@ func (m *defaultOrderRefundModel) FindOneByPlatformRefundId(ctx context.Context, } func (m *defaultOrderRefundModel) FindOneByRefundNo(ctx context.Context, refundNo string) (*OrderRefund, error) { - hmOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheHmOrderRefundRefundNoPrefix, refundNo) + tydataOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundRefundNoPrefix, refundNo) var resp OrderRefund - err := m.QueryRowIndexCtx(ctx, &resp, hmOrderRefundRefundNoKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { + err := m.QueryRowIndexCtx(ctx, &resp, tydataOrderRefundRefundNoKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) { query := fmt.Sprintf("select %s from %s where `refund_no` = ? and del_state = ? limit 1", orderRefundRows, m.table) if err := conn.QueryRowCtx(ctx, &resp, query, refundNo, globalkey.DelStateNo); err != nil { return nil, err @@ -184,17 +160,16 @@ func (m *defaultOrderRefundModel) Update(ctx context.Context, session sqlx.Sessi if err != nil { return nil, err } - hmOrderRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, data.Id) - hmOrderRefundOrderIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundOrderIdPrefix, data.OrderId) - hmOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) - hmOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheHmOrderRefundRefundNoPrefix, data.RefundNo) + tydataOrderRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, data.Id) + tydataOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) + tydataOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundRefundNoPrefix, data.RefundNo) return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRefundRowsWithPlaceHolder) if session != nil { return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) } return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id) - }, hmOrderRefundIdKey, hmOrderRefundOrderIdKey, hmOrderRefundPlatformRefundIdKey, hmOrderRefundRefundNoKey) + }, tydataOrderRefundIdKey, tydataOrderRefundPlatformRefundIdKey, tydataOrderRefundRefundNoKey) } func (m *defaultOrderRefundModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *OrderRefund) error { @@ -209,17 +184,16 @@ func (m *defaultOrderRefundModel) UpdateWithVersion(ctx context.Context, session if err != nil { return err } - hmOrderRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, data.Id) - hmOrderRefundOrderIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundOrderIdPrefix, data.OrderId) - hmOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) - hmOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheHmOrderRefundRefundNoPrefix, data.RefundNo) + tydataOrderRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, data.Id) + tydataOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) + tydataOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundRefundNoPrefix, data.RefundNo) sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRefundRowsWithPlaceHolder) if session != nil { return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) } return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion) - }, hmOrderRefundIdKey, hmOrderRefundOrderIdKey, hmOrderRefundPlatformRefundIdKey, hmOrderRefundRefundNoKey) + }, tydataOrderRefundIdKey, tydataOrderRefundPlatformRefundIdKey, tydataOrderRefundRefundNoKey) if err != nil { return err } @@ -442,21 +416,20 @@ func (m *defaultOrderRefundModel) Delete(ctx context.Context, session sqlx.Sessi return err } - hmOrderRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, id) - hmOrderRefundOrderIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundOrderIdPrefix, data.OrderId) - hmOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheHmOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) - hmOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheHmOrderRefundRefundNoPrefix, data.RefundNo) + tydataOrderRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, id) + tydataOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId) + tydataOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTydataOrderRefundRefundNoPrefix, data.RefundNo) _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("delete from %s where `id` = ?", m.table) if session != nil { return session.ExecCtx(ctx, query, id) } return conn.ExecCtx(ctx, query, id) - }, hmOrderRefundIdKey, hmOrderRefundOrderIdKey, hmOrderRefundPlatformRefundIdKey, hmOrderRefundRefundNoKey) + }, tydataOrderRefundIdKey, tydataOrderRefundPlatformRefundIdKey, tydataOrderRefundRefundNoKey) return err } func (m *defaultOrderRefundModel) formatPrimary(primary interface{}) string { - return fmt.Sprintf("%s%v", cacheHmOrderRefundIdPrefix, primary) + return fmt.Sprintf("%s%v", cacheTydataOrderRefundIdPrefix, primary) } func (m *defaultOrderRefundModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error { query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", orderRefundRows, m.table) diff --git a/app/main/model/vars.go b/app/main/model/vars.go index 5299429..fc458e0 100644 --- a/app/main/model/vars.go +++ b/app/main/model/vars.go @@ -57,6 +57,7 @@ const ( QueryStateSuccess = "success" QueryStateProcessing = "processing" QueryStateCleaned = "cleaned" + QueryStateRefunded = "refunded" ) const ( diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index 8a26384..3e6c3b6 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -1,7 +1,7 @@ # 设置输出编码为UTF-8 [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 数据库连接信息 - 修改了URL格式 -$DB_URL = "tydata:5vg67b3UNHu8@(127.0.0.1:21001)/hm" +$DB_URL = "tydata:5vg67b3UNHu8@(127.0.0.1:21001)/tydata" $OUTPUT_DIR = "./model" $TEMPLATE_DIR = "../template" @@ -24,12 +24,12 @@ $tables = @( # "agent_wallet", # "agent_real_name" # "agent_withdrawal" - "agent_withdrawal_tax" + # "agent_withdrawal_tax" # "agent_withdrawal_tax_exemption" # "feature", # "global_notifications" # "order", - # "order_refund" + "order_refund" # "product", # "product_feature", # "query", @@ -58,5 +58,5 @@ $tables = @( # 为每个表生成模型 foreach ($table in $tables) { - goctl model mysql datasource -url="tydata:5vg67b3UNHu8@tcp(127.0.0.1:21001)/hm" -table="$table" -dir="./model" --home="../template" -cache=true --style=goZero + goctl model mysql datasource -url="tydata:5vg67b3UNHu8@tcp(127.0.0.1:21001)/tydata" -table="$table" -dir="./model" --home="../template" -cache=true --style=goZero }