# 预下单支付

C扫B当面付模式。调用接口生成二维码，消费者扫码完成支付。接口返回二维码内容，开发者需自行生成二维码图片。

预下单完成后需要主动发起轮询（调用查询接口）获取支付状态。

- 预下单成功标识：biz_response.result_code="PRECREATE_SUCCESS" 或 biz_response.data.order_status="CREATED"
- 订单有效支付时长约4分钟，超时未支付收钱吧会自动取消订单
- 轮询建议：0-1分钟每10s/5s/5s/10s/10s/10s/10s；1-2分钟每20s；2-4分钟每30s；第6分钟最后一次

**商户系统订单号必须在商户系统内唯一，支付失败订单的二次预下单请求，请创建新的商户订单号。**

## 接口说明

- 请求方式：`POST`
- 请求地址：`https://vsi-api.shouqianba.com/upay/v2/precreate`
- Operation ID：`precreate`

## 请求参数

无请求参数。

## 请求体

| 字段名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| client_sn | string | 是 | 商户系统订单号。必须在商户系统内唯一；且长度不超过32字节 |
| description | string | 否 | 商品详情。对商品或本次交易的描述 |
| extended | object | 否 | 扩展参数集合，JSON格式。最多支持24个字段，每个字段key长度不超过64字节，value长度不超过256字节。 |
| extended.attach | string | 否 | 附加数据。小程序扫码点餐订单必传：OrderSource=FoodOrder |
| extended.extend_params | object | 否 | 扩展参数。如：花呗分期参数 hb_fq_num、hb_fq_seller_percent 等。 |
| extended.extend_params.hb_fq_num | string | 否 | 花呗分期数，支持3/6/12期 |
| extended.extend_params.hb_fq_seller_percent | string | 否 | 花呗分期卖家承担手续费比例。100：商家承担；0：用户承担 |
| extended.goods_tag | string | 否 | 商品标记 |
| extended.sub_appid | string | 否 | 指定上送appid获取用户身份标识 |
| goods_details | array[object] | 否 | 商品详情列表 |
| goods_details[].goods_id | string | 是 | 商品的编号 |
| goods_details[].goods_name | string | 是 | 商品名称，如ipad |
| goods_details[].price | number | 是 | 商品单价，单位为分，如2000 |
| goods_details[].promotion_type | number | 是 | 优惠类型。0：没有优惠（收钱吧不处理单品信息）；1：支付机构优惠（收钱吧处理单品信息并上送到支付机构） |
| goods_details[].quantity | number | 是 | 商品数量，如10 |
| latitude | string | 否 | 纬度。经纬度必须同时出现 |
| longitude | string | 否 | 经度。经纬度必须同时出现 |
| notify_url | string | 否 | 支付回调的地址。如果支付成功通知时间间隔为1s,5s,30s,600s |
| operator | string | 是 | 门店操作员。发起本次交易的操作员 |
| payer_uid | string | 否 | 付款人id。消费者在支付通道的唯一id。WAP支付、小程序支付必传。微信WAP支付必须传open_id；支付宝WAP支付必传用户授权的userId |
| payway | string | 是 | 支付方式。内容为数字的字符串。2:支付宝 3:微信 |
| reflect | string | 否 | 反射参数。任何调用者希望原样返回的信息 |
| sub_payway | string | 否 | 二级支付方式。内容为数字的字符串。如果要使用WAP支付，则必须传"3"；使用小程序支付，则必须传"4" |
| subject | string | 是 | 交易简介。本次交易的概述 |
| terminal_sn | string | 是 | 收钱吧终端ID |
| total_amount | string | 是 | 交易总金额。以分为单位，不超过10位纯数字字符串 |

## 请求示例

```json
{
  "client_sn": "6918981703584786",
  "extended": {
    "extend_params": {
      "hb_fq_num": "3",
      "hb_fq_seller_percent": "0"
    }
  },
  "operator": "Roy",
  "payway": "1",
  "sub_payway": "2",
  "subject": "收钱吧",
  "terminal_sn": "101234641234111234",
  "total_amount": "1"
}
```

## 响应体

