Compare commits
16 Commits
b91923c44f
...
7f2aceb5a7
| Author | SHA1 | Date |
|---|---|---|
|
|
7f2aceb5a7 | |
|
|
7607a7118c | |
|
|
80bdf8b00a | |
|
|
6f19814aa1 | |
|
|
d84f870745 | |
|
|
1ae0da11e9 | |
|
|
8c2c4bfc20 | |
|
|
1011e33ea2 | |
|
|
f0d430473f | |
|
|
18c62257b4 | |
|
|
f15f96a570 | |
|
|
d32fc30bfc | |
|
|
a30b92ea68 | |
|
|
c3d5ed9774 | |
|
|
a2202ea200 | |
|
|
aa9effcaf4 |
443
README.md
443
README.md
|
|
@ -1,74 +1,393 @@
|
|||
## Snow
|
||||
Snow是一套简单易用的Go语言业务框架,整体逻辑设计简洁,支持HTTP服务、队列调度和任务调度等常用业务场景模式。
|
||||
# PaymentCenter 支付中心
|
||||
|
||||
## Quick start
|
||||
一个基于 Go + Gin 的统一支付网关系统,为商户提供下单、退款、查询、收银台等支付能力,底层对接微信支付、支付宝等第三方支付平台。
|
||||
|
||||
### Build
|
||||
sh build/shell/build.sh
|
||||
> 代码位置:后端接口位于 `app/`,收银台页面模板位于 `front/templates/`。
|
||||
|
||||
### Run
|
||||
```shell
|
||||
1. build/bin/snow -a api #启动Api服务
|
||||
2. build/bin/snow -a cron #启动Cron定时任务服务
|
||||
3. build/bin/snow -a job #启动队列调度服务
|
||||
4. build/bin/snow -a command -m test #执行名称为test的脚本任务
|
||||
---
|
||||
|
||||
## 1. 技术栈
|
||||
|
||||
| 组件 | 选型 |
|
||||
|------|------|
|
||||
| 语言 | Go |
|
||||
| Web 框架 | [Gin](https://github.com/gin-gonic/gin) |
|
||||
| ORM | [xorm](https://xorm.io/) |
|
||||
| 第三方支付 | [go-pay](https://github.com/go-pay/gopay) |
|
||||
| JSON | [bytedance/sonic](https://github.com/bytedance/sonic) |
|
||||
| 参数校验 | go-playground/validator.v9 |
|
||||
| 缓存/分布式锁 | Redis(snow-core/redis) |
|
||||
| 数据库 | MySQL |
|
||||
| 加密算法 | RSA / SM2 / SM4 / AES / DES3 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 目录结构
|
||||
|
||||
```
|
||||
PaymentCenter/
|
||||
├── app/
|
||||
│ ├── constants/ # 常量定义(错误码、公共枚举、pojo)
|
||||
│ │ ├── common/common.go # 订单状态、支付渠道、路由前缀
|
||||
│ │ └── errorcode/ # 错误码与中文消息
|
||||
│ ├── http/
|
||||
│ │ ├── routes/route.go # 路由注册入口
|
||||
│ │ ├── requestmapping/ # 路由→请求结构体映射
|
||||
│ │ ├── middlewares/ # 中间件(CORS、鉴权、加解密、参数校验)
|
||||
│ │ ├── controllers/
|
||||
│ │ │ ├── base.go # 公共:Success/Error/GenRequest/ApiRes
|
||||
│ │ │ ├── front/ # C 端:支付 API、收银台、回调
|
||||
│ │ │ └── backend/ # 管理后台
|
||||
│ │ └── entities/ # 请求/响应结构体
|
||||
│ ├── services/
|
||||
│ │ ├── api_request_valid.go # App 校验 & IP 白名单
|
||||
│ │ ├── order.go # 订单 CRUD & 状态检查
|
||||
│ │ ├── pay_page.go # 收银台渠道列表、订单状态检查
|
||||
│ │ ├── apicrypt/ # RSA/SM2/SM4 加解密实现
|
||||
│ │ └── thirdpay/ # 第三方支付业务封装
|
||||
│ │ ├── pay.go # 下单/退款/关闭主流程
|
||||
│ │ ├── pay_page.go # 收银台业务:V2 预下单、查询
|
||||
│ │ ├── pay_query.go # 三方查询
|
||||
│ │ ├── do/ # 渠道策略层(PayCheck、Pay、PayWay 映射)
|
||||
│ │ └── thirdpay_notify/ # 回调异步通知处理
|
||||
│ ├── third/paymentService/ # go-pay 封装(微信/支付宝底层调用)
|
||||
│ ├── models/ # xorm 实体(orders、app、merchant、pay_channel…)
|
||||
│ ├── data/ # Repository 层(OrderRepo、PayChannelRepo 等)
|
||||
│ ├── utils/ # snowflake、JWT、HTTP client、useragent、DES
|
||||
│ │ └── encrypt/ # AES、RSA、SM2、SM4
|
||||
│ ├── caches/ # 缓存
|
||||
│ └── mq/ # 消息队列
|
||||
└── front/
|
||||
└── templates/
|
||||
├── payPage.html # 收银台主页面
|
||||
├── payTemplateDefault.html # 渠道跳转模板
|
||||
├── success.html # 支付成功(JSAPI 场景)
|
||||
└── fail.html # 支付失败
|
||||
```
|
||||
|
||||
## Documents
|
||||
---
|
||||
|
||||
- [项目地址](https://github.com/qit-team/snow)
|
||||
- [中文文档](https://github.com/qit-team/snow/wiki)
|
||||
- [changelog](https://github.com/qit-team/snow/blob/master/CHANGLOG.md)
|
||||
- [xorm](http://gobook.io/read/github.com/go-xorm/manual-zh-CN/)
|
||||
## 3. 架构分层与调用链
|
||||
|
||||
##
|
||||
<!--
|
||||
```
|
||||
Gin 路由
|
||||
│
|
||||
▼
|
||||
Middleware(CORS → ValidateRequest / ValidatePayRequest → 加解密)
|
||||
│
|
||||
▼
|
||||
Controller(front/ 或 backend/)
|
||||
│
|
||||
▼
|
||||
services/(业务编排 + services/thirdpay/)
|
||||
│
|
||||
▼
|
||||
services/thirdpay/do/(PayCheck → Pay → PayWay 策略)
|
||||
│
|
||||
▼
|
||||
third/paymentService/(go-pay 底层调用)→ 微信 / 支付宝
|
||||
│
|
||||
▼
|
||||
data/(Repository)→ models/(xorm ORM)→ MySQL
|
||||
```
|
||||
|
||||
// validator的示例
|
||||
// HandleTestValidator godoc
|
||||
// @Summary HandleTestValidator的示例
|
||||
// @Description HandleTestValidator的示例
|
||||
// @Tags snow
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param testValidator body entities.TestValidatorRequest true "example of validator"
|
||||
// @Success 200 {array} entities.TestValidatorRequest
|
||||
// @Failure 400 {object} controllers.HTTPError
|
||||
// @Failure 404 {object} controllers.HTTPError
|
||||
// @Failure 500 {object} controllers.HTTPError
|
||||
// @Router /test_validator [post]
|
||||
func HandleTestValidator(c *gin.Context) {
|
||||
request := new(entities.TestValidatorRequest)
|
||||
err := GenRequest(c, request)
|
||||
if err != nil {
|
||||
Error(c, errorcode.ParamError)
|
||||
return
|
||||
}
|
||||
- **控制器层**:只做 HTTP 层的事(绑定请求、调用 service、封装返回)
|
||||
- **服务层**:核心业务(状态机、幂等、分布式锁、渠道路由)
|
||||
- **Repository(data/)**:只做数据库 CRUD,不包含业务逻辑
|
||||
|
||||
Success(c, request)
|
||||
return
|
||||
---
|
||||
|
||||
## 4. C 端接口清单
|
||||
|
||||
> 接口前缀:`/pay/front/api/v1` 或 `/pay/front/api/v2`
|
||||
|
||||
| 方法 | 路由 | 中间件 | 功能 |
|
||||
|------|------|--------|------|
|
||||
| POST | `/notify/wx/:payChannelId` | - | 微信支付回调 |
|
||||
| POST | `/notify/ali/:payChannelId` | - | 支付宝支付回调 |
|
||||
| POST | `/pay/url` (V1) | ValidatePayRequest | 下单,同步返回支付 URL / JsInfo |
|
||||
| POST | `/pay/url` (V2) | ValidatePayRequest | 预下单,仅创建订单,返回收银台 URL |
|
||||
| POST | `/pay/refund` | ValidatePayRequest | 退款 |
|
||||
| POST | `/pay/query` | ValidatePayRequest | 查询订单状态 |
|
||||
| POST | `/pay/close` | ValidatePayRequest | 关闭订单 |
|
||||
| GET | `/payPage?no={id}` | - | 收银台 HTML 页面入口 |
|
||||
| POST | `/payPage/list` | ValidateRequest | 获取可用支付渠道列表 |
|
||||
| GET | `/payPage/submit` | ValidateRequest | 获取支付跳转链接(渲染 payTemplateDefault.html)|
|
||||
| POST | `/payPage/query` | - | 收银台页面轮询订单状态 |
|
||||
| POST | `/ali/getOauth` | ValidateRequest | 支付宝小程序获取 openId |
|
||||
| POST/GET | `/wx/*` | ValidateRequest | 微信授权 / openId / JSAPI / 小程序支付 |
|
||||
|
||||
- 路由定义参见 [app/http/routes/route.go](file:///e:/goproject/goproject/PaymentCenter/app/http/routes/route.go)
|
||||
- 路由→结构体映射参见 [app/http/requestmapping/front.go](file:///e:/goproject/goproject/PaymentCenter/app/http/requestmapping/front.go)
|
||||
|
||||
---
|
||||
|
||||
## 5. 两种下单模式
|
||||
|
||||
### 5.1 模式一:V1 直接下单(`POST /pay/front/api/v1/pay/url`)
|
||||
|
||||
适用于商户自己管理收银台页面:
|
||||
|
||||
1. 商户构造请求 `RequestBody{ app_id, timestamp, data, key }`,加密后发起
|
||||
2. 中间件 `ValidatePayRequest()`:查 App 配置 → 解密 → 反序列化为 `PayReqs`
|
||||
3. 控制器调用 `thirdpay.ThirdPayInfoCheck()` → `thirdpay.ThirdPayUrl()`
|
||||
4. 同步返回 `ApiResponse{ Order, Url, JsInfo }`
|
||||
|
||||
### 5.2 模式二:V2 预下单 + 收银台(推荐)
|
||||
|
||||
适用于商户跳转至我方收银台页面:
|
||||
|
||||
1. 商户调用 `POST /pay/front/api/v2/pay/url`
|
||||
2. `PayUrlV2Service()`:
|
||||
- Redis 分布式锁(`payUrl:{out_trade_no}`,3 秒)
|
||||
- 检查商户是否有可用支付渠道
|
||||
- 按 `out_trade_no + app_id` 查询订单;不存在则新建订单(状态 WAITPAY)
|
||||
- 返回收银台 URL:`https://pay-host/pay/front/api/v1/payPage?no={orders.id}`
|
||||
3. 商户将用户浏览器跳转到收银台
|
||||
4. **收银台页面**(`payPage.html`):
|
||||
- 读取 URL 参数 `no`(**订单自增 ID,不是 out_trade_no**)
|
||||
- `POST /payPage/list?id=xxx` 拉取渠道列表
|
||||
- 单渠道直接跳转 `/payPage/submit`,多渠道让用户选择
|
||||
- 选择后跳转到第三方支付页面
|
||||
- 支付完成后轮询 `/payPage/query`,成功后跳转到商户 `return_url`
|
||||
|
||||
---
|
||||
|
||||
## 6. 收银台页面流程
|
||||
|
||||
```
|
||||
商户后台
|
||||
│ POST /v2/pay/url ─────┐
|
||||
│ ▼
|
||||
│ 支付中心创建订单
|
||||
│ │
|
||||
│ ▼
|
||||
│ 返回 payPage?no={orderId}
|
||||
│
|
||||
└── 用户浏览器 ───► GET payPage.html
|
||||
│
|
||||
├── JS 调 POST /payPage/list 获取渠道
|
||||
│
|
||||
├── GET /payPage/submit 获取跳转链接
|
||||
│ └──► payTemplateDefault.html window.location
|
||||
│
|
||||
├── POST /payPage/query 轮询订单状态
|
||||
│
|
||||
└── 支付成功 → 跳转 return_url
|
||||
```
|
||||
|
||||
页面文件:
|
||||
|
||||
- [payPage.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payPage.html) — 收银台主页(含加载态、渠道选择、状态确认弹窗)
|
||||
- [payTemplateDefault.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payTemplateDefault.html) — 第三方支付跳转
|
||||
- [success.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/success.html) — 微信 JSAPI 成功
|
||||
- [fail.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/fail.html) — 支付失败
|
||||
|
||||
前端注意:`payPage.html` 中的 `API_BASE_URL` 默认写死为 `http://localhost:7081`,部署时需要替换为生产地址。
|
||||
|
||||
---
|
||||
|
||||
## 7. 请求加解密体系
|
||||
|
||||
### 7.1 两个核心中间件
|
||||
|
||||
| 中间件 | 路由 | 说明 |
|
||||
|--------|------|------|
|
||||
| `ValidateRequest()` | 收银台列表、授权、小程序等 | 普通参数解析(form/json)+ validator 校验 + 可选日志 |
|
||||
| `ValidatePayRequest()` | `/pay/url`、`/pay/refund`、`/pay/query`、`/pay/close` | 支付专用:`app_id` 查表 → 按 `key_type` 解密 data → 二次解析校验 |
|
||||
|
||||
中间件代码:[app/http/middlewares/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/middlewares/base.go)
|
||||
|
||||
### 7.2 支付请求结构(加密封装)
|
||||
|
||||
```
|
||||
{
|
||||
"app_id": 123, // 应用 ID,查表得 KeyType
|
||||
"timestamp": 1700000000, // 时间戳
|
||||
"data": "...", // 真实业务参数的密文(PayReqs JSON → 加密 → Base64)
|
||||
"key": "..." // 部分算法所需对称密钥密文
|
||||
}
|
||||
```
|
||||
|
||||
// Address houses a users address information
|
||||
type Address struct {
|
||||
Street string `json:"street" validate:"required" example:"huandaodonglu"`
|
||||
City string `json:"city" validate:"required" example:"xiamen"`
|
||||
Planet string `json:"planet" validate:"required" example:"snow"`
|
||||
Phone string `json:"phone" validate:"required" example:"snow"`
|
||||
}
|
||||
解密后 `data` 对应的业务结构,在 `requestmapping.FrontRequestMap` 中按路由映射。
|
||||
|
||||
// 请求数据结构
|
||||
type TestValidatorRequest struct {
|
||||
//tips,因为组件required不管是没传值或者传 0 or "" 都通过不了,但是如果用指针类型,那么0就是0,而nil无法通过校验
|
||||
Id *int64 `json:"id" validate:"required" example:"1"`
|
||||
Age int `json:"age" validate:"required,gte=0,lte=130" example:"20"`
|
||||
Name *string `json:"name" validate:"required" example:"snow"`
|
||||
Email string `json:"email" validate:"required,email" example:"snow@github.com"`
|
||||
Url string `json:"url" validate:"required" example:"github.com/qit-team/snow"`
|
||||
Mobile string `json:"mobile" validate:"required" example:"snow"`
|
||||
RangeNum int `json:"range_num" validate:"max=10,min=1" example:"3"`
|
||||
TestNum *int `json:"test_num" validate:"required,oneof=5 7 9" example:"7"`
|
||||
Content *string `json:"content" example:"snow"`
|
||||
Addresses []*Address `json:"addresses" validate:"required,dive,required" `
|
||||
}
|
||||
-->
|
||||
### 7.3 加密算法(由 `app.key_type` 决定)
|
||||
|
||||
| 类型 | 实现文件 |
|
||||
|------|---------|
|
||||
| NO_CRYPT | 明文(不加密) |
|
||||
| RSA | [services/apicrypt/rsa.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/rsa.go) |
|
||||
| SM2 | [services/apicrypt/sm2.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/sm2.go) |
|
||||
| SM4 | [services/apicrypt/sm4.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/sm4.go) |
|
||||
|
||||
注册处:[services/apicrypt/types.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/types.go) 中的 `ApiCryptMap`
|
||||
|
||||
### 7.4 响应加密
|
||||
|
||||
- 非生产环境:`controllers.Success/Error` 直接返回 `{ code, message, data }` JSON
|
||||
- 生产环境(`config.GetConf().Env == "production"`):整体 JSON 用 DES3 + Base64 加密后以纯文本返回
|
||||
- 对应方法:`controllers.EncriptJson()`
|
||||
|
||||
---
|
||||
|
||||
## 8. 订单模型 & 状态机
|
||||
|
||||
### 8.1 Orders 表
|
||||
|
||||
字段定义:[app/models/ordersmodel/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/models/ordersmodel/orders.go)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | int64 | 主键,snowflake 生成 |
|
||||
| merchant_id | int64 | 商户 |
|
||||
| pay_channel_id | int64 | 支付渠道实例 |
|
||||
| app_id | int64 | 应用 |
|
||||
| out_trade_no | string(50) | 外部/商户订单号 |
|
||||
| order_type | tinyint | 1=支付, 2=退款 |
|
||||
| refund_order_id | int64 | 退款关联的原订单 |
|
||||
| amount | int | 订单金额,单位:**分** |
|
||||
| actual_amount | int | 实际金额,单位:**分** |
|
||||
| payer_total | int | 付款方金额,单位:**分** |
|
||||
| ext_json | string(1024) | 扩展 JSON |
|
||||
| desc | string(100) | 商品描述 |
|
||||
| status | tinyint | 订单状态(见下) |
|
||||
| create_time / update_time | datetime | 自动维护 |
|
||||
|
||||
### 8.2 订单状态(`constants/common/common.go`)
|
||||
|
||||
| 常量 | 值 | 说明 |
|
||||
|------|----|------|
|
||||
| ORDER_STATUS_WAITPAY | 1 | 待支付(刚创建) |
|
||||
| ORDER_STATUS_PAYING | 2 | 支付中(已调第三方下单) |
|
||||
| ORDER_STATUS_PAYED | 3 | 支付成功 |
|
||||
| ORDER_STATUS_FAILED | 4 | 支付失败 |
|
||||
| ORDER_STATUS_CLOSE | 5 | 已关闭 |
|
||||
|
||||
### 8.3 状态流转
|
||||
|
||||
```
|
||||
WAITPAY(1) ──► PAYING(2) ──┬──► PAYED(3)
|
||||
│ │
|
||||
└─────► CLOSE(5) └──► FAILED(4)
|
||||
```
|
||||
|
||||
状态检查方法:`services.OrderStatusCheck(order)`,位置 [app/services/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/pay_page.go#L89-L103)
|
||||
|
||||
---
|
||||
|
||||
## 9. 支付渠道体系
|
||||
|
||||
### 9.1 渠道类型枚举
|
||||
|
||||
定义在 `constants/common/common.go`:
|
||||
|
||||
| 常量 | 值 | 含义 |
|
||||
|------|----|------|
|
||||
| PAY_CHANNEL_WECHAT_JSAPI | 1 | 微信公众号 JSAPI |
|
||||
| PAY_CHANNEL_WECHAT_H5 | 2 | 微信 H5 |
|
||||
| PAY_CHANNEL_WECHAT_APP | 3 | 微信 APP |
|
||||
| PAY_CHANNEL_WECHAT_NATIVE | 4 | 微信 Native 扫码 |
|
||||
| PAY_CHANNEL_WECHAT_MINI | 5 | 微信小程序 |
|
||||
| PAY_CHANNEL_ALIPAY_WEB | 6 | 支付宝网页/移动应用 |
|
||||
| PAY_CHANNEL_ALIPAY_MINI | 7 | 支付宝小程序 |
|
||||
| PAY_CHANNEL_ALIPAY_JSAPI | 8 | 支付宝 JSAPI |
|
||||
| PAY_CHANNEL_ALIPAY_PC | 9 | 支付宝 PC 网站 |
|
||||
|
||||
### 9.2 策略映射(渠道 → 实现方法)
|
||||
|
||||
- 下单:`services/thirdpay/do/pay_way.go` 的 `PayWayList[channelType]`
|
||||
- 退款:`services/thirdpay/do/refund_way.go` 的 `RefundWayList[channelType]`
|
||||
- 底层统一入口:`third/paymentService/payment_service.go` 的 `PaymentService(ctx, req)`
|
||||
- 根据 `req.ChannelType` 路由到 `AliPayService()` 或 `WechatPayService()`
|
||||
|
||||
### 9.3 客户端环境 → 可用渠道
|
||||
|
||||
- 微信浏览器内 → JSAPI(需要 openId,收银台会自动先走授权)
|
||||
- PC 浏览器 → 微信 Native、支付宝 PC
|
||||
- 手机浏览器(非微信内)→ 微信 H5、支付宝 Web
|
||||
|
||||
实现:`services.PayPageChannelList()` + `services.ClientEnvCheck(ua)`
|
||||
|
||||
---
|
||||
|
||||
## 10. 新增功能的操作清单
|
||||
|
||||
### 10.1 新增一个 C 端 API
|
||||
|
||||
1. 在 `app/http/entities/front/` 定义 Request/Response 结构体
|
||||
2. 在 `app/http/requestmapping/front.go` 的两个 map 中添加路由 → 结构体映射
|
||||
3. 在 `app/http/routes/route.go` 注册路由,挂上合适的中间件
|
||||
4. 在 `app/http/controllers/front/` 对应文件新增 handler(用 `controllers.GetRequest(c).(*front.XXX)` 取参数)
|
||||
5. 在 `app/services/` 或 `app/services/thirdpay/` 实现业务逻辑
|
||||
|
||||
### 10.2 新增一个支付渠道
|
||||
|
||||
1. 在 `constants/common/common.go` 增加 `PAY_CHANNEL_XXX` 常量和 `PayChannelName`/`PayChannelList` 条目
|
||||
2. 在 `services/thirdpay/do/pay_way.go` 的 `PayWayList` 注册实现方法
|
||||
3. 在 `third/paymentService/wechat_service.go` 或 `ali_service.go` 增加对应分支
|
||||
4. 若需区分客户端环境,更新 `OpenInPayChannelMap`
|
||||
|
||||
### 10.3 新增一个页面模板
|
||||
|
||||
1. 在 `front/templates/` 下新增 `.html`
|
||||
2. 路由里通过 `c.HTML(http.StatusOK, "文件名.html", gin.H{...})` 渲染
|
||||
3. `router.LoadHTMLGlob("./front/templates/*")` 已在 routes 中注册
|
||||
|
||||
### 10.4 新增一个错误码
|
||||
|
||||
1. 在 `constants/errorcode/error_code.go` 定义 const,并在 `ErrCodeMap` 注册中文消息
|
||||
2. 使用:`controllers.Error(c, errorcode.XXX)` 或 `controllers.ApiRes(c, nil, code)`
|
||||
|
||||
### 10.5 新增数据模型 / Repository
|
||||
|
||||
1. 在 `app/models/xxxmodel/` 定义结构体(xorm tag + TableName + GetInstance 单例)
|
||||
2. 在 `app/data/` 新增 `XxxRepo` 封装 xorm 操作(推荐配合 `builder.Cond` 拼装条件)
|
||||
3. 在 `app/services/` 新增 `XxxFindOne` / `XxxList` 等服务方法
|
||||
|
||||
---
|
||||
|
||||
## 11. 编码规范与注意事项
|
||||
|
||||
- **金额单位**:全链路使用 **分**(int);前端展示时 `/100` 转元;不得出现 float64 金额
|
||||
- **订单 ID vs out_trade_no**:
|
||||
- `orders.id` = 雪花自增 ID(支付中心内部、收银台查询使用)
|
||||
- `out_trade_no` = 商户外部订单号(商户下单、查询使用)
|
||||
- **不要混用**
|
||||
- **幂等性**:V2 下单通过 Redis 分布式锁(key=`payUrl:{out_trade_no}`,3 秒)+ 数据库 `(out_trade_no, app_id)` 唯一约束保证
|
||||
- **中间件选型**:
|
||||
- 加密支付接口 → `ValidatePayRequest()`
|
||||
- 收银台、授权、小程序等 → `ValidateRequest()`
|
||||
- 回调接口 → 直接在 controller 解析(走第三方验签)
|
||||
- **统一返回**:`controllers.Success/Error/ApiRes/HandCodeRes`,不要手写 JSON
|
||||
- **错误码来源**:`constants/errorcode/error_code.go`,不要硬编码数字
|
||||
- **日志**:`utils.Log(ctx, tag, ...)`;支付链路关键节点必须有日志
|
||||
- **单元测试**:工具类、加解密、snowflake 等均有 `_test.go`,新工具函数建议配套
|
||||
|
||||
---
|
||||
|
||||
## 12. 关键文件速查
|
||||
|
||||
| 功能 | 文件 |
|
||||
|------|------|
|
||||
| 路由注册 | [app/http/routes/route.go](file:///e:/goproject/goproject/PaymentCenter/app/http/routes/route.go) |
|
||||
| 路由→结构体映射 | [app/http/requestmapping/front.go](file:///e:/goproject/goproject/PaymentCenter/app/http/requestmapping/front.go) |
|
||||
| 中间件 | [app/http/middlewares/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/middlewares/base.go) |
|
||||
| 公共返回/参数解析 | [app/http/controllers/base.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/base.go) |
|
||||
| 支付接口 controller | [app/http/controllers/front/api.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/api.go) |
|
||||
| 收银台 controller | [app/http/controllers/front/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/pay_page.go) |
|
||||
| 回调/微信/支付宝 controller | [app/http/controllers/front/payment_controller.go](file:///e:/goproject/goproject/PaymentCenter/app/http/controllers/front/payment_controller.go) |
|
||||
| 请求结构体 | [app/http/entities/front/pay.go](file:///e:/goproject/goproject/PaymentCenter/app/http/entities/front/pay.go) |
|
||||
| 订单服务 | [app/services/order.go](file:///e:/goproject/goproject/PaymentCenter/app/services/order.go) |
|
||||
| 收银台服务(渠道列表/状态检查) | [app/services/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/pay_page.go) |
|
||||
| App 校验 | [app/services/api_request_valid.go](file:///e:/goproject/goproject/PaymentCenter/app/services/api_request_valid.go) |
|
||||
| 第三方支付主流程 | [app/services/thirdpay/pay.go](file:///e:/goproject/goproject/PaymentCenter/app/services/thirdpay/pay.go) |
|
||||
| 收银台/V2 下单 | [app/services/thirdpay/pay_page.go](file:///e:/goproject/goproject/PaymentCenter/app/services/thirdpay/pay_page.go) |
|
||||
| 加解密类型注册 | [app/services/apicrypt/types.go](file:///e:/goproject/goproject/PaymentCenter/app/services/apicrypt/types.go) |
|
||||
| 错误码 | [app/constants/errorcode/error_code.go](file:///e:/goproject/goproject/PaymentCenter/app/constants/errorcode/error_code.go) |
|
||||
| 公共常量 | [app/constants/common/common.go](file:///e:/goproject/goproject/PaymentCenter/app/constants/common/common.go) |
|
||||
| Orders 模型 | [app/models/ordersmodel/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/models/ordersmodel/orders.go) |
|
||||
| Order Repository | [app/data/orders.go](file:///e:/goproject/goproject/PaymentCenter/app/data/orders.go) |
|
||||
| 底层 go-pay 调用入口 | app/third/paymentService/payment_service.go |
|
||||
| 收银台页面 | [front/templates/payPage.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payPage.html) |
|
||||
| 跳转模板 | [front/templates/payTemplateDefault.html](file:///e:/goproject/goproject/PaymentCenter/front/templates/payTemplateDefault.html) |
|
||||
| 雪花 ID 生成 | [app/utils/snowflake/snow_flake.go](file:///e:/goproject/goproject/PaymentCenter/app/utils/snowflake/snow_flake.go) |
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const (
|
|||
PAY_CHANNEL_ALIPAY_MINI = 7
|
||||
PAY_CHANNEL_ALIPAY_JSAPI = 8
|
||||
PAY_CHANNEL_ALIPAY_PC = 9
|
||||
PAY_CHANNEL_PSBC = 11
|
||||
|
||||
// 统一登陆信息
|
||||
ADMIN_USER_ID = "User-Id"
|
||||
|
|
@ -43,6 +44,7 @@ const (
|
|||
|
||||
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
|
||||
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
|
||||
PAY_CHANNLE_TYPE_PSBC = 3 // 支付类型:邮储
|
||||
|
||||
THIRD_ORDER_TYPE_PAY = 1 // 发起支付
|
||||
THIRD_ORDER_TYPE_ORDER_QUERY = 2 // 查询订单
|
||||
|
|
@ -66,6 +68,7 @@ var PayChannelName = map[int]string{
|
|||
PAY_CHANNEL_ALIPAY_MINI: "支付宝支付",
|
||||
PAY_CHANNEL_ALIPAY_JSAPI: "支付宝支付",
|
||||
PAY_CHANNEL_ALIPAY_PC: "支付宝支付",
|
||||
PAY_CHANNEL_PSBC: "邮储支付",
|
||||
}
|
||||
|
||||
var PayChannelList = map[int]string{
|
||||
|
|
@ -77,6 +80,7 @@ var PayChannelList = map[int]string{
|
|||
PAY_CHANNEL_ALIPAY_WEB: "支付宝网页&移动应用",
|
||||
PAY_CHANNEL_ALIPAY_MINI: "支付宝小程序",
|
||||
PAY_CHANNEL_ALIPAY_JSAPI: "支付宝JSAPI",
|
||||
PAY_CHANNEL_PSBC: "邮储JSAPI",
|
||||
}
|
||||
|
||||
var OrderTypeList = map[int]string{
|
||||
|
|
@ -102,6 +106,6 @@ const (
|
|||
// 客户端环境和支付渠道的映射关系
|
||||
var OpenInPayChannelMap = map[int][]int{
|
||||
OpenInWeChat: {PAY_CHANNEL_WECHAT_JSAPI},
|
||||
OpenInMobile: {PAY_CHANNEL_WECHAT_H5, PAY_CHANNEL_ALIPAY_WEB},
|
||||
OpenInWindows: {PAY_CHANNEL_WECHAT_NATIVE, PAY_CHANNEL_ALIPAY_PC},
|
||||
OpenInMobile: {PAY_CHANNEL_WECHAT_H5, PAY_CHANNEL_ALIPAY_WEB, PAY_CHANNEL_PSBC},
|
||||
OpenInWindows: {PAY_CHANNEL_WECHAT_NATIVE, PAY_CHANNEL_ALIPAY_PC, PAY_CHANNEL_PSBC},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package data
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/models/orderexceptionmodel"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
type OrderExceptionRepo struct {
|
||||
repo xorm.Interface
|
||||
}
|
||||
|
||||
func NewOrderExceptionRepo(repo xorm.Interface) *OrderExceptionRepo {
|
||||
return &OrderExceptionRepo{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *OrderExceptionRepo) InsertOne(orderException *orderexceptionmodel.OrderException) (int64, error) {
|
||||
|
||||
return m.repo.InsertOne(orderException)
|
||||
}
|
||||
|
||||
type Exception int
|
||||
|
||||
const (
|
||||
OrderStatusOverButPaySuccess Exception = 1
|
||||
)
|
||||
|
||||
func (e Exception) GetDesc() string {
|
||||
return ExceptionOrderStatusOverButPayFailMap[e]
|
||||
}
|
||||
|
||||
func (e Exception) ToInt() int {
|
||||
return int(e)
|
||||
}
|
||||
|
||||
var ExceptionOrderStatusOverButPayFailMap = map[Exception]string{
|
||||
OrderStatusOverButPaySuccess: "订单状态为终态但是收到支付成功的消息",
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
|
@ -27,6 +28,16 @@ func PayUrl(c *gin.Context) {
|
|||
controllers.ApiRes(c, nil, check.CheckCode)
|
||||
return
|
||||
}
|
||||
|
||||
// 关闭关联订单
|
||||
if len(check.Reqs.CloseOutTradeNo) != 0 {
|
||||
check.CloseOrderWithOutTradeNo(check.Reqs.CloseOutTradeNo)
|
||||
if check.CheckCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, check.CheckCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pay := thirdpay.ThirdPayUrl(check)
|
||||
if pay.PayCode != errorcode.Success {
|
||||
controllers.ApiRes(c, nil, pay.PayCode, pay.ThirdMsg)
|
||||
|
|
@ -35,6 +46,7 @@ func PayUrl(c *gin.Context) {
|
|||
|
||||
res.Order = thirdpay.NewOrdersResp(pay.Order)
|
||||
res.Url = pay.Url
|
||||
res.ThirdMsg = pay.ThirdMsg
|
||||
res.JsInfo = pay.JsApiInfo
|
||||
controllers.ApiRes(c, res, pay.PayCode)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
package front
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/constants/common"
|
||||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/thirdpay_notify"
|
||||
"PaymentCenter/app/third/paymentService"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// PsbcCallback 邮储支付回调
|
||||
func PsbcCallback(c *gin.Context) {
|
||||
logger.Info(c, "PsbcCallback-回调数据", c.Request)
|
||||
payChannelId := c.Param("payChannelId")
|
||||
logger.Info(c, "PsbcCallback-回调数据payChannelId", payChannelId)
|
||||
if payChannelId == "" {
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
logger.Error(c, "PsbcCallback-读取请求体失败", err.Error())
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
bodyStr := string(body)
|
||||
logger.Info(c, "PsbcCallback-回调数据body", bodyStr)
|
||||
|
||||
var payChannelModel paychannelmodel.PayChannel
|
||||
payChannelIdInt, _ := strconv.Atoi(payChannelId)
|
||||
payChannelModel.Id = int64(payChannelIdInt)
|
||||
code := services.PayChannelGet(&payChannelModel)
|
||||
if code == errorcode.PayChannelNotFound {
|
||||
logger.Error(c, "PsbcCallback-回调数据未获取到支付配置,404")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
var psbcConfig paymentService.PsbcPay
|
||||
err = json.Unmarshal([]byte(payChannelModel.ExtJson), &psbcConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "PsbcCallback-回调数据解析支付配置错误", fmt.Sprintf("错误原因:%s", err.Error()))
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
if psbcConfig.MchtNo == "" || psbcConfig.PrivateKey == "" || psbcConfig.BankKey == "" {
|
||||
logger.Error(c, "PsbcCallback-回调数据解析支付配置错误,解析出来的信息为空")
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
psbcConfig.AppID = payChannelModel.AppId
|
||||
|
||||
orderId, amountTotal, payerTotal, status, err := paymentService.PsbcVerifyAndParseNotify(bodyStr, psbcConfig)
|
||||
if err != nil {
|
||||
logger.Error(c, "PsbcCallback-回调数据验签失败", err.Error())
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info(c, "PsbcCallback-解析邮储回调结果", fmt.Sprintf("orderId:%d, amountTotal:%d, payerTotal:%d, status:%s", orderId, amountTotal, payerTotal, status))
|
||||
|
||||
var orderStatus int
|
||||
var errCode int
|
||||
var msg string
|
||||
switch status {
|
||||
case "SUCCESS":
|
||||
orderStatus = common.ORDER_STATUS_PAYED
|
||||
errCode = errorcode.Success
|
||||
msg = "支付成功"
|
||||
case "FAIL":
|
||||
orderStatus = common.ORDER_STATUS_FAILED
|
||||
errCode = errorcode.ParamError
|
||||
msg = "支付失败"
|
||||
default:
|
||||
logger.Error(c, "PsbcCallback-订单状态异常", status)
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderId, errCode, orderStatus, int(amountTotal), int(payerTotal), msg)
|
||||
notifyResultJson, _ := json.Marshal(notifyResult)
|
||||
|
||||
go func() {
|
||||
payCallback := bodyStr
|
||||
payParam := "{}"
|
||||
merchantCallback := string(notifyResultJson)
|
||||
logStatus := common.THIRD_ORDER_LOG_STATUS_SUCCESS
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
logStatus = common.THIRD_ORDER_LOG_STATUS_FAIL
|
||||
}
|
||||
paymentService.SaveLog(orderId, common.THIRD_ORDER_TYPE_CALL_BACK, payCallback, payParam, merchantCallback, logStatus)
|
||||
}()
|
||||
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
logger.Error(c, "PsbcCallback-回调执行失败,失败原因:", fmt.Sprintf("%+v", notifyResult))
|
||||
c.String(http.StatusBadRequest, "%s", "fail")
|
||||
return
|
||||
}
|
||||
|
||||
c.String(http.StatusOK, "%s", "success")
|
||||
return
|
||||
}
|
||||
|
|
@ -28,7 +28,8 @@ type PayCommonReqBody struct {
|
|||
|
||||
type PayReqs struct {
|
||||
PayCommonReqBody
|
||||
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
|
||||
OutTradeNo string `json:"out_trade_no" validate:"required" label:"外侧商户订单号"`
|
||||
CloseOutTradeNo string `json:"close_out_trade_no" label:"关闭外侧商户订单号"`
|
||||
}
|
||||
|
||||
type RefundReqs struct {
|
||||
|
|
@ -61,9 +62,10 @@ type CloseReqs struct {
|
|||
|
||||
// api 接口返回数据, 统一返回结构, order数据会进行加密
|
||||
type ApiResponse struct {
|
||||
Order interface{} `json:"order,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
JsInfo *WxMiniPayResponse `json:"js_info,omitempty"`
|
||||
Order interface{} `json:"order,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
ThirdMsg string `json:"third_msg,omitempty"`
|
||||
JsInfo *WxMiniPayResponse `json:"js_info,omitempty"`
|
||||
}
|
||||
|
||||
type PayChannelListRequest struct {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"PaymentCenter/app/http/trace"
|
||||
"PaymentCenter/app/utils/metric"
|
||||
"PaymentCenter/config"
|
||||
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qit-team/snow-core/http/middleware"
|
||||
|
|
@ -57,6 +58,7 @@ func RegisterRoute(router *gin.Engine) {
|
|||
{
|
||||
notify.POST("/wx/:payChannelId", front.WxCallback)
|
||||
notify.POST("/ali/:payChannelId", front.AliCallback)
|
||||
notify.POST("/psbc/:payChannelId", front.PsbcCallback)
|
||||
}
|
||||
|
||||
pay := v1.Group("/pay", middlewares.ValidatePayRequest())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package orderexceptionmodel
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qit-team/snow-core/db"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
m *OrderExceptionModel
|
||||
)
|
||||
|
||||
// 实体
|
||||
type OrderException struct {
|
||||
Id int64
|
||||
OrderId int64 `xorm:"'order_id' bigint(20)"`
|
||||
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
|
||||
ExceptionType int `xorm:"'exception_type' TINYINT"`
|
||||
ExceptionDesc string `xorm:"'exception_desc' varchar(50)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
}
|
||||
|
||||
// 表名
|
||||
func (m *OrderException) TableName() string {
|
||||
return "order_exceptions"
|
||||
}
|
||||
|
||||
// 私有化,防止被外部new
|
||||
type OrderExceptionModel struct {
|
||||
db.Model //组合基础Model,集成基础Model的属性和方法
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
func GetInstance() *OrderExceptionModel {
|
||||
once.Do(func() {
|
||||
m = new(OrderExceptionModel)
|
||||
//m.DiName = "" //设置数据库实例连接,默认db.SingletonMain
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
package ordersmodel
|
||||
|
||||
import (
|
||||
"github.com/qit-team/snow-core/db"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qit-team/snow-core/db"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -13,22 +14,23 @@ var (
|
|||
|
||||
// 实体
|
||||
type Orders struct {
|
||||
Id int64
|
||||
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
|
||||
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
|
||||
AppId int64 `xorm:"'app_id' bigint(20)"`
|
||||
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
|
||||
OrderType int `xorm:"'order_type' TINYINT"`
|
||||
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
|
||||
Amount int `xorm:"'amount' int(11)"`
|
||||
ActualAmount int `xorm:"'actual_amount' int(11)"`
|
||||
PayerTotal int `xorm:"'payer_total' int(11)"`
|
||||
ExtJson string `xorm:"'ext_json' varchar(1024)"`
|
||||
Desc string `xorm:"'desc' varchar(100)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
Id int64
|
||||
MerchantId int64 `xorm:"'merchant_id' bigint(20)"`
|
||||
PayChannelId int64 `xorm:"'pay_channel_id' bigint(20)"`
|
||||
AppId int64 `xorm:"'app_id' bigint(20)"`
|
||||
OutTradeNo string `xorm:"'out_trade_no' varchar(50)"`
|
||||
OrderType int `xorm:"'order_type' TINYINT"`
|
||||
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
|
||||
Amount int `xorm:"'amount' int(11)"`
|
||||
ActualAmount int `xorm:"'actual_amount' int(11)"`
|
||||
PayerTotal int `xorm:"'payer_total' int(11)"`
|
||||
ExtJson string `xorm:"'ext_json' varchar(1024)"`
|
||||
Desc string `xorm:"'desc' varchar(100)"`
|
||||
RelationCloseOutTradeNo string `xorm:"'relation_close_out_trade_no' varchar(50)"`
|
||||
CreateTime time.Time `xorm:"'create_time' datetime created"`
|
||||
UpdateTime time.Time `xorm:"'update_time' timestamp updated"`
|
||||
Status int `xorm:"'status' TINYINT"`
|
||||
DeleteTime time.Time `xorm:"'delete_time' timestamp deleted"`
|
||||
}
|
||||
|
||||
type OrdersBackendList struct {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"PaymentCenter/app/models/merchantmodel"
|
||||
"PaymentCenter/app/models/paychannelmodel"
|
||||
"database/sql"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"xorm.io/builder"
|
||||
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
|
|
@ -21,16 +22,17 @@ import (
|
|||
)
|
||||
|
||||
type PayParam struct {
|
||||
Merchant *merchantmodel.Merchant
|
||||
Channel *paychannelmodel.PayChannel
|
||||
App_id int64
|
||||
OutTradeNo string
|
||||
Amount int
|
||||
ExtJson string
|
||||
Desc string
|
||||
ClientIp string
|
||||
ReturnUrl string
|
||||
OpenId string
|
||||
Merchant *merchantmodel.Merchant
|
||||
Channel *paychannelmodel.PayChannel
|
||||
App_id int64
|
||||
OutTradeNo string
|
||||
Amount int
|
||||
ExtJson string
|
||||
Desc string
|
||||
ClientIp string
|
||||
ReturnUrl string
|
||||
OpenId string
|
||||
CloseOutTradeNo string
|
||||
}
|
||||
|
||||
type Pay struct {
|
||||
|
|
@ -48,16 +50,17 @@ func NewPayWithPayCheck(paycheck *PayCheck) *Pay {
|
|||
return &Pay{
|
||||
ctx: paycheck.ctx,
|
||||
PayParam: &PayParam{
|
||||
Merchant: paycheck.Merchant,
|
||||
Channel: paycheck.Channel,
|
||||
App_id: paycheck.Reqs.AppId,
|
||||
OutTradeNo: paycheck.Reqs.OutTradeNo,
|
||||
Amount: paycheck.Reqs.Amount,
|
||||
ExtJson: paycheck.Reqs.ExtJson,
|
||||
Desc: paycheck.Reqs.Desc,
|
||||
ClientIp: paycheck.AppCheck.Ip,
|
||||
ReturnUrl: paycheck.Reqs.ReturnUrl,
|
||||
OpenId: paycheck.Reqs.OpenId,
|
||||
Merchant: paycheck.Merchant,
|
||||
Channel: paycheck.Channel,
|
||||
App_id: paycheck.Reqs.AppId,
|
||||
OutTradeNo: paycheck.Reqs.OutTradeNo,
|
||||
Amount: paycheck.Reqs.Amount,
|
||||
ExtJson: paycheck.Reqs.ExtJson,
|
||||
Desc: paycheck.Reqs.Desc,
|
||||
ClientIp: paycheck.AppCheck.Ip,
|
||||
ReturnUrl: paycheck.Reqs.ReturnUrl,
|
||||
OpenId: paycheck.Reqs.OpenId,
|
||||
CloseOutTradeNo: paycheck.Reqs.CloseOutTradeNo,
|
||||
},
|
||||
RelationOrder: paycheck.OldOrder,
|
||||
PayCode: errorcode.Success,
|
||||
|
|
@ -85,15 +88,16 @@ func (w *Pay) CreateOrder(order_type int) {
|
|||
}
|
||||
|
||||
order := &ordersmodel.Orders{
|
||||
MerchantId: w.PayParam.Merchant.Id,
|
||||
PayChannelId: w.PayParam.Channel.Id,
|
||||
AppId: w.PayParam.App_id,
|
||||
OutTradeNo: w.PayParam.OutTradeNo,
|
||||
OrderType: order_type,
|
||||
Amount: w.PayParam.Amount,
|
||||
ExtJson: w.PayParam.ExtJson,
|
||||
Desc: w.PayParam.Desc,
|
||||
Status: common.ORDER_STATUS_WAITPAY,
|
||||
MerchantId: w.PayParam.Merchant.Id,
|
||||
PayChannelId: w.PayParam.Channel.Id,
|
||||
AppId: w.PayParam.App_id,
|
||||
OutTradeNo: w.PayParam.OutTradeNo,
|
||||
OrderType: order_type,
|
||||
Amount: w.PayParam.Amount,
|
||||
ExtJson: w.PayParam.ExtJson,
|
||||
Desc: w.PayParam.Desc,
|
||||
RelationCloseOutTradeNo: w.PayParam.CloseOutTradeNo,
|
||||
Status: common.ORDER_STATUS_WAITPAY,
|
||||
}
|
||||
if order_type == common.ORDER_TYPE_REFUND {
|
||||
order.RefundOrderId = w.RelationOrder.Id
|
||||
|
|
@ -179,6 +183,9 @@ func (w *Pay) PayUrl() (url string) {
|
|||
// 支付宝jsapi支付
|
||||
res = paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
|
||||
case common.PAY_CHANNEL_PSBC:
|
||||
res = paymentService.PaymentService(*w.ctx, *thirdPay)
|
||||
|
||||
default:
|
||||
w.PayCode = errorcode.PayChannelNotBuild
|
||||
return
|
||||
|
|
@ -208,6 +215,9 @@ func (w *Pay) PayUrl() (url string) {
|
|||
// 获取签名
|
||||
err = w.JsApiInfo.SignPaySign(thirdPay.Wx.PrivateKey)
|
||||
}
|
||||
} else if w.PayParam.Channel.ChannelType == common.PAY_CHANNEL_PSBC {
|
||||
// 邮储支付返回 handCodePay 参数
|
||||
w.ThirdMsg = res.Result
|
||||
} else {
|
||||
w.Url = res.Result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"PaymentCenter/app/constants/errorcode"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/services/thirdpay/types"
|
||||
|
||||
"xorm.io/builder"
|
||||
|
||||
"PaymentCenter/app/models/merchantmodel"
|
||||
|
|
@ -84,11 +85,24 @@ func (w *PayCheck) CheckOrderPay() {
|
|||
if w.OldOrder.Status == common.ORDER_STATUS_PAYING && w.Reqs.PayChannelId != w.OldOrder.PayChannelId {
|
||||
w.CheckCode = errorcode.OrderPayChannelChange
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (w *PayCheck) CloseOrderWithOutTradeNo(OutTradeNum string) {
|
||||
if len(OutTradeNum) != 0 {
|
||||
w.GetOldOrder(&types.OrderFindOne{
|
||||
OutTradeNo: w.Reqs.CloseOutTradeNo,
|
||||
})
|
||||
if w.OldOrder.Status == common.ORDER_STATUS_PAYED || w.OldOrder.Status == common.ORDER_STATUS_CLOSE {
|
||||
w.CheckCode = errorcode.OrderStatusErr
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *PayCheck) CheckOrderRefund() (order *ordersmodel.Orders) {
|
||||
// 查询原来的支付单
|
||||
w.GetOldOrder(&types.OrderFindOne{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ var PayWayList = map[int]func(commonPayInfo *paymentService.PayOrderRequest, cha
|
|||
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPI,
|
||||
common.PAY_CHANNEL_WECHAT_MINI: WechatJSAPI,
|
||||
common.PAY_CHANNEL_ALIPAY_JSAPI: AlipayWeb,
|
||||
common.PAY_CHANNEL_PSBC: Psbc,
|
||||
}
|
||||
|
||||
func WechatH5(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
|
|
@ -42,3 +43,12 @@ func WechatJSAPI(commonPayInfo *paymentService.PayOrderRequest, channel *paychan
|
|||
commonPayInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
||||
func Psbc(commonPayInfo *paymentService.PayOrderRequest, channel *paychannelmodel.PayChannel) error {
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonPayInfo.Psbc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonPayInfo.Psbc.AppID = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ var RefundWayList = map[int]func(commonRefundInfo *paymentService.OrderRefundReq
|
|||
common.PAY_CHANNEL_ALIPAY_PC: AlipayWebRefund,
|
||||
common.PAY_CHANNEL_WECHAT_JSAPI: WechatJSAPIRefund,
|
||||
common.PAY_CHANNEL_WECHAT_MINI: WechatJSAPIRefund,
|
||||
common.PAY_CHANNEL_PSBC: PsbcRefund,
|
||||
}
|
||||
|
||||
func WechatH5Refund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
|
|
@ -44,3 +45,13 @@ func WechatJSAPIRefund(commonRefundInfo *paymentService.OrderRefundRequest, chan
|
|||
commonRefundInfo.Wx.AppId = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
||||
func PsbcRefund(commonRefundInfo *paymentService.OrderRefundRequest, channel *paychannelmodel.PayChannel) error {
|
||||
commonRefundInfo.PayChannel = common.PAY_CHANNLE_TYPE_PSBC
|
||||
err := sonic.Unmarshal([]byte(channel.ExtJson), &commonRefundInfo.Psbc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commonRefundInfo.Psbc.AppID = channel.AppId
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"PaymentCenter/app/services/thirdpay/types"
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
"context"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
|
|
@ -122,7 +123,11 @@ func ThirdCloseOrder(ctx context.Context, closeReq front.CloseReqs, appCheck *se
|
|||
// 调用上游关闭订单
|
||||
client := thirdpay.NewPayWithPayCheck(check)
|
||||
client.Order = check.OldOrder
|
||||
client.CloseOrder()
|
||||
if client.PayParam.Channel.ChannelType != common.PAY_CHANNEL_ALIPAY_WEB {
|
||||
//阿里云的网页支付,创单和完成支付是同时完成的,没有关单的必要状态,所以直接关闭掉系统内的订单就好了
|
||||
//在支付成功回调里如果订单状态为关闭,那么这个单需要走退款
|
||||
client.CloseOrder()
|
||||
}
|
||||
code = client.PayCode
|
||||
message = client.ThirdMsg
|
||||
// 修改订单状态为已关闭
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ func OrderQueryAndNotify(ctx context.Context, orderInfo *ordersmodel.OrdersLeftP
|
|||
AlipayRootCert: ali.AlipayRootCert,
|
||||
AlipayPublicCert: ali.AlipayPublicCert,
|
||||
}
|
||||
case common.PAY_CHANNLE_TYPE_PSBC:
|
||||
psbc := paymentService.PsbcPay{}
|
||||
_ = json.Unmarshal([]byte(orderInfo.ExtJson), &psbc)
|
||||
query.PayChannel = payCommon.PAY_CHANNLE_TYPE_PSBC
|
||||
psbc.AppID = orderInfo.AppId
|
||||
query.Psbc = psbc
|
||||
default:
|
||||
utils.Log(nil, "查询订单,支付渠道不支持", orderInfo.ChannelType)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -7,12 +7,15 @@ import (
|
|||
"PaymentCenter/app/http/entities"
|
||||
"PaymentCenter/app/models/appmodel"
|
||||
"PaymentCenter/app/models/ordercallbacklogmodel"
|
||||
"PaymentCenter/app/models/orderexceptionmodel"
|
||||
"PaymentCenter/app/models/ordersmodel"
|
||||
"PaymentCenter/app/services"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/app/utils/httpclient"
|
||||
"github.com/bytedance/sonic"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
|
|
@ -83,6 +86,7 @@ func (o *OrderNotify) Handle() (res *OrderNotifyResp) {
|
|||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
}
|
||||
|
||||
o.checkApp()
|
||||
if o.Code != errorcode.Success {
|
||||
return o.NotifyRespFail(o.Code)
|
||||
|
|
@ -205,16 +209,42 @@ func (o *OrderNotify) checkApp() {
|
|||
}
|
||||
|
||||
func (o *OrderNotify) checkOrder() {
|
||||
utils.Log(nil, "检查订单状态", o.OrderId)
|
||||
cond := builder.NewCond()
|
||||
cond = cond.And(builder.Eq{"id": o.OrderId})
|
||||
o.order, o.Code = services.OrderFindOne(&ordersmodel.Orders{}, cond)
|
||||
if o.Code != errorcode.OrdersExist {
|
||||
if o.Code != errorcode.Success {
|
||||
utils.Log(nil, "订单状态错误,当前查询code", o.Code)
|
||||
return
|
||||
}
|
||||
utils.Log(nil, "收到回调,当前状态", o.order.Status)
|
||||
switch o.order.Status {
|
||||
case common.ORDER_STATUS_PAYING:
|
||||
return
|
||||
case common.ORDER_STATUS_PAYED:
|
||||
return
|
||||
default:
|
||||
utils.Log(nil, "订单状态异常,加入异常数据表", o.order.Status)
|
||||
exceptionModel := data.NewOrderExceptionRepo(orderexceptionmodel.GetInstance().GetDb())
|
||||
_, err := exceptionModel.InsertOne(&orderexceptionmodel.OrderException{
|
||||
OrderId: o.order.Id,
|
||||
OutTradeNo: o.order.OutTradeNo,
|
||||
ExceptionType: data.OrderStatusOverButPaySuccess.ToInt(),
|
||||
ExceptionDesc: fmt.Sprintf("%s:%s:%d", data.OrderStatusOverButPaySuccess.GetDesc(), "当前状态为", o.order.Status),
|
||||
CreateTime: time.Now(),
|
||||
Status: o.order.Status,
|
||||
})
|
||||
|
||||
if o.order.Status != common.ORDER_STATUS_PAYING {
|
||||
if err != nil {
|
||||
utils.Log(nil, "异常数据记录失败:%s", err.Error())
|
||||
}
|
||||
o.Code = errorcode.OrderStatusErr
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
//if o.order.Status != common.ORDER_STATUS_PAYING {
|
||||
// o.Code = errorcode.OrderStatusErr
|
||||
// return
|
||||
//}
|
||||
//return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ type Reqs struct {
|
|||
OutTradeNo string `json:"out_trade_no"`
|
||||
RefundOutTradeNo string `json:"refund_out_trade_no"`
|
||||
RefundOrderId string `json:"refundOrder_id"`
|
||||
CloseOutTradeNo string `json:"close_out_trade_no"`
|
||||
}
|
||||
|
||||
type OrderFindOne struct {
|
||||
|
|
|
|||
|
|
@ -10,10 +10,11 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/alipay"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AliInitClient 使用提供的支付请求参数初始化支付宝客户端
|
||||
|
|
@ -349,6 +350,7 @@ func AliRefundOrderQuery(ctx context.Context, orderRefundQueryRequest OrderRefun
|
|||
|
||||
// AliCloseOrder 支付宝订单关闭
|
||||
func AliCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
|
||||
|
||||
// 初始化支付宝客户端
|
||||
aliClient, err := AliInitClient(orderCloseRequest.Ali)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ const (
|
|||
PAY_CHANNEL_ALIPAY_JSAPI = 8
|
||||
PAY_CHANNEL_ALIPAY_PC = 9
|
||||
PAY_CHANNEL_ALIPAY_QrCode = 10
|
||||
PAY_CHANNEL_PSBC = 11
|
||||
|
||||
PAY_SUCCESS_CODE = 200 // 支付响应成功
|
||||
PAY_ERROR_CODE = 500 // 支付响应失败
|
||||
|
|
@ -23,15 +24,18 @@ const (
|
|||
|
||||
WX_SUCCESS_CODE = 200 // 微信状态码返回成功
|
||||
|
||||
WX_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
WX_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
ALI_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
ALI_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
WX_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
WX_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/wx/" // 微信支付回调地址
|
||||
ALI_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
ALI_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/ali/" // 支付宝支付回调地址
|
||||
PSBC_NOTIFY_URL_TEST = common.FRONT_V1 + "/notify/psbc/" // 邮储支付回调地址测试环境
|
||||
PSBC_NOTIFY_URL_PROD = common.FRONT_V1 + "/notify/psbc/" // 邮储支付回调地址生产环境
|
||||
|
||||
ORDER_NO_TYPE_ORDER_NO = 2
|
||||
|
||||
PAY_CHANNLE_TYPE_WECHAT = 1 // 支付类型: 微信
|
||||
PAY_CHANNLE_TYPE_ZFB = 2 // 支付类型:支付宝
|
||||
PAY_CHANNLE_TYPE_PSBC = 3 // 支付类型:邮储
|
||||
|
||||
PAY_REFUND_STATU_COMMON = 0 // 未申请
|
||||
PAY_REFUND_STATU_ING = 1 // 退款中
|
||||
|
|
|
|||
|
|
@ -13,16 +13,17 @@ import (
|
|||
)
|
||||
|
||||
type PayOrderRequest struct {
|
||||
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
|
||||
OrderId int64 `json:"order_id"` // 平台订单号
|
||||
ChannelType int `json:"channel_type"` // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
Description string `json:"description"` // 商品描述
|
||||
Amount int `json:"amount"` // 金额单位为分
|
||||
PayerClientIp string `json:"payer_client_ip"` // 终端IP
|
||||
ReturnUrl string `json:"return_url"` // 支付成功后回调地址
|
||||
Wx WxPay `json:"wx"` // 微信支付参数
|
||||
Ali AliPay `json:"ali"` // 支付宝参数
|
||||
OpenId string `json:"open_id"` // 支付者信息。 openid
|
||||
PayChannelId int64 `json:"pay_channel_id"` // 支付方式ID
|
||||
OrderId int64 `json:"order_id"` // 平台订单号
|
||||
ChannelType int `json:"channel_type"` // 支付渠道枚举,1微信JSAPI,2微信H5,3微信app,4微信Native,5微信小程序,6支付宝网页&移动应用,7支付宝小程序,8支付宝JSAPI
|
||||
Description string `json:"description"` // 商品描述
|
||||
Amount int `json:"amount"` // 金额单位为分
|
||||
PayerClientIp string `json:"payer_client_ip"` // 终端IP
|
||||
ReturnUrl string `json:"return_url"` // 支付成功后回调地址
|
||||
Wx WxPay `json:"wx"` // 微信支付参数
|
||||
Ali AliPay `json:"ali"` // 支付宝参数
|
||||
Psbc PsbcPay `json:"psbc"` // 邮储支付参数
|
||||
OpenId string `json:"open_id"` // 支付者信息。 openid
|
||||
}
|
||||
|
||||
type WxPay struct {
|
||||
|
|
@ -72,6 +73,9 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder
|
|||
case payCommon.PAY_CHANNEL_ALIPAY_JSAPI:
|
||||
// 支付宝JSAPI支付
|
||||
info, err = ALiJsApiPayInfo(c, payOrderRequest)
|
||||
case payCommon.PAY_CHANNEL_PSBC:
|
||||
// 邮储支付
|
||||
info, err = PsbcPayInfo(c, payOrderRequest)
|
||||
|
||||
default:
|
||||
payOrderResponse = PayOrderResponse{
|
||||
|
|
@ -109,10 +113,11 @@ func PaymentService(c context.Context, payOrderRequest PayOrderRequest) PayOrder
|
|||
}
|
||||
|
||||
type PayOrderQueryRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 商户订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
OrderId int64 `json:"order_id"` // 商户订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
Psbc PsbcPay `json:"psbc"`
|
||||
}
|
||||
|
||||
type PayOrderQueryResponse struct {
|
||||
|
|
@ -143,6 +148,8 @@ func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest)
|
|||
info, err = WxOrderQuery(c, payOrderQueryRequest.Wx, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = ALiOrderQuery(c, payOrderQueryRequest.Ali, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||
case payCommon.PAY_CHANNLE_TYPE_PSBC:
|
||||
info, err = PsbcOrderQuery(c, payOrderQueryRequest.Psbc, strconv.FormatInt(payOrderQueryRequest.OrderId, 10))
|
||||
default:
|
||||
payOrderQueryResponse = PayOrderQueryResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
|
|
@ -177,13 +184,15 @@ func PayOrderQuery(c context.Context, payOrderQueryRequest PayOrderQueryRequest)
|
|||
}
|
||||
|
||||
type OrderRefundRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 订单编号
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
RefundReason string `json:"refund_reason"` // 退款原因
|
||||
RefundAmount int64 `json:"refund_amount"` // 退款金额,单位分, 微信需要传入订单总额,不是用户实际支付金额
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
OrderId int64 `json:"order_id"` // 订单编号
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
RefundReason string `json:"refund_reason"` // 退款原因
|
||||
RefundAmount int64 `json:"refund_amount"` // 退款金额,单位分, 微信需要传入订单总额,不是用户实际支付金额
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
TransactionId string `json:"transaction_id"` // 第三方交易号
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
Psbc PsbcPay `json:"psbc"`
|
||||
}
|
||||
|
||||
type OrderRefundResponse struct {
|
||||
|
|
@ -213,6 +222,8 @@ func OrderRefund(c context.Context, orderRefundRequest OrderRefundRequest) Order
|
|||
info, err = WxOrderRefund(c, orderRefundRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
info, err = AliRefundOrder(c, orderRefundRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_PSBC:
|
||||
info, err = PsbcRefundOrder(c, orderRefundRequest)
|
||||
default:
|
||||
orderRefundResponse = OrderRefundResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
|
|
@ -247,11 +258,12 @@ func OrderRefund(c context.Context, orderRefundRequest OrderRefundRequest) Order
|
|||
}
|
||||
|
||||
type OrderRefundQueryRequest struct {
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
RefundOrderId int64 `json:"refund_order_id"` // 退款订单号
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
Psbc PsbcPay `json:"psbc"`
|
||||
}
|
||||
type OrderRefundQueryResponse struct {
|
||||
Code int `json:"code"`
|
||||
|
|
@ -304,10 +316,11 @@ func OrderRefundQuery(c context.Context, orderRefundQueryRequest OrderRefundQuer
|
|||
}
|
||||
|
||||
type OrderCloseRequest struct {
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
OrderId int64 `json:"order_id"` // 支付订单号
|
||||
PayChannel int `json:"pay_channel"` // 支付渠道类型 1:wx,2:zfb
|
||||
Wx WxPay `json:"wx"`
|
||||
Ali AliPay `json:"ali"`
|
||||
Psbc PsbcPay `json:"psbc"`
|
||||
}
|
||||
|
||||
type OrderCloseResponse struct {
|
||||
|
|
@ -331,7 +344,10 @@ func OrderClose(c context.Context, orderCloseRequest OrderCloseRequest) OrderClo
|
|||
// 微信H5支付
|
||||
info, err = WxCloseOrder(c, orderCloseRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_ZFB:
|
||||
|
||||
info, err = AliCloseOrder(c, orderCloseRequest)
|
||||
case payCommon.PAY_CHANNLE_TYPE_PSBC:
|
||||
info, err = PsbcCloseOrder(c, orderCloseRequest)
|
||||
default:
|
||||
orderCloseResponse = OrderCloseResponse{
|
||||
Code: payCommon.PAY_ERROR_CODE,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
# Payment SDK
|
||||
|
||||
支付能力独立 SDK,封装邮储手机银行支付、查询、退款、对账单、回调验签等能力,供支付中心或其他业务系统复用。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 支付链接生成(SM2+SM4 加密)
|
||||
- 订单支付状态查询
|
||||
- 退款申请
|
||||
- 对账单查询与下载
|
||||
- 回调通知验签与解密
|
||||
- 工具方法:订单号生成、Map 转签名字符串、HMAC-SHA256 签名
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 初始化客户端
|
||||
|
||||
```go
|
||||
import "qteam/app/sdk/payment"
|
||||
|
||||
cfg := payment.Config{
|
||||
MerchantId: "yourMerchantId",
|
||||
MchtNo: "yourMchtNo",
|
||||
AppID: "yourAppId",
|
||||
SopPublicKey: "yourSopPublicKey",
|
||||
PrivateKey: "yourPrivateKey",
|
||||
Pubkey: "yourPubkey",
|
||||
BankKey: "yourBankKey",
|
||||
Sha: "yourShaKey",
|
||||
ReturnUrl: "https://your-domain.com/return",
|
||||
SuccessUrl: "https://your-domain.com/success",
|
||||
NotifyUrl: "https://your-domain.com/notify",
|
||||
ShowTitleBar: "1",
|
||||
LoginHost: "https://login.example.com/",
|
||||
OrderHost: "https://order.example.com/",
|
||||
FileHost: "https://file.example.com/",
|
||||
ShopId: "yourShopId",
|
||||
}
|
||||
|
||||
client := payment.NewClient(cfg)
|
||||
```
|
||||
|
||||
### 2. 创建支付链接
|
||||
|
||||
```go
|
||||
link, err := client.CreatePaymentLink(payment.PaymentLinkRequest{
|
||||
OrderNo: payment.GenerateOrderNumber(),
|
||||
ProductName: "测试商品",
|
||||
Price: "19.90",
|
||||
BackUrl: "https://mall.example.com/pay",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("支付链接:", link.PayUrl)
|
||||
fmt.Println("订单号:", link.OrderNo)
|
||||
fmt.Println("前端验签:", link.Sign)
|
||||
```
|
||||
|
||||
### 3. 查询订单
|
||||
|
||||
```go
|
||||
result, err := client.OrderQuery("SJ20240101000000001")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("订单状态:", result.OrderSta)
|
||||
fmt.Println("响应码:", result.RespCode)
|
||||
```
|
||||
|
||||
### 4. 申请退款
|
||||
|
||||
```go
|
||||
refund, err := client.Refund(payment.RefundRequest{
|
||||
OrderNo: "SJ20240101000000001",
|
||||
Price: "19.90",
|
||||
OrgTxnSeq: "bankOrderNo123",
|
||||
RefundDesc: "用户主动退款",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("退款订单号:", refund.RefundOrderNo)
|
||||
fmt.Println("退款状态:", refund.RefundOrderSta)
|
||||
```
|
||||
|
||||
### 5. 对账单查询与下载
|
||||
|
||||
```go
|
||||
// 查询对账单
|
||||
bill, err := client.BillQuery(time.Now())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 下载对账单
|
||||
for _, file := range bill.Files {
|
||||
fileId := file["fileId"].(string)
|
||||
data, err := client.BillDownload(fileId, time.Now())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// 处理对账单数据
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 处理回调通知
|
||||
|
||||
```go
|
||||
// 解密通知
|
||||
decrypted, err := client.DecryptNotify(rawJson)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 验签并解析
|
||||
notifyData, err := client.VerifyAndParseNotify(rawJson)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("通知数据:", notifyData)
|
||||
```
|
||||
|
||||
## 核心类型说明
|
||||
|
||||
### Config
|
||||
|
||||
支付配置,包含商户信息、密钥、URL 等必要配置。
|
||||
|
||||
### PaymentLinkRequest
|
||||
|
||||
```go
|
||||
type PaymentLinkRequest struct {
|
||||
OrderNo string
|
||||
ProductName string
|
||||
Price string
|
||||
BackUrl string
|
||||
}
|
||||
```
|
||||
|
||||
### PaymentLinkResponse
|
||||
|
||||
```go
|
||||
type PaymentLinkResponse struct {
|
||||
OrderNo string
|
||||
NotifyUrl string
|
||||
Sign string
|
||||
PlainText string
|
||||
PayUrl string
|
||||
}
|
||||
```
|
||||
|
||||
### OrderQueryResponse
|
||||
|
||||
```go
|
||||
type OrderQueryResponse struct {
|
||||
OrderNo string
|
||||
OrderSta string
|
||||
RespCode string
|
||||
RespMsg string
|
||||
}
|
||||
```
|
||||
|
||||
### RefundResponse
|
||||
|
||||
```go
|
||||
type RefundResponse struct {
|
||||
RespCode string
|
||||
RespMsg string
|
||||
RefundOrderNo string
|
||||
RefundOrderSta string
|
||||
TxnAmt string
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **密钥安全**:私钥、公钥等敏感信息请通过配置中心或环境变量传入,不要硬编码在代码中。
|
||||
2. **并发安全**:`GenerateOrderNumber` 和 `RandomNumber` 基于时间戳生成,高并发场景下建议由调用方保证唯一性。
|
||||
3. **错误处理**:所有接口均返回 `error`,调用方需根据业务场景处理重试、降级等逻辑。
|
||||
4. **状态码映射**:邮储订单状态码 `03-支付成功`、`04-支付失败`、`05-检查失败` 等,请参考 `types.go` 中的常量定义。
|
||||
|
||||
## 与现有系统集成建议
|
||||
|
||||
- **支付中心**:可直接使用此 SDK 封装统一支付服务。
|
||||
- **业务系统**:通过依赖此 SDK 接入支付能力,避免重复实现加密、验签逻辑。
|
||||
- **测试环境**:可通过 `Config` 切换测试环境地址和密钥。
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BillQuery 查询对账单
|
||||
// 对齐 YouChuKoffee 的 AccountBillQuery 流程:
|
||||
// 1. 构建完整 {head, body} 结构(body 包含 accountingDate, fileIntfcName)
|
||||
// 2. 整个 {head, body} 一起加密
|
||||
// 3. head 同时作为 HTTP Header 明文传输
|
||||
func (c *Client) BillQuery(date time.Time) (*BillQueryResponse, error) {
|
||||
now := time.Now().Format("20060102150405")
|
||||
BusiMainId := now + RandomNumber(10)
|
||||
|
||||
if date.IsZero() {
|
||||
date = time.Now().AddDate(0, 0, -1)
|
||||
}
|
||||
|
||||
// 构建完整 request(head+body 一起加密,对齐 YouChuKoffee)
|
||||
requestBody := map[string]interface{}{
|
||||
"head": map[string]string{
|
||||
"partnerTxSriNo": BusiMainId,
|
||||
"reqTime": now,
|
||||
"method": "ufile.query.commonQuery",
|
||||
"version": "1",
|
||||
"merchantId": c.cfg.MerchantId,
|
||||
"appID": c.cfg.AppID,
|
||||
"accessType": "API",
|
||||
"reserve": "",
|
||||
},
|
||||
"body": map[string]string{
|
||||
"accountingDate": date.Format("20060102"),
|
||||
"fileIntfcName": c.cfg.MchtNo,
|
||||
},
|
||||
}
|
||||
|
||||
// 整个 {head, body} 一起加密
|
||||
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密请求失败: %v", err)
|
||||
}
|
||||
|
||||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result BillQueryResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// BillDownload 下载对账单
|
||||
// 对齐 YouChuKoffee 的 AccountBillDownload 流程:
|
||||
// 1. 构建完整 {head, body} 结构(body 包含 fileIntfcName, sm4Key, fileId)
|
||||
// 2. 整个 {head, body} 一起加密
|
||||
// 3. head 同时作为 HTTP Header 明文传输
|
||||
func (c *Client) BillDownload(fileId string, date time.Time) ([]byte, error) {
|
||||
now := time.Now().Format("20060102150405")
|
||||
BusiMainId := now + RandomNumber(10)
|
||||
|
||||
// 构建完整 request(head+body 一起加密,对齐 YouChuKoffee)
|
||||
requestBody := map[string]interface{}{
|
||||
"head": map[string]string{
|
||||
"partnerTxSriNo": BusiMainId,
|
||||
"reqTime": now,
|
||||
"method": "ufile.download.commonDownload",
|
||||
"version": "1",
|
||||
"merchantId": c.cfg.MerchantId,
|
||||
"appID": c.cfg.AppID,
|
||||
"accessType": "API",
|
||||
"reserve": "",
|
||||
},
|
||||
"body": map[string]string{
|
||||
"fileIntfcName": c.cfg.MchtNo,
|
||||
"sm4Key": "",
|
||||
"fileId": fileId,
|
||||
},
|
||||
}
|
||||
|
||||
// 整个 {head, body} 一起加密
|
||||
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密请求失败: %v", err)
|
||||
}
|
||||
|
||||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.FileHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"github.com/tjfoc/gmsm/x509"
|
||||
)
|
||||
|
||||
// Client 支付客户端
|
||||
type Client struct {
|
||||
cfg Config
|
||||
}
|
||||
|
||||
// NewClient 创建支付客户端
|
||||
func NewClient(cfg Config) *Client {
|
||||
return &Client{cfg: cfg}
|
||||
}
|
||||
|
||||
// doPost 发送 POST 请求到邮储银行
|
||||
// head 信息通过 HTTP Header 明文传输,encryptedBody 作为 HTTP POST Body
|
||||
// 对齐 YouChuKoffee 的 postbank.doPost 流程
|
||||
func (c *Client) doPost(url string, head map[string]string, encryptedBody []byte) ([]byte, error) {
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(encryptedBody))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建请求失败: %v", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
|
||||
for k, v := range head {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 60 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// MapToString 将 map 转换为排序后的 key=value&key=value 格式
|
||||
func MapToString(m map[string]string) string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var result []string
|
||||
for _, k := range keys {
|
||||
result = append(result, fmt.Sprintf("%s=%s", k, m[k]))
|
||||
}
|
||||
return strings.Join(result, "&")
|
||||
}
|
||||
|
||||
// HmacSha256To16 生成 HMAC-SHA256 签名(16进制)
|
||||
func HmacSha256To16(key string, data string) string {
|
||||
mac := hmac.New(sha256.New, []byte(key))
|
||||
mac.Write([]byte(data))
|
||||
encode := mac.Sum(nil)
|
||||
return hex.EncodeToString(encode)
|
||||
}
|
||||
|
||||
// GenerateOrderNumber 生成订单号
|
||||
func GenerateOrderNumber() string {
|
||||
datePart := time.Now().Format("20060102150405")
|
||||
randomPart := fmt.Sprintf("%06d", time.Now().Nanosecond()%1000000)
|
||||
return "SJ" + datePart + randomPart
|
||||
}
|
||||
|
||||
// RandomNumber 生成指定长度的随机数字字符串
|
||||
func RandomNumber(n int) string {
|
||||
result := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
result[i] = byte(time.Now().Nanosecond()%10 + '0')
|
||||
time.Sleep(1)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// EncryptMobile 手机银行支付参数加密
|
||||
// 返回: tysdPayParams(base64), tysdEncryptKey(base64)
|
||||
func (c *Client) EncryptMobile(inputJson string, signStr string) (string, string, error) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Println("加密失败", err)
|
||||
}
|
||||
}()
|
||||
|
||||
sm4Key := generateSM4Key()
|
||||
|
||||
// SM2 加密 SM4 密钥(使用银行公钥)
|
||||
bankPubKey, err := x509.ReadPublicKeyFromHex(c.cfg.BankKey)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取银行公钥失败: %v", err)
|
||||
}
|
||||
encryptKeyBytes, err := sm2.Encrypt(bankPubKey, sm4Key, nil, sm2.C1C3C2)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm2加密失败: %v", err)
|
||||
}
|
||||
encryptKey := hex.EncodeToString(encryptKeyBytes)
|
||||
if len(encryptKey) > 2 && encryptKey[0:2] == "04" {
|
||||
encryptKeyBytes = encryptKeyBytes[1:]
|
||||
}
|
||||
|
||||
// SM2 签名(与 YouChuKoffee 对齐:UserID 传 nil,默认值 1234567812345678)
|
||||
merchantPrivKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("读取商户私钥失败: %v", err)
|
||||
}
|
||||
r, s, err := sm2.Sm2Sign(merchantPrivKey, []byte(signStr), nil, rand.Reader)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("签名失败: %v", err)
|
||||
}
|
||||
sig := encodeBase64(rsToBytes(r, s))
|
||||
|
||||
// 拼接参数并 SM4 ECB 加密
|
||||
param := fmt.Sprintf("%s&sign=%s", inputJson, sig)
|
||||
tmp, err := sm4ECBEncrypt(sm4Key, pkcs5Padding([]byte(param), 16))
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("sm4加密失败: %v", err)
|
||||
}
|
||||
|
||||
return encodeBase64(tmp), encodeBase64(encryptKeyBytes), nil
|
||||
}
|
||||
|
||||
// DecryptResponse 解密银行响应
|
||||
func (c *Client) DecryptResponse(respJson string, isRequest bool) (string, error) {
|
||||
var reqData map[string]string
|
||||
if err := json.Unmarshal([]byte(respJson), &reqData); err != nil {
|
||||
return "", fmt.Errorf("解析响应JSON失败: %v,响应内容: %s", err, respJson)
|
||||
}
|
||||
|
||||
dataKey := "response"
|
||||
if isRequest {
|
||||
dataKey = "request"
|
||||
}
|
||||
|
||||
_, hasData := reqData[dataKey]
|
||||
_, hasSignature := reqData["signature"]
|
||||
_, hasEncryptKey := reqData["encryptKey"]
|
||||
|
||||
if !hasData || !hasSignature || !hasEncryptKey {
|
||||
if code, ok := reqData["code"]; ok {
|
||||
msg := reqData["msg"]
|
||||
if msg == "" {
|
||||
msg = reqData["message"]
|
||||
}
|
||||
return "", fmt.Errorf("银行返回错误,错误码: %s,错误信息: %s", code, msg)
|
||||
}
|
||||
if respCode, ok := reqData["respCode"]; ok {
|
||||
respMsg := reqData["respMsg"]
|
||||
return "", fmt.Errorf("银行返回错误,错误码: %s,错误信息: %s", respCode, respMsg)
|
||||
}
|
||||
missingFields := []string{}
|
||||
if !hasData {
|
||||
missingFields = append(missingFields, dataKey)
|
||||
}
|
||||
if !hasSignature {
|
||||
missingFields = append(missingFields, "signature")
|
||||
}
|
||||
if !hasEncryptKey {
|
||||
missingFields = append(missingFields, "encryptKey")
|
||||
}
|
||||
return "", fmt.Errorf("响应格式不正确,缺少字段: %v,响应内容: %s", missingFields, respJson)
|
||||
}
|
||||
|
||||
reqData["accessToken"] = ""
|
||||
inData := reqData[dataKey]
|
||||
inSignature := reqData["signature"]
|
||||
inEncryptKey := reqData["encryptKey"]
|
||||
|
||||
// 验签
|
||||
checked := c.verify(fmt.Sprintf("%s%s%s", inData, inEncryptKey, ""), inSignature)
|
||||
if !checked {
|
||||
return "", fmt.Errorf("签名验证失败")
|
||||
}
|
||||
|
||||
// 解密 SM4 密钥
|
||||
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取私钥失败: %v", err)
|
||||
}
|
||||
hexEncryptKey, err := hex.DecodeString(inEncryptKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解密sm4key失败: %v", err)
|
||||
}
|
||||
sm4Key, err := sm2.Decrypt(privKey, hexEncryptKey, sm2.C1C3C2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解密sm2key失败: %v", err)
|
||||
}
|
||||
|
||||
// 解密数据
|
||||
request, _ := base64.StdEncoding.DecodeString(inData)
|
||||
encryptedSm4Key, err := sm4.CBCDecrypt(sm4Key, getSM4IV(), request)
|
||||
decryptedStr := string(pkcs5UnPadding(encryptedSm4Key))
|
||||
|
||||
// 提取 body 字段(银行解密后的结构为 {head, body},业务数据在 body 中)
|
||||
var decryptedMap map[string]interface{}
|
||||
if jsonErr := json.Unmarshal([]byte(decryptedStr), &decryptedMap); jsonErr == nil {
|
||||
if bodyVal, bodyOk := decryptedMap["body"]; bodyOk && bodyVal != nil {
|
||||
if bodyStr, isStr := bodyVal.(string); isStr {
|
||||
return bodyStr, nil
|
||||
}
|
||||
bodyBytes, marshalErr := json.Marshal(bodyVal)
|
||||
if marshalErr == nil {
|
||||
return string(bodyBytes), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decryptedStr, nil
|
||||
}
|
||||
|
||||
// VerifySignature 验签
|
||||
func (c *Client) VerifySignature(content, signature string) bool {
|
||||
return c.verify(content, signature)
|
||||
}
|
||||
|
||||
func (c *Client) verify(content, signature string) bool {
|
||||
pubKey, err := x509.ReadPublicKeyFromHex(c.cfg.SopPublicKey)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("pubKeyBytes sm2 ReadPublicKeyFromHex err: %v", err))
|
||||
}
|
||||
r, s := signToRS(signature)
|
||||
return sm2.Sm2Verify(pubKey, []byte(content), []byte(c.cfg.MerchantId), r, s)
|
||||
}
|
||||
|
||||
func signToRS(signStr string) (*big.Int, *big.Int) {
|
||||
sub := strings.Split(signStr, "#")
|
||||
if len(sub) != 2 {
|
||||
panic(fmt.Sprintf("err rs: %x", sub))
|
||||
}
|
||||
r, _ := new(big.Int).SetString(sub[0], 16)
|
||||
s, _ := new(big.Int).SetString(sub[1], 16)
|
||||
return r, s
|
||||
}
|
||||
|
||||
func rsToBytes(r, s *big.Int) []byte {
|
||||
rBytes := r.Bytes()
|
||||
sBytes := s.Bytes()
|
||||
result := make([]byte, 0, len(rBytes)+len(sBytes))
|
||||
result = append(result, rBytes...)
|
||||
result = append(result, sBytes...)
|
||||
return result
|
||||
}
|
||||
|
||||
func encodeBase64(data []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
func getSM4IV() []byte {
|
||||
return []byte("UISwD9fW6cFh9SNS")
|
||||
}
|
||||
|
||||
func generateSM4Key() []byte {
|
||||
key := make([]byte, 16)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("生成SM4密钥失败: %v", err))
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := make([]byte, padding)
|
||||
for i := 0; i < padding; i++ {
|
||||
padtext[i] = byte(padding)
|
||||
}
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func pkcs5UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
if length == 0 {
|
||||
return origData
|
||||
}
|
||||
unpadding := int(origData[length-1])
|
||||
if unpadding > length {
|
||||
return origData
|
||||
}
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
func sm4ECBEncrypt(key, plaintext []byte) ([]byte, error) {
|
||||
block, err := sm4.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
plaintext = pkcs5Padding(plaintext, blockSize)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
for start := 0; start < len(plaintext); start += blockSize {
|
||||
block.Encrypt(ciphertext[start:start+blockSize], plaintext[start:start+blockSize])
|
||||
}
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ZZMarquis/gm/sm4"
|
||||
"github.com/tjfoc/gmsm/sm2"
|
||||
"github.com/tjfoc/gmsm/x509"
|
||||
)
|
||||
|
||||
// EncryptRequest 加密请求
|
||||
// 对齐 YouChuKoffee 的 EncryptRequest → postbank.Encrypt 流程:
|
||||
// 1. 序列化完整 request({head, body} 一起)
|
||||
// 2. SM4 CBC 加密 → base64 → addNewline(每76字符加 \r\n)
|
||||
// 3. SM2 加密 SM4 密钥(使用 SOP 公钥)→ HEX 大写作为 encryptKey
|
||||
// 4. signature = SM2_Sign(request_base64 + encryptKey + accessToken)
|
||||
// 5. 返回 {request, signature, encryptKey, accessToken}
|
||||
func EncryptRequest(request interface{}, cfg Config) (map[string]string, error) {
|
||||
client := NewClient(cfg)
|
||||
accessToken := ""
|
||||
|
||||
// Step 1: 序列化完整 request({head, body} 一起加密)
|
||||
inputBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("序列化请求失败: %v", err)
|
||||
}
|
||||
inputJson := string(inputBytes)
|
||||
|
||||
// Step 2: SM4 CBC 加密
|
||||
sm4Key := generateSM4Key()
|
||||
iv := getSM4IV()
|
||||
paddedData := pkcs5Padding([]byte(inputJson), sm4.BlockSize)
|
||||
tmp, err := sm4.CBCEncrypt(sm4Key, iv, paddedData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SM4加密失败: %v", err)
|
||||
}
|
||||
responseMsg := base64.StdEncoding.EncodeToString(tmp)
|
||||
responseMsg = addNewline(responseMsg) // 对齐 YouChuKoffee,每76字符加 \r\n
|
||||
|
||||
// Step 3: SM2 加密 SM4 密钥
|
||||
sopPubKey, err := x509.ReadPublicKeyFromHex(cfg.SopPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取SOP公钥失败: %v", err)
|
||||
}
|
||||
encryptKeyBytes, err := sm2.Encrypt(sopPubKey, sm4Key, rand.Reader, sm2.C1C3C2)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("SM2加密SM4密钥失败: %v", err)
|
||||
}
|
||||
encryptKey := strings.ToUpper(hex.EncodeToString(encryptKeyBytes))
|
||||
|
||||
// Step 4: 签名(对齐 YouChuKoffee sign():UserID = MerchantId)
|
||||
signContent := fmt.Sprintf("%s%s%s", responseMsg, encryptKey, accessToken)
|
||||
signature, err := client.signWithUserID(signContent, []byte(cfg.MerchantId))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成签名失败: %v", err)
|
||||
}
|
||||
|
||||
result := map[string]string{
|
||||
"request": responseMsg,
|
||||
"signature": signature,
|
||||
"encryptKey": encryptKey,
|
||||
"accessToken": accessToken,
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// signWithUserID 使用指定 UserID 对内容进行 SM2 签名
|
||||
// 对齐 YouChuKoffee 的 sign() + rSToSign():直接返回 r.Text(16) + "#" + s.Text(16),不做 base64 编码
|
||||
func (c *Client) signWithUserID(content string, userId []byte) (string, error) {
|
||||
privKey, err := x509.ReadPrivateKeyFromHex(c.cfg.PrivateKey)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("读取私钥失败: %v", err)
|
||||
}
|
||||
r, s, err := sm2.Sm2Sign(privKey, []byte(content), userId, rand.Reader)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("SM2签名失败: %v", err)
|
||||
}
|
||||
return r.Text(16) + "#" + s.Text(16), nil
|
||||
}
|
||||
|
||||
// addNewline 每76个字符添加 \r\n,对齐 YouChuKoffee 的 postbank.addNewline
|
||||
func addNewline(str string) string {
|
||||
lineLength := 76
|
||||
var result strings.Builder
|
||||
for i := 0; i < len(str); i++ {
|
||||
if i > 0 && i%lineLength == 0 {
|
||||
result.WriteString("\r\n")
|
||||
}
|
||||
result.WriteByte(str[i])
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DecryptNotify 解密回调通知
|
||||
func (c *Client) DecryptNotify(rawJson string) (string, error) {
|
||||
return c.DecryptResponse(rawJson, true)
|
||||
}
|
||||
|
||||
// VerifyNotifySignature 验证回调通知签名
|
||||
func (c *Client) VerifyNotifySignature(content, signature string) bool {
|
||||
return c.VerifySignature(content, signature)
|
||||
}
|
||||
|
||||
// ParseNotify 解析回调通知
|
||||
func (c *Client) ParseNotify(rawJson string) (*NotifyRequest, error) {
|
||||
var req NotifyRequest
|
||||
if err := json.Unmarshal([]byte(rawJson), &req); err != nil {
|
||||
return nil, fmt.Errorf("解析通知失败: %v", err)
|
||||
}
|
||||
return &req, nil
|
||||
}
|
||||
|
||||
// VerifyAndParseNotify 验签并解析回调通知
|
||||
func (c *Client) VerifyAndParseNotify(rawJson string) (*YouChuOrderNotifyRequest, error) {
|
||||
decrypted, err := c.DecryptNotify(rawJson)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密通知失败: %v", err)
|
||||
}
|
||||
|
||||
var result YouChuOrderNotifyRequest
|
||||
if err := json.Unmarshal([]byte(decrypted), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析解密后数据失败: %v,解密内容: %s", err, decrypted)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OrderQuery 查询订单支付状态
|
||||
// 对齐 YouChuKoffee 的 OrderQuery 流程:
|
||||
// 1. 构建完整 {head, body} 结构
|
||||
// 2. 整个 {head, body} 一起加密(EncryptRequest)
|
||||
// 3. head 同时作为 HTTP Header 明文传输
|
||||
func (c *Client) OrderQuery(orderNo string) (*OrderQueryResponse, error) {
|
||||
now := time.Now().Format("20060102150405")
|
||||
BusiMainId := now + RandomNumber(10)
|
||||
|
||||
// 构建完整 request(head+body 一起加密,对齐 YouChuKoffee)
|
||||
requestBody := map[string]interface{}{
|
||||
"head": map[string]string{
|
||||
"partnerTxSriNo": BusiMainId,
|
||||
"reqTime": now,
|
||||
"method": "b2c.gatewaypay.orderQuery",
|
||||
"version": "1",
|
||||
"merchantId": c.cfg.MerchantId,
|
||||
"appID": c.cfg.AppID,
|
||||
"accessType": "API",
|
||||
"reserve": "",
|
||||
},
|
||||
"body": map[string]interface{}{
|
||||
"busiMainId": BusiMainId,
|
||||
"reqTransTime": now,
|
||||
"data": map[string]string{
|
||||
"txnCode": "1004",
|
||||
"sourceId": "16",
|
||||
"reqTraceId": now + RandomNumber(10),
|
||||
"reqDate": now, // 14 位 YYYYMMDDHHmmss
|
||||
"txnDt": now,
|
||||
"mchtNo": c.cfg.MchtNo,
|
||||
"oldSeqNo": orderNo,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 整个 {head, body} 一起加密
|
||||
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密请求失败: %v", err)
|
||||
}
|
||||
|
||||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result OrderQueryResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
|
||||
return nil, fmt.Errorf("订单查询失败,错误码: %s,错误信息: %s", result.RespCode, result.RespMsg)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreatePaymentLink 创建支付链接
|
||||
func (c *Client) CreatePaymentLink(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
||||
var payUrlTemplate string
|
||||
if len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?") {
|
||||
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
|
||||
orderData := map[string]string{
|
||||
"merchantNo": c.cfg.MchtNo,
|
||||
"orderInfos": req.ProductName,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
|
||||
"acctType": "2",
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
|
||||
}
|
||||
|
||||
signData := map[string]string{
|
||||
"merchantNo": c.cfg.MchtNo,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
}
|
||||
|
||||
sign, enKey, err := c.EncryptMobile(MapToString(orderData), MapToString(signData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密支付参数失败: %v", err)
|
||||
}
|
||||
|
||||
payUrl := fmt.Sprintf(payUrlTemplate,
|
||||
req.BackUrl,
|
||||
sign,
|
||||
c.cfg.ShopId,
|
||||
enKey,
|
||||
url.QueryEscape(c.cfg.ReturnUrl),
|
||||
c.cfg.ShowTitleBar,
|
||||
)
|
||||
|
||||
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
|
||||
signature := HmacSha256To16(c.cfg.Sha, plainText)
|
||||
|
||||
return &PaymentLinkResponse{
|
||||
OrderNo: req.OrderNo,
|
||||
NotifyUrl: c.cfg.NotifyUrl,
|
||||
Sign: signature,
|
||||
PlainText: plainText,
|
||||
PayUrl: payUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreatePaymentLinkWithBackUrl 创建支付链接(带 fromId 判断)
|
||||
func (c *Client) CreatePaymentLinkWithBackUrl(req PaymentLinkRequest) (*PaymentLinkResponse, error) {
|
||||
var payUrlTemplate string
|
||||
hasQuery := len(req.BackUrl) > 0 && strings.Contains(req.BackUrl, "?")
|
||||
hasFromId := len(req.BackUrl) > 0 && contains(req.BackUrl, "fromId")
|
||||
|
||||
if hasFromId {
|
||||
if hasQuery {
|
||||
payUrlTemplate = "%s&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
} else {
|
||||
if hasQuery {
|
||||
payUrlTemplate = "%s&fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
} else {
|
||||
payUrlTemplate = "%s?fromId=include_sb&tysdPayParams=%s&tysdShopid=%s&tysdEncryptKey=%s&returnUrl=%s&showTitleBar=%s"
|
||||
}
|
||||
}
|
||||
|
||||
orderData := map[string]string{
|
||||
"merchantNo": c.cfg.MchtNo,
|
||||
"orderInfos": req.ProductName,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
"successUrl": hex.EncodeToString([]byte(c.cfg.SuccessUrl)),
|
||||
"acctType": "2",
|
||||
"notifyUrl": hex.EncodeToString([]byte(c.cfg.NotifyUrl)),
|
||||
}
|
||||
|
||||
signData := map[string]string{
|
||||
"merchantNo": c.cfg.MchtNo,
|
||||
"orderNo": req.OrderNo,
|
||||
"amount": req.Price,
|
||||
}
|
||||
|
||||
sign, enKey, err := c.EncryptMobile(MapToString(orderData), MapToString(signData))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密支付参数失败: %v", err)
|
||||
}
|
||||
|
||||
payUrl := fmt.Sprintf(payUrlTemplate,
|
||||
req.BackUrl,
|
||||
sign,
|
||||
c.cfg.ShopId,
|
||||
enKey,
|
||||
url.QueryEscape(c.cfg.ReturnUrl),
|
||||
c.cfg.ShowTitleBar,
|
||||
)
|
||||
|
||||
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
|
||||
signature := HmacSha256To16(c.cfg.Sha, plainText)
|
||||
|
||||
return &PaymentLinkResponse{
|
||||
OrderNo: req.OrderNo,
|
||||
NotifyUrl: c.cfg.NotifyUrl,
|
||||
Sign: signature,
|
||||
PlainText: plainText,
|
||||
PayUrl: payUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
return len(s) > 0 && len(substr) > 0 && strings.Contains(s, substr)
|
||||
}
|
||||
|
||||
// CreateHandCodePayParams 生成 handCodePay 插件参数
|
||||
func (c *Client) CreateHandCodePayParams(req PaymentLinkRequest) (*HandCodePayResponse, error) {
|
||||
plainText := c.cfg.MchtNo + "|" + req.OrderNo + "|" + req.Price
|
||||
signature := HmacSha256To16(c.cfg.Sha, plainText)
|
||||
|
||||
txnDt := time.Now().Format("2006-01-02")
|
||||
|
||||
plain := fmt.Sprintf("TermSsn=%s|MercCode=%s|TranAmt=%s|MercUrl=%s|psbcmcc=%s|BackLink=%s|TxnDt=%s",
|
||||
req.OrderNo,
|
||||
c.cfg.MchtNo,
|
||||
req.Price,
|
||||
c.cfg.NotifyUrl,
|
||||
c.cfg.Psbcmcc,
|
||||
req.BackUrl,
|
||||
txnDt,
|
||||
)
|
||||
|
||||
return &HandCodePayResponse{
|
||||
Plain: plain,
|
||||
Sign: signature,
|
||||
PlainText: plainText,
|
||||
Signature: "",
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Refund 申请退款
|
||||
// 对齐 YouChuKoffee 的 OrderRefund 流程:
|
||||
// 1. 构建完整 {head, body} 结构(body 包含 busiMainId, reqTransTime, data)
|
||||
// 2. 整个 {head, body} 一起加密
|
||||
// 3. head 同时作为 HTTP Header 明文传输
|
||||
func (c *Client) Refund(req RefundRequest) (*RefundResponse, error) {
|
||||
now := time.Now().Format("20060102150405")
|
||||
BusiMainId := now + RandomNumber(10)
|
||||
|
||||
// 构建完整 request(head+body 一起加密,对齐 YouChuKoffee)
|
||||
requestBody := map[string]interface{}{
|
||||
"head": map[string]string{
|
||||
"partnerTxSriNo": BusiMainId,
|
||||
"reqTime": now,
|
||||
"method": "b2c.gatewaypay.orderRefund",
|
||||
"version": "1",
|
||||
"merchantId": c.cfg.MerchantId,
|
||||
"appID": c.cfg.AppID,
|
||||
"accessType": "API",
|
||||
"reserve": "",
|
||||
},
|
||||
"body": map[string]interface{}{
|
||||
"busiMainId": BusiMainId,
|
||||
"reqTransTime": now,
|
||||
"data": map[string]string{
|
||||
"txnCode": "1003",
|
||||
"sourceId": "16",
|
||||
"reqTraceId": req.OrderNo + now[4:14], // MMDDHHmmss 10位后缀
|
||||
"reqDate": now, // 14 位 YYYYMMDDHHmmss
|
||||
"mchtNo": c.cfg.MchtNo,
|
||||
"orgTxnSeq": req.OrgTxnSeq,
|
||||
"txnAmt": req.Price,
|
||||
"orgTxnAmt": req.Price,
|
||||
"refundDesc": "用户主动退款",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 整个 {head, body} 一起加密
|
||||
encryptedReq, err := EncryptRequest(requestBody, c.cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加密请求失败: %v", err)
|
||||
}
|
||||
|
||||
encryptedBytes, _ := json.Marshal(encryptedReq)
|
||||
url := c.cfg.OrderHost + c.cfg.MerchantId + ".htm?partnerTxSriNo=" + BusiMainId
|
||||
|
||||
// head 同时作为 HTTP Header 明文传输
|
||||
head := requestBody["head"].(map[string]string)
|
||||
body, err := c.doPost(url, head, encryptedBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseData, err := c.DecryptResponse(string(body), false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解密响应失败: %v,原始响应: %s", err, string(body))
|
||||
}
|
||||
|
||||
var result RefundResponse
|
||||
if err := json.Unmarshal([]byte(responseData), &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v,响应内容: %s", err, responseData)
|
||||
}
|
||||
|
||||
if result.RespCode != "" && result.RespCode != "0000" && result.RespCode != "00" {
|
||||
return nil, fmt.Errorf("退款申请失败,错误码: %s,错误信息: %s", result.RespCode, result.RespMsg)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
package payment
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config 支付配置
|
||||
type Config struct {
|
||||
MerchantId string
|
||||
MchtNo string
|
||||
AppID string
|
||||
SopPublicKey string
|
||||
PrivateKey string
|
||||
Pubkey string
|
||||
BankKey string
|
||||
Sha string
|
||||
ReturnUrl string
|
||||
SuccessUrl string
|
||||
NotifyUrl string
|
||||
ShowTitleBar string
|
||||
LoginHost string
|
||||
OrderHost string
|
||||
FileHost string
|
||||
ShopId string
|
||||
Psbcmcc string // 三方服务商标识,如 LSXD、JBZ
|
||||
}
|
||||
|
||||
// PaymentLinkRequest 生成支付链接请求
|
||||
type PaymentLinkRequest struct {
|
||||
OrderNo string
|
||||
ProductName string
|
||||
Price string
|
||||
BackUrl string
|
||||
}
|
||||
|
||||
// PaymentLinkResponse 生成支付链接响应
|
||||
type PaymentLinkResponse struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
NotifyUrl string `json:"notify_url"`
|
||||
Sign string `json:"sign"`
|
||||
PlainText string `json:"plain_text"`
|
||||
PayUrl string `json:"pay_url"`
|
||||
}
|
||||
|
||||
// HandCodePayResponse handCodePay 插件参数
|
||||
type HandCodePayResponse struct {
|
||||
Plain string `json:"plain"`
|
||||
Sign string `json:"sign"`
|
||||
PlainText string `json:"plain_text"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
// OrderQueryRequest 订单查询请求
|
||||
type OrderQueryRequest struct {
|
||||
OrderNo string
|
||||
}
|
||||
|
||||
// OrderQueryResponse 订单查询响应
|
||||
type OrderQueryResponse struct {
|
||||
RespCode string `json:"code"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
RespCd string `json:"respCd"`
|
||||
ReqTraceId string `json:"reqTraceId"` //请求方流水号或者订单号,
|
||||
OrderNo string `json:"orderNo"` //统一收单订单号
|
||||
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败 05-检查失败
|
||||
TxnFg string `json:"txnFg"` //0-正常 2-已部分退货 3- 已全部退货
|
||||
TxnAmt string `json:"txnAmt"` // 交易金额 单位为元,精确到小数点后2位
|
||||
}
|
||||
|
||||
// RefundRequest 退款请求
|
||||
type RefundRequest struct {
|
||||
OrderNo string
|
||||
Price string
|
||||
OrgTxnSeq string
|
||||
RefundDesc string
|
||||
}
|
||||
|
||||
// RefundResponse 退款响应
|
||||
type RefundResponse struct {
|
||||
RespCode string `json:"code"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
RespCd string `json:"respCd"`
|
||||
TxnCode string `json:"txnCode"`
|
||||
SourceId string `json:"sourceId"`
|
||||
ReqTraceId string `json:"ReqTraceId"`
|
||||
RefundOrderNo string `json:"refundOrderNo"`
|
||||
RefundOrderSta string `json:"refundOrderSta"`
|
||||
MchtNo string `json:"mchtNo"`
|
||||
TxnAmt string `json:"txnAmt"`
|
||||
}
|
||||
|
||||
// BillQueryRequest 对账单查询请求
|
||||
type BillQueryRequest struct {
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
// BillQueryResponse 对账单查询响应
|
||||
type BillQueryResponse struct {
|
||||
Files []map[string]interface{} `json:"files"`
|
||||
}
|
||||
|
||||
// BillDownloadRequest 对账单下载请求
|
||||
type BillDownloadRequest struct {
|
||||
FileId string
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
// NotifyRequest 回调通知请求
|
||||
type NotifyRequest struct {
|
||||
Request string `json:"request"`
|
||||
Signature string `json:"signature"`
|
||||
AccessToken string `json:"accessToken"`
|
||||
EncryptKey string `json:"encryptKey"`
|
||||
}
|
||||
|
||||
// NotifyResponse 回调通知响应
|
||||
type NotifyResponse struct {
|
||||
RespCode string `json:"respCode"`
|
||||
RespMsg string `json:"respMsg"`
|
||||
Data interface{} `json:"data"`
|
||||
LinkUrl string `json:"linkUrl"`
|
||||
}
|
||||
|
||||
type YouChuOrderNotifyRequest struct {
|
||||
TxnCode string `json:"txnCode"`
|
||||
SourceId string `json:"sourceId"`
|
||||
ReqDate string `json:"reqDate"`
|
||||
ReqTraceId string `json:"reqTraceId"` // 商户提交的订单号
|
||||
OrderNo string `json:"orderNo"` // 银行的订单号
|
||||
TxnAmt string `json:"txnAmt"`
|
||||
OrderSta string `json:"orderSta"` //03-支付成功 04-支付失败05-检查失败
|
||||
MchtNo string `json:"mchtNo"`
|
||||
TermId string `json:"termId"`
|
||||
TxnFlag string `json:"txnFlag"` //01-消费 03-退货
|
||||
TxnKind string `json:"txnKind"` //01-银行卡 02-微信 03-支付宝
|
||||
}
|
||||
|
||||
// OrderStatus 订单状态
|
||||
type OrderStatus string
|
||||
|
||||
const (
|
||||
OrderStatusWait OrderStatus = "01"
|
||||
OrderStatusSuccess OrderStatus = "03"
|
||||
OrderStatusFail OrderStatus = "04"
|
||||
OrderStatusCheckFail OrderStatus = "05"
|
||||
)
|
||||
|
||||
// RefundStatus 退款状态
|
||||
type RefundStatus string
|
||||
|
||||
const (
|
||||
RefundStatusSuccess RefundStatus = "03"
|
||||
RefundStatusFail RefundStatus = "04"
|
||||
)
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
"PaymentCenter/app/third/paymentService/payCommon"
|
||||
psbc "PaymentCenter/app/third/paymentService/psbc"
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PsbcPay struct {
|
||||
MerchantId string `json:"merchant_id"` // 商户ID
|
||||
MchtNo string `json:"mcht_no"` // 商户号
|
||||
AppID string `json:"app_id"` // 应用ID
|
||||
SopPublicKey string `json:"sop_public_key"` // SOP公钥
|
||||
PrivateKey string `json:"private_key"` // 商户私钥
|
||||
Pubkey string `json:"pubkey"` // 商户公钥
|
||||
BankKey string `json:"bank_key"` // 银行公钥
|
||||
Sha string `json:"sha"` // SHA密钥
|
||||
ReturnUrl string `json:"return_url"` // 支付返回地址
|
||||
SuccessUrl string `json:"success_url"` // 支付成功地址
|
||||
NotifyUrl string `json:"notify_url"` // 回调通知地址
|
||||
ShowTitleBar string `json:"show_title_bar"` // 是否显示标题栏
|
||||
LoginHost string `json:"login_host"` // 登录服务地址
|
||||
OrderHost string `json:"order_host"` // 订单服务地址
|
||||
FileHost string `json:"file_host"` // 文件服务地址
|
||||
ShopId string `json:"shop_id"` // 店铺ID
|
||||
Psbcmcc string `json:"psbcmcc"` // 三方服务商标识
|
||||
}
|
||||
|
||||
func PsbcInitClient(psbcConfig PsbcPay) *psbc.Client {
|
||||
cfg := psbc.Config{
|
||||
MerchantId: psbcConfig.MerchantId,
|
||||
MchtNo: psbcConfig.MchtNo,
|
||||
AppID: psbcConfig.AppID,
|
||||
SopPublicKey: psbcConfig.SopPublicKey,
|
||||
PrivateKey: psbcConfig.PrivateKey,
|
||||
Pubkey: psbcConfig.Pubkey,
|
||||
BankKey: psbcConfig.BankKey,
|
||||
Sha: psbcConfig.Sha,
|
||||
ReturnUrl: psbcConfig.ReturnUrl,
|
||||
SuccessUrl: psbcConfig.SuccessUrl,
|
||||
NotifyUrl: psbcConfig.NotifyUrl,
|
||||
ShowTitleBar: psbcConfig.ShowTitleBar,
|
||||
LoginHost: psbcConfig.LoginHost,
|
||||
OrderHost: psbcConfig.OrderHost,
|
||||
FileHost: psbcConfig.FileHost,
|
||||
ShopId: psbcConfig.ShopId,
|
||||
Psbcmcc: psbcConfig.Psbcmcc,
|
||||
}
|
||||
return psbc.NewClient(cfg)
|
||||
}
|
||||
|
||||
func PsbcPayInfo(c context.Context, payOrderRequest PayOrderRequest) (string, error) {
|
||||
envConfig := config.GetConf()
|
||||
notifyUrl := fmt.Sprintf(envConfig.PayService.Host+payCommon.PSBC_NOTIFY_URL_TEST+"%d", payOrderRequest.PayChannelId)
|
||||
|
||||
psbcConfig := payOrderRequest.Psbc
|
||||
psbcConfig.NotifyUrl = notifyUrl
|
||||
psbcClient := PsbcInitClient(psbcConfig)
|
||||
|
||||
amount := fmt.Sprintf("%.2f", float64(payOrderRequest.Amount)/100.0)
|
||||
orderNo := strconv.FormatInt(payOrderRequest.OrderId, 10)
|
||||
|
||||
req := psbc.PaymentLinkRequest{
|
||||
OrderNo: orderNo,
|
||||
ProductName: payOrderRequest.Description,
|
||||
Price: amount,
|
||||
BackUrl: payOrderRequest.ReturnUrl,
|
||||
}
|
||||
|
||||
resp, err := psbcClient.CreateHandCodePayParams(req)
|
||||
if err != nil {
|
||||
logger.Error(c, "PsbcPayInfo 发生错误", fmt.Sprintf("错误信息:%s", err.Error()))
|
||||
return "", err
|
||||
}
|
||||
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
logger.Error(c, "PsbcPayInfo 序列化失败", fmt.Sprintf("错误信息:%s", err.Error()))
|
||||
return "", err
|
||||
}
|
||||
return string(respBytes), nil
|
||||
}
|
||||
|
||||
func PsbcOrderQuery(ctx context.Context, psbcConfig PsbcPay, orderNo string) (PayOrderQueryInfo, error) {
|
||||
psbcClient := PsbcInitClient(psbcConfig)
|
||||
|
||||
resp, err := psbcClient.OrderQuery(orderNo)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "PsbcOrderQuery 发生错误", fmt.Sprintf("错误信息:%s", err.Error()))
|
||||
return PayOrderQueryInfo{}, err
|
||||
}
|
||||
|
||||
tradeState := "NOTPAY"
|
||||
tradeStateDesc := ""
|
||||
switch resp.OrderSta {
|
||||
case "03":
|
||||
tradeState = "SUCCESS"
|
||||
tradeStateDesc = "支付成功"
|
||||
case "04", "05":
|
||||
tradeState = "FAIL"
|
||||
tradeStateDesc = "支付失败"
|
||||
default:
|
||||
tradeState = "NOTPAY"
|
||||
tradeStateDesc = "未支付"
|
||||
}
|
||||
|
||||
var amountTotal int64
|
||||
var payerTotal int64
|
||||
if resp.TxnAmt != "" {
|
||||
amountFloat, err := strconv.ParseFloat(resp.TxnAmt, 64)
|
||||
if err == nil {
|
||||
amountTotal = int64(amountFloat * 100)
|
||||
payerTotal = int64(amountFloat * 100)
|
||||
}
|
||||
}
|
||||
|
||||
successTime := ""
|
||||
|
||||
outTradeNo, _ := strconv.ParseInt(orderNo, 10, 64)
|
||||
return PayOrderQueryInfo{
|
||||
AppId: psbcConfig.AppID,
|
||||
OutTradeNo: outTradeNo,
|
||||
TransactionId: resp.OrderNo,
|
||||
TradeState: tradeState,
|
||||
TradeStateDesc: tradeStateDesc,
|
||||
SuccessTime: successTime,
|
||||
AmountTotal: amountTotal,
|
||||
PayerTotal: payerTotal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PsbcRefundOrder(ctx context.Context, orderRefundRequest OrderRefundRequest) (OrderRefundInfo, error) {
|
||||
psbcClient := PsbcInitClient(orderRefundRequest.Psbc)
|
||||
|
||||
refundAmount := fmt.Sprintf("%.2f", float64(orderRefundRequest.RefundAmount)/100.0)
|
||||
orderNo := strconv.FormatInt(orderRefundRequest.OrderId, 10)
|
||||
|
||||
req := psbc.RefundRequest{
|
||||
OrderNo: orderNo,
|
||||
Price: refundAmount,
|
||||
OrgTxnSeq: orderRefundRequest.TransactionId,
|
||||
RefundDesc: orderRefundRequest.RefundReason,
|
||||
}
|
||||
|
||||
resp, err := psbcClient.Refund(req)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "PsbcRefundOrder 发生错误", fmt.Sprintf("申请退款接口失败,错误信息:%s", err.Error()))
|
||||
return OrderRefundInfo{}, err
|
||||
}
|
||||
|
||||
refundStatus := payCommon.PAY_REFUND_STATU_COMMON
|
||||
switch resp.RefundOrderSta {
|
||||
case "03":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_SUCCESS
|
||||
case "04":
|
||||
refundStatus = payCommon.PAY_REFUND_STATU_FAIL
|
||||
}
|
||||
|
||||
refundFee := int64(0)
|
||||
if resp.TxnAmt != "" {
|
||||
amountFloat, err := strconv.ParseFloat(resp.TxnAmt, 64)
|
||||
if err == nil {
|
||||
refundFee = int64(amountFloat * 100)
|
||||
}
|
||||
}
|
||||
|
||||
return OrderRefundInfo{
|
||||
OutTradeNo: orderRefundRequest.OrderId,
|
||||
TransactionId: resp.RefundOrderNo,
|
||||
RefundFee: refundFee,
|
||||
RefundOrderId: orderRefundRequest.RefundOrderId,
|
||||
RefundStatus: refundStatus,
|
||||
RefundSuccessTime: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PsbcCloseOrder(ctx context.Context, orderCloseRequest OrderCloseRequest) (OrderCloseInfo, error) {
|
||||
return OrderCloseInfo{
|
||||
OutTradeNo: orderCloseRequest.OrderId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PsbcVerifyAndParseNotify(rawBody string, psbcConfig PsbcPay) (orderId int64, amountTotal int64, payerTotal int64, status string, err error) {
|
||||
psbcClient := PsbcInitClient(psbcConfig)
|
||||
|
||||
result, err := psbcClient.VerifyAndParseNotify(rawBody)
|
||||
if err != nil {
|
||||
logger.Error(context.Background(), "PsbcVerifyAndParseNotify 发生错误", fmt.Sprintf("验签解密失败,错误信息:%s", err.Error()))
|
||||
return 0, 0, 0, "", err
|
||||
}
|
||||
|
||||
orderId, err = strconv.ParseInt(result.ReqTraceId, 10, 64)
|
||||
if err != nil {
|
||||
logger.Error(context.Background(), "PsbcVerifyAndParseNotify 发生错误", fmt.Sprintf("订单号转换失败,错误信息:%s", err.Error()))
|
||||
return 0, 0, 0, "", err
|
||||
}
|
||||
|
||||
if result.TxnAmt != "" {
|
||||
amountFloat, err := strconv.ParseFloat(result.TxnAmt, 64)
|
||||
if err == nil {
|
||||
amountTotal = int64(amountFloat * 100)
|
||||
payerTotal = amountTotal
|
||||
}
|
||||
}
|
||||
|
||||
orderSta := ""
|
||||
if result.OrderSta != "" {
|
||||
orderSta = result.OrderSta
|
||||
}
|
||||
|
||||
switch orderSta {
|
||||
case "03":
|
||||
status = "SUCCESS"
|
||||
case "04", "05":
|
||||
status = "FAIL"
|
||||
default:
|
||||
status = "NOTPAY"
|
||||
}
|
||||
|
||||
return orderId, amountTotal, payerTotal, status, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package paymentService
|
||||
|
||||
import (
|
||||
"PaymentCenter/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/qit-team/snow-core/kernel/server"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPsbcPay(t *testing.T) {
|
||||
c := context.Background()
|
||||
//解析启动命令
|
||||
opts := config.GetOptions()
|
||||
if opts.ShowVersion {
|
||||
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
//加载配置
|
||||
opts.ConfFile = "../../../.env"
|
||||
cf, err := config.Load(opts.ConfFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//注册日志类服务
|
||||
err = logger.Pr.Register(logger.SingletonMain, cf.Log, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//data := `{"merchant_id": "your_merchant_id", "mcht_no": "your_mcht_no", "app_id": "your_app_id", "sop_public_key": "your_sop_public_key", "private_key": "your_private_key", "pubkey": "your_pubkey", "bank_key": "your_bank_key", "sha": "your_sha_key", "return_url": "https://example.com/return", "success_url": "https://example.com/success", "notify_url": "https://example.com/notify", "show_title_bar": "1", "login_host": "https://login.example.com", "order_host": "https://order.example.com", "file_host": "https://file.example.com", "shop_id": "your_shop_id"}`
|
||||
|
||||
psbc := PsbcPay{
|
||||
MerchantId: "testMerchant001",
|
||||
MchtNo: "100610100019042",
|
||||
AppID: "961925472724332544001",
|
||||
SopPublicKey: "04CABE03249C94BDC8A6A4440DA1B2ADFACF73F4340E5F1B9A76463694B44C2E5600A9BEAA035739383C292CF9F1C4695FAAC7963CD5033D5D647A6B1EBE78EC6A",
|
||||
PrivateKey: "140c5c68da1829b79d8e4629a8b9548bd694ccc7061fbacb1079aed0e5ac33fa",
|
||||
Pubkey: "0447fe9ed13aac6200c92b893ad1289a98437c8404e64b1d2f7c755698a8b8e8acb35c1db2bedc5213c930bdfc10efb0e12269cf6a06877679f114fe5ae9dd4469",
|
||||
BankKey: "04E0E2E37F11901483CDFBC47F489D87D5D78C55DD7F919B73DEA83007748668B7871A1BA9608F156E25B7D64C7821379BAC1E2C591D5A50FF311D1AAE026C1DAE",
|
||||
Sha: "636879vrt96t57w6f59",
|
||||
ReturnUrl: "http://milk.h5.test.86698.cn/#/pages/ycnc/order",
|
||||
SuccessUrl: "http://milk.h5.test.86698.cn/#/pages/ycnc/orderDetail?isPayBack=true&order_no=",
|
||||
NotifyUrl: "http://milk.test.api.cdlsxd.cn/api/v1/order/notify",
|
||||
ShowTitleBar: "true",
|
||||
LoginHost: "http://wap.dev.psbc.com/sop-h5/biz/crecard/",
|
||||
OrderHost: "http://wap.dev.psbc.com/sop-h5/biz/unionpay/",
|
||||
FileHost: "",
|
||||
ShopId: "LSXD0001",
|
||||
}
|
||||
data, _ := json.Marshal(psbc)
|
||||
fmt.Println(string(data))
|
||||
//err = sonic.Unmarshal([]byte(data), &psbc)
|
||||
//if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
//}
|
||||
|
||||
request := PayOrderRequest{
|
||||
PayChannelId: 8935141660703064070,
|
||||
OrderId: 374700296052352,
|
||||
ChannelType: 11, // 11-邮储支付
|
||||
Description: "测试商品",
|
||||
Amount: 100,
|
||||
PayerClientIp: "192.168.110.235",
|
||||
Psbc: psbc,
|
||||
}
|
||||
//支付
|
||||
orderResult := PaymentService(c, request)
|
||||
t.Log(orderResult)
|
||||
|
||||
//// 查询订单
|
||||
//qreq := PayOrderQueryRequest{
|
||||
// OrderId: request.OrderId,
|
||||
// PayChannel: 3,
|
||||
// Psbc: request.Psbc,
|
||||
//}
|
||||
//queryResult := PayOrderQuery(c, qreq)
|
||||
//t.Log(queryResult)
|
||||
|
||||
//// 退款
|
||||
//refund := OrderRefundRequest{
|
||||
// OrderId: 3747002960422784848,
|
||||
// RefundOrderId: 2017620703512514385,
|
||||
// RefundReason: "测试支付商品",
|
||||
// RefundAmount: 500,
|
||||
// PayChannel: 11,
|
||||
// Psbc: request.Psbc,
|
||||
//}
|
||||
//refundResult := OrderRefund(c, refund)
|
||||
//t.Log(refundResult)
|
||||
|
||||
//// 关闭订单
|
||||
//closeOrder := OrderCloseRequest{
|
||||
// OrderId: request.OrderId,
|
||||
// PayChannel: 3,
|
||||
// Psbc: request.Psbc,
|
||||
//}
|
||||
//closeResutl := OrderClose(c, closeOrder)
|
||||
//t.Log(closeResutl)
|
||||
}
|
||||
|
|
@ -457,33 +457,13 @@ func PayType(payChannel int) int {
|
|||
return common.PAY_CHANNLE_TYPE_WECHAT
|
||||
case common.PAY_CHANNEL_ALIPAY_JSAPI, common.PAY_CHANNEL_ALIPAY_WEB, common.PAY_CHANNEL_ALIPAY_MINI, common.PAY_CHANNEL_ALIPAY_PC:
|
||||
return common.PAY_CHANNLE_TYPE_ZFB
|
||||
case common.PAY_CHANNEL_PSBC:
|
||||
return common.PAY_CHANNLE_TYPE_PSBC
|
||||
default:
|
||||
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
|
||||
}
|
||||
|
||||
// AcquireLock 尝试获取分布式锁,localValue用于检测是否是同一个客户端持有的锁锁
|
||||
func AcquireLock(key, lockValue string, expired time.Duration) (bool, error) {
|
||||
ctx := context.Background()
|
||||
|
|
|
|||
37
go.mod
37
go.mod
|
|
@ -5,7 +5,7 @@ go 1.23.0
|
|||
toolchain go1.23.10
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
github.com/BurntSushi/toml v1.1.0
|
||||
github.com/ZZMarquis/gm v1.3.2
|
||||
github.com/ahmetb/go-linq/v3 v3.2.0
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
|
|
@ -17,7 +17,7 @@ require (
|
|||
github.com/go-pay/util v0.0.2
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
|
|
@ -26,19 +26,19 @@ require (
|
|||
github.com/openzipkin/zipkin-go v0.2.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/qit-team/snow-core v0.1.28
|
||||
github.com/qit-team/snow-core v0.1.29
|
||||
github.com/qit-team/work v0.3.11
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271
|
||||
github.com/swaggo/gin-swagger v1.3.3
|
||||
github.com/swaggo/swag v1.7.9
|
||||
github.com/tjfoc/gmsm v1.4.1
|
||||
github.com/valyala/fasthttp v1.31.0
|
||||
github.com/valyala/fasthttp v1.48.0
|
||||
google.golang.org/grpc v1.56.3
|
||||
google.golang.org/protobuf v1.36.6
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||
xorm.io/builder v0.3.9
|
||||
xorm.io/xorm v1.2.5
|
||||
xorm.io/builder v0.3.13
|
||||
xorm.io/xorm v1.3.2
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -51,15 +51,16 @@ require (
|
|||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2 // indirect
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
|
|
@ -71,7 +72,7 @@ require (
|
|||
github.com/go-pay/xlog v0.0.3 // indirect
|
||||
github.com/go-pay/xtime v0.0.2 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.4 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
|
|
@ -81,7 +82,7 @@ require (
|
|||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
|
||||
|
|
@ -94,21 +95,24 @@ require (
|
|||
github.com/nats-io/jwt v0.3.2 // indirect
|
||||
github.com/nats-io/nkeys v0.1.3 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/stathat/consistent v1.0.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/tidwall/gjson v1.12.1 // indirect
|
||||
github.com/tidwall/gjson v1.15.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
|
|
@ -121,9 +125,8 @@ require (
|
|||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
stathat.com/c/consistent v1.0.0 // indirect
|
||||
xorm.io/core v0.7.3 // indirect
|
||||
)
|
||||
|
|
|
|||
180
go.sum
180
go.sum
|
|
@ -39,9 +39,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
|||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
|
|
@ -83,12 +84,11 @@ github.com/aliyun/aliyun-mns-go-sdk v1.0.2/go.mod h1:eD/mEH7SwtLSwI9p8fP9VTH2cYM
|
|||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/aliyunmq/mq-http-go-sdk v1.0.3/go.mod h1:JYfRMQoPexERvnNNBcal0ZQ2TVQ5ialDiW9ScjaadEM=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.0 h1:3eABKfxc1WmS2lLTTbKMe1gZfZV6u1Sx9orFnOfABV0=
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q=
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.1 h1:WY/LkOYSQaVyV+HOqdiIgF4LE3beZ/jwdSLKZlzpabw=
|
||||
github.com/apache/rocketmq-client-go/v2 v2.1.1/go.mod h1:GZzExtXY9zpI6FfiVJYAhw2IXQtgnHUuWpULo7nr5lw=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
|
|
@ -108,6 +108,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
|||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
|
|
@ -120,6 +124,10 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
|
@ -158,8 +166,9 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
|||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
|
|
@ -178,7 +187,9 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
|
|
@ -193,7 +204,7 @@ github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9S
|
|||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
|
|
@ -235,28 +246,28 @@ github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvSc
|
|||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
|
||||
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
|
@ -308,7 +319,7 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
|
|||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
|
@ -342,6 +353,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
|||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
|
@ -472,10 +484,12 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
|||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
|
|
@ -494,7 +508,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
|
||||
|
|
@ -528,13 +542,11 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
|
||||
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
|
|
@ -586,12 +598,13 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
|||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
|
|
@ -606,8 +619,12 @@ github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
|||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||
|
|
@ -653,8 +670,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/qit-team/snow-core v0.1.28 h1:RrX7i6GLbcMMSVzAT1lXgS/S3M2b1OrAnsoPaRGR4PI=
|
||||
github.com/qit-team/snow-core v0.1.28/go.mod h1:J9CNj6P2IRh72yVa7rut4T8ikq/4DjaisLqXZy40TNg=
|
||||
github.com/qit-team/snow-core v0.1.29 h1:tJVfFiv4kHo6DqfsPwwf/LfYSS2pik2WabnLsxzO358=
|
||||
github.com/qit-team/snow-core v0.1.29/go.mod h1:D8PXgiIFjSCelYyRSeZPSwebcDtsrCioTi/qtXR2yQM=
|
||||
github.com/qit-team/work v0.3.11 h1:AAtLTCOJ01WMFcvviK9rDGhHzaHE3bvunMOnSZ/80k8=
|
||||
github.com/qit-team/work v0.3.11/go.mod h1:h5m1cZjn+BznChuAyMiR/+IUyWEmaMylPKRhq/AlxKw=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
|
|
@ -676,6 +693,7 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC
|
|||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
|
|
@ -686,16 +704,15 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJ
|
|||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/assertions v1.2.1 h1:bKNHfEv7tSIjZ8JbKaFjzFINljxG4lzZvmHUnElzOIg=
|
||||
github.com/smartystreets/assertions v1.2.1/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
|
|
@ -709,6 +726,8 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
|
|||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stathat/consistent v1.0.0 h1:ZFJ1QTRn8npNBKW065raSZ8xfOqhpb8vLOkfp4CcL/U=
|
||||
github.com/stathat/consistent v1.0.0/go.mod h1:uajTPbgSygZBJ+V+0mY7meZ8i0XAcZs7AQ6V121XSxw=
|
||||
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw=
|
||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||
|
|
@ -728,6 +747,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
|
|
@ -740,15 +761,14 @@ github.com/swaggo/swag v1.7.9 h1:6vCG5mm43ebDzGlZPMGYrYI4zKFfOr5kicQX8qjeDwc=
|
|||
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
|
||||
github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
|
||||
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw=
|
||||
github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
|
|
@ -756,9 +776,9 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
|||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go v1.2.11/go.mod h1:2CGjQPolsidfhgBxo2wBo1Xh48rJWqUepV6q7OMkdWA=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
|
|
@ -766,8 +786,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
|
|||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.31.0 h1:lrauRLII19afgCs2fnWRJ4M5IkV0lo2FqA61uGkNBfE=
|
||||
github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||
github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc=
|
||||
github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
|
|
@ -778,7 +798,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
|
|
@ -801,8 +821,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
|
|
@ -817,6 +837,9 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
|||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
|
@ -836,10 +859,12 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -877,7 +902,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -927,11 +953,12 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
|||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -958,6 +985,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -1024,21 +1053,30 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -1048,6 +1086,11 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
@ -1118,7 +1161,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
@ -1242,7 +1286,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
|
|
@ -1265,8 +1310,9 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
|
|||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
|
@ -1355,7 +1401,6 @@ modernc.org/ccgo/v3 v3.12.95 h1:Ym2JG2G3P4IyZqjTTojHTl7qO0RysXeGSYPSoKPSBxc=
|
|||
modernc.org/ccgo/v3 v3.12.95/go.mod h1:ZcLyvtocXYi8uF+9Ebm3G8EF8HNY5hGomBqthDp4eC8=
|
||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
|
||||
modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg=
|
||||
|
|
@ -1408,30 +1453,29 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14=
|
|||
modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM=
|
||||
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
|
||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
|
||||
modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE=
|
||||
modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8=
|
||||
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
|
||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
|
||||
modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY=
|
||||
modernc.org/tcl v1.9.2/go.mod h1:aw7OnlIoiuJgu1gwbTZtrKnGpDqH9wyH++jZcxdqNsg=
|
||||
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
|
||||
modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY=
|
||||
modernc.org/z v1.2.20/go.mod h1:zU9FiF4PbHdOTUxw+IF8j7ArBMRPsHgq10uVPt6xTzo=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
stathat.com/c/consistent v1.0.0 h1:ezyc51EGcRPJUxfHGSgJjWzJdj3NiMU9pNfLNGiXV0c=
|
||||
stathat.com/c/consistent v1.0.0/go.mod h1:QkzMWzcbB+yQBL2AttO6sgsQS/JSTapcDISJalmCDS0=
|
||||
xorm.io/builder v0.3.9 h1:Sd65/LdWyO7LR8+Cbd+e7mm3sK/7U9k0jS3999IDHMc=
|
||||
xorm.io/builder v0.3.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
||||
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/core v0.7.3 h1:W8ws1PlrnkS1CZU1YWaYLMQcQilwAmQXU0BJDJon+H0=
|
||||
xorm.io/core v0.7.3/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
|
||||
xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo=
|
||||
xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0=
|
||||
xorm.io/xorm v1.3.2 h1:uTRRKF2jYzbZ5nsofXVUx6ncMaek+SHjWYtCXyZo1oM=
|
||||
xorm.io/xorm v1.3.2/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
||||
3
main.go
3
main.go
|
|
@ -4,6 +4,7 @@ import (
|
|||
"PaymentCenter/app/console"
|
||||
"PaymentCenter/app/http/routes"
|
||||
"PaymentCenter/app/jobs"
|
||||
"PaymentCenter/app/utils"
|
||||
"PaymentCenter/bootstrap"
|
||||
"PaymentCenter/config"
|
||||
_ "PaymentCenter/docs"
|
||||
|
|
@ -66,7 +67,7 @@ func main() {
|
|||
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
utils.Log(nil, "正在启动服务...")
|
||||
handleCmd(opts)
|
||||
|
||||
err := startServer(opts)
|
||||
|
|
|
|||
Loading…
Reference in New Issue