334 lines
15 KiB
PHP
334 lines
15 KiB
PHP
|
<?php
|
|||
|
/**
|
|||
|
* Created by PhpStorm.
|
|||
|
* User: Administrator
|
|||
|
* Date: 2021/4/26 0026
|
|||
|
* Time: 14:20
|
|||
|
*/
|
|||
|
namespace app\models\common;
|
|||
|
use function EasyWeChat\Kernel\Support\generate_sign;
|
|||
|
use GuzzleHttp\Client;
|
|||
|
use GuzzleHttp\HandlerStack;
|
|||
|
use WechatPay\GuzzleMiddleware\Auth\CertificateVerifier;
|
|||
|
use WechatPay\GuzzleMiddleware\Auth\WechatPay2Validator;
|
|||
|
use WechatPay\GuzzleMiddleware\Util\AesUtil;
|
|||
|
use WechatPay\GuzzleMiddleware\Validator;
|
|||
|
use Yii;
|
|||
|
use yii\db\ActiveRecord;
|
|||
|
use GuzzleHttp\Exception\RequestException;
|
|||
|
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
|
|||
|
use WechatPay\GuzzleMiddleware\Util\PemUtil;
|
|||
|
use app\models\common\Config;
|
|||
|
class NoopValidator implements Validator
|
|||
|
{
|
|||
|
public function validate(\Psr\Http\Message\ResponseInterface $response)
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class WeChatPay extends ActiveRecord
|
|||
|
{
|
|||
|
public static function getPayConfig($uniacid)
|
|||
|
{
|
|||
|
try{
|
|||
|
$weChatPaySerialNo = (new \yii\db\Query())
|
|||
|
->from('{{%ybwm_core_system}}')
|
|||
|
->where(['ident' => 'weChatServicePaySerialNo', 'uniacid' => $uniacid])
|
|||
|
->one();
|
|||
|
$payData=Config::getSystemSet('payConfig',$uniacid);
|
|||
|
// 商户相关配置
|
|||
|
// $merchantId = '1556224401'; // 商户号
|
|||
|
// $merchantSerialNumber = '7816CD8F2C3D62D6B243C2C4905770AEF62DA9A7'; // 商户API证书序列号
|
|||
|
$merchantSerialNumber = $payData['servicePayNo']; // 商户API证书序列号
|
|||
|
$merchantId = $payData['serviceMchId']; // 商户号
|
|||
|
$merchantPrivateKey = PemUtil::loadPrivateKey(Yii::$app->basePath."/payment/" . 'service_apiclient_key_' . $uniacid . '.pem'); // 商户私钥
|
|||
|
// 微信支付平台配置
|
|||
|
$wechatpayCertificate = PemUtil::loadCertificate(Yii::$app->basePath."/payment/" . 'wechatpay_'.$weChatPaySerialNo['data'].'.pem'); // 微信支付平台证书
|
|||
|
// 构造一个WechatPayMiddleware
|
|||
|
$wechatpayMiddleware = WechatPayMiddleware::builder()
|
|||
|
->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)// 传入商户相关配置
|
|||
|
->withWechatPay([$wechatpayCertificate])// 可传入多个微信支付平台证书,参数类型为array
|
|||
|
->build();
|
|||
|
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
|
|||
|
$stack = HandlerStack::create();
|
|||
|
$stack->push($wechatpayMiddleware, 'wechatpay');
|
|||
|
// 创建Guzzle HTTP Client时,将HandlerStack传入
|
|||
|
return new Client(['handler' => $stack]);
|
|||
|
}catch (\Exception $exception){
|
|||
|
return [];
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public static function test($uniacid, $origin, $outTradeNo, $money, $notifyUrl, $note, $module, $openId, $storeId, $profit_sharing)
|
|||
|
{
|
|||
|
|
|||
|
$client = self::getPayConfig($uniacid);
|
|||
|
if (Yii::$app->params['isDev'] == true) {
|
|||
|
$url = Yii::$app->request->hostInfo . '/addons/' . $module . '/index.php/' . $notifyUrl;
|
|||
|
} else {
|
|||
|
$url = Yii::$app->request->hostInfo . '/index.php/' . $notifyUrl;
|
|||
|
}
|
|||
|
try {
|
|||
|
$resp = $client->request(
|
|||
|
'POST',
|
|||
|
'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', //请求URL
|
|||
|
[
|
|||
|
// JSON请求体
|
|||
|
'json' => [
|
|||
|
"mchid" => "1556224401",
|
|||
|
"appid" => "wx2f926923ad50c5e5",
|
|||
|
"payer" => [
|
|||
|
"openid" => $openId,
|
|||
|
],
|
|||
|
"amount" => [
|
|||
|
"total" => $money * 100,
|
|||
|
],
|
|||
|
"description" => $note,
|
|||
|
"notify_url" => $url,
|
|||
|
"out_trade_no" => $outTradeNo,
|
|||
|
],
|
|||
|
'headers' => ['Accept' => 'application/json']
|
|||
|
]
|
|||
|
);//
|
|||
|
$statusCode = $resp->getStatusCode();
|
|||
|
if ($statusCode == 200) { //处理
|
|||
|
$prepay_id = json_decode($resp->getBody()->getContents(), true)['prepay_id'];
|
|||
|
$params = [
|
|||
|
'appId' => 'wx2f926923ad50c5e5',
|
|||
|
'timeStamp' => strval(time()),
|
|||
|
'nonceStr' => uniqid(),
|
|||
|
'package' => "prepay_id=$prepay_id",
|
|||
|
];
|
|||
|
$var = '';
|
|||
|
foreach ($params as $key => $value) {
|
|||
|
$var .= $value . PHP_EOL;
|
|||
|
}
|
|||
|
$mch_private_key = PemUtil::loadPrivateKey(Yii::$app->basePath."/payment/" . 'apiclient_key_' . $uniacid . '.pem');
|
|||
|
openssl_sign($var, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
|
|||
|
// echo base64_encode($raw_sign);die;
|
|||
|
$params['signType'] = 'RSA';
|
|||
|
$params['paySign'] = base64_encode($raw_sign);
|
|||
|
return $params;
|
|||
|
} else if ($statusCode == 204) { //处理成功,无返回Body
|
|||
|
echo "success";
|
|||
|
}
|
|||
|
} catch (RequestException $e) {
|
|||
|
// 进行错误处理
|
|||
|
echo $e->getMessage() . "\n";
|
|||
|
if ($e->hasResponse()) {
|
|||
|
echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// /www/server/php/72/bin/php tool/CertificateDownloader.php -k admin888admin888admin888admin888 -m 1541578721 -f /www/wwwroot/bkycms.com/addons/yb_wm/payment/service_apiclient_key_39.pem -s 1E6373075BB556DEB62105E3300E51A0725C95D0 -o /www/wwwroot/bkycms.com/addons/yb_wm/payment/
|
|||
|
}
|
|||
|
|
|||
|
public static function downloadCert($opts){
|
|||
|
try {
|
|||
|
// 构造一个WechatPayMiddleware
|
|||
|
$builder = WechatPayMiddleware::builder()
|
|||
|
->withMerchant($opts['mchid'], $opts['serialno'], PemUtil::loadPrivateKey($opts['privatekey'])); // 传入商户相关配置
|
|||
|
if (isset($opts['wechatpay-cert'])) {
|
|||
|
$builder->withValidator(new NoopValidator()); // 临时"跳过”应答签名的验证
|
|||
|
// $builder->withWechatPay([ PemUtil::loadCertificate($opts['wechatpay-cert']) ]); // 使用平台证书验证
|
|||
|
}
|
|||
|
else {
|
|||
|
$builder->withValidator(new NoopValidator()); // 临时"跳过”应答签名的验证
|
|||
|
}
|
|||
|
|
|||
|
$wechatpayMiddleware = $builder->build();
|
|||
|
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
|
|||
|
$stack = HandlerStack::create();
|
|||
|
$stack->push($wechatpayMiddleware, 'wechatpay');
|
|||
|
|
|||
|
// 创建Guzzle HTTP Client时,将HandlerStack传入
|
|||
|
$client = new Client(['handler' => $stack]);
|
|||
|
// 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
|
|||
|
$resp = $client->request('GET', 'https://api.mch.weixin.qq.com/v3/certificates', [
|
|||
|
'headers' => [ 'Accept' => 'application/json' ]
|
|||
|
]);
|
|||
|
if ($resp->getStatusCode() < 200 || $resp->getStatusCode() > 299) {
|
|||
|
return "download failed, code={$resp->getStatusCode()}, body=[{$resp->getBody()}]";
|
|||
|
}
|
|||
|
|
|||
|
$list = json_decode($resp->getBody(), true);
|
|||
|
$plainCerts = [];
|
|||
|
$x509Certs = [];
|
|||
|
|
|||
|
$decrypter = new AesUtil($opts['key']);
|
|||
|
foreach ($list['data'] as $item) {
|
|||
|
$encCert = $item['encrypt_certificate'];
|
|||
|
$plain = $decrypter->decryptToString($encCert['associated_data'],
|
|||
|
$encCert['nonce'], $encCert['ciphertext']);
|
|||
|
if (!$plain) {
|
|||
|
return "加密证书解密失败!";
|
|||
|
}
|
|||
|
// 通过加载对证书进行简单合法性检验
|
|||
|
$cert = \openssl_x509_read($plain); // 从字符串中加载证书
|
|||
|
if (!$cert) {
|
|||
|
return "下载证书检查失败";
|
|||
|
}
|
|||
|
$plainCerts[] = $plain;
|
|||
|
$x509Certs[] = $cert;
|
|||
|
}
|
|||
|
$validator = new WechatPay2Validator(new CertificateVerifier($x509Certs));
|
|||
|
if (!$validator->validate($resp)) {
|
|||
|
return "使用下载的证书验证响应失败!";
|
|||
|
}
|
|||
|
$effective_time=0;
|
|||
|
$wechatpayCertificate=[];//平台证书
|
|||
|
// 输出证书信息,并保存到文件
|
|||
|
foreach ($list['data'] as $index => $item) {
|
|||
|
if((new \DateTime($item['effective_time']))->getTimestamp()>$effective_time){
|
|||
|
$effective_time=(new \DateTime($item['effective_time']))->getTimestamp();
|
|||
|
$wechatpayCertificate=[
|
|||
|
'serial_no'=>$item['serial_no'],
|
|||
|
'text'=> $plainCerts[$index],
|
|||
|
'effective_time'=> (new \DateTime($item['effective_time']))->getTimestamp(),
|
|||
|
'expire_time'=> (new \DateTime($item['expire_time']))->getTimestamp(),
|
|||
|
];
|
|||
|
}
|
|||
|
}
|
|||
|
$info = (new \yii\db\Query())
|
|||
|
->from('{{%ybwm_core_system}}')
|
|||
|
->where(['ident' => 'weChatServicePaySerialNo', 'uniacid' => $opts['uniacid']])
|
|||
|
->one();
|
|||
|
if($info){
|
|||
|
$data['changeAt']=time();
|
|||
|
$data['data']=$wechatpayCertificate['serial_no'];
|
|||
|
Yii::$app->db->createCommand()->update('{{%ybwm_core_system}}',$data,['id'=>$info['id']] )->execute();
|
|||
|
}else{
|
|||
|
$data['data']=$wechatpayCertificate['serial_no'];
|
|||
|
$data['createdAt']=time();
|
|||
|
$data['ident']='weChatServicePaySerialNo';
|
|||
|
$data['name']='微信支付平台证书序列号';
|
|||
|
$data['uniacid']=$opts['uniacid'];
|
|||
|
Yii::$app->db->createCommand()->insert('{{%ybwm_core_system}}', $data)->execute();
|
|||
|
}
|
|||
|
$outpath = $opts['output'].'wechatpay_'.$wechatpayCertificate['serial_no'].'.pem';
|
|||
|
$res=file_put_contents($outpath, $wechatpayCertificate['text']);
|
|||
|
if($res){
|
|||
|
return true;
|
|||
|
}else{
|
|||
|
return '证书生成失败';
|
|||
|
}
|
|||
|
}
|
|||
|
catch (RequestException $e) {
|
|||
|
echo "download failed, message=[{$e->getMessage()}] ";
|
|||
|
if ($e->hasResponse()) {
|
|||
|
return "code={$e->getResponse()->getStatusCode()}, body=[{$e->getResponse()->getBody()}]\n";
|
|||
|
}
|
|||
|
}
|
|||
|
catch (\Exception $e) {
|
|||
|
return "download failed, message=[{$e->getMessage()}]\n";
|
|||
|
}
|
|||
|
return '证书生成失败';
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @param $orderId
|
|||
|
* @param string $status
|
|||
|
* @param int $type[1.外卖2店内3快餐]
|
|||
|
* @return bool|string
|
|||
|
* @throws \GuzzleHttp\Exception\GuzzleException
|
|||
|
*/
|
|||
|
public static function reporting($orderId,$status='CREATE_DEAL',$type=1){
|
|||
|
if($type==1){
|
|||
|
$order = (new \yii\db\Query())
|
|||
|
->from('{{%ybwm_takeout_order}}')
|
|||
|
->where('id=:id', [':id' => $orderId])->one();
|
|||
|
$originMoney=bcadd(bcadd($order['originMoney'],$order['deliveryMoney'],2),$order['boxMoney'],2);
|
|||
|
$discount_amount=bcsub($order['money'],$originMoney,2);
|
|||
|
}else{
|
|||
|
$order = (new \yii\db\Query())
|
|||
|
->from('{{%ybwm_instore_order}}')
|
|||
|
->where('id=:id', [':id' => $orderId])->one();
|
|||
|
$originMoney=bcadd($order['originMoney'],$order['tablewareMoney'],2);
|
|||
|
$discount_amount=bcsub($order['money'],$originMoney,2);
|
|||
|
}
|
|||
|
$payData=Config::getSystemSet('payConfig',$order['uniacid']);
|
|||
|
if($payData['smOpen']!=1){
|
|||
|
return false;
|
|||
|
}
|
|||
|
$client = self::getPayConfig($order['uniacid']);
|
|||
|
if(!$client){
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
$config=Config::getSystemSet('miniConfig',$order['uniacid']);
|
|||
|
$payConfig=Config::getSystemSet('payConfig',$order['uniacid']);//服务商配置
|
|||
|
$storeSet=Config::getStoreSet('serviceCharge',$order['storeId']);//商户子商户号设置
|
|||
|
$subMchId=$storeSet['subMchId']?:$payConfig['sonMchId'];
|
|||
|
$goods=(new \yii\db\Query())
|
|||
|
->from('{{%ybwm_order_goods}}')
|
|||
|
->where('orderId=:orderId AND item='.$type, [':orderId' => $orderId])->all();
|
|||
|
$goodsArr=[];
|
|||
|
for($i=0;$i<count($goods);$i++){
|
|||
|
$goodsArr[]=[
|
|||
|
'out_dish_no'=>$goods[$i]['goodsId'],
|
|||
|
'name'=>$goods[$i]['name'],
|
|||
|
'price'=>$goods[$i]['money']*100,
|
|||
|
'unit'=>'BY_SHARE',
|
|||
|
'count'=>floatval($goods[$i]['num']),
|
|||
|
];
|
|||
|
}
|
|||
|
$user=(new \yii\db\Query())
|
|||
|
->from('{{%ybwm_member}}')
|
|||
|
->where('id=:id', [':id' => $order['userId']])->one();
|
|||
|
$data=[
|
|||
|
'sp_appid'=>$payConfig['serviceAppId'],
|
|||
|
'sp_mchid'=>$payConfig['serviceMchId'],
|
|||
|
'sub_mchid'=>$subMchId,
|
|||
|
'sub_appid'=>$config['appId'],
|
|||
|
'out_shop_no'=>$order['storeId'],
|
|||
|
'sub_openid'=>$user['openId'],
|
|||
|
'login_token'=>$user['login_token'],
|
|||
|
'order_entry'=>'yb_wm/index/goods',
|
|||
|
'total_amount'=>$originMoney*100,
|
|||
|
'discount_amount'=>$discount_amount*100,
|
|||
|
'user_amount'=>$order['money']*100,
|
|||
|
'status'=>$status,
|
|||
|
'action_time'=>date(DATE_RFC3339),
|
|||
|
'out_trade_no'=>$order['outTradeNo'],
|
|||
|
'out_order_no'=>$order['outTradeNo'],
|
|||
|
'dish_list'=>$goodsArr,
|
|||
|
];
|
|||
|
if($status=='PAY_SUCCESS'){
|
|||
|
$data['pay_time']=date(DATE_RFC3339);
|
|||
|
$data['transaction_id']=$order['transaction_id'];
|
|||
|
}
|
|||
|
try {
|
|||
|
$resp = $client->request(
|
|||
|
'POST',
|
|||
|
'https://api.mch.weixin.qq.com/v3/catering/orders/sync-status', //请求URL
|
|||
|
[
|
|||
|
// JSON请求体
|
|||
|
'json' => $data,
|
|||
|
'headers' => ['Accept' => 'application/json']
|
|||
|
]
|
|||
|
);
|
|||
|
$statusCode = $resp->getStatusCode();
|
|||
|
if ($statusCode == 200) { //处理成功
|
|||
|
// $res = json_decode($resp->getBody()->getContents(), true);
|
|||
|
return true;
|
|||
|
} else if ($statusCode == 204) { //处理成功,无返回Body
|
|||
|
return true;
|
|||
|
}
|
|||
|
} catch (RequestException $e) {
|
|||
|
// 进行错误处理
|
|||
|
if ($e->hasResponse()) {
|
|||
|
return "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|