| <?php /** ?* @Author: [FENG] <1161634940@qq.com> ?* @Date:?? 2020-05-13 17:02:49 ?* @Last Modified by:?? [FENG] <1161634940@qq.com> ?* @Last Modified time: 2021-06-15T17:06:18+08:00 ?*/ namespace fengkui\Pay; use fengkui\Supports\Http; /** ?* Bytedance 字节跳动支付 ?* 小程序担保支付(V1) ?*/ class Bytedance { ????// 接口版本 ????const EDITON = 'v1'; ????// 统一下订单管理 ????private static $ecpayUrl = 'https://developer.toutiao.com/api/apps/ecpay/'; ????// 服务端预下单 ????private static $createOrderUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/create_order'; ????// 订单查询 ????private static $queryOrderUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/query_order'; ????// 退款 ????private static $createRefundUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/create_refund'; ????// 查询退款 ????private static $queryRefundUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/query_refund'; ????// 分账请求 ????private static $settleUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/settle'; ????// 查询分账 ????private static $querySettleUrl = 'https://developer.toutiao.com/api/apps/ecpay/v1/query_settle'; ????// 服务商进件 ????private static $addMerchantUrl = 'https://developer.toutiao.com/api/apps/ecpay/saas/add_merchant'; ????// 分账方进件 ????private static $addSubMerchantUrl = 'https://developer.toutiao.com/api/apps/ecpay/saas/add_sub_merchant'; ????// 支付相关配置 ????private static $config = array( ????????'app_id'??????? => '', // App ID ????????'salt'????????? => '', // 支付密钥值 ????????'notify_url'??? => '', // 支付回调地址 ????????'thirdparty_id' => '', // 第三方平台服务商 id,非服务商模式留空 ????); ????/** ?????* [__construct 构造函数] ?????* @param [type] $config [传递支付相关配置] ?????*/ ????public function __construct($config=NULL){ ????????$config && self::$config = array_merge(self::$config, $config); ????} ????/** ?????* [createOrder 下单支付] ?????* @param? [type] $order [description] ?????* @return [type]??????? [description] ?????* $order = array( ?????*????? 'body'???????? => '', // 产品描述 ?????*????? 'total_amount' => '', // 订单金额(分) ?????*????? 'order_sn'???? => '', // 订单编号 ?????* ); ?????*/ ????public static function createOrder($order) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id'??????? => $config['app_id'], // 是 小程序 AppID ????????????'out_order_no'? => (string)$order['order_sn'], // 是 开发者侧的订单号, 同一小程序下不可重复 ????????????'total_amount'? => $order['total_amount'], // 是 支付价格; 接口中参数支付金额单位为[分] ????????????'subject'?????? => $order['body'], // 是 商品描述; 长度限制 128 字节,不超过 42 个汉字 ????????????'body'????????? => $order['body'], // 是 商品详情 ????????????'valid_time'??? => 3600 * 2, // 是 订单过期时间(秒); 最小 15 分钟,最大两天 ????????????// 'sign'????????? => '', // 是 开发者对核心字段签名, 签名方式见文档附录, 防止传输过程中出现意外 ????????????// 'cp_extra'????? => '', // 否 开发者自定义字段,回调原样回传 ????????????// 'notify_url'??? => $config['notify_url'], // 否 商户自定义回调地址 ????????????// 'thirdparty_id' => '', // 否 第三方平台服务商 id,非服务商模式留空 ????????????'disable_msg'?? => 1, // 否 是否屏蔽担保支付的推送消息,1-屏蔽 0-非屏蔽,接入 POI 必传 ????????????// 'msg_page'????? => '', // 否 担保支付消息跳转页 ????????????// 'store_uid'???? => '', // 否 多门店模式下,门店 uid ????????]; ????????!empty($order['cp_extra']) && $params['cp_extra'] = $order['cp_extra']; ????????!empty($config['notify_url']) && $params['notify_url'] = $config['notify_url']; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????if (!empty($config['msg_page'])) { ????????????$params['disable_msg'] = 0; ????????????$params['msg_page'] = $config['msg_page']; ????????} ????????$params['sign'] = self::makeSign($params); ????????// dump($params);die; ????????$url = self::$createOrderUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [queryOrder 订单查询] ?????* @param? [type] $orderSn [开发者侧的订单号, 不可重复] ?????* @return [type]????????? [description] ?????*/ ????public static function queryOrder($orderSn) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id' => $config['app_id'], // 小程序 AppID ????????????'out_order_no' => (string)$orderSn, // 开发者侧的订单号, 不可重复 ????????????// 'sign' => '', // 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????????// 'thirdparty_id' => '', // 服务商模式接入必传?? 第三方平台服务商 id,非服务商模式留空 ????????]; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????$params['sign'] = self::makeSign($params); ????????$url = self::$queryOrderUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [notifyOrder 订单回调验证] ?????* @return [array] [返回数组格式的notify数据] ?????*/ ????public static function notifyOrder() ????{ ????????$data = $_POST; // 获取回调数据 ????????$config = self::$config; ????????if (!$data || empty($data['msg'])) ????????????die('暂无回调信息'); ????????$result = json_decode($data['msg'], true); // 进行签名验证 ????????// 判断签名是否正确? 判断支付状态 ????????if ($result && $data['type']=='payment') { ????????????return $data; ????????} else { ????????????return false; ????????} ????} ????/** ?????* [createRefund 订单退款] ?????* @param? [type] $order [订单相关信息] ?????* @return [type]??????? [description] ?????* $order = array( ?????*????? 'order_sn'???? => '', // 订单编号 ?????*????? 'refund_sn'??? => '', // 退款编号 ?????*????? 'total_amount' => '', // 订单金额(分) ?????*????? 'body'???????? => '', // 退款原因 ?????* ); ?????*/ ????public static function createRefund($order) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id'??????? => $config['app_id'], // 是?? 小程序 id ????????????'out_order_no'? => (string)$order['order_sn'], // 是? 商户分配订单号,标识进行退款的订单 ????????????'out_refund_no' => (string)$order['refund_sn'], // 是 商户分配退款号 ????????????'refund_amount' => $order['total_amount'], // 是? 退款金额,单位[分] ????????????'reason'??????? => $order['body'] ?? '用户申请退款', // 是? 退款理由,长度上限 100 ????????????// 'cp_extra'????? => '', // 否?? 开发者自定义字段,回调原样回传 ????????????// 'notify_url'??? => '', // 否?? 商户自定义回调地址 ????????????// 'sign'????????? => '', // 是?? 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????????// 'thirdparty_id' => '', // 否,服务商模式接入必传 第三方平台服务商 id,非服务商模式留空 ????????????'disable_msg'?? => 1, // 否?? 是否屏蔽担保支付消息,1-屏蔽 ????????????// 'msg_page'????? => '', // 否?? 担保支付消息跳转页 ????????????// 'all_settle'??? => '', // 否?? 是否为分账后退款,1-分账后退款;0-分账前退款。分账后退款会扣减可提现金额,请保证余额充足 ????????]; ????????!empty($order['cp_extra']) && $params['cp_extra'] = $order['cp_extra']; ????????!empty($order['all_settle']) && $params['all_settle'] = $order['all_settle']; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????if (!empty($config['msg_page'])) { ????????????$params['disable_msg'] = 0; ????????????$params['msg_page'] = $config['msg_page']; ????????} ????????$params['sign'] = self::makeSign($params); ????????$url = self::$queryOrderUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [queryRefund 退款查询] ?????* @param? [type] $refundSn [开发者侧的订单号, 不可重复] ?????* @return [type]?????????? [description] ?????*/ ????public static function queryRefund($refundSn) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id' => $config['app_id'], // 小程序 AppID ????????????'out_refund_no' => $refundSn, // 开发者侧的退款号 ????????????// 'sign' => '', // 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????????// 'thirdparty_id' => '', // 服务商模式接入必传?? 第三方平台服务商 id,非服务商模式留空 ????????]; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????$params['sign'] = self::makeSign($params); ????????$url = self::$queryRefundUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [notifyRefund 退款回调验证] ?????* @return [array] [返回数组格式的notify数据] ?????*/ ????public static function notifyRefund() ????{ ????????$data = $_POST; // 获取回调数据 ????????$config = self::$config; ????????if (!$data || empty($data['status'])) ????????????die('暂无回调信息'); ????????$result = json_decode($data['msg'], true); // 进行签名验证 ????????// 判断签名是否正确? 判断支付状态 ????????if ($result && $data['status']!='FAIL') { ????????????return $data; ????????} else { ????????????return false; ????????} ????} ????/** ?????* [settle 分账请求] ?????* @param? [type] $order [分账信息] ?????* @return [type]??????? [description] ?????* $order = array( ?????*????? 'body'???????? => '', // 产品描述 ?????*????? 'total_amount' => '', // 订单金额(分) ?????*????? 'order_sn'???? => '', // 订单编号 ?????* ); ?????*/ ????public static function settle($order) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id'??????? => $config['app_id'], // 是 小程序 AppID ????????????'out_order_no'? => (string)$order['order_sn'], // 是 商户分配订单号,标识进行结算的订单 ????????????'out_settle_no' => (string)$order['settle_sn'], // 是 开发者侧的结算号, 不可重复 ????????????'settle_desc'?? => $order['body'], // 是? 结算描述,长度限制 80 个字符 ????????????// 'cp_extra'????? => '', // 否?? 开发者自定义字段,回调原样回传 ????????????// 'notify_url'??? => '', // 否?? 商户自定义回调地址 ????????????// 'sign'????????? => '', // 是?? 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????????// 'thirdparty_id' => '', // 否,服务商模式接入必传 第三方平台服务商 id,非服务商模式留空 ????????????// 'settle_params' => '', // 否,其他分账方信息,分账分配参数 SettleParameter 数组序列化后生成的 json 格式字符串 ????????]; ????????!empty($order['cp_extra']) && $params['cp_extra'] = $order['cp_extra']; ????????!empty($order['settle_params']) && $params['settle_params'] = $order['settle_params']; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????$params['sign'] = self::makeSign($params); ????????$url = self::$settleUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [querySettle 分账查询] ?????* @param? [type] $settleSn [开发者侧的订单号, 不可重复] ?????* @return [type]????????? [description] ?????*/ ????public static function querySettle($settleSn) ????{ ????????$config = self::$config; ????????$params = [ ????????????'app_id' => $config['app_id'], // 小程序 AppID ????????????'out_settle_no' => $settleSn, // 开发者侧的分账号 ????????????// 'sign' => '', // 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????????// 'thirdparty_id' => '', // 服务商模式接入必传?? 第三方平台服务商 id,非服务商模式留空 ????????]; ????????!empty($config['thirdparty_id']) && $params['thirdparty_id'] = $config['thirdparty_id']; ????????$params['sign'] = self::makeSign($params); ????????$url = self::$querySettleUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [notifySettle 分账回调验证] ?????* @return [array] [返回数组格式的notify数据] ?????*/ ????public static function notifySettle() ????{ ????????$data = $_POST; // 获取回调数据 ????????$config = self::$config; ????????if (!$data || empty($data['status'])) ????????????die('暂无回调信息'); ????????$result = json_decode($data['msg'], true); // 进行签名验证 ????????// 判断签名是否正确? 判断支付状态 ????????if ($result && $data['status']!='FAIL') { ????????????return $data; ????????} else { ????????????return false; ????????} ????} ????/** ?????* [addMerchant 服务商进件] ?????* @param [type]? $accessToken [授权码兑换接口调用凭证] ?????* @param [type]? $componentId [小程序第三方平台应用] ?????* @param integer $urlType???? [链接类型:1-进件页面 2-账户余额页] ?????*/ ????public static function addMerchant($accessToken, $componentId, $urlType=1) ????{ ????????$params = [ ????????????'component_access_token' => $accessToken, // 是?? 授权码兑换接口调用凭证 ????????????'thirdparty_component_id' => $componentId, // 是? 小程序第三方平台应用 id ????????????'url_type' => $urlType, // 是 链接类型:1-进件页面 2-账户余额页 ????????]; ????????$url = self::$addMerchantUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [addSubMerchant 分账方进件] ?????* @param [type]? $thirdpartyId [小程序第三方平台应用] ?????* @param [type]? $merchantId?? [商户 id,用于接入方自行标识并管理进件方。由服务商自行分配管理] ?????* @param integer $urlType????? [链接类型:1-进件页面 2-账户余额页] ?????*/ ????public static function addSubMerchant($thirdpartyId, $merchantId, $urlType=1) ????{ ????????$params = [ ????????????'thirdparty_id' => $thirdpartyId, // 是?? 小程序第三方平台应用 id ????????????'sub_merchant_id' => $merchantId, // 是?? 商户 id,用于接入方自行标识并管理进件方。由服务商自行分配管理 ????????????'url_type' => $urlType, // 是 链接类型:1-进件页面 2-账户余额页 ????????????// 'sign' => '', // 开发者对核心字段签名, 签名方式见文档, 防止传输过程中出现意外 ????????]; ????????$params['sign'] = self::makeSign($params); ????????$url = self::$addSubMerchantUrl; ????????$response = Http::post($url, json_encode($params)); ????????$result = json_decode($response, true); ????????return $result; ????} ????/** ?????* [success 通知状态] ?????*/ ????public static function success() ????{ ????????$array = ['err_no'=>0, 'err_tips'=>'success']; ????????die(json_encode($array)); ????} ????/** ?????* [makeSign 生成秘钥] ?????* @param? [type] $data [加密数据] ?????* @return [type]?????? [description] ?????*/ ????public static function makeSign($data) { ????????$config = self::$config; ????????$rList = array(); ????????foreach($data as $k => $v) { ????????????if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id") ????????????????continue; ????????????$value = trim(strval($v)); ????????????$len = strlen($value); ????????????if ($len > 1 && substr($value, 0,1)=="\"" && substr($value,$len, $len-1)=="\"") ????????????????$value = substr($value,1, $len-1); ????????????$value = trim($value); ????????????if ($value == "" || $value == "null") ????????????????continue; ????????????array_push($rList, $value); ????????} ????????array_push($rList, $config['salt']); ????????sort($rList, 2); ????????return md5(implode('&', $rList)); ????} } |