diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index 39aaee3..415a04e 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -73,6 +73,8 @@ const ( OrderAppidNotEqRefundAppid = 1412 OrderNotSupportRefundPart = 1413 OrderRefundAmountError = 1414 + // 关闭订单 + CloseOrderPayed = 1420 //请求日志 RequestLogErrors = 1500 @@ -165,6 +167,8 @@ var MsgZH = map[int]string{ OrderRefundAmountError: "退款金额错误", RefundOutTradeNoSame: "支付商户单号和退款商户单号不能相同", + CloseOrderPayed: "订单已支付成功,无法关闭", + ThirdRefundFail: "第三方退款失败", } var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} diff --git a/app/http/controllers/front/api.go b/app/http/controllers/front/api.go index b853328..eb37208 100644 --- a/app/http/controllers/front/api.go +++ b/app/http/controllers/front/api.go @@ -86,3 +86,16 @@ func QueryOrder(c *gin.Context) { res.Order = data controllers.ApiRes(c, res, errorcode.Success) } + +// 关闭订单 +func CloseOrder(c *gin.Context) { + req := controllers.GetRequest(c).(*front.CloseReqs) + c.Set("OutTradeNo", req.OutTradeNo) + appCheckInfo := controllers.GetAppCheckInfo(c).(*services.AppCheck) + + code, message := thirdpay.ThirdCloseOrder(c.Request.Context(), *req, appCheckInfo, c.ClientIP()) + + var res front.ApiResponse + res.Order = message + controllers.ApiRes(c, res, code) +} diff --git a/app/http/entities/front/pay.go b/app/http/entities/front/pay.go index ee688c3..4b4cf86 100644 --- a/app/http/entities/front/pay.go +++ b/app/http/entities/front/pay.go @@ -43,8 +43,15 @@ type QueryReqs struct { OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"` } +// 关闭订单 +type CloseReqs struct { + ApiCommonBody + PayChannelId int64 `json:"pay_channel_id" validate:"required" label:"支付渠道"` + OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"` +} + // api 接口返回数据, 统一返回结构, order数据会进行加密 type ApiResponse struct { - Order interface{} `json:"order"` + Order interface{} `json:"order,omitempty"` Url string `json:"url,omitempty"` } diff --git a/app/http/requestmapping/front.go b/app/http/requestmapping/front.go index 9589f86..d7c1d4e 100644 --- a/app/http/requestmapping/front.go +++ b/app/http/requestmapping/front.go @@ -9,6 +9,7 @@ var FrontRequestMap = map[string]func() (validForm interface{}, isSaveLog bool){ common.FRONT_V1 + "/pay/url": func() (interface{}, bool) { return new(front.PayReqs), true }, common.FRONT_V1 + "/pay/refund": func() (interface{}, bool) { return new(front.RefundReqs), true }, common.FRONT_V1 + "/pay/query": func() (interface{}, bool) { return new(front.QueryReqs), false }, + common.FRONT_V1 + "/pay/close": func() (interface{}, bool) { return new(front.CloseReqs), true }, } var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{ @@ -16,4 +17,5 @@ var FrontRequestMapBeforeDecrypt = map[string]func() interface{}{ common.FRONT_V1 + "/pay/url": func() interface{} { return new(front.RequestBody) }, common.FRONT_V1 + "/pay/refund": func() interface{} { return new(front.RequestBody) }, common.FRONT_V1 + "/pay/query": func() interface{} { return new(front.RequestBody) }, + common.FRONT_V1 + "/pay/close": func() interface{} { return new(front.CloseReqs) }, } diff --git a/app/http/routes/route.go b/app/http/routes/route.go index 810cd2d..9b79b9a 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -61,6 +61,7 @@ func RegisterRoute(router *gin.Engine) { pay.POST("/url", front.PayUrl) pay.POST("/query", front.QueryOrder) //查询订单 pay.POST("/refund", front.Refund) + pay.POST("/close", front.CloseOrder) } // 测试微信支付唤起 v1.GET("/brokerWechatUrl", front.BrokerWechatUrl) diff --git a/app/services/thirdpay/do/pay.go b/app/services/thirdpay/do/pay.go index c954d7b..2b7670b 100644 --- a/app/services/thirdpay/do/pay.go +++ b/app/services/thirdpay/do/pay.go @@ -7,6 +7,7 @@ import ( "PaymentCenter/app/models/paychannelmodel" "PaymentCenter/app/services" "PaymentCenter/app/third/paymentService/payCommon" + "PaymentCenter/app/utils" "context" "xorm.io/builder" @@ -165,3 +166,41 @@ func (w *Pay) Refund() { w.ThirdMsg = res.ErrorMsg } } + +// 关闭订单 +func (w *Pay) CloseOrder() { + + var ( + payFunc func(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error + ok bool + ) + thirdPay := &paymentService.PayOrderRequest{ + PayChannelId: w.PayParam.Channel.Id, + OrderId: w.Order.Id, + ChannelType: w.PayParam.Channel.ChannelType, + Description: w.Order.Desc, + Amount: w.Order.Amount, + PayerClientIp: w.PayParam.ClientIp, + ReturnUrl: w.PayParam.ReturnUrl, + } + if payFunc, ok = PayWayList[w.PayParam.Channel.ChannelType]; !ok { + w.PayCode = errorcode.PayChannelNotBuild + return + } + err := payFunc(thirdPay, w.PayParam.Channel) + if err != nil { + w.PayCode = errorcode.PayChannelExtJsonError + return + } + + closeRequest := paymentService.OrderCloseRequest{ + OrderId: thirdPay.OrderId, + PayChannel: utils.PayType(thirdPay.ChannelType), + Wx: thirdPay.Wx, + Ali: thirdPay.Ali, + } + + res := paymentService.OrderClose(*w.ctx, closeRequest) + w.ThirdMsg = res.ErrorMsg + w.PayCode = res.Code +} diff --git a/app/services/thirdpay/pay.go b/app/services/thirdpay/pay.go index 24ba937..fccf9f5 100644 --- a/app/services/thirdpay/pay.go +++ b/app/services/thirdpay/pay.go @@ -9,6 +9,7 @@ import ( "PaymentCenter/app/services/thirdpay/api" thirdpay "PaymentCenter/app/services/thirdpay/do" "PaymentCenter/app/services/thirdpay/types" + "PaymentCenter/app/third/paymentService/payCommon" "context" "github.com/jinzhu/copier" ) @@ -91,3 +92,54 @@ func ThirdPay(check *thirdpay.PayCheck) (pay *thirdpay.Pay) { } return } + +func thirdPayCloseCheck(ctx context.Context, payReq *front.CloseReqs, appCheck *services.AppCheck, ip string) (check *thirdpay.PayCheck) { + var req types.Reqs + copier.Copy(&req, payReq) + check = thirdpay.NewPayCheck(&ctx, &req, appCheck, ip) + // 校验表单 + check.CheckPayInfo() + + return +} + +func ThirdCloseOrder(ctx context.Context, closeReq front.CloseReqs, appCheck *services.AppCheck, ip string) (code int, message string) { + check := thirdPayCloseCheck(ctx, &closeReq, appCheck, ip) + if check.CheckCode != errorcode.Success { + return + } + + check.GetOldOrder(&types.OrderFindOne{ + OutTradeNo: check.Reqs.OutTradeNo, + }) + if check.OldOrder != nil { + switch check.OldOrder.Status { + // 1待支付,2支付中, 4支付失败 + case common.ORDER_STATUS_WAITPAY, common.ORDER_STATUS_PAYING, common.ORDER_STATUS_FAILED: + // 调用上游关闭订单 + client := thirdpay.NewPayWithPayCheck(check) + client.Order = check.OldOrder + client.CloseOrder() + code = client.PayCode + message = client.ThirdMsg + // 修改订单状态为已关闭 + if client.PayCode == payCommon.PAY_SUCCESS_CODE { + check.OldOrder.Status = common.ORDER_STATUS_CLOSE + code = services.OrderUpdate(check.OldOrder, "status") + } + + // 3支付成功 + case common.ORDER_STATUS_PAYED: + code = errorcode.CloseOrderPayed + // 5已关闭 + case common.ORDER_STATUS_CLOSE: + code = errorcode.Success + default: + code = errorcode.SystemError + } + } else { + code = errorcode.OrdersNotFound + } + + return +} diff --git a/app/utils/util.go b/app/utils/util.go index c5e9473..93e524b 100644 --- a/app/utils/util.go +++ b/app/utils/util.go @@ -47,8 +47,7 @@ func GetHostIp() string { } func Log(c *gin.Context, name string, msg ...interface{}) { _, file, line, _ := runtime.Caller(1) - timeLayout := "2006-01-01 03:04:05" //转化所需模板 - var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout) + var datetime = time.Now().Format("2006-01-02 15:04:05") fmt.Println(name, msg, file, line, datetime) } @@ -462,3 +461,25 @@ func PayType(payChannel int) int { return 0 } } + +// redis控制访问频率 +func KeyExistsOrSet(key string, expire int) bool { + redisClient := redis.GetRedis() + + // 假设Exists方法返回的是int64类型,表示键是否存在(0为不存在,1为存在) + if exists, err := redisClient.Exists(context.Background(), key).Result(); err == nil && exists == 1 { + return true + } else if err != nil { + // 处理错误情况,可以根据实际情况记录日志或返回错误 + Log(nil, "redis_Exists异常", err) + return false + } + + // 如果键不存在,则设置键并返回false + if err := redisClient.SetEX(context.Background(), key, "", time.Duration(expire)*time.Second).Err(); err != nil { + // 处理设置键时的错误情况 + Log(nil, "redis_SetEX异常", err) + return false + } + return false +}