| 字段名 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| biz_response | object | 否 |  |
| biz_response.data | object | 否 | 预下单业务数据 |
| biz_response.data.client_sn | string | 是 | 商户订单号 |
| biz_response.data.net_amount | string | 是 | 实收金额 |
| biz_response.data.operator | string | 是 | 门店操作员 |
| biz_response.data.order_status | string | 是 | 订单状态 |
| biz_response.data.payway | string | 是 | 一级支付方式 |
| biz_response.data.qr_code | string | 否 | 二维码内容。预下单成功后生成的二维码 |
| biz_response.data.reflect | string | 否 | 透传参数 |
| biz_response.data.sn | string | 是 | 收钱吧唯一订单号 |
| biz_response.data.status | string | 是 | 流水状态 |
| biz_response.data.sub_payway | string | 是 | 二级支付方式 |
| biz_response.data.subject | string | 是 | 交易概述 |
| biz_response.data.total_amount | string | 是 | 交易总金额 |
| biz_response.data.trade_no | string | 否 | 支付服务商订单号 |
| biz_response.data.wap_pay_request | object | 否 | 支付通道返回的调用WAP支付需要传递的信息。WAP支付、小程序支付一定会返回 |
| biz_response.error_code | string | 否 | 业务执行错误码。业务执行失败时返回。 |
| biz_response.error_message | string | 否 | 业务执行错误信息。 |
| biz_response.result_code | string | 是 | 业务执行响应码。SUCCESS：成功；FAIL：失败；INPROGRESS：进行中；ERROR：未知。具体取值见附录《业务数据响应码列表》 |
| error_code | string | 否 | 通讯错误码。通讯失败时返回。见附录《公共错误码》 |
| error_message | string | 否 | 通讯错误信息描述。通讯失败时返回。 |
| result_code | string | 是 | 通讯响应码。200：通讯成功；400：客户端错误；500：服务端错误 |

## 响应示例

```json
{
  "biz_response": {
    "data": {
      "client_sn": "765432112",
      "net_amount": "1",
      "operator": "张三丰",
      "order_status": "CREATED",
      "qr_code": "https://qr.alipay.com/bax8z75ihyoqpgkv5f",
      "sn": "7894259244096169",
      "status": "IN_PROG",
      "subject": "coca cola",
      "total_amount": "1"
    },
    "result_code": "PRECREATE_SUCCESS"
  },
  "result_code": "200"
}
```

## 示例代码

### cURL

```bash
curl -X POST "https://vsi-api.shouqianba.com/upay/v2/precreate" \
  -H "Authorization: 100000000000000000 0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"client_sn":"6918981703584786","extended":{"extend_params":{"hb_fq_num":"3","hb_fq_seller_percent":"0"}},"operator":"Roy","payway":"1","sub_payway":"2","subject":"收钱吧","terminal_sn":"101234641234111234","total_amount":"1"}'
```

### Python

```python
import requests

url = "https://vsi-api.shouqianba.com/upay/v2/precreate"
headers = {"Content-Type": "application/json",
    "Authorization": "100000000000000000 0123456789abcdef0123456789abcdef",
}
json_data = {
    "client_sn": "6918981703584786",
    "extended": {
        "extend_params": {
            "hb_fq_num": "3",
            "hb_fq_seller_percent": "0"
        }
    },
    "operator": "Roy",
    "payway": "1",
    "sub_payway": "2",
    "subject": "收钱吧",
    "terminal_sn": "101234641234111234",
    "total_amount": "1"
}

response = requests.post(
    url,
    headers=headers,
    json=json_data,
)

print(response.json())
```

### Java

```java
// 预下单支付
OkHttpClient client = new OkHttpClient();
String json = "{\"client_sn\":\"6918981703584786\",\"extended\":{\"extend_params\":{\"hb_fq_num\":\"3\",\"hb_fq_seller_percent\":\"0\"}},\"operator\":\"Roy\",\"payway\":\"1\",\"sub_payway\":\"2\",\"subject\":\"收钱吧\",\"terminal_sn\":\"101234641234111234\",\"total_amount\":\"1\"}";
RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));

Request request = new Request.Builder()
    .url("https://vsi-api.shouqianba.com/upay/v2/precreate")
    .addHeader("Authorization", "100000000000000000 0123456789abcdef0123456789abcdef")
    .post(body)
    .build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
```

### Go

```go
package main

import (
    "fmt"
    "io"
    "net/http"
    "bytes"
)

func main() {
	jsonBody := []byte(`{"client_sn":"6918981703584786","extended":{"extend_params":{"hb_fq_num":"3","hb_fq_seller_percent":"0"}},"operator":"Roy","payway":"1","sub_payway":"2","subject":"收钱吧","terminal_sn":"101234641234111234","total_amount":"1"}`)
	reqBody := bytes.NewBuffer(jsonBody)
	req, err := http.NewRequest("POST", "https://vsi-api.shouqianba.com/upay/v2/precreate", reqBody)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "100000000000000000 0123456789abcdef0123456789abcdef")
	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(respBytes))
}
```

### Node.js

```javascript
const https = require("https");

const options = {
  method: "POST",
  hostname: "vsi-api.shouqianba.com",
  path: "/upay/v2/precreate",
  headers: {
    "Authorization": "100000000000000000 0123456789abcdef0123456789abcdef",
    "Content-Type": "application/json"
  }
};

const postData = JSON.stringify({"client_sn":"6918981703584786","extended":{"extend_params":{"hb_fq_num":"3","hb_fq_seller_percent":"0"}},"operator":"Roy","payway":"1","sub_payway":"2","subject":"收钱吧","terminal_sn":"101234641234111234","total_amount":"1"});

const req = https.request(options, (res) => {
  let data = "";
  res.on("data", (chunk) => { data += chunk; });
  res.on("end", () => { console.log(JSON.parse(data)); });
});
req.write(postData);
req.end();
```
