diff --git a/.gitignore b/.gitignore
index 42bce322..1a9d7eda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,5 +17,5 @@ download_statement
/application/libraries/composer
/application/config/database.php
-
+**/*cert
diff --git a/webht/third_party/pay/config/1353239702_cert/证书使用说明.txt b/webht/third_party/pay/config/1353239702_cert/证书使用说明.txt
new file mode 100644
index 00000000..041befb4
--- /dev/null
+++ b/webht/third_party/pay/config/1353239702_cert/证书使用说明.txt
@@ -0,0 +1,18 @@
+欢迎使用微信支付!
+附件中的三份文件(证书pkcs12格式、证书pem格式、证书密钥pem格式),为接口中强制要求时需携带的证书文件。
+证书属于敏感信息,请妥善保管不要泄露和被他人复制。
+不同开发语言下的证书格式不同,以下为说明指引:
+ 证书pkcs12格式(apiclient_cert.p12)
+ 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份
+ 部分安全性要求较高的API需要使用该证书来确认您的调用身份
+ windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户号(如:1900006031)
+ 证书pem格式(apiclient_cert.pem)
+ 从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制
+ 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供
+ 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem
+ 证书密钥pem格式(apiclient_key.pem)
+ 从apiclient_cert.p12中导出密钥部分的文件,为pem格式
+ 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供
+ 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem
+备注说明:
+ 由于绝大部分操作系统已内置了微信支付服务器证书的根CA证书, 2018年3月6日后, 不再提供CA证书文件(rootca.pem)下载
\ No newline at end of file
diff --git a/webht/third_party/pay/config/wxpay.php b/webht/third_party/pay/config/wxpay.php
index 7401ce27..38c2953a 100644
--- a/webht/third_party/pay/config/wxpay.php
+++ b/webht/third_party/pay/config/wxpay.php
@@ -21,10 +21,12 @@ $config['trippest']["app_id"] = "wx7e605820faf98a05";
$config['trippest']["mch_id"] = "1528541381";
$config['trippest']["key"] = "b6f4db121410468e814d812c6c641efd";
$config['trippest']["app_secret"] = "";
+$config['trippest']["cert_path"] = dirname(__FILE__) . "/1528541381_cert";
// ChinaHighlights = China train booking
$config['cht']["notify_url"] = "https://www.mycht.cn/webht.php/apps/pay/wxpayservice/notify/cht";
$config['cht']["app_id"] = "wxd6c8dd69af5128cd";
$config['cht']["mch_id"] = "1353239702";
$config['cht']["key"] = "aada7476b3fecc2c6e33a7c765298516";
$config['cht']["app_secret"] = "";
+$config['cht']["cert_path"] = dirname(__FILE__) . "/1353239702_cert";
// wx5d01021a6d515098 花梨鹰小程序
diff --git a/webht/third_party/pay/controllers/PaymentService.php b/webht/third_party/pay/controllers/PaymentService.php
index 97a288cc..8bca1f84 100644
--- a/webht/third_party/pay/controllers/PaymentService.php
+++ b/webht/third_party/pay/controllers/PaymentService.php
@@ -87,7 +87,7 @@ class PaymentService extends CI_Controller {
"wx5d01021a6d515098" => "HLY", // "花梨鹰小程序", // 交行收款码
"wxd6c8dd69af5128cd" => "", // "NATIVE",
"wx7e605820faf98a05" => "Trippest-NATIVE",
- "0" => "unknown",
+ "0" => "",
);
public function set_brandname(&$ele)
{
@@ -761,10 +761,10 @@ class PaymentService extends CI_Controller {
* 15号之后开始检查
* 换美元汇率: https://www.chinahighlights.com/api/cht/currency/getCurrencydata.php
**/
- public function check_paypal_limit()
+ public function check_paypal_limit($notify = '1')
{
$this->load->helper('file');
- if (date('d') < '15') {
+ if (date('d') < '15' && $notify == '1') {
return false;
}
$this_month = date('Y-m-02');
@@ -776,7 +776,7 @@ class PaymentService extends CI_Controller {
mkdir(APPPATH . 'cache/', 0755, TRUE);
}
$read_next_check = read_file($filename);
- if ($today < $read_next_check) {
+ if ($today < $read_next_check && $notify == '1') {
echo 'Next Check Date: ' . $read_next_check . '
';
return false;
}
@@ -804,15 +804,17 @@ class PaymentService extends CI_Controller {
write_file($filename, $next_month);
// 达到了 120 万美元, 就发邮件, 提醒切换渠道
$time_set = date('Y-m-d_H_i_s');
- $fromName = 'PayPal 额度提醒';
- $fromEmail = 'lyt@hainatravel.com';
- $toName = 'LOT, fgy'; // 'fgy';
- $toEmail = 'lyt@hainatravel.com, fgy@hainatravel.com'; // 'fgy@hainatravel.com';
- $subject = $fromName;
- $body = "PayPal收款额度已达, 可切换信用卡渠道.
当前总额: {$current_total} 万 USD
------------
支付系统自动发送
". date("Y-m-d H:i"). "
";
- $M_AddTime = $time_set;
- $M_State = 0;
- $this->account_model->save_automail($fromName, $fromEmail, $toName, $toEmail, $subject, $body, 0, $M_State, $M_AddTime, $fromName, $fromName);
+ if ($notify === '1') {
+ $fromName = 'PayPal 额度提醒';
+ $fromEmail = 'lyt@hainatravel.com';
+ $toName = 'LOT, fgy'; // 'fgy';
+ $toEmail = 'lyt@hainatravel.com, fgy@hainatravel.com'; // 'fgy@hainatravel.com';
+ $subject = $fromName;
+ $body = "PayPal收款额度已达, 可切换信用卡渠道.
当前总额: {$current_total} 万 USD
------------
支付系统自动发送
". date("Y-m-d H:i"). "
";
+ $M_AddTime = $time_set;
+ $M_State = 0;
+ $this->account_model->save_automail($fromName, $fromEmail, $toName, $toEmail, $subject, $body, 0, $M_State, $M_AddTime, $fromName, $fromName);
+ }
echo $toEmail.'
';
echo $body;
return false;
@@ -822,7 +824,7 @@ class PaymentService extends CI_Controller {
* 检查PayPal的费率
*
**/
- public function check_paypal_rate()
+ public function check_paypal_rate($notify = '1')
{
if (date('d') !== '2') {
echo '不是2号,不检查';
@@ -839,15 +841,17 @@ class PaymentService extends CI_Controller {
$current_ACDC = isset($ACDC[0]) ? $ACDC[0]['calc_rate']*100 : '';
// BCDC 钱包渠道大于 3.2%
$time_set = date('Y-m-d_H_i_s');
- $fromName = 'PayPal 费率提醒';
- $fromEmail = 'lyt@hainatravel.com';
- $toName = 'LOT, fgy'; // 'fgy';
- $toEmail = 'lyt@hainatravel.com, fgy@hainatravel.com'; // 'fgy@hainatravel.com';
- $subject = $fromName;
- $body = "PayPal费率高于3.2%,请及时处理.
当前费率:
PayPal钱包渠道: {$current_BCDC}%
PayPal ACDC渠道(GooglePay, ApplePay): {$current_ACDC}%
------------
支付系统自动发送
". date("Y-m-d H:i"). "
";
- $M_AddTime = $time_set;
- $M_State = 0;
- $this->account_model->save_automail($fromName, $fromEmail, $toName, $toEmail, $subject, $body, 0, $M_State, $M_AddTime, $fromName, $fromName);
+ if ($notify === '1') {
+ $fromName = 'PayPal 费率提醒';
+ $fromEmail = 'lyt@hainatravel.com';
+ $toName = 'LOT, fgy'; // 'fgy';
+ $toEmail = 'lyt@hainatravel.com, fgy@hainatravel.com'; // 'fgy@hainatravel.com';
+ $subject = $fromName;
+ $body = "PayPal费率高于3.2%,请及时处理.
当前费率:
PayPal钱包渠道: {$current_BCDC}%
PayPal ACDC渠道(GooglePay, ApplePay): {$current_ACDC}%
------------
支付系统自动发送
". date("Y-m-d H:i"). "
";
+ $M_AddTime = $time_set;
+ $M_State = 0;
+ $this->account_model->save_automail($fromName, $fromEmail, $toName, $toEmail, $subject, $body, 0, $M_State, $M_AddTime, $fromName, $fromName);
+ }
echo $toEmail.'
';
echo $body;
return false;
diff --git a/webht/third_party/pay/controllers/WxpayService.php b/webht/third_party/pay/controllers/WxpayService.php
index c139f948..921a0925 100644
--- a/webht/third_party/pay/controllers/WxpayService.php
+++ b/webht/third_party/pay/controllers/WxpayService.php
@@ -126,10 +126,12 @@ class WxpayService extends CI_Controller {
$this->query_builder->set_bill_type($bill_type);
$this->load->library('Wxpay_call');
$result = $this->wxpay_call->get_bill_data($this->query_builder);
+ $fund_result = $this->wxpay_call->get_fund_bill_data($this->query_builder);
if ($result['status'] !== true) {
log_message('error',"get wxpay bill failed. $target_account $bill_date");
}
- foreach ($result['data'] as $key => $row) {
+ $all_bill = array_merge($result['data'], $fund_result['data']);
+ foreach ($all_bill as $key => $row) {
$save_column = array();
$save_column['OPN_accountMethod'] = $this->config->item('method_code', 'wxpay');
if ($row['refund_id'] != '0') {
@@ -146,7 +148,7 @@ class WxpayService extends CI_Controller {
$save_column['OPN_entryAmountCNY'] = floatval($ssje); // $save_column['OPN_netAmount'];
$save_column['OPN_noticeType'] = 'refund';
- $save_column['OPN_relatedId'] = $row['transaction_id'];
+ $save_column['OPN_relatedId'] = isset($row['fund_transaction_id']) ? $row['fund_transaction_id'] : $row['transaction_id'];
$save_column['OPN_transactionResult'] = $row['refund_status'] === 'SUCCESS' ? 'completed' : strtolower($row['refund_status']);
} else {
// 收款
@@ -180,6 +182,7 @@ class WxpayService extends CI_Controller {
$save_column['OPN_rawContent'] = json_encode($row);
$save_column['OPN_noticeTime'] = date('Y-m-d H:i:s');
+ // var_dump($save_column);
$this->note_model->insert_note($save_column, true);
}
return;
diff --git a/webht/third_party/pay/libraries/wxpay_call.php b/webht/third_party/pay/libraries/wxpay_call.php
index f632b733..14845342 100644
--- a/webht/third_party/pay/libraries/wxpay_call.php
+++ b/webht/third_party/pay/libraries/wxpay_call.php
@@ -8,6 +8,7 @@ class Wxpay_call
private $api_info_arr = array();
private $merchant_account = '';
+ private $wx_site_config = array();
public function __construct($account = '')
{
@@ -16,6 +17,7 @@ class Wxpay_call
$this->ci->config->load('wxpay', true);
// $this->ci->load->model('WxpayQueryContentBuilder', 'query_builder');
$this->merchant_account = $account;
+ bcscale(2);
}
private function init_api($account = '')
@@ -95,7 +97,7 @@ class Wxpay_call
$query_content_input = $query_content->getBizContent(true);
//检测必填参数
if(!$query_content_input['bill_date']) {
- throw new WxPayException("对账单接口中,缺少必填参数bill_date!");
+ throw new Exception("对账单接口中,缺少必填参数bill_date!");
}
$this->api_info_arr['nonce_str'] = ($this->get_nonce_str());//随机字符串
@@ -127,6 +129,92 @@ class Wxpay_call
return $ret;
}
+ /**
+ * 获取资金账单数据
+ */
+ public function get_fund_bill_data($query_content)
+ {
+ $ret = array('status'=>false, 'data'=>array());
+ $this->init_api();
+ // return false;
+ $url = "https://api.mch.weixin.qq.com/pay/downloadfundflow";
+ $query_content_input = $query_content->getBizContent(true);
+ //检测必填参数
+ if(!$query_content_input['bill_date']) {
+ throw new Exception("对账单接口中,缺少必填参数bill_date!", 1);
+ }
+ unset($query_content_input['bill_type']);
+ $query_content_input['account_type'] = 'Basic';
+ $this->api_info_arr['nonce_str'] = ($this->get_nonce_str());//随机字符串
+
+ $ready_api = array_merge($this->api_info_arr, $query_content_input);
+ $this->api_info_arr['sign'] = $this->make_sign($ready_api, 'HMAC-SHA256');//签名
+ $ready_api['sign'] = $this->api_info_arr['sign'];
+ $xml = to_xml($ready_api);
+
+ $response = $this->post_xml_curl($this->api_info_arr, $xml, $url, 20);
+ if(substr($response, 0 , 5) == ""){
+ log_message('error',"Wxpay fund bill error \r\n" . var_export($response, 1));
+ return $ret;
+ }
+ $ret['status'] = true;
+ $response_arr = explode("\n",$response);
+ // var_dump($response_arr);
+ // die();
+ $data_title = $this->fund_bill_data_title();
+ $data_arr = [];
+ for ($i=1; $i < count($response_arr)-1; $i++) {
+ if (empty($response_arr[$i])) {
+ continue;
+ }
+ $row = explode(",", $response_arr[$i]);
+ $row_arr = array();
+ foreach ($data_title as $key => $title) {
+ if ( ! isset($row[$key])) {
+ continue;
+ }
+ $row_arr[$title] = str_replace("`","",trim($row[$key]));
+ }
+ $row_arr['wxpay_fee'] = '';
+ !empty($row_arr['trade_direction']) ? $data_arr[] = $row_arr : false;
+ }
+ $ret_g = array_reduce($data_arr, function($carry, $item) {
+ $item['currency_type'] = 'CNY';
+ $item['trade_state'] = $item['trade_type'];
+ $item['trade_type'] = 'BILL';
+ $item['bank_type'] = $item['item_name'] = $item['attach'] = $item['openid'] = '';
+ if (isset($carry[$item['transaction_id']]) && !empty($carry[$item['transaction_id']])) {
+ $fee = $item['trade_direction'] == '支出' && stripos($item['sub_trade_type'], '手续费') !== false ? $item['settlement_total_fee'] : 0;
+ $net_amount = bcsub($carry[$item['transaction_id']][0]['settlement_total_fee'], $fee);
+ $carry[$item['transaction_id']][0]['net_amount'] = $net_amount;
+ $carry[$item['transaction_id']][0]['wxpay_fee'] = $fee;
+ $carry[$item['transaction_id']][0]['refund_id'] = '0';
+ } else {
+ if ($item['sub_trade_type'] == '退款') {
+ $item['net_amount'] = $item['settlement_total_fee'];
+ preg_match_all('/(\d+\.\d+)/', $item['remark'], $matches);
+ $amount = isset($matches[1][0]) ? $matches[1][0] : $item['settlement_total_fee'];
+ $fee = isset($matches[1][1]) ? $matches[1][1] * -1 : '';
+ $item['settlement_refund_fee'] = $amount;
+ $item['call_refund_fee'] = $amount;
+ $item['wxpay_fee'] = $fee;
+ $item['out_refund_id'] = $item['out_trade_no'];
+ $item['refund_id'] = $item['transaction_id'];
+ $item['refund_status'] = 'SUCCESS';
+ $item['out_trade_no'] = '';
+ }
+ $item['item_name'] = preg_match('/^[A-Z0-9]{6}-[A-Z0-9]{7}-[A-Z0-9]{4}$/', $item['out_trade_no']) ? '收钱码收款' : '';
+ $carry[$item['transaction_id']][] = $item;
+ }
+ return $carry;
+ }, []);
+ $ret['data'] = array_reduce(array_values($ret_g), function($carry, $item) {
+ $carry[] = $item[0];
+ return $carry;
+ }, []);
+ return $ret;
+ }
+
/*!
* @Author: LYT
* @Date: 2019-06-18 15:23:15
@@ -166,6 +254,27 @@ class Wxpay_call
);
}
+ /**
+ * 资金账单数据的格式
+ * 记账时间,微信支付业务单号,资金流水单号,业务名称,业务类型,收支类型,收支金额(元),账户结余(元),资金变更提交申请人,备注,业务凭证号
+ */
+ private function fund_bill_data_title()
+ {
+ return array(
+ "complete_time", // 记账时间
+ "transaction_id", // 微信支付业务单号
+ "fund_transaction_id", // 资金流水单号
+ "trade_type", // 业务名称
+ "sub_trade_type", // 业务类型
+ "trade_direction", // 收支类型
+ "settlement_total_fee", // 收支金额(元)
+ "balance", // 账户结余(元)
+ "handler", // 资金变更提交申请人
+ "remark", // 备注
+ "out_trade_no", // 业务凭证号, 退款是out_refund_id
+ );
+ }
+
/**
* 以post方式提交xml到对应的接口url
*
@@ -197,6 +306,14 @@ class Wxpay_call
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
}
+ if (is_dir($this->wx_site_config['cert_path'])) {
+ curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
+ curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
+ curl_setopt($ch, CURLOPT_SSLKEYPASSWD, $this->wx_site_config['mch_id']);
+ curl_setopt($ch, CURLOPT_SSLCERT, $this->wx_site_config['cert_path'] . "/apiclient_cert.pem");
+ curl_setopt($ch, CURLOPT_SSLKEY, $this->wx_site_config['cert_path'] . "/apiclient_key.pem");
+ }
+
curl_setopt($ch,CURLOPT_USERAGENT, $ua);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
@@ -242,7 +359,11 @@ class Wxpay_call
return true;
}
- public function make_sign($xml_arr, $needSignType = false)
+ /**
+ * @param mixed $xml_arr
+ * @param string $SignType 签名方式,MD5 或 HMAC-SHA256
+ */
+ public function make_sign($xml_arr, $SignType = 'MD5')
{
//签名步骤一:按字典序排序参数
ksort($xml_arr);
@@ -250,12 +371,17 @@ class Wxpay_call
//签名步骤二:在string后加入KEY
$string = $string . "&key=" . $this->wx_site_config['key'];
//签名步骤三:MD5加密或者HMAC-SHA256
- if(!isset($xml_arr['sign']) || strlen($xml_arr['sign']) <= 32){
- //如果签名小于等于32个,则使用md5验证
- $string = md5($string);
- } else {
- //是用sha256校验
- $string = hash_hmac("sha256", $string , $this->wx_site_config['key']);
+ switch ($SignType) {
+ case 'MD5':
+ $string = md5($string);
+ break;
+ case 'HMAC-SHA256':
+ $string = hash_hmac("sha256", $string, $this->wx_site_config['key']);
+ break;
+
+ default:
+ $string = md5($string);
+ break;
}
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
@@ -294,6 +420,9 @@ class Wxpay_call
return $str;
}
+ /**
+ * @deprecated
+ */
protected function curl($url, $postFields = null) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
diff --git a/webht/third_party/pay/models/Online_payment_note_model.php b/webht/third_party/pay/models/Online_payment_note_model.php
index 75082daf..58d32e10 100644
--- a/webht/third_party/pay/models/Online_payment_note_model.php
+++ b/webht/third_party/pay/models/Online_payment_note_model.php
@@ -39,7 +39,7 @@ class Online_payment_note_model extends CI_Model {
$query = $this->info->query($sql);
if ($query->num_rows() > 0) {
$update = array(
- 'OPN_payFee' => isset($column['OPN_payFee']) ? bcsub(0,$column['OPN_payFee']) : null,
+ 'OPN_payFee' => isset($column['OPN_payFee']) ? $column['OPN_payFee'] : null,
'OPN_netAmount' => $column['OPN_netAmount'],
'OPN_entryAmountCNY' => $column['OPN_entryAmountCNY'],
);