perf: 微信: 下载资金账单; 证书

webht/payment
Lei OT 1 year ago
parent d1782865c9
commit d8f1751378

2
.gitignore vendored

@ -17,5 +17,5 @@ download_statement
/application/libraries/composer
/application/config/database.php
**/*cert

@ -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下载

@ -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 花梨鹰小程序

@ -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 . '<br>';
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收款额度已达, 可切换信用卡渠道. <br>当前总额: {$current_total} 万 USD<br/>------------<br/>支付系统自动发送<br>". date("Y-m-d H:i"). " <br>";
$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收款额度已达, 可切换信用卡渠道. <br>当前总额: {$current_total} 万 USD<br/>------------<br/>支付系统自动发送<br>". date("Y-m-d H:i"). " <br>";
$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.'<br>';
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%,请及时处理. <br>当前费率: <br/>PayPal钱包渠道: {$current_BCDC}%<br/>PayPal ACDC渠道(GooglePay, ApplePay): {$current_ACDC}%<br/>------------<br/>支付系统自动发送<br>". date("Y-m-d H:i"). " <br>";
$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%,请及时处理. <br>当前费率: <br/>PayPal钱包渠道: {$current_BCDC}%<br/>PayPal ACDC渠道(GooglePay, ApplePay): {$current_ACDC}%<br/>------------<br/>支付系统自动发送<br>". date("Y-m-d H:i"). " <br>";
$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.'<br>';
echo $body;
return false;

@ -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;

@ -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) == "<xml>"){
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);

@ -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'],
);

Loading…
Cancel
Save