## 右上角收藏，回家不迷路

|    第三方    | token | openid | 支付 | 回调 | 退款 | 订单查询 | 解密手机号 | 分账 | 模版消息 |
| :----------: | :---: | :----: | :--: | :--: | :--: | :------: | :--------: | :--: | :------: |
|  微信小程序  |   ✓   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     ✓      |  x   |    ✓     |
|  百度小程序  |   ✓   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     ✓      |  x   |    ✓     |
|  抖音小程序  |   ✓   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     ✓      |  ✓   |    ✓     |
|  快手小程序  |   ✓   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     ✓      |  ✓   |    x     |
| 支付宝小程序 |   x   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     ✓      |  x   |    ✓     |
|   微信 h5    |   x   |   x    |  ✓   |  ✓   |  ✓   |    ✓     |     x      |  x   |    x     |
|   微信 APP   |   x   |   ✓    |  ✓   |  ✓   |  ✓   |    ✓     |     x      |  x   |    x     |
|  微信公众号  |   x   |   x    |  ✓   |  ✓   |  ✓   |    ✓     |     x      |  x   |    ✓     |

### ⚠️ 注意

> 金额单位分 100=1 元

> 微信支付未使用 APIv3 接口规则

> 返回结果 array 由开发者自行判断

> 抖音小程序由字节小程序转变而来，支持多端（头条、抖音、今日头条等关联应用）

### 官方文档

[微信小程序接口文档](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1)

