529 lines
23 KiB
PHP
529 lines
23 KiB
PHP
<?php
|
|
/**
|
|
* SaaSMall商城系统 - 团队十年电商经验汇集巨献!
|
|
* =========================================================
|
|
* Copy right 2019-2029 成都SAAS云科技有限公司, 保留所有权利。
|
|
* ----------------------------------------------
|
|
* 官方网址: https://www.gobuysaas.com
|
|
* =========================================================
|
|
*/
|
|
|
|
namespace addon\alipay\model;
|
|
|
|
use addon\alipay\data\sdk\AopClient;
|
|
use addon\alipay\data\sdk\request\AlipayFundTransToaccountTransferRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradeAppPayRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradeCloseRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradePagePayRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradeRefundRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradeWapPayRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradePrecreateRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradePayRequest;
|
|
use addon\alipay\data\sdk\request\AlipayTradeCreateRequest;
|
|
use addon\alipay\data\sdk\request\AlipayOpenMiniOrderCreateRequest;
|
|
use app\model\BaseModel;
|
|
use app\model\order\Order as OrderModel;
|
|
use app\model\system\Pay as PayCommon;
|
|
use addon\alipay\data\sdk\request\AlipayFundTransUniTransferRequest;
|
|
use addon\alipay\data\sdk\AopCertClient;
|
|
use app\model\system\Pay as PayModel;
|
|
use think\facade\Log;
|
|
|
|
/**
|
|
* 支付宝支付配置
|
|
*/
|
|
class Pay extends BaseModel
|
|
{
|
|
|
|
public $aop;
|
|
public $config;
|
|
public $site_id;
|
|
|
|
function __construct($site_id)
|
|
{
|
|
try {
|
|
// 获取支付宝支付参数(统一支付到平台账户)
|
|
$config_model = new Config();
|
|
$config_result = $config_model->getPayConfig($site_id);
|
|
$config = $config_result["data"];
|
|
$this->site_id = $site_id;
|
|
if (!empty($config)) {
|
|
$config_info = $config["value"];
|
|
}
|
|
if ($config_info['is_isp'] == 1) {
|
|
$platform = config('alipay.platform');
|
|
$authConfig = new \addon\aliapp\model\Config();
|
|
$uniInfo = $authConfig->getAppConfig($site_id)['data']['value'];
|
|
$config_info['app_auth_token'] = $uniInfo['app_auth_token'];//$authConfig->getAppConfig($site_id)['data']['value'];
|
|
$config_info['app_id'] = $platform['appid'];
|
|
$config_info['public_key'] = $platform['public_key'];
|
|
$config_info['private_key'] = $platform['private_key'];
|
|
$config_info['alipay_public_key'] = $platform['alipay_public_key'];
|
|
$config_info['encryptKey'] = $platform['encryptKey'];
|
|
}
|
|
$this->config = $config_info;
|
|
$countersign_type = $config_info['countersign_type'] ?? 0; //加密模式
|
|
if ($countersign_type == 1) {
|
|
$appCertPath = $config_info["public_key_crt"] ?? "";
|
|
$alipayCertPath = $config_info["alipay_public_key_crt"] ?? "";
|
|
$rootCertPath = $config_info["alipay_with_crt"] ?? "";
|
|
$this->aop = new AopCertClient();
|
|
//调用getPublicKey从支付宝公钥证书中提取公钥
|
|
$this->aop->alipayrsaPublicKey = $this->aop->getPublicKey($alipayCertPath);
|
|
//是否校验自动下载的支付宝公钥证书,如果开启校验要保证支付宝根证书在有效期内
|
|
$this->aop->isCheckAlipayPublicCert = false;
|
|
//调用getCertSN获取证书序列号
|
|
$this->aop->appCertSN = $this->aop->getCertSN($appCertPath);
|
|
//调用getRootCertSN获取支付宝根证书序列号
|
|
$this->aop->alipayRootCertSN = $this->aop->getRootCertSN($rootCertPath);
|
|
} else {
|
|
// 获取支付宝支付参数(统一支付到平台账户)
|
|
$this->aop = new AopClient();
|
|
$this->aop->alipayrsaPublicKey = $config_info['public_key'] ?? "";
|
|
$this->aop->alipayPublicKey = $config_info['alipay_public_key'] ?? "";
|
|
}
|
|
$this->aop->encryptKey = $config_info['encryptKey'];
|
|
$this->aop->appAuthToken = $config_info['app_auth_token']; //'202301BB4cac4962a7194c0483136df3df1a2X84';
|
|
$this->aop->appId = $config_info["app_id"] ?? "";
|
|
$this->aop->rsaPrivateKey = $config_info['private_key'] ?? "";
|
|
$this->aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
|
|
$this->aop->apiVersion = '1.0';
|
|
$this->aop->signType = 'RSA2';
|
|
$this->aop->postCharset = 'UTF-8';
|
|
$this->aop->format = 'json';
|
|
} catch (\Exception $e) {
|
|
exit(json_encode($this->error('', '支付宝配置错误')));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成支付
|
|
* @param $param
|
|
*/
|
|
public function pay($param)
|
|
{
|
|
//构造要请求的参数数组,无需改动
|
|
$parameter = array(
|
|
"out_trade_no" => $param["out_trade_no"],
|
|
"subject" => str_sub($param["pay_body"], 15),
|
|
"total_amount" => (float)$param["pay_money"],
|
|
"body" => str_sub($param["pay_body"], 60),
|
|
"product_code" => 'FAST_INSTANT_TRADE_PAY',
|
|
"timeout_express" => '20m',
|
|
);
|
|
if ($param["hb_fq_num"] > 0) {
|
|
$parameter['extend_params'] = [
|
|
'hb_fq_num' => $param["hb_fq_num"],
|
|
'hb_fq_seller_percent' => 100
|
|
];
|
|
} else {
|
|
$parameter['disable_pay_channels'] = 'pcreditpayInstallment';
|
|
}
|
|
switch ($param["app_type"]) {
|
|
case "h5":
|
|
$request = new AlipayTradeWapPayRequest();
|
|
break;
|
|
case "pc":
|
|
$request = new AlipayTradePagePayRequest();
|
|
break;
|
|
case "app":
|
|
$request = new AlipayTradeAppPayRequest();
|
|
break;
|
|
case 'wechat':
|
|
$request = new AlipayTradeWapPayRequest();
|
|
break;
|
|
case 'cashier':
|
|
$request = new AlipayTradePrecreateRequest();
|
|
$parameter['product_code'] = 'FACE_TO_FACE_PAYMENT';
|
|
break;
|
|
case "aliapp":
|
|
$parameter['product_code'] = 'JSAPI_PAY';
|
|
$ali_openid = model('member')->getValue(['member_id' => $param['member_id']], 'ali_openid');
|
|
if (is_numeric($ali_openid)) {
|
|
$parameter['buyer_id'] = $ali_openid;
|
|
} else {
|
|
$parameter['buyer_open_id'] = $ali_openid;
|
|
}
|
|
if (input('trade_component_order_id', '') || $param['trade_component_order_id']) {
|
|
$parameter['extend_params']['trade_component_order_id'] = input('trade_component_order_id');//交易组件IDroyalty_freeze
|
|
}
|
|
if ($param["pay_type"] == 'zmxxpay') { //芝麻先享
|
|
$parameter['product_code'] = 'JSAPI_PAY';//交易组件ID
|
|
$parameter['extend_params']['creditTradeScene'] = 'CREDIT_PAY';
|
|
$parameter['extend_params']['zmServiceId'] = $this->config['zmServiceId'];
|
|
}
|
|
$check = event('PaySecurityCheck', ['site_id' => $this->site_id, 'pay_type' => 'alipay'], true);
|
|
if ($check && $check['code'] < 0) {
|
|
return $this->error('', $check['message'] ?? '安全验证失败');
|
|
}
|
|
$res = event('checkAccountsAuth', ['site_id' => $this->config['site_id'], 'pay_type' => 'wechatpay', 'out_trade_no' => $param["out_trade_no"]]);//检查分账状态
|
|
if ($res && array_sum(array_column($res, 'isDivide'))) {
|
|
$divideState = array_sum(array_column($res, 'divideState'));
|
|
if (!$divideState) return $this->error('', implode(',', array_column($res, 'err_msg')));
|
|
$parameter['extend_params']['royalty_freeze'] = true; //判断是否参与分账
|
|
}
|
|
$request = new AlipayTradeCreateRequest();
|
|
break;
|
|
}
|
|
$parameter = json_encode($parameter);
|
|
$request->setBizContent($parameter);
|
|
$request->SetReturnUrl($param["return_url"]);
|
|
$request->SetNotifyUrl($param["notify_url"]);
|
|
if (in_array($param["app_type"], ['h5'])) {
|
|
$result = $this->aop->pageExecute($request, 'get');
|
|
return $this->success([
|
|
'type' => 'url',
|
|
'data' => $result
|
|
]);
|
|
} else {
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
if ($param["app_type"] == 'cashier') {
|
|
return $this->success([
|
|
'type' => 'qrcode',
|
|
'data' => [
|
|
'qrcode' => $result->$responseNode->qr_code
|
|
]
|
|
]);
|
|
}
|
|
return $this->success($result->$responseNode);
|
|
} else {
|
|
return $this->error("", $result->$responseNode->sub_msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***
|
|
* 支付宝交易组件公域ID
|
|
* @param $param
|
|
* @return \SimpleXMLElement|string
|
|
* @throws \think\Exception
|
|
*/
|
|
public function miniComponentOrderid($param)
|
|
{
|
|
if (!isset($param['requireOrder'])) return '';
|
|
$order_model = new OrderModel();
|
|
$orderInfo = $order_model->getOrderDetail($param['order_id'])['data'];
|
|
$buyer_id = model('member')->getValue(['member_id' => $param['member_id']], 'ali_openid');
|
|
$order_name = str_sub($orderInfo["order_name"], 100);
|
|
$order_goods = $orderInfo['order_goods'][0];
|
|
$goods_class_arr = array_column($orderInfo['order_goods'], 'goods_class');
|
|
$goods_class = array_sum($goods_class_arr);
|
|
if ($goods_class >= 1) {
|
|
$merchant_biz_type = 'KX_SHOPPING';
|
|
if (in_array(2, $goods_class_arr)) {
|
|
$merchant_biz_type = 'GROUP_SECURITIES';
|
|
}
|
|
} else {
|
|
$merchant_biz_type = 'VIRTUAL_RECHARGE';
|
|
}
|
|
$orderArr = [
|
|
'out_order_id' => $param["out_trade_no"],
|
|
'title' => $order_name,
|
|
'buyer_id' => $buyer_id,
|
|
'source_id' => $param['sourceId'] ?? '',
|
|
'merchant_biz_type' => $merchant_biz_type,
|
|
'path' => '/pages/index/index',
|
|
'order_detail' => [
|
|
'item_infos' => [
|
|
'goods_id' => $order_goods['goods_id'],
|
|
'out_item_id' => $order_goods['goods_id'],
|
|
'out_sku_id' => $order_goods['sku_id'],
|
|
'goods_name' => $order_name,
|
|
'item_cnt' => $orderInfo["goods_num"],
|
|
'sale_price' => sprintf("%.2f", ($orderInfo["order_money"] / $orderInfo["goods_num"])), //商品单价
|
|
],
|
|
'price_info' => [
|
|
'freight' => $orderInfo['delivery_money'], //运费
|
|
'order_price' => sprintf("%.2f", $orderInfo["pay_money"]), //商品单价(float)$orderInfo["pay_money"], //订单节点
|
|
],
|
|
],
|
|
'seller_id' => $this->config['alipay_pid'], //系统不存在
|
|
];
|
|
if ($merchant_biz_type != 'VIRTUAL_RECHARGE' && $orderInfo['full_address']) {
|
|
$orderArr['address_info'] = [
|
|
'receiver_name' => $orderInfo['name'] ?: $orderInfo['mobile'],
|
|
'detailed_address' => $orderInfo['address'] . $orderInfo['full_address'],
|
|
'tel_number' => $orderInfo['mobile'] ?: $orderInfo['telephone']
|
|
];
|
|
}
|
|
$request = new AlipayOpenMiniOrderCreateRequest();
|
|
$request->setBizContent(json_encode($orderArr));
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
$trade_component_order_id = $result->$responseNode->order_id;
|
|
$data = [
|
|
'trade_component_order_id' => $trade_component_order_id,
|
|
'source_id' => $orderArr['source_id']
|
|
];
|
|
model('pay')->update($data, [['out_trade_no', '=', $param["out_trade_no"]]]);
|
|
model('order')->update(['is_video_number' => 1], [['order_id', '=', $param['order_id']]]);
|
|
return $trade_component_order_id;
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 支付关闭
|
|
* @param unknown $orderNumber
|
|
* @return multitype:number string |multitype:number mixed
|
|
*/
|
|
public function close($param)
|
|
{
|
|
$parameter = array(
|
|
"out_trade_no" => $param["out_trade_no"]
|
|
);
|
|
// 建立请求
|
|
$request = new AlipayTradeCloseRequest();
|
|
$request->setBizContent(json_encode($parameter));
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
return $this->success();
|
|
} else {
|
|
return $this->error("", $result->$responseNode->sub_msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 支付宝支付原路返回
|
|
* @param unknown $param 支付参数
|
|
*/
|
|
public function refund($param)
|
|
{
|
|
$pay_info = $param["pay_info"];
|
|
$refund_no = $param["refund_no"];
|
|
$out_trade_no = $pay_info["trade_no"] ?? '';
|
|
$refund_fee = $param["refund_fee"];
|
|
$parameter = array(
|
|
'trade_no' => $out_trade_no,
|
|
'refund_amount' => sprintf("%.2f", $refund_fee),
|
|
'out_request_no' => $refund_no
|
|
);
|
|
if (isset($param['is_video_number']) && $param['is_video_number']) {
|
|
$parameter['refund_goods_detail'][] = [
|
|
'goods_id' => $param['goods_id'],
|
|
'out_item_id' => $param['goods_id'],
|
|
'out_sku_id' => $param['sku_id'],
|
|
'refund_amount' => sprintf("%.2f", $refund_fee)
|
|
];
|
|
}
|
|
if ($pay_info["pay_type"] == 'zmxxpay') {
|
|
$parameter['extend_params'] = [
|
|
'is_fulfilled' => true
|
|
];
|
|
}
|
|
// 建立请求
|
|
$request = new AlipayTradeRefundRequest ();
|
|
$request->setBizContent(json_encode($parameter));
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
return $this->success();
|
|
} else {
|
|
if ($result->$responseNode->sub_msg == '交易已经关闭') {
|
|
return $this->success();
|
|
}
|
|
return $this->error($pay_info["pay_type"], $result->$responseNode->sub_msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 支付宝转账
|
|
* @param $param
|
|
* @return array
|
|
* @throws \think\Exception
|
|
*/
|
|
public function payTransfer($param)
|
|
{
|
|
try {
|
|
$config_model = new Config();
|
|
$config_result = $config_model->getPayConfig($param['site_id']);
|
|
if ($config_result['code'] < 0) return $config_result;
|
|
$config = $config_result['data']['value'];
|
|
if (empty($config)) return $this->error([], '未配置支付宝支付');
|
|
if (!$config['transfer_status']) return $this->error([], '未启用支付宝转账');
|
|
$parameter = [
|
|
'out_biz_no' => $param['out_trade_no'],
|
|
'payee_type' => 'ALIPAY_LOGONID',
|
|
'payee_account' => $param["account_number"],
|
|
'amount' => sprintf("%.2f", $param['amount']),
|
|
'payee_real_name' => $param["real_name"],
|
|
'remark' => $param["desc"]
|
|
];
|
|
// 建立请求
|
|
$request = new AlipayFundTransToaccountTransferRequest();
|
|
$request->setBizContent(json_encode($parameter));
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
return $this->success([
|
|
'out_trade_no' => $result->$responseNode->out_biz_no, // 商户交易号
|
|
'payment_no' => $result->$responseNode->order_id, // 微信付款单号
|
|
'payment_time' => date_to_time($result->$responseNode->pay_date) // 付款成功时间
|
|
]);
|
|
} else {
|
|
return $this->error([], $result->$responseNode->sub_msg);
|
|
}
|
|
} catch (\Exception $e) {
|
|
return $this->error([], $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 异步完成支付
|
|
* @param $param
|
|
*/
|
|
public function payNotify()
|
|
{
|
|
try {
|
|
$res = $this->aop->rsaCheckV1($_POST, $this->aop->alipayrsaPublicKey, $this->aop->signType);
|
|
if ($res) { // 验证成功
|
|
$out_trade_no = $_POST['out_trade_no'];
|
|
// 支付宝交易号
|
|
$trade_no = $_POST['trade_no'];
|
|
// 交易状态
|
|
$trade_status = $_POST['trade_status'];
|
|
$pay_common = new PayCommon();
|
|
if ($trade_status == "TRADE_SUCCESS") {
|
|
$retval = $pay_common->onlinePay($out_trade_no, "alipay", $trade_no, "alipay");
|
|
}
|
|
echo "success";
|
|
} else {
|
|
// 验证失败
|
|
echo "fail";
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::write('NotifyinputException' . $e->getMessage());
|
|
echo "fail";
|
|
}
|
|
}
|
|
|
|
public function SysPayNotify($data)
|
|
{
|
|
try {
|
|
unset($data['site_id'], $data['app_type'], $data['paytype']);
|
|
$res = $this->aop->rsaCheckV1($data, $this->aop->alipayrsaPublicKey, $this->aop->signType);
|
|
if ($res) { // 验证成功
|
|
$out_trade_no = $data['out_trade_no'];
|
|
// 支付宝交易号
|
|
$trade_no = $data['trade_no'];
|
|
// 交易状态
|
|
$trade_status = $data['trade_status'];
|
|
$pay_common = new PayCommon();
|
|
if ($trade_status == "TRADE_SUCCESS") {
|
|
$retval = $pay_common->onlinePay($out_trade_no, "alipay", $trade_no, "alipay");
|
|
}
|
|
return "success";
|
|
} else {
|
|
// 验证失败
|
|
return "fail";
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::write('NotifyinputException' . $e->getMessage());
|
|
return "fail";
|
|
}
|
|
}
|
|
|
|
public function payNewTransfer($param)
|
|
{
|
|
try {
|
|
$config_model = new Config();
|
|
$config_result = $config_model->getPayConfig($param['site_id']);
|
|
if ($config_result['code'] < 0) return $config_result;
|
|
$config = $config_result['data']['value'];
|
|
if (empty($config)) return $this->error([], '未配置支付宝支付');
|
|
if (!$config['transfer_status']) return $this->error([], '未启用支付宝转账');
|
|
$parameter = [
|
|
'out_biz_no' => $param['out_trade_no'],
|
|
'trans_amount' => sprintf("%.2f", $param['amount']),
|
|
'product_code' => 'TRANS_ACCOUNT_NO_PWD',
|
|
'biz_scene' => 'DIRECT_TRANSFER',
|
|
'order_title' => '支付宝转账',
|
|
'remark' => $param["desc"],
|
|
'payee_info' => [
|
|
'identity' => $param["account_number"],
|
|
'identity_type' => "ALIPAY_LOGON_ID",
|
|
'name' => $param["real_name"]
|
|
]
|
|
];
|
|
// 建立请求
|
|
$request = new AlipayFundTransUniTransferRequest();
|
|
$request->setBizContent(json_encode($parameter));
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
return $this->success([
|
|
'out_trade_no' => $result->$responseNode->out_biz_no, // 商户交易号
|
|
'payment_no' => $result->$responseNode->order_id, // 微信付款单号
|
|
'payment_time' => date_to_time($result->$responseNode->trans_date) // 付款成功时间
|
|
]);
|
|
} else {
|
|
return $this->error([], $result->$responseNode->sub_msg);
|
|
}
|
|
} catch (\Exception $e) {
|
|
return $this->error([], $e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 付款码支付
|
|
* @param $param
|
|
*/
|
|
public function micropay($param)
|
|
{
|
|
try {
|
|
//构造要请求的参数数组,无需改动
|
|
$parameter = array(
|
|
"out_trade_no" => $param["out_trade_no"],
|
|
"subject" => str_sub($param["pay_body"], 15),
|
|
"total_amount" => (float)$param["pay_money"],
|
|
"scene" => "bar_code",
|
|
"auth_code" => $param['auth_code'],
|
|
);
|
|
$parameter = json_encode($parameter);
|
|
$request = new AlipayTradePayRequest();
|
|
$request->setBizContent($parameter);
|
|
$result = $this->aop->execute($request, null, $this->aop->appAuthToken);
|
|
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
|
|
$resultCode = $result->$responseNode->code;
|
|
if (!empty($resultCode) && $resultCode == 10000) {
|
|
$pay_common = new PayModel();
|
|
return $res = $pay_common->onlinePay($param['out_trade_no'], 'alipay', $result->$responseNode->trade_no, 'alipay');
|
|
} else {
|
|
return $this->error([], $result->$responseNode->sub_msg);
|
|
}
|
|
} catch (\Exception $e) {
|
|
return $this->error([], $e->getMessage());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Common: 判断:是否开启 花呗分期
|
|
* Author: wu-hui
|
|
* Time: 2023/01/15 11:50
|
|
* @param $siteId
|
|
* @return int
|
|
*/
|
|
public static function isOpenStages($siteId)
|
|
{
|
|
$configResult = (new Config())->getPayConfig($siteId);
|
|
if (!$configResult['data']) return 0;// 没有配置数据 未开启花呗
|
|
if (!$configResult['data']['value']) return 0;// 没有配置数据 未开启花呗
|
|
|
|
|
|
return @(int)$configResult['data']['value']['is_huabei'];
|
|
}
|
|
|
|
}
|