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