|
- 内饰颜色:
+ 内饰颜色:=$incolor?>
|
@@ -68,14 +69,16 @@
车辆单价为车身单价,续航里程为300KM以上的车辆已按扣减国家补贴后的价格结算。不包含车辆购置税、车辆保险费、挂牌杂费等其他费用。乙方如需委托甲方代理上牌、委托运输等服务的,双方应另外签订《委托服务协议》。
第三条付款方式
- 乙方在签订合同时即付定金人民币: 元,定金在结算时冲抵车款。
- 乙方选择一次性付款方式 / 分期付款方式
+ 乙方在签订合同时即付定金人民币:=$dep_price?>元,定金在结算时冲抵车款。
+ 乙方选择=$row['payway']?'一次性付款方式':'分期付款方式'?>
第四条 车辆交付
- 1、交车时间:合同签订之日起 XX天内。
+ 1、交车时间:合同签订之日起 =$give_time?>天内。
+
2、提车方式:乙方自提
- 3、交车地点 : XX市XX区/县 XXXX店 先按当前门店 。
+ 3、交车地点 :=$address?>。
4、交车时里程表记录小于100公里
5、备注:如乙方购买续航里程为300KM以上车辆,上牌性质是公户或营运车辆需确保购买车辆自行驶证注册日期起1年之内行驶2万公里,且至车辆注册之日起2年内不得过户,如因违反此条约使甲方在申领国补过程中造成的损失,一切责任及后果由乙方承担。
第五条 车辆确认
diff --git a/api/views/wxapp/licheb/html2pdf/car_ck.php b/api/views/wxapp/licheb/html2pdf/car_ck.php
index 3da3ec72..e8eb9e37 100644
--- a/api/views/wxapp/licheb/html2pdf/car_ck.php
+++ b/api/views/wxapp/licheb/html2pdf/car_ck.php
@@ -8,15 +8,14 @@
车辆信息确认单
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- (证件类型):证件号码
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- (证件类型):委托人证件号码
- 联系电话:(委托人手机号码)
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
乙方于=date('Y年m月d日',$c_time)?>在甲方购买 =$brand_name?> 车辆 1 台,并确认车架号为:=$vin?>。乙方已对上述车辆的厂牌型号、配置等进行认真检查并验收合格无异议。
diff --git a/api/views/wxapp/licheb/html2pdf/car_fh.php b/api/views/wxapp/licheb/html2pdf/car_fh.php
index 60d40f64..76acbaef 100644
--- a/api/views/wxapp/licheb/html2pdf/car_fh.php
+++ b/api/views/wxapp/licheb/html2pdf/car_fh.php
@@ -8,15 +8,15 @@
车辆交付表
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- (证件类型):证件号码
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- (证件类型):委托人证件号码
- 联系电话:(委托人手机号码)
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 身份证号码:=$cardid?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
一、车辆信息
@@ -25,12 +25,12 @@
品牌:=$brand_name?>
|
- 车系:
+ 车系:=$series_name?>
|
|
- 车型:
+ 车型:=$version?>
|
车身颜色:=$color?>
@@ -38,15 +38,15 @@
|
|
- 内饰颜色:
+ 内饰颜色:=$incolor?>
|
- 车架号:XW111111111111
+ 车架号:=$vin?>
|
|
- 车牌号:闽D232333
+ 车牌号:=$agent['car_num']?>
|
|
@@ -54,8 +54,8 @@
二、结算信息
- 应付款合计 50100 ,其中包含:车辆价款 50000,委托代办款项 3000
- 已付款合计 50000
+ 应付款合计 =number_format($price+$total_price,2)?> ,其中包含:车辆价款 =number_format($price,2)?>,委托代办款项 =number_format($total_price,2)?>
+ 已付款合计 =number_format($pay_price,2)?>
三、证件资料交接信息
证件信息由后台配置,销售交付时钩选才显示:
diff --git a/api/views/wxapp/licheb/protocol/agent.php b/api/views/wxapp/licheb/protocol/agent.php
index aab1655c..5db66610 100644
--- a/api/views/wxapp/licheb/protocol/agent.php
+++ b/api/views/wxapp/licheb/protocol/agent.php
@@ -12,23 +12,21 @@
委托代理服务协议
- 协议编号:(右对齐,6位地区编码+合同类型id+yymmdd+6位随机数)
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- (证件类型):证件号码
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- (证件类型):委托人证件号码
- 联系电话:(委托人手机号码)
+ 协议编号:=$cid?>
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
乙方为节省时间和精力,就甲乙双方《车辆买卖合同》标的的车辆,自愿委托甲方办理下列委托事项,并达成如下协议:
一、委托代办服务事项(乙方授权甲方代办下列事项)
- 代办保险服务 每个车一个价格
- 代办上牌服务 每个地级市一个价格
- 代办金融服务 (公式)
- 购买精品包
- 代办服务总价:(计算出合同总价,含保险)元, 壹千贰百叁十个肆玩万元整,保险费用由乙方直接支付给保险公司。
+
+ =$val['title']?>
+ }?>
+ 代办服务总价:=$total_price?>元,=num_to_rmb($total_price)?>,保险费用由乙方直接支付给保险公司。
二、双方特别约定
1、车牌选号若为代选号牌时,均由甲方电话通知乙方,因乙方未能及时选号等其它原因,甲方有权代理决定并不对最终选号结果负责;若为自选号牌,甲方可配合乙方上牌,但不对最终选号结果负责。
2、乙方委托甲方代办车辆挂牌服务时,乙方应事先办妥机动车车辆保险,投保险种包括但不限于车辆损失险和第三者责任险。甲方在代办服务过程中造成车辆毁损、灭失的,乙方应当先向保险公司索赔,赔付不足部分由甲方予以修复或赔偿。
diff --git a/api/views/wxapp/licheb/protocol/car.php b/api/views/wxapp/licheb/protocol/car.php
index 0c4ff0bf..9166692a 100644
--- a/api/views/wxapp/licheb/protocol/car.php
+++ b/api/views/wxapp/licheb/protocol/car.php
@@ -13,36 +13,37 @@
车辆买卖合同
合同编号:=$cid?>
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- 联系电话:(委托人手机号码)
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
甲、乙双方依据《中华人民共和国合同法》及其他有关法律、法规的规定,在平等、自愿、协商一致的基础上,就买卖汽车事宜,订立本合同。
第一条 车辆基本情况
|
- 品牌:
+ 品牌:=$brand_name?>
|
- 车系:
+ 车系:=$series_name?>
|
|
- 车型:
+ 车型:=$version?>
|
- 车身颜色:
+ 车身颜色:=$color?>
|
|
- 内饰颜色:
+ 内饰颜色:=$incolor?>
|
@@ -72,14 +73,16 @@
车辆单价为车身单价,续航里程为300KM以上的车辆已按扣减国家补贴后的价格结算。不包含车辆购置税、车辆保险费、挂牌杂费等其他费用。乙方如需委托甲方代理上牌、委托运输等服务的,双方应另外签订《委托服务协议》。
第三条付款方式
- 乙方在签订合同时即付定金人民币: 元,定金在结算时冲抵车款。
- 乙方选择一次性付款方式 / 分期付款方式
+ 乙方在签订合同时即付定金人民币:=$dep_price?>元,定金在结算时冲抵车款。
+ 乙方选择=$row['payway']?'一次性付款方式':'分期付款方式'?>
第四条 车辆交付
- 1、交车时间:合同签订之日起 XX天内。
+ 1、交车时间:合同签订之日起 =$give_time?>天内。
+
2、提车方式:乙方自提
- 3、交车地点 : XX市XX区/县 XXXX店 先按当前门店 。
+ 3、交车地点 :=$address?>。
4、交车时里程表记录小于100公里
5、备注:如乙方购买续航里程为300KM以上车辆,上牌性质是公户或营运车辆需确保购买车辆自行驶证注册日期起1年之内行驶2万公里,且至车辆注册之日起2年内不得过户,如因违反此条约使甲方在申领国补过程中造成的损失,一切责任及后果由乙方承担。
第五条 车辆确认
diff --git a/api/views/wxapp/licheb/protocol/car_ck.php b/api/views/wxapp/licheb/protocol/car_ck.php
index c1c4f53d..65bf4b47 100644
--- a/api/views/wxapp/licheb/protocol/car_ck.php
+++ b/api/views/wxapp/licheb/protocol/car_ck.php
@@ -12,15 +12,14 @@
车辆信息确认单
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- (证件类型):证件号码
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- (证件类型):委托人证件号码
- 联系电话:(委托人手机号码)
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
乙方于=date('Y年m月d日',$c_time)?>在甲方购买 =$brand_name?> 车辆 1 台,并确认车架号为:=$vin?>。乙方已对上述车辆的厂牌型号、配置等进行认真检查并验收合格无异议。
diff --git a/api/views/wxapp/licheb/protocol/car_fh.php b/api/views/wxapp/licheb/protocol/car_fh.php
index 9e17fe01..72f712b8 100644
--- a/api/views/wxapp/licheb/protocol/car_fh.php
+++ b/api/views/wxapp/licheb/protocol/car_fh.php
@@ -12,15 +12,15 @@
车辆交付表
- 甲方(出卖人):(根据门店所属公司)
- 统一社会信用代码:(根据门店所属公司)
- 乙方(买受人):(用户真实姓名)
- (证件类型):证件号码
- 联系电话:(用户手机号码)
- #假如有委托人#
- 委托代理人:(委托人真实姓名)
- (证件类型):委托人证件号码
- 联系电话:(委托人手机号码)
+ 甲方(出卖人):=$company['title']?>
+ 统一社会信用代码:=$company['credit_code']?>
+ 乙方(买受人):=$name?>
+ 身份证号码:=$cardid?>
+ 联系电话:=$mobile?>
+
+ 委托代理人:=$info_json['entrust_name']?>
+ 委托人身份证:=$info_json['entrust_idcard']?>
+ }?>
一、车辆信息
@@ -29,12 +29,12 @@
品牌:=$brand_name?>
|
- 车系:
+ 车系:=$series_name?>
|
|
- 车型:
+ 车型:=$version?>
|
车身颜色:=$color?>
@@ -42,15 +42,15 @@
|
|
- 内饰颜色:
+ 内饰颜色:=$incolor?>
|
- 车架号:XW111111111111
+ 车架号:=$vin?>
|
|
- 车牌号:闽D232333
+ 车牌号:=$agent['car_num']?>
|
|
@@ -58,8 +58,8 @@
二、结算信息
- 应付款合计 50100 ,其中包含:车辆价款 50000,委托代办款项 3000
- 已付款合计 50000
+ 应付款合计 =number_format($price+$total_price,2)?> ,其中包含:车辆价款 =number_format($price,2)?>,委托代办款项 =number_format($total_price,2)?>
+ 已付款合计 =number_format($pay_price,2)?>
三、证件资料交接信息
证件信息由后台配置,销售交付时钩选才显示:
diff --git a/common/composer.json b/common/composer.json
index 3cef7554..d9ccf189 100644
--- a/common/composer.json
+++ b/common/composer.json
@@ -1,6 +1,7 @@
{
"require": {
"gregwar/image": "^2.1",
- "tencentcloud/ocr": "^3.0"
+ "tencentcloud/ocr": "^3.0",
+ "wechatpay/wechatpay-guzzle-middleware": "^0.2.2"
}
}
diff --git a/common/composer.lock b/common/composer.lock
index 3311f081..6d64f719 100644
--- a/common/composer.lock
+++ b/common/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "6f7afccbfb645077ee3dcb371ebf6039",
+ "content-hash": "4f7bbe710bfa187154b75afba695ea66",
"packages": [
{
"name": "gregwar/cache",
@@ -908,6 +908,57 @@
"description": "TencentCloudApi php sdk ocr",
"homepage": "https://github.com/tencentcloud-sdk-php/ocr",
"time": "2021-07-16T01:13:52+00:00"
+ },
+ {
+ "name": "wechatpay/wechatpay-guzzle-middleware",
+ "version": "0.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wechatpay-apiv3/wechatpay-guzzle-middleware.git",
+ "reference": "6782ac33ed8cf97628609a71cdc5e84a6a40677a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wechatpay-apiv3/wechatpay-guzzle-middleware/zipball/6782ac33ed8cf97628609a71cdc5e84a6a40677a",
+ "reference": "6782ac33ed8cf97628609a71cdc5e84a6a40677a",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "ext-openssl": "*",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "^6.3"
+ },
+ "suggest": {
+ "ext-bcmath": "Require bcmath in php 5.* version.",
+ "guzzlehttp/guzzle": "For using wechatpay guzzle middleware."
+ },
+ "bin": [
+ "tool/CertificateDownloader.php"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "WechatPay\\GuzzleMiddleware\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "description": "WechatPay API V3 Guzzle Middleware",
+ "homepage": "https://wechatpay-api.gitbook.io/wechatpay-api-v3/",
+ "keywords": [
+ "wechatpay"
+ ],
+ "time": "2021-03-05T03:09:29+00:00"
}
],
"packages-dev": [],
diff --git a/common/helpers/comm_helper.php b/common/helpers/comm_helper.php
index 254bcd2e..f72682c3 100644
--- a/common/helpers/comm_helper.php
+++ b/common/helpers/comm_helper.php
@@ -1039,3 +1039,16 @@ if(!function_exists('convert_url_query')){
return $params;
}
}
+if(!function_exists('create_contract_no')){
+ /**
+ * 生成合同编号
+ * int $city_id
+ * int $id 合同id
+ * int $type 合同类型 (0整车合同 1代理协议 2确定信息 3交接信息)
+ */
+ function create_contract_no($city_id = 350200, $id, $type = 0)
+ {
+ return $city_id . $type . $id . date('Ymd') . sprintf("%06d", rand(1,999999));
+ }
+
+}
diff --git a/common/libraries/Pdf.php b/common/libraries/Pdf.php
index efdc163e..b6122464 100644
--- a/common/libraries/Pdf.php
+++ b/common/libraries/Pdf.php
@@ -45,6 +45,7 @@ class Pdf {
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
+ $pdf->setCellHeightRatio(1.1); //设置行高
$pdf->SetMargins(PDF_MARGIN_LEFT, 5,PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
diff --git a/common/libraries/WechatPayV3.php b/common/libraries/WechatPayV3.php
new file mode 100644
index 00000000..d54d0974
--- /dev/null
+++ b/common/libraries/WechatPayV3.php
@@ -0,0 +1,90 @@
+merchantId = $config['merchantId']; //商户号
+ $this->merchantSerialNumber = $config['merchantSerialNumber']; //商户API证书序列号
+ $this->merchantPrivateKey = $config['merchantPrivateKey']; //商户证书路径
+ $this->wechatpayCertificate = $config['wechatpayCertificate']; //微信支付平台证书
+ }
+
+ public function unifiedOrder($json,$appid,$noncestr){
+ $url = 'https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi';
+ // 商户相关配置
+ //$merchantId = '1612096731'; // 商户号
+ //$merchantSerialNumber = '761590F1FF6DFC2466894F96E2DE1169CE644A74'; // 商户API证书序列号
+ $merchantPrivateKey = PemUtil::loadPrivateKey($this->merchantPrivateKey); // 商户私钥
+ // 微信支付平台配置
+ $wechatpayCertificate = PemUtil::loadCertificate($this->wechatpayCertificate); // 微信支付平台证书
+
+ // 构造一个WechatPayMiddleware
+ $wechatpayMiddleware = WechatPayMiddleware::builder()
+ ->withMerchant($this->merchantId, $this->merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
+ ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
+ ->build();
+
+ // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
+ $stack = GuzzleHttp\HandlerStack::create();
+ $stack->push($wechatpayMiddleware, 'wechatpay');
+
+ // 创建Guzzle HTTP Client时,将HandlerStack传入
+ $client = new GuzzleHttp\Client(['handler' => $stack]);
+
+ // 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
+ try {
+ $resp = $client->request('POST', $url, [
+ 'json' => $json,
+ 'headers' => [ 'Accept' => 'application/json' ]
+ ]);
+
+ $body = json_decode($resp->getBody(),true);
+ if(!$body['prepay_id']){
+ return ['code'=>0,'msg'=>'下单失败'];
+ }
+ //微信支付(小程序)签名
+ $timeStamp = time();
+ $str = $this->getWechartSign($appid,$timeStamp,$noncestr,'prepay_id='.$body['prepay_id']);
+ $data = array('appid'=>$appid,'timeStamp'=>"$timeStamp",'package'=>'prepay_id='.$body['prepay_id'],'paySign'=>$str,'nonceStr'=>$noncestr,'signType'=>'RSA');
+
+ return ['code'=>1,'data'=>$data];
+ } catch (RequestException $e) {
+ // 进行错误处理
+ //echo $e->getMessage()."\n";
+ $error_msg = $e->getMessage();
+ if ($e->hasResponse()) {
+ //echo $e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase()."\n";
+ //echo $e->getResponse()->getBody();
+ }
+ return ['code'=>0,'msg'=>$error_msg];
+ }
+ }
+ //调起支付的签名
+ private function getWechartSign($appid,$timeStamp,$noncestr,$prepay_id){
+ $str = $appid."\n".$timeStamp."\n".$noncestr."\n".$prepay_id."\n";
+ $key = file_get_contents($this->merchantPrivateKey);
+ $str = $this->getSha256WithRSA($str,$key);
+ return $str;
+ }
+
+ private function getSha256WithRSA($content, $privateKey){
+ $binary_signature = "";
+ $algo = "SHA256";
+ openssl_sign($content, $binary_signature, $privateKey, $algo);
+ $sign = base64_encode($binary_signature);
+ return $sign;
+ }
+
+}
diff --git a/common/libraries/receiver/Orders_entity.php b/common/libraries/receiver/Orders_entity.php
index d3a53468..d0da3e6b 100644
--- a/common/libraries/receiver/Orders_entity.php
+++ b/common/libraries/receiver/Orders_entity.php
@@ -6,6 +6,7 @@
class Orders_entity{
private $ci;
+ const SRV_MCH_ID = '1612636924'; //收取服务费商户号 厦门狸车服务
public function __construct(){
$this->ci = & get_instance();
@@ -22,11 +23,11 @@ class Orders_entity{
switch($type){
case 0;
$path = '/wxapp/licheb/protocol/car';
- $title = '车辆整车合同';
+ $title = '车辆买卖合同';
break;
case 1:
$path = '/wxapp/licheb/protocol/agent';
- $title = '委托代理服务协议';
+ $title = '委托服务协议';
break;
case 2:
$path = '/wxapp/licheb/protocol/car_ck';
@@ -34,7 +35,7 @@ class Orders_entity{
break;
case 3:
$path = '/wxapp/licheb/protocol/car_fh';
- $title = '车辆交接信息';
+ $title = '车辆交付表';
break;
default:
}
@@ -46,9 +47,9 @@ class Orders_entity{
/**
* 签完成协议后操作
- * @param $oid int 订单id
+ * @param $oid int 订单id
* @param $app_id int 小程序id
- * @param $userinfo array() 小程序用户信息
+ * @param $userinfo array 小程序用户信息
*/
public function sign_after($oid,$app_id,$userinfo){
$this->ci->load->model('receiver/order/receiver_orders_model','orders_model');
@@ -79,16 +80,19 @@ class Orders_entity{
}
}else{
$this->ci->signs_model->update(['status'=>1],['o_id'=>$row['id']]);
- $res = $this->c_order($row,$app_id,$userinfo);
+ $res = $this->c_order(self::SRV_MCH_ID,$row,$app_id,$userinfo);
}
return $res;
}
/**
* 创建定金消费订单
- * @param $oder array 订单数据
+ * @param $mch_id string 微信商户号
+ * @param $oder array 订单数据
+ * @param $app_id int 应用id
+ * @param $userinfo array 用户信息
* return boolean
*/
- public function c_order($order,$app_id,$userinfo){
+ public function c_order($mch_id,$order,$app_id,$userinfo){
$this->ci->load->model('apporder/order_purchase_model');
$this->ci->load->model('auto/auto_series_model');
$this->ci->load->model('auto/auto_brand_model');
@@ -107,6 +111,7 @@ class Orders_entity{
'app_id' => $app_id,
'app_uid' => $userinfo['uid'],
'sid' => $sid,
+ 'mch_id' => $mch_id,
'item_id' => $order['id'],
'item_title' => $brand['name'].$series['name'],
'item_num' => 1,
@@ -244,6 +249,120 @@ class Orders_entity{
}
return $res;
}
+
+ //确认车辆完成创建两个支付订单
+ public function check_finish($oid,$app_id,$userinfo){
+ $this->ci->load->model('receiver/order/receiver_orders_model','orders_model');
+ $this->ci->load->model('apporder/order_purchase_model');
+ $this->ci->load->model('auto/auto_series_model');
+ $this->ci->load->model('auto/auto_brand_model');
+ $this->ci->load->model('auto/auto_cars_model');
+ $this->ci->load->model("biz/biz_model");
+ $this->ci->load->model('receiver/receiver_service_package_model','package_model');
+ $this->ci->load->model('receiver/receiver_services_model','services_model');
+ $this->ci->load->model("sys/sys_company_model");
+ $this->ci->load->model('sys/sys_city_model');
+
+ $row = $this->ci->orders_model->get(['id'=>$oid]);
+ if(!$row){
+ return false;
+ }
+ $brand = $this->ci->auto_brand_model->get(['id'=>$row['brand_id']],'name');
+ $series = $this->ci->auto_series_model->get(['id'=>$row['s_id']],'name');
+ $car_json = json_decode($row['car_json'],true);
+ $color = isset($car_json['color']) ? $car_json['color'] : '';
+
+ $jsondata['car'] = $car_json;
+ if($color['jsondata']['img']){
+ $jsondata['cover'] = $color['jsondata']['img'];
+ }
+ //获取门店信息
+ $biz = $this->ci->biz_model->get(['id'=>$row['biz_id']],'company_id,city_id');
+ $company = $this->ci->sys_company_model->get(['id'=>$biz['company_id']]);
+ //获取服务包
+ $packs = $this->ci->package_model->get(['id'=>$row['pack_id']],'srv_ids');
+ $services = [];
+ if($packs['srv_ids']){
+ $services = $this->ci->services_model->select(["id in ({$packs['srv_ids']})"],'','','','title,field_name');
+ }
+ $attrs = "{$row['cor_id']}_{$row['v_id']}_{$row['incor_id']}";
+ $car = $this->ci->auto_cars_model->get(['attrs'=>$attrs,'s_id'=>$row['s_id']]);
+ //获取挂牌价
+ $city = $this->ci->sys_city_model->get(['city_id'=>$biz['city_id']],'fee_carno');
+ $car['fee_carno'] = $city['fee_carno'];
+ $srv_price = 0;
+ if($services){
+ foreach($services as $key=>$val){
+ $field_arr = explode('.',$val['field_name']);
+ if($car[$field_arr[1]]){
+ $srv_price += $car[$field_arr[1]];
+ }
+ }
+ }
+ if($row['payway']){ //全款
+ $to_com_price = $car['price']; //给销售公司金额 裸车价格
+ $to_srv_price = $car['price'] + $srv_price - $to_com_price - $row['deposit'] - $car['price_insure']; //给服务公司金额 裸车价格+服务费-给销售公司金额-定金-保险
+ $to_srv_price = $to_srv_price>0 ? $to_srv_price : 0;
+ }else{ //分期
+ $to_com_price = $car['first_pay']; //给销售公司金额
+ $to_srv_price = $car['first_pay'] + $srv_price - $to_com_price - $row['deposit'] - $car['price_insure']; //给服务公司的金额 首付+服务费-给销售公司-定金-保险
+ $to_srv_price = $to_srv_price>0 ? $to_srv_price : 0;
+ }
+ $add_data = [];
+ if($to_srv_price>0){
+ $order_type = 5;
+ $sid = create_order_no(350200,'liche',1,$order_type);
+ $add_data[] = [
+ 'app_id' => $app_id,
+ 'app_uid' => $userinfo['uid'],
+ 'sid' => $sid,
+ 'mch_id' => self::SRV_MCH_ID,
+ 'item_id' => $row['id'],
+ 'item_title' => $brand['name'].$series['name'],
+ 'item_num' => 1,
+ 'type' => $order_type,
+ 'item_price' => $to_srv_price,
+ 'total_price' => $to_srv_price,
+ 'uname' => $userinfo['nickname'],
+ 'mobile' => $userinfo['mobile'],
+ 'payway' => 1,
+ 'status' => 1,
+ 'status_detail' => 11,
+ 'jsondata' => json_encode($jsondata,JSON_UNESCAPED_UNICODE),
+ 'c_time' => time(),
+ 'cf_id' => $row['id']
+ ];
+ }
+ if($to_com_price>0){
+ $order_type = 6;
+ $sid = create_order_no(350200,'liche',1,$order_type);
+ $add_data[] = [
+ 'app_id' => $app_id,
+ 'app_uid' => $userinfo['uid'],
+ 'sid' => $sid,
+ 'mch_id' => $company['wx_mchid'],
+ 'item_id' => $row['id'],
+ 'item_title' => $brand['name'].$series['name'],
+ 'item_num' => 1,
+ 'type' => $order_type,
+ 'item_price' => $to_com_price,
+ 'total_price' => $to_com_price,
+ 'uname' => $userinfo['nickname'],
+ 'mobile' => $userinfo['mobile'],
+ 'payway' => 1,
+ 'status' => 1,
+ 'status_detail' => 11,
+ 'jsondata' => json_encode($jsondata,JSON_UNESCAPED_UNICODE),
+ 'c_time' => time(),
+ 'cf_id' => $row['id']
+ ];
+ }
+ $result = false;
+ if($add_data){
+ $result = $this->ci->order_purchase_model->add_batch($add_data);
+ }
+ return $result;
+ }
}
?>
diff --git a/common/libraries/receiver/Sign_entity.php b/common/libraries/receiver/Sign_entity.php
index 6119aea4..58488ec6 100644
--- a/common/libraries/receiver/Sign_entity.php
+++ b/common/libraries/receiver/Sign_entity.php
@@ -9,8 +9,9 @@ class Sign_entity{
private $ci;
private $comp_img = 'https://qimg.haodian.cn/hdi/2021/07/f2308e9066d290eb/79063515aefc302f.png'; //公司印章图片地址
- public function __construct(){
+ public function __construct($params=[]){
$this->ci = & get_instance();
+ $params['comp_img'] && $this->comp_img = $params['comp_img'];
}
/**
@@ -63,60 +64,4 @@ class Sign_entity{
}
}
- /**
- * 图片签名
- * @param $orgin_url string 签名图片地址
- * @param $user_image base64 用户签名文件对象
- * @param $width int 用户签名x坐标
- * @param $height int 用户签名y坐标
- * @param $o_width int 公司签名x坐标
- * @param $o_height int 公司签名y坐标
- * @param $need_c boolean 是否需要公司章
- * @param $s_path string 图片保存地址
- * return string 返回合成后图片地址
- */
- public function test($origin_url,$user_file,$width,$height,$o_width='',$o_height='',$need_c=true,$s_path='' ){
-
- $user_file = "iVBORw0KGgoAAAANSUhEUgAAAXcAAAKdCAMAAADvKdm1AAAAAXNSR0IB2cksfwAAAFFQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXKkVQgAAABt0Uk5TADCA/99A78/Q8CAQwKBwv+BQkLBgr59/P2+PuKEyZQAAC7pJREFUeJzt3ely6zYMhuHKuy0v8ZJz2t7/hdaCvCTxJskkPvXgff51ppPSGJUEQVD66y8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+J8oCvUIQhoMh6OxehABTYbD4VQ9iIBmx7jP1YMIqHreB+pBxLM4hn1YqkcRz/gY9qV6EAEd05nhSj2IgFZM7xLLY9xJ392V1bK6UI8inhXZu0JRPe5r9Sji2RzD/qEeRDzbIauqwohNk8KAZEahrEpiO/Uo4qke9zklMW8lFWAJHncJHncNHncJHncNHncJHncNHncJHncNHncNHneJMY+7xI6mGYnqvGOrHkQ8BT2REutj2PfqQQQ0Pcb9oB5EPAuOVSUOx7DP1IMIaE+PmIK1onJ30t2W3jyJFV0zClYCpifSHR3vEnS8a9DxLnGg412hHFESU6DjXcIqYpyruvusFlUOPLxVx9kU3v1xjUxiTSFSwQozdG+0keRVgwealVqyrLtXRiG6bybqMN+aRAj8TB3lOyK8crJczdVhvkFDQjPVcUeq3H07G35EmGcSsMoMsXJXpUQcd7izPROVGXfsmTSqihh1d3f2HjGOmdxVTQRUxNxZzwwFYHcp90xobHHa2scoIvbHpYw8Ya5xtLiWkUek8H4+v1QRN+rBxGG5e9UAXF2O58KBl/LavFF92oAijZPdNXcvP1hbvViL2LkyU1THVhEO6PSm3+ruB6Z4H5a6f7lmsOfYycPiZ4tYPcWTxWe2uTnuKMji8zvcmVUGXxda5GCHqjd1yCVF4czshvDNKVM5p1CT1fjBjGKFg0//8QRhBYK73XQ76gUZDR7P41Wf64Rj7iyKJ1tTqxeQTGZh7yF4tHquz7VhJLZ+XhBYMtNkYan7k/cQLJhpsvh81Q/JTJPD+HVUmWkyeJi6XzHTpPckdb9ipklt0exUiZkmsduq+13MNGltm57lMdOkdL/qfhczTUK75nc7FvR1JFO0Ocdbc+iXyveGmVf2HPqlsf7RMPMCh35p2CzT5r2cVlH4lW08QVifUrv7wTs6yN5WTtufnJYzOsje9dklPaGD7F02ZbS/Hsy29T3WlTfrMGPQQfYOmy86vXODbesb6lSm21O75TpCV11SmatVu90WLjqlMhdcR+ioYypzMaZXtYvOqczFgF7V9or25YEbM5LJtqzjumMqc2HJJJeK29gkmSNsrpqytjaW6n0PNsWzfWrKntMkb7FaUYtvztbURN8GmnHc2lSSNfXyx2Zkkw2lWVPP7AIOHTWvpX6HUsHa2kS6NfXbX2SKfy7lmnq2pzT5StI19fJHP+ioeSHtmnpGafKFXO8lpDT5VPo19Yxr9E/kWFNPOOd+LMuaekYy+VCeNfWMZPKBzO/6JZm8L9+aekIyeY9FJe934UkmbxVvtIY1xjn3T/X3C3I/i5xz//BeR15ztoawtp7VYff4CNaaBoMvfnmF/XTOTVJjLOxe31je02Bwsn67EbKN+pybKzj1Wuf4HVXbt5LG12H3zO2swSB6Gm9hdw6CNRjETuPrsHv/Tx8+jdeEPXwarwp78DReF/bQabwy7IHT+MKlBPlQ1DTeDrGVvztoGp/3ELuJkGl8Hz5YG/DWWfZD7EbC3To75D/EbiTYrTP/WtgjoW6dSRP37yLdOutR2CPdOutV2MO8em877VfYT7XJ3+pR5DbqW9hPr96b/uGdwj2silgX2TGd1Ke1GW1nw3nf3tx7qAM/+f1HR76HSts/HSP/h082/TO2PH44Uo8jnvW8fytPCCWB19j2L8WNwXbSvGHVH3dcRQZRimQ9U/JZRQ2+TyGyDHbi2hdVkWyuHkREh+GcKg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBmfxfqEYS04+t6CvZlePUgAqq+VL9UDyIe+9QYnwByNzmGfa8eRDzjY9jnfDvV3TGZGa7UgwhodIz7Vj2IeBbVqso0427Nqiqx5Hu1CmU1zfBhbHfVl+Bn6kEEtDrGfaceRDxltVmlCOyummb4Kra/atM0UA8ingObJokNtRmFMcm7xJ4agcKCgyaJFeeqClaaoX/D3eAY9g/1IOKxEgGPu7sD59kSlAgk2DNpUCKQYM+kwZ5JgiRSgz2TBkmkBHsmDZJICfZMGiSREuyZNEgiNdgzSZBEakxpAVYoSCIlVjQrKVglknuT7tYkkRJUIiXGdLxLrKhEKlCa0aA0ozGiNKOwpTQjwfmehK2q3M52t+N8T4EmMY0VLyNQsMI7r1Zyt2HPpHCgRKBQjkhmFAYcqyosJpx3KHxSmVEY8y4CiSmviVQgh5Swwgz1X3dVHXJODunNyu7kkO6sMEMO6c1ySDoi3VGYkRhwqKqwIIeUoDAjseVwT4HTDo0di6rCmJ2qxJQWAoUB5V8FUneNDam7woF6mIIdMpG6u1txyKRA6i5hBQI6N9xRdZewOwa8VMkdR9kSa1J3BSsQTP/meXdWlSErIx55T4Ph2YRH3o/tmPbLIRsnV7ZjmpeL1YwH3tOv82FHOeeB97O97piqeX5CZcyFpZCnuow98J/a8USx+VqXYfvkZf29PaxaWkcsrdlZOWz5458pj+VWTn+eZNMv5mF3M5+XH1WlRjWeIGyj+qNfhn7g7KyB4KbovqdnLLPPu3P5okriJ0zx2awf1MGsfYnA52Ip490GAgv8lCw+C6sPPGhTWhH4XCxzf/iCGQv8xnVAQXw+P+SwQ5BfjuMJYncnc/+qnBH4DGzlnD2bwOvA86KrpCyVeXHBoJgT+MTqVOZVgl6wf0rreSpzZdUbivHJvEhlrg5kkwm9SmV+/qucgiTxOpX5Ysnamki9pjadtO0UhLU1gU2TVObKkhrW1rcN2p4msbamYBumdt9sZm1N4KZ9oAHW1rfdtg80YGsrgX/DvfaBBqjUvMf63Lvc2bO1lcB3delzb43Av2H7RmJC4Dsrv/S5t0fgu7rfpNQYge/mUZNSYwS+i+L9dykR+Pbqq5Jv3hgj8K1tkkSMwLeUqrZF4FuxcCV5UV4deC78NVLcvV7QDT3ajdVraqpQEfim0qypFwS+meTnRXXgOXJ9Lt2aesGthNfsqCP1e/II/CtFow7U1gj8c9aklGOfY3dceWHKA00bfzv8Za6DPFaHPc9nIwj8Y7/yhZ3AP2Zhz/di8ZLujrvWbfqtu6Ct5h7bL+X9Ng2Bv9Xs6tibCPyNb2/Jy2bLOch3P96Slw0HUN8s3L7EROC/2iToHmiIwF95zTKGwJ9lKLm//M8R+FPm7vhWawJfEUSBwItiQOBFEYgeeNnvjx144a+PHHjpb48bePEvjxr4f9S/O2TgFxv9rw4X+O35u4bi3xwt8KM66nP5L64D/696GF7sjRnDZQ++NFYH/jNIC992dnzY+/FNjoOduU578AgEUx92T/hAiLe6kyzQ6toXpbVp08Pnzw4ah5sgq2uPbG2SH3H7zFthqe2EG8beyvoz6f+oxxHPaXVlkvdW7125fuZuXG+hWF29LWwLNWEL5a3cxypQ9seOSV7jwCSvUW+hyOTdnbZQZPLuBkMOQyTqOhnlGndFfRjyWz2OcE6HIVFOvHukPgyhJu/uVK6hauCtZJIXoSYvQk1epODEW+NUk2cL5e1UriGtcUc/mciBfjKNLd3aGqd+MtIab3Rri5wKlATe3YC0RuNA4DXqyjD5pLu6WkOZzF197joln/RW55Mk8u7qMhn3Xf2RyIusmGo0DmQ1Ggc2UBorpngJSyeZ4v3ZzpUp3h9TvAhTvAZTvIhN8SOmeHc2xW/Uowgo+TfY0cyStVWi/GBtlWD7JML2SYTtk0a9fVKPIiCb4lla/VXvaOrHy71jqS5279WDCKhggteoMhr1GCIi7hrEXYO4axB3DeKu8TEcztRjiGg7++C1EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoLf+A6jRZVspl5i5AAAAAElFTkSuQmCC";
-
- $arrContextOptions=array(
- "ssl"=>array(
- "verify_peer"=>false,
- "verify_peer_name"=>false,
- ),
- );
- //临时保存用户签名图片
- if (!file_exists(FCPATH.'/temp')){
- $oldumask = umask(0);
- mkdir(FCPATH.'/temp', 0777, true);
- umask($oldumask);
- }
- $file_name = time().rand(1,9999999);
- !$s_path && $s_path = FCPATH.'temp/'.md5('sign'.$file_name).'.jpg';
- $imgPath = FCPATH.'temp/'.md5($file_name).'.png';
- $res = file_put_contents($imgPath,base64_decode($user_file));
- if(!$res){
- return false;
- }
- $yh_image = Image::open($imgPath)->cropResize(150,150)->rotate(-90);
-
-
- //原始签名文件
- $data = file_get_contents($origin_url,false,stream_context_create($arrContextOptions));
- $imgobj = Image::fromData($data);
- if($need_c){
- !$o_height && $o_height = $height;
- //公司
- $gs_data = file_get_contents($this->comp_img,false,stream_context_create($arrContextOptions));
- $gs_image = Image::fromData($gs_data)->cropResize(200,200);
- $imgobj->merge($gs_image,$o_width,$o_height);
- }
- $imgobj->merge($yh_image,$width,$height)->save($s_path);
- @unlink($imgPath);
- if(file_exists($s_path)){
- return str_replace(FCPATH,'',$s_path);
- }else{
- return false;
- }
- }
}
diff --git a/common/models/receiver/Receiver_service_package_model.php b/common/models/receiver/Receiver_service_package_model.php
new file mode 100644
index 00000000..c12dd103
--- /dev/null
+++ b/common/models/receiver/Receiver_service_package_model.php
@@ -0,0 +1,13 @@
+table_name, 'default');
+ }
+}
diff --git a/common/models/receiver/Receiver_services_model.php b/common/models/receiver/Receiver_services_model.php
new file mode 100644
index 00000000..d1bfbe44
--- /dev/null
+++ b/common/models/receiver/Receiver_services_model.php
@@ -0,0 +1,13 @@
+table_name, 'default');
+ }
+}
diff --git a/common/models/receiver/order/Receiver_order_ckcars_model.php b/common/models/receiver/order/Receiver_order_ckcars_model.php
index b46b5714..07a7706a 100644
--- a/common/models/receiver/order/Receiver_order_ckcars_model.php
+++ b/common/models/receiver/order/Receiver_order_ckcars_model.php
@@ -11,7 +11,7 @@ defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_order_ckcars_model extends HD_Model
{
private $table_name = 'lc_receiver_order_ckcars';
- private $status_arr = [ 0 => '车辆确认中',1 => '用户未签名',2=>'已确认'];
+ private $status_arr = [ 0 => '车辆确认中',1 => '用户未签名',2 => '尾款未支付' ,3 => '已确定'];
public function __construct()
{
diff --git a/common/services/apporder/Payment_service.php b/common/services/apporder/Payment_service.php
index dddb4b78..b65b496a 100644
--- a/common/services/apporder/Payment_service.php
+++ b/common/services/apporder/Payment_service.php
@@ -19,6 +19,8 @@ class Payment_service extends HD_Service{
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$this->load->model('receiver/order/receiver_order_signs_model','order_signs_model');
+ $this->load->model('receiver/order/receiver_order_bills_model','bills_model');
+ $this->load->model('receiver/order/receiver_order_ckcars_model','ckcars_model');
}
@@ -30,12 +32,12 @@ class Payment_service extends HD_Service{
public function after_pay($sid,$pay_price = ''){
if($sid){
debug_log("[start] ". __FUNCTION__ . ": sid:".$sid, $this->log_file);
- $order = $this->purchase_model->get(array('sid'=>$sid,'app_id'=>$this->app_id,'status'=>1));
+ $order = $this->purchase_model->get(array('sid'=>$sid,'app_id'=>$this->app_id));
if(!$order){
debug_log("[error] ". __FUNCTION__ . ":{$sid}_订单不存在", $this->log_file);
return array('code'=>0,'msg'=>'订单不存在');
}
- if(!$order['status']>1){
+ if($order['status']>1){
debug_log("[error] ". __FUNCTION__ . ":{$sid}_订单已支付", $this->log_file);
return array('code'=>0,'msg'=>'订单已支付');
}
@@ -92,6 +94,29 @@ class Payment_service extends HD_Service{
return array('code'=>0,'msg'=>'更新失败');
}
break;
+ case 5: //委托服务费
+ case 6: //首付或尾款
+ $upd = array('status'=>2,'status_detail'=>21,'pay_time'=>date('Y-m-d H:i:s'));
+ $pay_price && $upd['pay_price'] = $pay_price;
+ $res = $this->purchase_model->update($upd,array('id'=>$order['id']));
+ if($res){
+ $nopay = $this->purchase_model->count(['app_id'=>$this->app_id,'cf_id'=>$order['item_id'],'type in (5,6)'=>null,'status'=>1]); //未支付的尾款或者服务费
+ if(!$nopay){
+ //更新订单状态
+ $row = $this->orders_model->get(['id'=>$order['item_id']]);
+ if($row){
+ $this->ckcars_model->update(['status'=>3],['o_id'=>$row['id']]);
+ $this->orders_model->update(['status'=>3],['id'=>$row['id']]);
+ if(!$this->bills_model->count(['o_id'=>$row['id']])){
+ $this->bills_model->add(['o_id'=>$row['id'],'c_time'=>time()]);
+ }
+ }
+ }
+ return array('code'=>1,'msg'=>'操作成功');
+ }else{
+ return array('code'=>0,'msg'=>'更新失败');
+ }
+ break;
default:
debug_log("[error] ". __FUNCTION__ . ":{$item['type']}_未知商品类型", $this->log_file);
return array('code'=>0,'msg'=>'未知商品类型');
diff --git a/common/vendor/bin/CertificateDownloader.php b/common/vendor/bin/CertificateDownloader.php
new file mode 120000
index 00000000..8a1312ec
--- /dev/null
+++ b/common/vendor/bin/CertificateDownloader.php
@@ -0,0 +1 @@
+../wechatpay/wechatpay-guzzle-middleware/tool/CertificateDownloader.php
\ No newline at end of file
diff --git a/common/vendor/composer/autoload_psr4.php b/common/vendor/composer/autoload_psr4.php
index 3458ee1d..b216aa6b 100644
--- a/common/vendor/composer/autoload_psr4.php
+++ b/common/vendor/composer/autoload_psr4.php
@@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
+ 'WechatPay\\GuzzleMiddleware\\' => array($vendorDir . '/wechatpay/wechatpay-guzzle-middleware/src'),
'TencentCloud\\' => array($vendorDir . '/tencentcloud/common/src/TencentCloud', $vendorDir . '/tencentcloud/ocr/src/TencentCloud'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
diff --git a/common/vendor/composer/autoload_static.php b/common/vendor/composer/autoload_static.php
index 05f2ef3a..f6396a8e 100644
--- a/common/vendor/composer/autoload_static.php
+++ b/common/vendor/composer/autoload_static.php
@@ -19,6 +19,10 @@ class ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e
);
public static $prefixLengthsPsr4 = array (
+ 'W' =>
+ array (
+ 'WechatPay\\GuzzleMiddleware\\' => 27,
+ ),
'T' =>
array (
'TencentCloud\\' => 13,
@@ -43,6 +47,10 @@ class ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e
);
public static $prefixDirsPsr4 = array (
+ 'WechatPay\\GuzzleMiddleware\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/wechatpay/wechatpay-guzzle-middleware/src',
+ ),
'TencentCloud\\' =>
array (
0 => __DIR__ . '/..' . '/tencentcloud/common/src/TencentCloud',
diff --git a/common/vendor/composer/installed.json b/common/vendor/composer/installed.json
index f7e69ad3..f589d125 100644
--- a/common/vendor/composer/installed.json
+++ b/common/vendor/composer/installed.json
@@ -929,5 +929,58 @@
],
"description": "TencentCloudApi php sdk ocr",
"homepage": "https://github.com/tencentcloud-sdk-php/ocr"
+ },
+ {
+ "name": "wechatpay/wechatpay-guzzle-middleware",
+ "version": "0.2.2",
+ "version_normalized": "0.2.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wechatpay-apiv3/wechatpay-guzzle-middleware.git",
+ "reference": "6782ac33ed8cf97628609a71cdc5e84a6a40677a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wechatpay-apiv3/wechatpay-guzzle-middleware/zipball/6782ac33ed8cf97628609a71cdc5e84a6a40677a",
+ "reference": "6782ac33ed8cf97628609a71cdc5e84a6a40677a",
+ "shasum": "",
+ "mirrors": [
+ {
+ "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+ "preferred": true
+ }
+ ]
+ },
+ "require": {
+ "ext-openssl": "*",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "^6.3"
+ },
+ "suggest": {
+ "ext-bcmath": "Require bcmath in php 5.* version.",
+ "guzzlehttp/guzzle": "For using wechatpay guzzle middleware."
+ },
+ "time": "2021-03-05T03:09:29+00:00",
+ "bin": [
+ "tool/CertificateDownloader.php"
+ ],
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "WechatPay\\GuzzleMiddleware\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "description": "WechatPay API V3 Guzzle Middleware",
+ "homepage": "https://wechatpay-api.gitbook.io/wechatpay-api-v3/",
+ "keywords": [
+ "wechatpay"
+ ]
}
]
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/.gitignore b/common/vendor/wechatpay/wechatpay-guzzle-middleware/.gitignore
new file mode 100644
index 00000000..f86afcbc
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/.gitignore
@@ -0,0 +1,9 @@
+# ref: https://github.com/github/gitignore/blob/master/Composer.gitignore
+
+composer.phar
+/vendor/
+test/
+
+# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
+# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
+composer.lock
\ No newline at end of file
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/LICENSE b/common/vendor/wechatpay/wechatpay-guzzle-middleware/LICENSE
new file mode 100644
index 00000000..261eeb9e
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/README.md b/common/vendor/wechatpay/wechatpay-guzzle-middleware/README.md
new file mode 100644
index 00000000..ed2d28f3
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/README.md
@@ -0,0 +1,262 @@
+# wechatpay-guzzle-middleware
+
+## 概览
+
+[微信支付API v3](https://wechatpay-api.gitbook.io/wechatpay-api-v3/)的[Guzzle HttpClient](http://docs.guzzlephp.org/)中间件Middleware,实现了请求签名的生成和应答签名的验证。
+
+如果你是使用Guzzle的商户开发者,可以在构造`GuzzleHttp\Client`时将`WechatPayGuzzleMiddleware`传入,得到的`GuzzleHttp\Client`实例在执行请求时将自动携带身份认证信息,并检查应答的微信支付签名。
+
+
+
+## 项目状态
+
+当前版本为`0.2.0`测试版本。请商户的专业技术人员在使用时注意系统和软件的正确性和兼容性,以及带来的风险。
+
+
+
+## 环境要求
+
+我们开发和测试使用的环境如下:
+
++ PHP 5.5+ / PHP 7.0+
++ guzzlehttp/guzzle 6.0+
+
+
+
+## 安装
+
+可以使用PHP包管理工具composer引入SDK到项目中:
+
+#### Composer
+
+方式一:在项目目录中,通过composer命令行添加:
+```shell
+composer require wechatpay/wechatpay-guzzle-middleware
+```
+
+
+方式二:在项目的composer.json中加入以下配置:
+
+```json
+ "require": {
+ "wechatpay/wechatpay-guzzle-middleware": "^0.2.0"
+ }
+```
+添加配置后,执行安装
+```shell
+composer install
+```
+
+
+
+## 开始
+
+首先,通过`WechatPayMiddlewareBuilder`构建一个`WechatPayMiddleware`,然后将其加入`GuzzleHttp\Client`的`HandlerStack`中。我们提供相应的方法,可以方便的传入商户私钥和微信支付平台证书等信息。
+
+```php
+use GuzzleHttp\Exception\RequestException;
+use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
+use WechatPay\GuzzleMiddleware\Util\PemUtil;
+
+// 商户相关配置
+$merchantId = '1000100'; // 商户号
+$merchantSerialNumber = 'XXXXXXXXXX'; // 商户API证书序列号
+$merchantPrivateKey = PemUtil::loadPrivateKey('/path/to/mch/private/key.pem'); // 商户私钥
+// 微信支付平台配置
+$wechatpayCertificate = PemUtil::loadCertificate('/path/to/wechatpay/cert.pem'); // 微信支付平台证书
+
+// 构造一个WechatPayMiddleware
+$wechatpayMiddleware = WechatPayMiddleware::builder()
+ ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
+ ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
+ ->build();
+
+// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
+$stack = GuzzleHttp\HandlerStack::create();
+$stack->push($wechatpayMiddleware, 'wechatpay');
+
+// 创建Guzzle HTTP Client时,将HandlerStack传入
+$client = new GuzzleHttp\Client(['handler' => $stack]);
+
+
+// 接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
+try {
+ $resp = $client->request('GET', 'https://api.mch.weixin.qq.com/v3/...', [ // 注意替换为实际URL
+ 'headers' => [ 'Accept' => 'application/json' ]
+ ]);
+
+ echo $resp->getStatusCode().' '.$resp->getReasonPhrase()."\n";
+ echo $resp->getBody()."\n";
+
+ $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/...', [
+ 'json' => [ // JSON请求体
+ 'field1' => 'value1',
+ 'field2' => 'value2'
+ ],
+ 'headers' => [ 'Accept' => 'application/json' ]
+ ]);
+
+ echo $resp->getStatusCode().' '.$resp->getReasonPhrase()."\n";
+ echo $resp->getBody()."\n";
+} catch (RequestException $e) {
+ // 进行错误处理
+ echo $e->getMessage()."\n";
+ if ($e->hasResponse()) {
+ echo $e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase()."\n";
+ echo $e->getResponse()->getBody();
+ }
+ return;
+}
+```
+
+### 上传媒体文件
+
+```php
+// 参考上述指引说明,并引入 `MediaUtil` 正常初始化,无额外条件
+use WechatPay\GuzzleMiddleware\Util\MediaUtil;
+// 实例化一个媒体文件流,注意文件后缀名需符合接口要求
+$media = new MediaUtil('/your/file/path/with.extension');
+
+// 正常使用Guzzle发起API请求
+try {
+ $resp = $client->request('POST', 'https://api.mch.weixin.qq.com/v3/[merchant/media/video_upload|marketing/favor/media/image-upload]', [
+ 'body' => $media->getStream(),
+ 'headers' => [
+ 'Accept' => 'application/json',
+ 'content-type' => $media->getContentType(),
+ ]
+ ]);
+ // POST 语法糖
+ $resp = $client->post('merchant/media/upload', [
+ 'body' => $media->getStream(),
+ 'headers' => [
+ 'Accept' => 'application/json',
+ 'content-type' => $media->getContentType(),
+ ]
+ ]);
+ echo $resp->getStatusCode().' '.$resp->getReasonPhrase()."\n";
+ echo $resp->getBody()."\n";
+} catch (Exception $e) {
+ echo $e->getMessage()."\n";
+ if ($e->hasResponse()) {
+ echo $e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase()."\n";
+ echo $e->getResponse()->getBody();
+ }
+ return;
+}
+```
+
+### 敏感信息加/解密
+
+```php
+// 参考上上述说明,引入 `SensitiveInfoCrypto`
+use WechatPay\GuzzleMiddleware\Util\SensitiveInfoCrypto;
+// 上行加密API 多于 下行解密,默认为加密,实例后直接当方法用即可
+$encryptor = new SensitiveInfoCrypto(PemUtil::loadCertificate('/path/to/wechatpay/cert.pem'));
+
+// 正常使用Guzzle发起API请求
+try {
+ // POST 语法糖
+ $resp = $client->post('/v3/applyment4sub/applyment/', [
+ 'json' => [
+ 'business_code' => 'APL_98761234',
+ 'contact_info' => [
+ 'contact_name' => $encryptor('value of `contact_name`'),
+ 'contact_id_number' => $encryptor('value of `contact_id_number'),
+ 'mobile_phone' => $encryptor('value of `mobile_phone`'),
+ 'contact_email' => $encryptor('value of `contact_email`'),
+ ],
+ //...
+ ],
+ 'headers' => [
+ // 命令行获取证书序列号
+ // openssl x509 -in /path/to/wechatpay/cert.pem -noout -serial | awk -F= '{print $2}'
+ // 或者使用工具类获取证书序列号 `PemUtil::parseCertificateSerialNo($certificate)`
+ 'Wechatpay-Serial' => 'must be the serial number via the downloaded pem file of `/v3/certificates`',
+ 'Accept' => 'application/json',
+ ],
+ ]);
+ echo $resp->getStatusCode().' '.$resp->getReasonPhrase()."\n";
+ echo $resp->getBody()."\n";
+} catch (Exception $e) {
+ echo $e->getMessage()."\n";
+ if ($e->hasResponse()) {
+ echo $e->getResponse()->getStatusCode().' '.$e->getResponse()->getReasonPhrase()."\n";
+ echo $e->getResponse()->getBody();
+ }
+ return;
+}
+
+// 单例加解密示例如下
+$crypto = new SensitiveInfoCrypto($wechatpayCertificate, $merchantPrivateKey);
+$encrypted = $crypto('Alice');
+$decrypted = $crypto->setStage('decrypt')($encrypted);
+```
+
+## 定制
+
+当默认的本地签名和验签方式不适合你的系统时,你可以通过实现`Signer`或者`Verifier`来定制签名和验签。比如,你的系统把商户私钥集中存储,业务系统需通过远程调用进行签名,你可以这样做。
+
+```php
+use WechatPay\GuzzleMiddleware\Auth\Signer;
+use WechatPay\GuzzleMiddleware\Auth\SignatureResult;
+use WechatPay\GuzzleMiddleware\Auth\WechatPay2Credentials;
+
+class CustomSigner implements Signer
+{
+ public function sign($message)
+ {
+ // 调用签名RPC服务,然后返回包含签名和证书序列号的SignatureResult
+ return new SignatureResult('xxxx', 'yyyyy');
+ }
+}
+
+$credentials = new WechatPay2Credentials($merchantId, new CustomSigner);
+
+$wechatpayMiddleware = WechatPayMiddleware::builder()
+ ->withCredentials($credentials)
+ ->withWechatPay([ $wechatpayCertificate ])
+ ->build();
+```
+
+
+
+## 常见问题
+
+### 如何下载平台证书?
+
+使用`WechatPayMiddlewareBuilder`需要调用`withWechatpay`设置[微信支付平台证书](https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/zheng-shu#ping-tai-zheng-shu),而平台证书又只能通过调用[获取平台证书接口](https://wechatpay-api.gitbook.io/wechatpay-api-v3/jie-kou-wen-dang/ping-tai-zheng-shu#huo-qu-ping-tai-zheng-shu-lie-biao)下载。为了解开"死循环",你可以在第一次下载平台证书时,按照下述方法临时"跳过”应答签名的验证。
+
+```php
+use WechatPay\GuzzleMiddleware\Validator;
+
+class NoopValidator implements Validator
+{
+ public function validate(\Psr\Http\Message\ResponseInterface $response)
+ {
+ return true;
+ }
+}
+
+$wechatpayMiddleware = WechatPayMiddleware::builder()
+ ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)
+ ->withValidator(new NoopValidator) // NOTE: 设置一个空的应答签名验证器,**不要**用在业务请求
+ ->build();
+```
+
+**注意**:业务请求请使用标准的初始化流程,务必验证应答签名。
+
+### 证书和回调解密需要的AesGcm解密在哪里?
+
+请参考[AesUtil.php](src/Util/AesUtil.php)。
+
+### 配合swoole使用时,上传文件接口报错
+
+建议升级至swoole 4.6+,swoole在 4.6.0 中增加了native-curl([swoole/swoole-src#3863](https://github.com/swoole/swoole-src/pull/3863))支持,我们测试能正常使用了。
+更详细的信息,请参考[#36](https://github.com/wechatpay-apiv3/wechatpay-guzzle-middleware/issues/36)。
+
+## 联系我们
+
+如果你发现了**BUG**或者有任何疑问、建议,请通过issue进行反馈。
+
+也欢迎访问我们的[开发者社区](https://developers.weixin.qq.com/community/pay)。
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/composer.json b/common/vendor/wechatpay/wechatpay-guzzle-middleware/composer.json
new file mode 100644
index 00000000..d5164b4a
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "wechatpay/wechatpay-guzzle-middleware",
+ "version": "0.2.2",
+ "description": "WechatPay API V3 Guzzle Middleware",
+ "type": "library",
+ "keywords": [
+ "wechatpay"
+ ],
+ "homepage": "https://wechatpay-api.gitbook.io/wechatpay-api-v3/",
+ "license": "Apache-2.0",
+ "require": {
+ "php": ">=5.5",
+ "ext-openssl": "*"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "^6.3"
+ },
+ "autoload": {
+ "psr-4": { "WechatPay\\GuzzleMiddleware\\" : "src/" }
+ },
+ "bin": [
+ "tool/CertificateDownloader.php"
+ ],
+ "suggest": {
+ "ext-bcmath": "Require bcmath in php 5.* version.",
+ "guzzlehttp/guzzle": "For using wechatpay guzzle middleware."
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/CertificateVerifier.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/CertificateVerifier.php
new file mode 100644
index 00000000..6947c43f
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/CertificateVerifier.php
@@ -0,0 +1,70 @@
+ publicKey)
+ */
+ protected $publicKeys = [];
+
+ /**
+ * Constructor
+ *
+ * @param array of string|resource $certifcates WechatPay Certificates (string - PEM formatted \
+ * certificate, or resource - X.509 certificate resource returned by openssl_x509_read)
+ */
+ public function __construct(array $certificates)
+ {
+ foreach ($certificates as $certificate) {
+ $serialNo = PemUtil::parseCertificateSerialNo($certificate);
+ $this->publicKeys[$serialNo] = \openssl_get_publickey($certificate);
+ }
+ }
+
+ /**
+ * Verify signature of message
+ *
+ * @param string $serialNumber certificate serial number
+ * @param string $message message to verify
+ * @param string $signautre signature of message
+ *
+ * @return bool
+ */
+ public function verify($serialNumber, $message, $signature)
+ {
+ $serialNumber = \strtoupper(\ltrim($serialNumber, '0')); // trim leading 0 and uppercase
+ if (!isset($this->publicKeys[$serialNumber])) {
+ return false;
+ }
+ if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {
+ throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
+ }
+ $signature = \base64_decode($signature);
+ return \openssl_verify($message, $signature, $this->publicKeys[$serialNumber],
+ 'sha256WithRSAEncryption');
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/PrivateKeySigner.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/PrivateKeySigner.php
new file mode 100644
index 00000000..5c6edf50
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/PrivateKeySigner.php
@@ -0,0 +1,72 @@
+certificateSerialNumber = $serialNumber;
+ $this->privateKey = $privateKey;
+ }
+
+ /**
+ * Sign Message
+ *
+ * @param string $message Message to sign
+ *
+ * @return string
+ */
+ public function sign($message)
+ {
+ if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {
+ throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
+ }
+
+ if (!\openssl_sign($message, $sign, $this->privateKey, 'sha256WithRSAEncryption')) {
+ throw new \UnexpectedValueException("签名验证过程发生了错误");
+ }
+ return new SignatureResult(\base64_encode($sign), $this->certificateSerialNumber);
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/SignatureResult.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/SignatureResult.php
new file mode 100644
index 00000000..e963edd0
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/SignatureResult.php
@@ -0,0 +1,64 @@
+sign = $sign;
+ $this->certificateSerialNumber = $serialNumber;
+ }
+
+ /**
+ * Get Signature
+ *
+ * @return string
+ */
+ public function getSign()
+ {
+ return $this->sign;
+ }
+
+ /**
+ * Get Certificate Serial Number
+ *
+ * @return string
+ */
+ public function getCertificateSerialNumber()
+ {
+ return $this->certificateSerialNumber;
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/Signer.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/Signer.php
new file mode 100644
index 00000000..094a131b
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/Signer.php
@@ -0,0 +1,33 @@
+merchantId = $merchantId;
+ $this->signer = $signer;
+ }
+
+ /**
+ * Get schema of credentials
+ *
+ * @return string
+ */
+ public function getSchema()
+ {
+ return 'WECHATPAY2-SHA256-RSA2048';
+ }
+
+ /**
+ * Get token of credentials
+ *
+ * @param RequestInterface $request Api request
+ *
+ * @return string
+ */
+ public function getToken(RequestInterface $request)
+ {
+ $nonce = $this->getNonce();
+ $timestamp = $this->getTimestamp();
+
+ $message = $this->buildMessage($nonce, $timestamp, $request);
+
+ $signResult = $this->signer->sign($message);
+ $sign = $signResult->getSign();
+ $serialNo = $signResult->getCertificateSerialNumber();
+
+ $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
+ $this->merchantId, $nonce, $timestamp, $serialNo, $sign
+ );
+ return $token;
+ }
+
+ /**
+ * Get Merchant Id
+ *
+ * @return string
+ */
+ public function getMerchantId()
+ {
+ return $this->merchantId;
+ }
+
+ /**
+ * Get sign timestamp
+ *
+ * @return integer
+ */
+ protected function getTimestamp()
+ {
+ return \time();
+ }
+
+ /**
+ * Get nonce
+ *
+ * @return string
+ */
+ protected function getNonce()
+ {
+ static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $charactersLength = strlen($characters);
+ $randomString = '';
+ for ($i = 0; $i < 32; $i++) {
+ $randomString .= $characters[rand(0, $charactersLength - 1)];
+ }
+ return $randomString;
+ }
+
+ /**
+ * Build message to sign
+ *
+ * @param string $nonce Nonce string
+ * @param integer $timestamp Unix timestamp
+ * @param RequestInterface $request Api request
+ *
+ * @return string
+ */
+ protected function buildMessage($nonce, $timestamp, RequestInterface $request)
+ {
+ $body = '';
+ $bodyStream = $request->getBody();
+ // non-seekable stream need to be handled by the caller
+ if ($bodyStream->isSeekable()) {
+ $body = (string)$bodyStream;
+ $bodyStream->rewind();
+ }
+
+ return $request->getMethod()."\n".
+ $request->getRequestTarget()."\n".
+ $timestamp."\n".
+ $nonce."\n".
+ $body."\n";
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/WechatPay2Validator.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/WechatPay2Validator.php
new file mode 100644
index 00000000..bdedae62
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Auth/WechatPay2Validator.php
@@ -0,0 +1,120 @@
+verifier = $verifier;
+ }
+
+ /**
+ * Validate Response
+ *
+ * @param ResponseInterface $response Api response to validate
+ *
+ * @return bool
+ */
+ public function validate(ResponseInterface $response)
+ {
+ $serialNo = $this->getHeader($response, 'Wechatpay-Serial');
+ $sign = $this->getHeader($response, 'Wechatpay-Signature');
+ $timestamp = $this->getHeader($response, 'Wechatpay-TimeStamp');
+ $nonce = $this->getHeader($response, 'Wechatpay-Nonce');
+
+ if (!isset($serialNo, $sign, $timestamp, $nonce)) {
+ return false;
+ }
+
+ if (!$this->checkTimestamp($timestamp)) {
+ // log here
+ return false;
+ }
+
+ $body = $this->getBody($response);
+ $message = "$timestamp\n$nonce\n$body\n";
+
+ return $this->verifier->verify($serialNo, $message, $sign);
+ }
+
+ /**
+ * Build message to sign
+ *
+ * @param string $nonce Nonce string
+ * @param integer $timestamp Unix timestamp
+ * @param RequestInterface $request Api request
+ *
+ * @return string
+ */
+ protected function getHeader(ResponseInterface $response, $name)
+ {
+ $values = $response->getHeader($name);
+ return empty($values) ? null : $values[count($values) - 1];
+ }
+
+ /**
+ * Check whether timestamp is valid
+ *
+ * @param integer $timestamp Unix timestamp
+ *
+ * @return bool
+ */
+ protected function checkTimestamp($timestamp)
+ {
+ // reject responses beyond 5 minutes
+ return \abs((int)$timestamp - \time()) <= 300;
+ }
+
+ /**
+ * Build message to sign
+ *
+ * @param string $nonce Nonce string
+ * @param integer $timestamp Unix timestamp
+ * @param RequestInterface $request Api request
+ *
+ * @return string
+ */
+ protected function getBody(ResponseInterface $response)
+ {
+ $body = '';
+ $bodyStream = $response->getBody();
+ // non-seekable stream need to be handled by the caller
+ if ($bodyStream->isSeekable()) {
+ $body = (string)$bodyStream;
+ $bodyStream->rewind();
+ }
+ return $body;
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Credentials.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Credentials.php
new file mode 100644
index 00000000..93c6129f
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Credentials.php
@@ -0,0 +1,39 @@
+aesKey = $aesKey;
+ }
+
+ /**
+ * Decrypt AEAD_AES_256_GCM ciphertext
+ *
+ * @param string $associatedData AES GCM additional authentication data
+ * @param string $nonceStr AES GCM nonce
+ * @param string $ciphertext AES GCM cipher text
+ *
+ * @return string|bool Decrypted string on success or FALSE on failure
+ */
+ public function decryptToString($associatedData, $nonceStr, $ciphertext)
+ {
+ $ciphertext = \base64_decode($ciphertext);
+ if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
+ return false;
+ }
+
+ // ext-sodium (default installed on >= PHP 7.2)
+ if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
+ \sodium_crypto_aead_aes256gcm_is_available()) {
+ return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
+ }
+
+ // ext-libsodium (need install libsodium-php 1.x via pecl)
+ if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
+ \Sodium\crypto_aead_aes256gcm_is_available()) {
+ return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
+ }
+
+ // openssl (PHP >= 7.1 support AEAD)
+ if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
+ $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
+ $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
+
+ return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
+ $authTag, $associatedData);
+ }
+
+ throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/MediaUtil.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/MediaUtil.php
new file mode 100644
index 00000000..c9c96b11
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/MediaUtil.php
@@ -0,0 +1,146 @@
+filepath = $filepath;
+ $this->fileStream = $fileStream;
+ $this->composeStream();
+ }
+
+ /**
+ * Compose the GuzzleHttp\Psr7\FnStream
+ */
+ private function composeStream()
+ {
+ $basename = \basename($this->filepath);
+ $stream = isset($this->fileStream) ? $this->fileStream : new LazyOpenStream($this->filepath, 'r');
+ if (!$stream->isSeekable()) {
+ $stream = new CachingStream($stream);
+ }
+
+ $json = \GuzzleHttp\json_encode([
+ 'filename' => $basename,
+ 'sha256' => \GuzzleHttp\Psr7\hash($stream, 'sha256'),
+ ]);
+ $this->meta = $json;
+
+ $multipart = new MultipartStream([
+ [
+ 'name' => 'meta',
+ 'contents' => $json,
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ],
+ [
+ 'name' => 'file',
+ 'filename' => $basename,
+ 'contents' => $stream,
+ ],
+ ]);
+ $this->multipart = $multipart;
+
+ $this->stream = FnStream::decorate($multipart, [
+ // for signature
+ '__toString' => function () use ($json) {
+ return $json;
+ },
+ // let the `CURL` to use `CURLOPT_UPLOAD` context
+ 'getSize' => function () {
+ return null;
+ },
+ ]);
+ }
+
+ /**
+ * Get the `meta` of the multipart data string
+ */
+ public function getMeta()
+ {
+ return $this->meta;
+ }
+
+ /**
+ * Get the `GuzzleHttp\Psr7\FnStream` context
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Get the `Content-Type` of the `GuzzleHttp\Psr7\MultipartStream`
+ */
+ public function getContentType()
+ {
+ return 'multipart/form-data; boundary=' . $this->multipart->getBoundary();
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/PemUtil.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/PemUtil.php
new file mode 100644
index 00000000..208e8c9c
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Util/PemUtil.php
@@ -0,0 +1,108 @@
+
+ * // Encrypt usage:
+ * $encryptor = new SensitiveInfoCrypto(
+ * PemUtil::loadCertificate('/downloaded/pubcert.pem')
+ * );
+ * $json = json_encode(['name' => $encryptor('Alice')]);
+ * // That's simple!
+ *
+ * // Decrypt usage:
+ * $decryptor = new SensitiveInfoCrypto(
+ * null,
+ * PemUtil::loadPrivateKey('/merchant/key.pem')
+ * );
+ * $decrypted = $decryptor->setStage('decrypt')(
+ * 'base64 encoding message was given by the payment plat'
+ * );
+ * // That's simple too!
+ *
+ * // Working both Encrypt and Decrypt usages:
+ * $crypto = new SensitiveInfoCrypto(
+ * PemUtil::loadCertificate('/merchant/cert.pem'),
+ * PemUtil::loadPrivateKey('/merchant/key.pem')
+ * );
+ * $encrypted = $crypto('Carol');
+ * $decrypted = $crypto->setStage('decrypt')($encrypted);
+ * // Having fun with this!
+ *
+ *
+ * @package WechatPay
+ */
+class SensitiveInfoCrypto implements \JsonSerializable {
+
+ /**
+ * @var resource|null $publicCert The public certificate
+ */
+ private $publicCert;
+
+ /**
+ * @var resource|null $privateKey The private key
+ */
+ private $privateKey;
+
+ /**
+ * @var string $message The encryped or decrypted content
+ */
+ private $message = '';
+
+ /**
+ * @var string $stage The crypto working scenario, default is `encrypt`.
+ * Mention here: while toggle the scenario,
+ * the next stage is the previous one.
+ */
+ private $stage = 'encrypt';
+
+ /**
+ * @var array $scenarios Methods that allowed.
+ */
+ private static $scenarios = ['encrypt', 'decrypt'];
+
+ /**
+ * Constructor
+ *
+ * @param resource|null $publicCert The public certificate resource
+ * @param resource|null $privateKey The private key resource
+ */
+ public function __construct($publicCert, $privateKey = null) {
+ $this->publicCert = $publicCert;
+ $this->privateKey = $privateKey;
+ }
+
+ /**
+ * Encrypt the string by the public certificate
+ *
+ * @param string $str The content shall be encrypted
+ *
+ * @return SensitiveInfoCrypto
+ */
+ private function encrypt($str) {
+ if (!is_resource($this->publicCert)) {
+ throw new \InvalidArgumentException('The publicCert must be resource.');
+ }
+ openssl_public_encrypt($str, $encrypted,
+ $this->publicCert, \OPENSSL_PKCS1_OAEP_PADDING);
+ $this->message = \base64_encode($encrypted);
+
+ return $this;
+ }
+
+ /**
+ * Decrypt the string by the private key certificate
+ *
+ * @param string $str The content shall be decrypted
+ *
+ * @return SensitiveInfoCrypto
+ */
+ private function decrypt($str) {
+ if (!is_resource($this->privateKey)) {
+ throw new \InvalidArgumentException('The privateKey must be resource.');
+ }
+ openssl_private_decrypt(\base64_decode($str), $decrypted,
+ $this->privateKey, \OPENSSL_PKCS1_OAEP_PADDING);
+ $this->message = $decrypted;
+
+ return $this;
+ }
+
+ /**
+ * Specify data which should be
+ *
+ * @return string
+ */
+ public function jsonSerialize() {
+ return $this->message;
+ }
+
+ /**
+ * Toggle the crypto instance onto `encrypt` or `decrypt` stage
+ *
+ * @param string $scenario Should be `encrypt` or `decrypt`
+ *
+ * @throws \InvalidArgumentException if the scenario is invalid.
+ *
+ * @return SensitiveInfoCrypto
+ */
+ public function setStage($scenario) {
+ if (!in_array($scenario, self::$scenarios)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Cannot setStage `%s`, here is only allowed one of the %s.',
+ $scenario,
+ \implode(', ', self::$scenarios)
+ ));
+ }
+ $this->stage = $scenario;
+
+ return $this;
+ }
+
+ public function __invoke($str) {
+ $copy = clone $this;
+ return $copy->{$this->stage}($str);
+ }
+
+ public function __toString() {
+ return $this->jsonSerialize();
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Validator.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Validator.php
new file mode 100644
index 00000000..35bfc138
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/Validator.php
@@ -0,0 +1,32 @@
+credentials = $credentials;
+ $this->validator = $validator;
+ }
+
+ /**
+ * Use as Guzzle middleware
+ *
+ * @param callable $handler
+ *
+ * @return callable
+ */
+ public function __invoke(callable $handler)
+ {
+ return function (RequestInterface $request, array $options) use ($handler) {
+ if (!self::isWechatPayApiUrl($request->getUri())) {
+ return $handler($request, $options);
+ }
+ if (!$request->getBody()->isSeekable() && \class_exists("\\GuzzleHttp\\Psr7\\CachingStream")) {
+ $request = $request->withBody(new \GuzzleHttp\Psr7\CachingStream($request->getBody()));
+ }
+ $schema = $this->credentials->getSchema();
+ $token = $this->credentials->getToken($request);
+ $request = $request->withHeader("Authorization", $schema.' '.$token);
+ if (self::isUserAgentOverwritable($request)) {
+ $request = $request->withHeader('User-Agent', self::getUserAgent());
+ }
+
+ return $handler($request, $options)->then(
+ function (ResponseInterface $response) use ($request) {
+ $code = $response->getStatusCode();
+ if ($code >= 200 && $code < 300) {
+ if (!$response->getBody()->isSeekable() && \class_exists("\\GuzzleHttp\\Psr7\\CachingStream")) {
+ $response = $response->withBody(new \GuzzleHttp\Psr7\CachingStream($response->getBody()));
+ }
+ if (!$this->validator->validate($response)) {
+ if (\class_exists('\\GuzzleHttp\\Exception\\ServerException')) {
+ throw new \GuzzleHttp\Exception\ServerException(
+ "应答的微信支付签名验证失败", $request, $response);
+ } else {
+ throw new \RuntimeException("应答的微信支付签名验证失败", $code);
+ }
+ }
+ }
+ return $response;
+ }
+ );
+ };
+ }
+
+ /**
+ * Create a new builder
+ *
+ * @return WechatPayMiddlewareBuilder
+ */
+ public static function builder()
+ {
+ return new WechatPayMiddlewareBuilder();
+ }
+
+ /**
+ * Check whether url is WechatPay API V3 url
+ */
+ protected static function isWechatPayApiUrl(UriInterface $url)
+ {
+ if ($url->getScheme() !== 'https' || !\in_array($url->getHost(), self::$API_DOMAINS)) {
+ return false;
+ }
+ foreach (self::$BASE_URLS as $baseUrl) {
+ if (\substr($url->getPath(), 0, strlen($baseUrl)) === $baseUrl) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get User Agent
+ * @return string
+ */
+ protected static function getUserAgent()
+ {
+ static $userAgent = '';
+ if (!$userAgent) {
+ $agent = 'WechatPay-Guzzle/'.self::VERSION;
+ if (\class_exists('\\GuzzleHttp\\Client')) {
+ $version = defined('\\GuzzleHttp\\Client::VERSION') ? \GuzzleHttp\Client::VERSION
+ : \GuzzleHttp\Client::MAJOR_VERSION;
+ $agent .= ' GuzzleHttp/'.$version;
+ }
+ if (extension_loaded('curl') && function_exists('curl_version')) {
+ $agent .= ' curl/'.\curl_version()['version'];
+ }
+ $agent .= \sprintf(" (%s/%s) PHP/%s", PHP_OS, \php_uname('r'), PHP_VERSION);
+ $userAgent = $agent;
+ }
+ return $userAgent;
+ }
+
+ private static function isUserAgentOverwritable(RequestInterface $request)
+ {
+ if (!$request->hasHeader('User-Agent')) {
+ return true;
+ }
+ $headers = $request->getHeader('User-Agent');
+ $userAgent = $headers[\count($headers) - 1];
+ if (\function_exists('\\GuzzleHttp\\default_user_agent')) {
+ return $userAgent === \GuzzleHttp\default_user_agent();
+ }
+ return false;
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/WechatPayMiddlewareBuilder.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/WechatPayMiddlewareBuilder.php
new file mode 100644
index 00000000..696d87c9
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/src/WechatPayMiddlewareBuilder.php
@@ -0,0 +1,125 @@
+credentials = new WechatPay2Credentials($merchantId,
+ new PrivateKeySigner($serialNo, $privateKey));
+ return $this;
+ }
+
+ /**
+ * Set Merchant Credentials
+ *
+ * @param Credentials $credentials Merchant Certificate Credentials
+ *
+ * @return $this
+ */
+ public function withCredentials(Credentials $credentials)
+ {
+ $this->credentials = $credentials;
+ return $this;
+ }
+
+ /**
+ * Set WechatPay Certificates Infomation
+ *
+ * @param array of string|resource $certifcates WechatPay Certificates (string - PEM formatted \
+ * certificate, or resource - X.509 certificate resource returned by openssl_x509_read)
+ *
+ * @return $this
+ */
+ public function withWechatPay(array $certificates)
+ {
+ $this->validator = new WechatPay2Validator(new CertificateVerifier($certificates));
+ return $this;
+ }
+
+ /**
+ * Set WechatPay Validator
+ *
+ * @param Validator $Validator WechatPay Validator
+ *
+ * @return $this
+ */
+ public function withValidator(Validator $validator)
+ {
+ $this->validator = $validator;
+ return $this;
+ }
+
+ /**
+ * Build WechatPayMiddleware
+ *
+ * @return WechatPayMiddleware
+ */
+ public function build()
+ {
+ if (!isset($this->credentials)) {
+ throw new \InvalidArgumentException('商户认证信息(credentials)未设置');
+ }
+ if (!isset($this->validator)) {
+ throw new \InvalidArgumentException('微信支付平台签名验证(validator)未设置');
+ }
+
+ return new WechatPayMiddleware($this->credentials, $this->validator);
+ }
+}
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/CertificateDownloader.php b/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/CertificateDownloader.php
new file mode 100755
index 00000000..cb4bed07
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/CertificateDownloader.php
@@ -0,0 +1,218 @@
+#!/usr/bin/env php
+parseOpts();
+ if (!$opts) {
+ $this->printHelp();
+ exit(1);
+ }
+
+ if (isset($opts['help'])) {
+ $this->printHelp();
+ exit(0);
+ }
+ if (isset($opts['version'])) {
+ echo self::VERSION . "\n";
+ exit(0);
+ }
+
+ $this->downloadCert($opts);
+ }
+
+ private function downloadCert($opts)
+ {
+ try {
+ // 构造一个WechatPayMiddleware
+ $builder = WechatPayMiddleware::builder()
+ ->withMerchant($opts['mchid'], $opts['serialno'], PemUtil::loadPrivateKey($opts['privatekey'])); // 传入商户相关配置
+ if (isset($opts['wechatpay-cert'])) {
+ $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 GuzzleHttp\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) {
+ echo "download failed, code={$resp->getStatusCode()}, body=[{$resp->getBody()}]\n";
+ return;
+ }
+
+ $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) {
+ echo "encrypted certificate decrypt fail!\n";
+ exit(1);
+ }
+ // 通过加载对证书进行简单合法性检验
+ $cert = \openssl_x509_read($plain); // 从字符串中加载证书
+ if (!$cert) {
+ echo "downloaded certificate check fail!\n";
+ exit(1);
+ }
+ $plainCerts[] = $plain;
+ $x509Certs[] = $cert;
+ }
+ // 使用下载的证书再来验证一次应答的签名
+ $validator = new WechatPay2Validator(new CertificateVerifier($x509Certs));
+ if (!$validator->validate($resp)) {
+ echo "validate response fail using downloaded certificates!";
+ exit(1);
+ }
+ // 输出证书信息,并保存到文件
+ foreach ($list['data'] as $index => $item) {
+ echo "Certificate {\n";
+ echo " Serial Number: ".$item['serial_no']."\n";
+ echo " Not Before: ".(new DateTime($item['effective_time']))->format('Y-m-d H:i:s')."\n";
+ echo " Not After: ".(new DateTime($item['expire_time']))->format('Y-m-d H:i:s')."\n";
+ echo " Text: \n ".str_replace("\n", "\n ", $plainCerts[$index])."\n";
+ echo "}\n";
+
+ $outpath = $opts['output'].DIRECTORY_SEPARATOR.'wechatpay_'.$item['serial_no'].'.pem';
+ file_put_contents($outpath, $plainCerts[$index]);
+ }
+ }
+ catch (RequestException $e) {
+ echo "download failed, message=[{$e->getMessage()}] ";
+ if ($e->hasResponse()) {
+ echo "code={$e->getResponse()->getStatusCode()}, body=[{$e->getResponse()->getBody()}]\n";
+ }
+ exit(1);
+ }
+ catch (Exception $e) {
+ echo "download failed, message=[{$e->getMessage()}]\n";
+ echo $e;
+ exit(1);
+ }
+ }
+
+ private function parseOpts()
+ {
+ $opts = [
+ [ 'key', 'k', true ],
+ [ 'mchid', 'm', true ],
+ [ 'privatekey', 'f', true ],
+ [ 'serialno', 's', true ],
+ [ 'output', 'o', true ],
+ [ 'wechatpay-cert', 'c', false ],
+ ];
+
+ $shortopts = 'hV';
+ $longopts = [ 'help', 'version' ];
+ foreach ($opts as $opt) {
+ $shortopts .= $opt[1].':';
+ $longopts[] = $opt[0].':';
+ }
+ $parsed = getopt($shortopts, $longopts);
+ if (!$parsed) {
+ return false;
+ }
+
+ $args = [];
+ foreach ($opts as $opt) {
+ if (isset($parsed[$opt[0]])) {
+ $args[$opt[0]] = $parsed[$opt[0]];
+ }
+ else if (isset($parsed[$opt[1]])) {
+ $args[$opt[0]] = $parsed[$opt[1]];
+ }
+ else if ($opt[2]) {
+ return false;
+ }
+ }
+
+ if (isset($parsed['h']) || isset($parsed['help'])) {
+ $args['help'] = true;
+ }
+ if (isset($parsed['V']) || isset($parsed['version'])) {
+ $args['version'] = true;
+ }
+ return $args;
+ }
+
+ private function printHelp()
+ {
+ echo << ]
+ -f= -k= -m=
+ -o= -s=
+ -m, --mchid= 商户号
+ -s, --serialno= 商户证书的序列号
+ -f, --privatekey=
+ 商户的私钥文件
+ -k, --key= ApiV3Key
+ -c, --wechatpay-cert=
+ 微信支付平台证书,验证签名
+ -o, --output=
+ 下载成功后保存证书的路径
+ -V, --version Print version information and exit.
+ -h, --help Show this help message and exit.
+
+EOD;
+ }
+}
+
+class NoopValidator implements Validator
+{
+ public function validate(\Psr\Http\Message\ResponseInterface $response)
+ {
+ return true;
+ }
+}
+
+
+// main
+(new CertificateDownloader())->run();
diff --git a/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/README.md b/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/README.md
new file mode 100644
index 00000000..d3e53bfb
--- /dev/null
+++ b/common/vendor/wechatpay/wechatpay-guzzle-middleware/tool/README.md
@@ -0,0 +1,45 @@
+# Certificate Downloader
+
+Certificate Downloader 是 PHP版 微信支付 APIv3 平台证书的命令行下载工具。该工具可从 `https://api.mch.weixin.qq.com/v3/certificates` 接口获取商户可用证书,并使用 [APIv3 密钥](https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/api-v3-mi-yao) 和 AES_256_GCM 算法进行解密,并把解密后证书下载到指定位置。
+
+## 使用
+使用方法与 [Java版Certificate Downloader](https://github.com/wechatpay-apiv3/CertificateDownloader) 一致,参数与常见问题请参考[其文档](https://github.com/wechatpay-apiv3/CertificateDownloader/blob/master/README.md)。
+
+```shell
+> php tool/CertificateDownloader.php
+Usage: 微信支付平台证书下载工具 [-hV] [-c=]
+ -f= -k= -m=
+ -o= -s=
+ -m, --mchid= 商户号
+ -s, --serialno= 商户证书的序列号
+ -f, --privatekey=
+ 商户的私钥文件
+ -k, --key= ApiV3Key
+ -c, --wechatpay-cert=
+ 微信支付平台证书,验证签名
+ -o, --output=
+ 下载成功后保存证书的路径
+ -V, --version Print version information and exit.
+ -h, --help Show this help message and exit.
+```
+
+完整命令示例:
+
+```shell
+php tool/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath} -c ${wechatpayCertificateFilePath}
+```
+
+
+
+## 常见问题
+
+### 如何保证证书正确
+请参见CertificateDownloader文档中[关于如何保证证书正确的说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E8%AF%81%E4%B9%A6%E6%AD%A3%E7%A1%AE)。
+
+### 如何使用信任链验证平台证书
+请参见CertificateDownloader文档中[关于如何使用信任链验证平台证书的说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E4%BF%A1%E4%BB%BB%E9%93%BE%E9%AA%8C%E8%AF%81%E5%B9%B3%E5%8F%B0%E8%AF%81%E4%B9%A6)。
+
+### 第一次下载证书
+
+请参见CertificateDownloader文档中[相关说明](https://github.com/wechatpay-apiv3/CertificateDownloader#%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%B8%8B%E8%BD%BD%E8%AF%81%E4%B9%A6)。
+
diff --git a/sql/order.sql b/sql/order.sql
index 1e5aabfd..c9ccf221 100644
--- a/sql/order.sql
+++ b/sql/order.sql
@@ -3,7 +3,7 @@
-- Author:lcc
-- Table:lc_order_purchase
-- ---------------------------
-drop table if exists hd_order_purchase;
+drop table if exists lc_order_purchase;
create table lc_order_purchase (
id int(10) unsigned not null auto_increment,
app_id int(10) unsigned not null comment '小程序id',
@@ -39,7 +39,7 @@ create table lc_order_purchase (
key idx_user_order (app_id,app_uid,status),
key idx_sid (sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='消费订单表';
-
+alter table lc_order_purchase add mch_id varchar(30) not null default '' comment '支付商户号' after sid;
-- ----------------------------
-- Title:订单总表
diff --git a/sql/receiver/order.sql b/sql/receiver/order.sql
index c312e870..ee79a47d 100644
--- a/sql/receiver/order.sql
+++ b/sql/receiver/order.sql
@@ -153,6 +153,7 @@ create table lc_receiver_order_signs (
-- Title:订单表
-- Author:lcc
-- Table:lc_receiver_orders
+-- info_json entrust_name 代办人姓名 entrust_idcard 代办人身份证
-- ---------------------------
drop table if exists lc_receiver_orders;
create table lc_receiver_orders (
@@ -180,3 +181,6 @@ create table lc_receiver_orders (
u_time timestamp not null default current_timestamp on update current_timestamp,
primary key (id)
) ENGINE=INNODB DEFAULT CHARSET=UTF8MB4 COLLATE=UTF8MB4_0900_AI_CI COMMENT='订单表';
+alter table lc_receiver_orders add pack_id int(10) unsigned not null default 0 comment '服务包id' after incor_id;
+alter table lc_receiver_orders add main_type tinyint(1) unsigned not null default 0 comment '购车主体(0个人 1公司)' after admin_id;
+alter table lc_receiver_orders add ifentrust tinyint(1) unsigned not null default 0 comment '是否委托代办' after main_type;
diff --git a/sql/receiver/services.sql b/sql/receiver/services.sql
new file mode 100644
index 00000000..8b69a4b4
--- /dev/null
+++ b/sql/receiver/services.sql
@@ -0,0 +1,28 @@
+-- ----------------------------
+-- Title:服务表
+-- Author:lcc
+-- Table:lc_receiver_services
+-- ---------------------------
+create table lc_receiver_services (
+ id int(10) unsigned not null auto_increment comment '自增id',
+ title varchar(50) not null default '' comment '服务名称',
+ field_name varchar(50) not null default '' comment '表名.字段名',
+ c_time int(10) unsigned not null default '0' comment '创建时间',
+ u_time timestamp not null default current_timestamp on update current_timestamp,
+ primary key (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='服务表';
+
+
+-- ----------------------------
+-- Title:服务包表
+-- Author:lcc
+-- Table:lc_receiver_service_package
+-- ---------------------------
+create table lc_receiver_service_package (
+ id int(10) unsigned not null auto_increment comment '自增id',
+ srv_ids varchar(50) not null default '' comment '服务包组合id',
+ status tinyint(2) not null default '1' comment '状态(-1删除 0禁用 1正常)',
+ c_time int(10) unsigned not null default '0' comment '创建时间',
+ u_time timestamp not null default current_timestamp on update current_timestamp,
+ primary key (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='服务包表'
diff --git a/www/wxpay/AesUtil.php b/www/wxpay/AesUtil.php
new file mode 100644
index 00000000..2ceb0850
--- /dev/null
+++ b/www/wxpay/AesUtil.php
@@ -0,0 +1,68 @@
+aesKey = $aesKey;
+ }
+
+ /**
+ * Decrypt AEAD_AES_256_GCM ciphertext
+ *
+ * @param string $associatedData AES GCM additional authentication data
+ * @param string $nonceStr AES GCM nonce
+ * @param string $ciphertext AES GCM cipher text
+ *
+ * @return string|bool Decrypted string on success or FALSE on failure
+ */
+ public function decryptToString($associatedData, $nonceStr, $ciphertext)
+ {
+ $ciphertext = \base64_decode($ciphertext);
+ if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
+ return false;
+ }
+
+ // ext-sodium (default installed on >= PHP 7.2)
+ if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
+ \sodium_crypto_aead_aes256gcm_is_available()) {
+ return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
+ }
+
+ // ext-libsodium (need install libsodium-php 1.x via pecl)
+ if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
+ \Sodium\crypto_aead_aes256gcm_is_available()) {
+ return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
+ }
+
+ // openssl (PHP >= 7.1 support AEAD)
+ if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
+ $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
+ $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);
+
+ return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
+ $authTag, $associatedData);
+ }
+
+ throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
+ }
+}
diff --git a/www/wxpay/index.php b/www/wxpay/index.php
new file mode 100644
index 00000000..42494a02
--- /dev/null
+++ b/www/wxpay/index.php
@@ -0,0 +1,29 @@
+ 0,'msg'=> ''];
+if(!$resource || !$nonceStr || !$associatedData || !$ciphertext){
+ $req['msg'] = '参数错误';
+ die(json_encode($req,JSON_UNESCAPED_UNICODE));
+}
+$AesUtil = new AesUtil($aesKey);
+try {
+ $result = $AesUtil->decryptToString($associatedData,$nonceStr,$ciphertext);
+ if($result){
+ $req['code'] = 1;
+ $req['data'] = json_decode($result);
+ $req['msg'] = '解密成功';
+ die(json_encode($req,JSON_UNESCAPED_UNICODE));
+ }else{
+ $req['msg'] = '解密失败';
+ die(json_encode($req,JSON_UNESCAPED_UNICODE));
+ }
+} catch (Exception $e) {
+ $req['msg'] = $e->getMessage();
+ die(json_encode($req,JSON_UNESCAPED_UNICODE));
+}
| |