219 lines
5.7 KiB
Markdown
219 lines
5.7 KiB
Markdown
|
|
# MT Pay - PingPong支付对接
|
|||
|
|
|
|||
|
|
## 项目简介
|
|||
|
|
|
|||
|
|
本项目实现了PingPong支付平台的内嵌SDK接入,支持收银台模式支付。
|
|||
|
|
|
|||
|
|
## 功能特性
|
|||
|
|
|
|||
|
|
- ✅ 支付订单创建(checkout接口)
|
|||
|
|
- ✅ MD5/SHA256签名生成和验证
|
|||
|
|
- ✅ 支付回调处理
|
|||
|
|
- ✅ 订单状态查询
|
|||
|
|
- ✅ 收银台页面集成
|
|||
|
|
- ✅ 支付记录管理
|
|||
|
|
- ✅ 预授权支持(AUTH/CAPTURE/VOID)
|
|||
|
|
|
|||
|
|
## 技术栈
|
|||
|
|
|
|||
|
|
- Spring Boot 4.0.0
|
|||
|
|
- Spring Data JPA
|
|||
|
|
- MySQL
|
|||
|
|
- Lombok
|
|||
|
|
- RestClient
|
|||
|
|
|
|||
|
|
## 数据库表结构
|
|||
|
|
|
|||
|
|
### payment_order(支付订单表)
|
|||
|
|
- 存储支付订单基本信息
|
|||
|
|
- 包含商户订单号、PingPong交易流水号、金额、状态等
|
|||
|
|
|
|||
|
|
### payment_record(支付记录表)
|
|||
|
|
- 存储支付操作记录
|
|||
|
|
- 包含回调记录、查询记录等
|
|||
|
|
|
|||
|
|
## 配置说明
|
|||
|
|
|
|||
|
|
在 `application.properties` 中配置以下参数:
|
|||
|
|
|
|||
|
|
```properties
|
|||
|
|
# PingPong支付配置
|
|||
|
|
pingpong.client-id=your-client-id # PingPong商户号
|
|||
|
|
pingpong.acc-id=your-acc-id # PingPong商户店铺编号
|
|||
|
|
pingpong.secret=your-secret-key # 签名密钥
|
|||
|
|
pingpong.sign-type=MD5 # 签名类型(MD5或SHA256)
|
|||
|
|
pingpong.gateway=https://sandbox-acquirer-payment.pingpongx.com # API网关地址
|
|||
|
|
pingpong.mode=sandbox # 环境模式(sandbox/test/build)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## API接口
|
|||
|
|
|
|||
|
|
### 1. 创建支付订单
|
|||
|
|
|
|||
|
|
**接口地址:** `POST /api/payment/checkout`
|
|||
|
|
|
|||
|
|
**请求示例:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"accId": "2018092714313010016291",
|
|||
|
|
"amount": "20.00",
|
|||
|
|
"currency": "USD",
|
|||
|
|
"merchantTransactionId": "MTN193495030728",
|
|||
|
|
"paymentType": "SALE",
|
|||
|
|
"shopperResultUrl": "http://your-domain.com/api/callback/result",
|
|||
|
|
"shopperCancelUrl": "http://your-domain.com/api/callback/result",
|
|||
|
|
"signType": "MD5",
|
|||
|
|
"riskInfo": {
|
|||
|
|
"customer": {
|
|||
|
|
"firstName": "James",
|
|||
|
|
"lastName": "LeBron",
|
|||
|
|
"email": "demo@pingpongx.com",
|
|||
|
|
"phone": "15988890852",
|
|||
|
|
"registerTime": "20191101122000",
|
|||
|
|
"registerIp": "222.126.52.23",
|
|||
|
|
"orderTime": "20191201122000",
|
|||
|
|
"orderIp": "222.126.52.23"
|
|||
|
|
},
|
|||
|
|
"goods": [{
|
|||
|
|
"name": "Macaron",
|
|||
|
|
"description": "Colorful macaron",
|
|||
|
|
"sku": "20191201331",
|
|||
|
|
"averageUnitPrice": "20",
|
|||
|
|
"number": "1",
|
|||
|
|
"virtualProduct": "N"
|
|||
|
|
}],
|
|||
|
|
"shipping": {
|
|||
|
|
"firstName": "James",
|
|||
|
|
"lastName": "LeBron",
|
|||
|
|
"phone": "13588185079",
|
|||
|
|
"street": "1986 Broad Street",
|
|||
|
|
"postcode": "35222",
|
|||
|
|
"city": "Birmingham",
|
|||
|
|
"state": "Alabama",
|
|||
|
|
"country": "US"
|
|||
|
|
},
|
|||
|
|
"billing": {
|
|||
|
|
"firstName": "James",
|
|||
|
|
"lastName": "LeBron",
|
|||
|
|
"phone": "13588185079",
|
|||
|
|
"street": "1986 Broad Street",
|
|||
|
|
"postcode": "35222",
|
|||
|
|
"city": "Birmingham",
|
|||
|
|
"state": "Alabama",
|
|||
|
|
"country": "US"
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"notificationUrl": "http://your-domain.com/api/callback/pingpong"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**响应示例:**
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": "0000",
|
|||
|
|
"message": "订单创建成功",
|
|||
|
|
"data": {
|
|||
|
|
"merchantTransactionId": "MTN193495030728",
|
|||
|
|
"token": "vr_YVR8u7rn7C1gG97DOg5W0OxzazxNYIE56ShWjA4lJrY4wchTnb47oNmp-9ubP",
|
|||
|
|
"paymentUrl": "https://sandbox-pay-checkout.pingpongx.com/index.html?token=...",
|
|||
|
|
"status": "PENDING"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 查询订单状态
|
|||
|
|
|
|||
|
|
**接口地址:** `GET /api/payment/order/{merchantTransactionId}`
|
|||
|
|
|
|||
|
|
### 3. 获取收银台页面
|
|||
|
|
|
|||
|
|
**接口地址:** `GET /api/payment/checkout/page?token={token}`
|
|||
|
|
|
|||
|
|
### 4. 支付回调接口
|
|||
|
|
|
|||
|
|
**接口地址:** `POST /api/callback/pingpong`
|
|||
|
|
|
|||
|
|
### 5. 支付结果页面
|
|||
|
|
|
|||
|
|
**接口地址:** `GET /api/callback/result?merchantTransactionId={id}&status={status}`
|
|||
|
|
|
|||
|
|
## 使用流程
|
|||
|
|
|
|||
|
|
1. **创建支付订单**
|
|||
|
|
- 调用 `/api/payment/checkout` 接口创建订单
|
|||
|
|
- 获取返回的 `token`
|
|||
|
|
|
|||
|
|
2. **跳转到收银台**
|
|||
|
|
- 方式1:直接使用返回的 `paymentUrl` 跳转
|
|||
|
|
- 方式2:调用 `/api/payment/checkout/page?token={token}` 获取收银台页面
|
|||
|
|
|
|||
|
|
3. **用户完成支付**
|
|||
|
|
- 用户在收银台页面完成支付
|
|||
|
|
- 支付完成后跳转到 `shopperResultUrl`
|
|||
|
|
|
|||
|
|
4. **接收回调通知**
|
|||
|
|
- PingPong会异步调用 `notificationUrl` 通知支付结果
|
|||
|
|
- 系统自动更新订单状态
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
1. **订单号唯一性**:`merchantTransactionId` 必须全局唯一,不可重复
|
|||
|
|
2. **金额格式**:`amount` 必须精确到两位小数,如 "20.00"
|
|||
|
|
3. **环境模式**:开发测试使用 `sandbox`,生产环境必须使用 `build`
|
|||
|
|
4. **签名验证**:所有回调都会进行签名验证,确保数据安全
|
|||
|
|
5. **风控信息**:`riskInfo` 中的 `shipping`、`billing`、`goods` 不能为空,影响交易成功率
|
|||
|
|
6. **REVIEW状态**:如果订单状态为 `REVIEW`,需要及时进行内部审核
|
|||
|
|
|
|||
|
|
## 预授权功能
|
|||
|
|
|
|||
|
|
### AUTH(预授权)
|
|||
|
|
- 在创建订单时设置 `paymentType` 为 `AUTH`
|
|||
|
|
|
|||
|
|
### CAPTURE(预授权完成)
|
|||
|
|
- 调用二次交易接口,设置 `paymentType` 为 `CAPTURE`
|
|||
|
|
- 需要在预授权成功后的7天内完成
|
|||
|
|
|
|||
|
|
### VOID(预授权撤销)
|
|||
|
|
- 调用二次交易接口,设置 `paymentType` 为 `VOID`
|
|||
|
|
- 只能全额撤销
|
|||
|
|
|
|||
|
|
## 开发说明
|
|||
|
|
|
|||
|
|
### 项目结构
|
|||
|
|
```
|
|||
|
|
com.mtkj.mtpay/
|
|||
|
|
├── config/ # 配置类
|
|||
|
|
├── controller/ # 控制器
|
|||
|
|
├── dto/ # 数据传输对象
|
|||
|
|
├── entity/ # 实体类
|
|||
|
|
├── exception/ # 异常处理
|
|||
|
|
├── repository/ # 数据访问层
|
|||
|
|
└── service/ # 业务服务层
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 核心服务
|
|||
|
|
|
|||
|
|
- **SignatureService**:签名生成和验证服务
|
|||
|
|
- **PingPongPayService**:PingPong API调用服务
|
|||
|
|
- **PaymentOrderService**:支付订单业务服务
|
|||
|
|
- **CallbackService**:回调处理服务
|
|||
|
|
|
|||
|
|
## 数据库初始化
|
|||
|
|
|
|||
|
|
项目启动后,JPA会自动创建表结构。也可以手动执行SQL:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 根据实体类自动生成,或参考实体类定义手动创建
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 测试
|
|||
|
|
|
|||
|
|
1. 配置沙箱环境参数
|
|||
|
|
2. 调用创建订单接口
|
|||
|
|
3. 使用沙箱测试卡号完成支付测试
|
|||
|
|
|
|||
|
|
## 许可证
|
|||
|
|
|
|||
|
|
MIT
|
|||
|
|
|