[百度小程序接口文档](https://smartprogram.baidu.com/docs/develop/function/tune_up_2.0/)

[快手小程序接口文档](https://mp.kuaishou.com/docs/develop/server/epay/interfaceDefinition.html)

[抖音小程序接口文档](https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/introduction/overview/)

[支付宝小程序接口文档](https://opendocs.alipay.com/mini/03l5wn)

# 安装说明

    composer require code-lives/applet-pays 5.7

# 预下单

```php
// 第一种使用方法 Factory:: ide 自动提示 Weixin
$pay= \Applet\Pay\Factory::Weixin()->init($config)->set("订单号","金额","描述")->getParam();

// 第二种方法
$PayName='Baidu';//百度
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述")->getParam();

$PayName='Byte';//抖音
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述","描述")->getParam();

$PayName='Weixin';//微信
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述","openid")->getParam();

$PayName='Kuaishou';//快手
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述",'openid', 'access_token')->getParam();

$PayName='Ali';//支付宝小程序
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述",'openid')->getParam();

$PayName='Weixin';//微信公众号【appid 和secret 换成公众号的】
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述","openid")->getParam();

$PayName='Weixin';//微信H5【appid 和secret 换成公众号的】
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述")->getH5Param();

$PayName='Weixin';//微信APP (没有openid)
$pay= \Applet\Pay\Factory::getInstance($PayName)->init($config)->set("订单号","金额","描述")->getParam();

```

# 百度小程序

### Config

| 参数名字        | 类型   | 必须 | 说明                                                            |
| --------------- | ------ | ---- | --------------------------------------------------------------- |
| appkey          | string | 是   | 百度小程序 appkey                                               |
| payappKey       | string | 是   | 百度小程序支付 appkey                                           |
| appSecret       | string | 是   | 百度小程序 aapSecret                                            |
| dealId          | int    | 是   | 百度小程序支付凭证                                              |
| isSkipAudit     | int    | 是   | 默认为 0； 0：不跳过开发者业务方审核；1：跳过开发者业务方审核。 |
| rsaPriKeyStr    | string | 是   | 私钥（只需要一行长串，不需要文件）                              |
| rsaPubKeyStr    | string | 是   | 百度小程序支付的平台公钥(支付回调需要)                          |
| notifyUrl       | string | 否   | 异步回调地址                                                    |
| refundNotifyUrl | string | 否   | 退款异步回调地址                                                |

### token

```php
$PayName='Baidu';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getToken();
```

| 返回参数     | 类型   | 必须 | 说明                   |
| ------------ | ------ | ---- | ---------------------- |
| expires_in   | string | 是   | 凭证有效时间，单位：秒 |
| session_key  | string | 是   | session_key            |
| access_token | string | 是   | 获取到的凭证           |

### openid

```php
$PayName='Baidu';//设置驱动
$code="";
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getOpenid($code);
```

| 返回参数    | 类型   | 必须 | 说明        |
| ----------- | ------ | ---- | ----------- |
| session_key | string | 是   | session_key |
| openid      | string | 是   | 用户 openid |

### 解密手机号

```php
$PayName='Baidu';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->decryptPhone($session_key, $iv, $ciphertext);
echo $phone['mobile'];
```

### 百度订单查询

| 参数名字     | 类型   | 必须 | 说明                 |
| ------------ | ------ | ---- | -------------------- |
| access_token | string | 是   | 根据上面的获取 token |
| tpOrderId    | string | 是   | 平台订单号           |

```php
$PayName='Baidu';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance('Baidu')->init($config);
$order = [
        'tpOrderId' => '',//订单号
        'access_token' => $Baidu->getToken()['access_token'],
    ];
$data = $Baidu->findOrder($order);
```

### 百度退款

| 参数名字         | 类型   | 必须 | 说明                                                                                               |
| ---------------- | ------ | ---- | -------------------------------------------------------------------------------------------------- |
| access_token     | string | 是   | 根据上面的获取 token                                                                               |
| bizRefundBatchId | int    | 是   | 百度平台的订单号                                                                                   |
| isSkipAudit      | int    | 是   | 默认为 0； 0：不跳过开发者业务方审核；1：跳过开发者业务方审核。                                    |
| orderId          | int    | 是   | 百度平台的订单号                                                                                   |
| refundReason     | string | 是   | 退款描述                                                                                           |
| refundType       | int    | 是   | 退款类型 1：用户发起退款；2：开发者业务方客服退款；3：开发者服务异常退款。百度小程序支付的平台公钥 |
| tpOrderId        | string | 是   | 自己平台订单号                                                                                     |
| userId           | int    | 是   | 用户 uid（不是自己平台 uid）                                                                       |

```php
$order = [
'token' => 'abcd',
'bizRefundBatchId' => 123456,//百度平台订单号
'isSkipAudit' => 1,
'orderId' => 123456,
'refundReason' => '测试退款',
'refundType' => 2,//
'tpOrderId' => '123',//自己平台订单号
'userId' => 123,
];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->applyOrderRefund($order);
```

### 百度小程序模版消息

```php
$data = [
    "touser_openId" => "",
    "template_id" => "",
    "page" => "pages/index/index",
    "subscribe_id" => '百度from组件subscribe-id 一致',
    "data" => json_encode([
        'keyword1' => ['value' => "第一个参数"],
        'keyword2' => ['value' => "第二个参数"],
        'keyword3' =>  ['value' => "第三个参数"],
    ])
];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->sendMsg($data,$token);
$data=[
   "errno" => 0,
    "msg" => "success",
    "data" => array=> [
    "msg_key" => 1663314134696897
  ]
]
```

# 抖音小程序

### Config

| 参数名字    | 类型   | 必须 | 说明                              |
| ----------- | ------ | ---- | --------------------------------- |
| token       | string | 是   | 担保交易回调的 Token(令牌)        |
| salt        | string | 是   | 担保交易的 SALT                   |
| merchant_id | string | 是   | 担保交易的商户号                  |
| app_id      | int    | 是   | 小程序的 APP_ID                   |
| secret      | string | 是   | 小程序的 APP_SECRET               |
| notify_url  | string | 是   | 支付回调 url                      |
| settle_url  | string | 否   | 分账回调 url,没有默认支付回调 url |

### token

```php
$PayName='Byte';//驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getToken();
```

| 返回参数     | 类型   | 必须 | 说明                   |
| ------------ | ------ | ---- | ---------------------- |
| expires_in   | string | 是   | 凭证有效时间，单位：秒 |
| access_token | string | 是   | 获取到的凭证           |

### openid

```php
$PayName='Byte';//设置驱动
$code="";
$anonymous_code="";//可以不传
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getOpenid($code,$anonymous_code);
```

| 返回参数    | 类型   | 必须 | 说明        |
| ----------- | ------ | ---- | ----------- |
| session_key | string | 是   | session_key |
| openid      | string | 是   | 用户 openid |
| unionid     | string | 是   | unionid     |

### 解密手机号

```php
$PayName='Baidu';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->decryptPhone($session_key, $iv, $encryptedData);
echo $phone['phoneNumber'];
```

### 订单查询

```php
$PayName='Byte';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance($payName)->init($config);
$data = $Baidu->findOrder("订单号");
```

### 分账

| 参数名字      | 类型   | 必须 | 说明                           |
| ------------- | ------ | ---- | ------------------------------ |
| out_order_no  | string | 是   | 平台订单号                     |
| out_settle_no | string | 是   | 自定义订单号                   |
| settle_desc   | int    | 是   | 分账描述                       |
| cp_extra      | string | 是   | 开发者自定义字段，回调原样回传 |

```php
$PayName='Byte';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance($payName)->init($config);
$data = $Baidu->settle($order);
```

### 退款

| 参数名字      | 类型   | 必须 | 说明         |
| ------------- | ------ | ---- | ------------ |
| out_order_no  | string | 是   | 平台订单号   |
| out_refund_no | int    | 是   | 自定义订单号 |
| reason        | int    | 是   | 退款说明     |
| refund_amount | string | 是   | 退款金额     |

```php
$order = [
        'out_order_no' => '',
        'out_refund_no' => time() . 'refund',
        'reason' => '就想退款，咋滴',
        'refund_amount' => 1, //退款金额
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->applyOrderRefund($order);
//返回  [err_no] => 1
//     [err_tips] => 成功
//     [refund_no] => 1212
```

### 模版消息

```php
$data = [
        'tpl_id' =>  "模版id",
        "open_id" => $parm['openid'],
        'data' => [
            '律师' => "张三",
            "回复时间" => date('Y-m-d H:i:s', time()),
            "回复内容" => "我回复你啦",
        ],
        "page" => "pages/index/index",
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->sendMsg($data,$token);

```

# 微信小程序

### Config

| 参数名字   | 类型   | 必须 | 说明                                                     |
| ---------- | ------ | ---- | -------------------------------------------------------- |
| appid      | int    | 是   | 小程序 appid                                             |
| secret     | int    | 是   | 小程序 secret                                            |
| mch_id     | string | 是   | 商户 mch_id                                              |
| mch_key    | string | 是   | 商户 mch_key                                             |
| notify_url | string | 是   | 异步地址                                                 |
| cert_pem   | string | 是   | cert_pem 证书                                            |
| key_pem    | string | 是   | key_pem 证书                                             |
| trade_type | string | 是   | 默认为：JSAPI。MWEB：代表微信 H5 、JSAPI：公众号或小程序 |

### token

```php
$PayName='Weixin';//驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getToken();
```

| 返回参数     | 类型   | 必须 | 说明                   |
| ------------ | ------ | ---- | ---------------------- |
| expires_in   | string | 是   | 凭证有效时间，单位：秒 |
| access_token | string | 是   | 获取到的凭证           |

### openid

```php
$PayName='Weixin';//设置驱动
$code="";
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getOpenid($code);
```

| 返回参数    | 类型   | 必须 | 说明        |
| ----------- | ------ | ---- | ----------- |
| session_key | string | 是   | session_key |
| openid      | string | 是   | 用户 openid |
| unionid     | string | 是   | unionid     |

### 微信解密手机号

```php
$PayName='Weixin';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->decryptPhone($session_key, $iv, $encryptedData);
echo $phone['phoneNumber'];
```

### 微信订单查询

```php
$PayName='Weixin';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance($payName)->init($config);
$data = $Baidu->findOrder("订单号");
```

### 微信退款

| 参数名字      | 类型   | 必须 | 说明         |
| ------------- | ------ | ---- | ------------ |
| out_trade_no  | string | 是   | 平台订单号   |
| out_refund_no | string | 是   | 自定义订单号 |
| refund_fee    | int    | 是   | 退款金额     |
| total_fee     | int    | 是   | 订单金额     |
| refund_desc   | string | 是   | 退款原因     |

```php
$order = [
        'out_trade_no' => '123',
        'total_fee' => 0.01,
        'out_refund_no' => time(),
        'refund_fee' => 0.01,
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->applyOrderRefund($order);
```

### 微信小程序模版消息

```php
$data = [
    "touser" => "",
    "template_id" => "",
    "page" => "pages/index/index",
    "miniprogram_state" => "developer",
    "lang" => "zh_CN",
    "data" => [
        'thing6' => ['value' => "第一个参数{{thing6.DATA}}"],
        'thing7' => ['value' => "第二个参数{{thing7.DATA}}"],
        'time8' =>  ['value' => "第三个参数{{time8.DATA}}"],
],
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->sendMsg($data,$token);
$data=[
    "errcode" => 0
    "errmsg" => "ok"
    "msgid" => 123456
]
```

# 支付宝小程序

> 使用密钥进行签名解密，没有使用证书签名解密。

> 订单查询、退款、参数设置可以设置其他，具体看文档。

> 返回值 看官方文档，每个返回值都不一样，自行判断，如 openid 返回[alipay_system_oauth_token_response] 退款返回[alipay_trade_create_response]

### Config

| 参数名字   | 类型   | 必须 | 说明                         |
| ---------- | ------ | ---- | ---------------------------- |
| appid      | string | 是   | 小程序 appid                 |
| secret     | string | 是   | 小程序 AES 用于手机号解密    |
| privateKey | string | 是   | 应用私钥（开发工具生成）     |
| publicKey  | string | 是   | 支付宝公钥（支付宝后台下载） |
| notify_url | string | 是   | 异步回调地址                 |

### 支付宝小程序 openid

> getOpenid 获取支付宝的用户 user_id 类似于微信的 openid

```php
$PayName='Ali';//设置驱动
$code="";
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getOpenid($code);
//返回参数
$data = array(
    [alipay_system_oauth_token_response] => Array
        (
            [access_token] => 123
            [alipay_user_id] => 123
            [auth_start] => 2023-03-26 20:56:36
            [expires_in] => 1296000
            [re_expires_in] => 2592000
            [refresh_token] => auth
            [user_id] => 123
        )
    [sign] =>
    )
```

### 支付宝小程序解密手机号

```php
$PayName='Ali';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->decryptPhone($session_key, $iv, $encryptedData);
echo $phone['mobile'];
```

### 支付宝小程序订单查询

```php
$PayName='Ali';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance($payName)->init($config);
$data = $Baidu->findOrder(['out_trade_no' => '1679838318']);
```

### 支付宝小程序退款

| 参数名字      | 类型   | 必须 | 说明       |
| ------------- | ------ | ---- | ---------- |
| out_trade_no  | string | 是   | 平台订单号 |
| refund_amount | int    | 是   | 退款金额   |

```php
$orders = [
        'out_order_no' => $order['out_order_no'],
        'refund_amount' => $order['refund_amount'],
    ];
$PayName='Ali';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->applyOrderRefund($order);
```

### 支付宝小程序模版消息

模版消息设置比较麻烦。需要先到开发平台添加进入小程序进行产品绑定，在去商家平台设置[文档](https://opendocs.alipay.com/b/03ksho)

```php
$data = [
        'to_user_id' => '用户uid',
        'user_template_id' => '模版id',
        'page' => 'pages/index/index',
        'data' => json_encode([
            'keyword1' => ['value' => '1'],
            'keyword2' =>  ['value' => '2'],
            'keyword3' => ['value' => '3'],
        ]),
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->sendMsg($data,$token);
```

# 快手小程序

### Config

| 参数名字   | 类型   | 必须 | 说明                                |
| ---------- | ------ | ---- | ----------------------------------- |
| app_id     | int    | 是   | 小程序 appid                        |
| app_secret | int    | 是   | 小程序 secret                       |
| notify_url | string | 是   | 回调地址                            |
| settle_url | string | 是   | 结算回调地址，没有就默认 notify_url |
| type       | int    | 是   | 类目                                |

### openid

```php
$PayName='Kuaishou';//设置驱动
$code="";
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->getOpenid($code);
```

| 返回参数    | 类型   | 必须 | 说明          |
| ----------- | ------ | ---- | ------------- |
| session_key | string | 是   | session_key   |
| open_id     | string | 是   | 用户 open_id  |
| result      | string | 是   | 状态 1 是成功 |

### 快手解密手机号

```php
$PayName='Kuaishou';//设置驱动
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->decryptPhone($session_key, $iv, $encryptedData);
echo $phone['phoneNumber'];
```

### 快手订单查询

```php
$PayName='Kuaishou';//设置驱动
$Baidu = \Applet\Pay\Factory::getInstance($payName)->init($config);
$data = $Baidu->findOrder("订单号",$access_token);
```

### 快手退款

| 参数名字      | 类型    | 必须 | 说明         |
| ------------- | ------- | ---- | ------------ |
| out_trade_no  | string  | 是   | 平台订单号   |
| out_refund_no | strging | 是   | 自定义订单号 |
| refund_amount | int     | 是   | 退款金额     |
| reason        | string  | 是   | 退款原因     |
| access_token  | string  | 是   | access_token |
| attach        | string  | 否   | 自定义       |

```php
$orders = [
        'out_order_no' => $order['out_order_no'],
        'out_refund_no' => $order['out_refund_no'],
        'reason' => $order['reason'],
        'attach' => $order['attach'],
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->applyOrderRefund($order);
```

### 快手结算

| 参数名字      | 类型   | 必须 | 说明         |
| ------------- | ------ | ---- | ------------ |
| out_order_no  | string | 是   | 平台订单号   |
| out_settle_no | string | 是   | 自定义订单号 |
| reason        | string | 是   | 退款原因     |
| access_token  | string | 是   | access_token |
| attach        | string | 否   | 自定义       |

```php
//注意 需要设置回调 notify_url  在config 设置 settle_url 如果没有 默认为 notify_url
$orders = [
        'out_order_no' => $order['out_order_no'],
        'out_settle_no' => $order['out_settle_no'],
        'reason' => $order['reason'],
        'attach' => $order['attach'],
    ];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->settle($order,$access_token);
```

### 快手小程序模版消息

```php
$data = [
    "open_id" => "",
    "tpl_id" => "",
    "page" => "pages/index/index",
    "data" => [
        'key1' =>  "第一个",
        'key2' =>  "第二个",
        'key3' =>  "第三个",
    ]
];
$data= \Applet\Pay\Factory::getInstance($PayName)->init($config)->sendMsg($data,$token);
$data=[
    "err_no" => 1001,
    "err_tips" => "该用户未订阅"
]
```

# 微信 APP

### Config

| 参数名字   | 类型   | 必须 | 说明            |
| ---------- | ------ | ---- | --------------- |
| appid      | int    | 是   | 开发平台 appid  |
| secret     | int    | 是   | 开放平台 secret |
| mch_id     | string | 是   | 商户 mch_id     |
| mch_key    | string | 是   | 商户 mch_key    |
| trade_type | string | 是   | APP             |
| notify_url | string | 是   | 异步地址        |

# 异步通知

## 抖音

```php
$pay = \Applet\Pay\Factory::getInstance('Byte')->init($config);
$status = $pay->notifyCheck(); //验证
if ($status) {
    $orderSn = $pay->getNotifyOrder(); //订单数据$orderSn['msg']['cp_orderno'] $orderSn['msg']['seller_uid']
    switch ($orderSn['type']) {
        case 'payment': // 支付相关回调
            /**
             *业务处理
            */
            echo json_encode(['err_no' => 0, 'err_tips' => 'success']);exit; // 操作成功需要给头条返回的信息
            break;
        case 'refund': // 退款相关回调
            /**
             *业务处理
            */
            echo json_encode(['err_no' => 0, 'err_tips' => 'success']);exit; // 操作成功需要给头条返回的信息
            break;
        case 'settle': // 分账相关回调
            /**
             *业务处理
            */
            echo json_encode(['err_no' => 0, 'err_tips' => 'success']);exit; // 操作成功需要给头条返回的信息
            break;
        default: // 未知数据
            return '数据异常';
    }
}
```

## 微信回调(通用微信 H5 支付、小程序、微信公众号) 记得改 config 配置

```php
$pay = \Applet\Pay\Factory::getInstance('Weixin')->init($config);
$status = $pay->notifyCheck();//验证
if($status){
    $order = $pay->getNotifyOrder();//订单数据
    //$order['out_trade_no']//平台订单号
    //$order['transaction_id']//微信订单号
    echo 'success';exit;
}
```

## 百度小程序回调

```php
$pay = \Applet\Pay\Factory::getInstance('Baidu')->init($config);
$status = $pay->notifyCheck();//验证
if($status){
    $order = $pay->getNotifyOrder();
    //$order['tpOrderId']
    //$order['orderId']
    //$order['userId']
    echo 'success';exit;
}
```

## 快手小程序

```php
$pay = \Applet\Pay\Factory::getInstance('Kuaishou')->init($config);
$status = $pay->notifyCheck(); //验证
if ($status) {
    $order = $pay->getNotifyOrder(); //订单数据
    //$order['data']['out_order_no']//平台订单号
    echo json_encode(['result' => 1, 'message_id' => $order['message_id']]);exit;
}
```

## 支付宝小程序

```php
$pay = \Applet\Pay\Factory::getInstance('Ali')->init($config);
$status = $pay->notifyCheck(); //验证
if ($status) {
    $order = $pay->getNotifyOrder(); //订单数据
    //$order['out_trade_no']//平台订单号
}
```
