diff --git a/webht/third_party/pay/config/wxpay.php b/webht/third_party/pay/config/wxpay.php index 30f0a87c..ac42b017 100644 --- a/webht/third_party/pay/config/wxpay.php +++ b/webht/third_party/pay/config/wxpay.php @@ -7,6 +7,7 @@ $config["method_code"] = 15016; /*! * 各账号的设置 */ +$config['all_account'] = "cht,trippest"; // test $config['test']["notify_url"] = "https://www.mycht.cn/webht.php/apps/pay/wxpayservice/notify/test"; $config['test']["app_id"] = "wx426b3015555a46be"; diff --git a/webht/third_party/pay/controllers/WxpayService.php b/webht/third_party/pay/controllers/WxpayService.php index 145ecb49..2e3bf914 100644 --- a/webht/third_party/pay/controllers/WxpayService.php +++ b/webht/third_party/pay/controllers/WxpayService.php @@ -24,7 +24,7 @@ class WxpayService extends CI_Controller { public function notify($site='cht') { error_reporting(0); -log_message('error','notify begin ----'); +// log_message('error','notify begin ----'); $response['return_code'] = 'FAIL'; $response['return_msg'] = ''; $GLOBALS['__WX_SITE_NAME__'] = $site; @@ -48,7 +48,7 @@ log_message('error','notify begin ----'); $response['return_msg'] = 'OK'; } else { $xml_arr['total_fee'] = bcdiv($xml_arr['total_fee'], $this->config->item('currency_unit', 'wxpay')); - $ssje = $this->account_model->get_ssje($xml_arr['total_fee'], $xml_arr['fee_type'], $this->config->item('currency_unit', 'wxpay')); + $ssje = $this->account_model->get_ssje($xml_arr['total_fee'], str_replace("CNY", "RMB", strtoupper($xml_arr['fee_type'])), $this->config->item('method_code', 'wxpay')); $save_column = array(); $save_column['OPN_transactionId'] = $xml_arr['transaction_id']; $save_column['OPN_orderId'] = $xml_arr['out_trade_no']; @@ -85,12 +85,78 @@ log_message('error','notify begin ----'); return $this->response_to_wx($response); } + public function download_all_bill() + { + $all_account = explode(",", $this->config->item('all_account', 'wxpay')); + foreach ($all_account as $account) { + $this->download_bill($account); + } + return; + } + + public function download_bill($target_account) + { + $GLOBALS['__WX_SITE_NAME__'] = $target_account; + + $bill_date = $this->input->get_post("date"); + $bill_date = $bill_date ? $bill_date : date("Ymd", strtotime("-1 day")); + $bill_type = 'ALL'; + $this->load->model('WxpayQueryContentBuilder', 'query_builder'); + $this->query_builder->set_bill_date($bill_date); + $this->query_builder->set_bill_type($bill_type); + $this->load->library('Wxpay_call'); + $result = $this->wxpay_call->get_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) { + $save_column = array(); + $save_column['OPN_accountMethod'] = $this->config->item('method_code', 'wxpay'); + if ($row['refund_id'] != '0') { + // 退款 + $ssje = $this->account_model->get_ssje($row['settlement_refund_fee'], str_replace("CNY", "RMB", strtoupper($row['currency_type'])), $save_column['OPN_accountMethod']); + $save_column['OPN_transactionId'] = $row['refund_id']; + $save_column['OPN_orderAmount'] = "-" . $row['settlement_refund_fee']; + $save_column['OPN_payAmount'] = "-" . $row['settlement_refund_fee']; + $save_column['OPN_resultCode'] = $row['refund_status']; + $save_column['OPN_resultMsg'] = $row['refund_status']; + $save_column['OPN_entryAmountCNY'] = floatval("-" . $ssje); + $save_column['OPN_noticeType'] = 'refund'; + } else { + // 收款 + $ssje = $this->account_model->get_ssje($row['settlement_total_fee'], str_replace("CNY", "RMB", strtoupper($row['currency_type'])), $save_column['OPN_accountMethod']); + $save_column['OPN_transactionId'] = $row['transaction_id']; + $save_column['OPN_orderAmount'] = $row['settlement_total_fee']; + $save_column['OPN_payAmount'] = $row['settlement_total_fee']; + $save_column['OPN_resultCode'] = $row['trade_state']; + $save_column['OPN_resultMsg'] = $row['trade_state']; + $save_column['OPN_entryAmountCNY'] = floatval($ssje); + $save_column['OPN_noticeType'] = 'pay'; + } + $save_column['OPN_noticeSendStatus'] = 'unsend'; + $save_column['OPn_transactionResult'] = 'completed'; + $save_column['OPN_orderId'] = $row['out_trade_no']; + $save_column['OPN_rawOrderId'] = $row['out_trade_no']; + $save_column['OPN_invoiceId'] = $row['out_trade_no']; + $save_column['OPN_subject'] = $row['item_name']; + $save_column['OPN_currency'] = $row['currency_type']; + $save_column['OPN_acquiringTime'] = date('Y-m-d H:i:s',strtotime($row['complete_time'])); + $save_column['OPN_completeTime'] = date('Y-m-d H:i:s',strtotime($row['complete_time'])); + $save_column['OPN_remark'] = $row['attach']; + $save_column['OPN_payerLogId'] = $row['openid']; + $save_column['OPN_fundSource'] = $row['trade_type'] . "-" .$row['bank_type']; + $save_column['OPN_rawContent'] = json_encode($row); + $save_column['OPN_noticeTime'] = date('Y-m-d H:i:s'); + + $this->note_model->insert_note($save_column) ; + } + return; + } + public function response_to_wx($response_arr) { $response_body = to_xml($response_arr); -// log_message('error',var_export($response_body, 1)); echo $response_body; - # exit(); // end } public function check_sign($xml_arr) diff --git a/webht/third_party/pay/libraries/wxpay_call.php b/webht/third_party/pay/libraries/wxpay_call.php new file mode 100644 index 00000000..096ab917 --- /dev/null +++ b/webht/third_party/pay/libraries/wxpay_call.php @@ -0,0 +1,282 @@ +ci =& get_instance(); + $this->ci->load->helper('payment'); + $this->ci->config->load('wxpay', true); + // $this->ci->load->model('WxpayQueryContentBuilder', 'query_builder'); + } + + private function init_api() + { + $this->wx_site_config = $this->ci->config->item($GLOBALS['__WX_SITE_NAME__'], 'wxpay'); + $this->api_info_arr['appid'] = $this->wx_site_config['app_id']; + $this->api_info_arr['mch_id'] = $this->wx_site_config['mch_id']; + $this->api_info_arr['key'] = $this->wx_site_config['key']; + $this->api_info_arr['app_secret'] = $this->wx_site_config['app_secret']; + } + + /** + * 下载对账单,WxPayDownloadBill中bill_date为必填参数 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayDownloadBill $inputObj + * @param int $timeOut + * @throws WxPayException + * @return 成功时返回,其他抛异常 + */ + public function get_bill_data($query_content) + { + $ret = array('status'=>false, 'data'=>array()); + $this->init_api(); + // return false; + $url = "https://api.mch.weixin.qq.com/pay/downloadbill"; + $query_content_input = $query_content->getBizContent(true); + //检测必填参数 + if(!$query_content_input['bill_date']) { + throw new WxPayException("对账单接口中,缺少必填参数bill_date!"); + } + $this->api_info_arr['nonce_str'] = ($this->get_nonce_str());//随机字符串 + + $this->api_info_arr['sign'] = $this->make_sign(array_merge($this->api_info_arr, $query_content_input));//签名 + $xml = to_xml(array_merge($this->api_info_arr, $query_content_input)); + + $response = $this->post_xml_curl($this->api_info_arr, $xml, $url, 6); + if(substr($response, 0 , 5) == ""){ + log_message('error',"Wxpay bill error \r\n" . var_export($response, 1)); + return $ret; + } + $ret['status'] = true; + $response_arr = explode("\n",$response); + $data_title = $this->bill_data_title(); + 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])); + } + !empty($row_arr['trade_type']) ? $ret['data'][] = $row_arr : false; + } + return $ret; + } + + /*! + * @Author: LYT + * @Date: 2019-06-18 15:23:15 + * @Desc: 账单数据的格式 + * 交易时间,公众账号ID,商户号,特约商户号,设备号,微信订单号,商户订单号,用户标识,交易类型,交易状态,付款银行,货币种类,应结订单金额,代金券金额,微信退款单号,商户退款单号,退款金额,充值券退款金额,退款类型,退款状态,商品名称,商户数据包,手续费,费率,订单金额,申请退款金额,费率备注 + */ + private function bill_data_title() + { + return array( + "complete_time", // 交易时间 + "app_id", // 公众账号ID + "mch_id", // 商户号 + "special_mch_id", // 特约商户号 + "device_info", // 设备号 + "transaction_id", // 微信订单号 + "out_trade_no", // 商户订单号 + "openid", // 用户标识 + "trade_type", // 交易类型 + "trade_state", // 交易状态 + "bank_type", // 付款银行 + "currency_type", // 货币种类 + "settlement_total_fee", // 应结订单金额 + "coupon_fee", // 代金券金额 + "refund_id", // 微信退款单号 + "out_refund_id",// 商户退款单号 + "settlement_refund_fee", // 退款金额 + "refund_coupon_fee", // 充值券退款金额 + "refund_type", // 退款类型 + "refund_status", // 退款状态 + "item_name", // 商品名称 + "attach", // 商户数据包 + "wxpay_fee", // 手续费 + "rate", // 费率 + "total_fee", // 订单金额 + "call_refund_fee", // 申请退款金额 + "rate_memo" // 费率备注 + ); + } + + /** + * 以post方式提交xml到对应的接口url + * + * @param WxPayConfigInterface $config 配置对象 + * @param string $xml 需要post的xml数据 + * @param string $url url + * @param bool $useCert 是否需要证书,默认不需要 + * @param int $second url执行超时时间,默认30s + * @throws WxPayException + */ + private function post_xml_curl($config, $xml, $url, $second = 30) + { + $ch = curl_init(); + $curlVersion = curl_version(); + $ua = "WXPaySDK/3.0.9 (".PHP_OS.") PHP/".PHP_VERSION." CURL/".$curlVersion['version']." " + .$config['mch_id']; + + //设置超时 + curl_setopt($ch, CURLOPT_TIMEOUT, $second); + + curl_setopt($ch,CURLOPT_URL, $url); + // curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); + // curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验 + if(stripos($url,"https://")!==FALSE){ + curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + } else { + curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); + curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验 + } + curl_setopt($ch,CURLOPT_USERAGENT, $ua); + //设置header + curl_setopt($ch, CURLOPT_HEADER, FALSE); + //要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + + //post提交方式 + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + //运行curl + $data = curl_exec($ch); + //返回结果 + if($data){ + curl_close($ch); + return $data; + } else { + $error = curl_errno($ch); + curl_close($ch); + log_message('error',"curl出错,错误码:$error " . curl_error($ch)); + } + } + + + public function check_sign($xml_arr) + { + if ( ! array_key_exists('sign', $xml_arr)) { + log_message('error','Wxpay notify error: no sign.'); + return false; + } + if ($this->make_sign($xml_arr) !== $xml_arr['sign']) { + log_message('error','Wxpay notify error: sign.' . $this->make_sign($xml_arr)); + return false; + } + if ($this->wx_site_config['app_id'] !== $xml_arr['appid']) { + log_message('error','Wxpay notify error: appid.'); + return false; + } + if ($this->wx_site_config['mch_id'] !== $xml_arr['mch_id']) { + log_message('error','Wxpay notify error: mch_id.'); + return false; + } + return true; + } + + public function make_sign($xml_arr, $needSignType = false) + { + //签名步骤一:按字典序排序参数 + ksort($xml_arr); + $string = $this->to_url_params($xml_arr); + //签名步骤二:在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']); + } + //签名步骤四:所有字符转为大写 + $result = strtoupper($string); + return $result; + } + + /** + * 格式化参数格式化成url参数 + */ + public function to_url_params($xml_arr) + { + $buff = ""; + foreach ($xml_arr as $k => $v) + { + if($k != "sign" && $v != "" && !is_array($v)){ + $buff .= $k . "=" . $v . "&"; + } + } + + $buff = trim($buff, "&"); + return $buff; + } + + /** + * 产生随机字符串,不长于32位 + * @param int $length + * @return 产生的随机字符串 + */ + public static function get_nonce_str($length = 32) + { + $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; + $str =""; + for ( $i = 0; $i < $length; $i++ ) { + $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); + } + return $str; + } + + protected function curl($url, $postFields = null) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_FAILONERROR, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + $postBodyString = ""; + + if (is_array($postFields) && 0 < count($postFields)) { + foreach ($postFields as $k => $v) { + if ("@" != substr($v, 0, 1)) //判断是不是文件上传 + { + $postBodyString .= "$k=" . urlencode($this->characet($v, "UTF-8")) . "&"; + } + } + unset($k, $v); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1)); + } + $headers = array('content-type: application/x-www-form-urlencoded;charset=UTF-8'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + $reponse = curl_exec($ch); + + if (curl_errno($ch)) { + log_message('error', " iPayLinks curl error code: ".curl_error($ch)."; curl postBodyString: ".substr($postBodyString, 0, -1)); + } else { + $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if (200 !== $httpStatusCode) { + log_message('error', " iPayLinks Request html Status Code: ".$httpStatusCode."; curl postBodyString: ".substr($postBodyString, 0, -1)); + } + } + curl_close($ch); + return $reponse; + } + +} + +/* End of file Wxpay_call.php */ diff --git a/webht/third_party/pay/models/Online_payment_account_model.php b/webht/third_party/pay/models/Online_payment_account_model.php index 6ff43412..5c9195e9 100644 --- a/webht/third_party/pay/models/Online_payment_account_model.php +++ b/webht/third_party/pay/models/Online_payment_account_model.php @@ -17,6 +17,7 @@ class Online_payment_account_model extends CI_Model { $sql = "SELECT dbo.GetSSJEFromSQJE(?, ?, ?) as ssje"; $query = $this->HT->query($sql,array($code, $currency, $amount)); $result = $query->result(); + if ( ! empty($result)) { return $result[0]->ssje; } diff --git a/webht/third_party/pay/models/WxpayQueryContentBuilder.php b/webht/third_party/pay/models/WxpayQueryContentBuilder.php new file mode 100644 index 00000000..ffa56617 --- /dev/null +++ b/webht/third_party/pay/models/WxpayQueryContentBuilder.php @@ -0,0 +1,56 @@ +bizContentarr)){ + $this->bizContent = json_encode($this->bizContentarr); // 5.4增加的常量 JSON_UNESCAPED_UNICODE + } + $ret = ($arr===false) ? $this->bizContent : $this->bizContentarr ; + return $ret; + } + + public function set_bill_date($bill_date) + { + $this->bill_date = $bill_date; + $this->bizContentarr['bill_date'] = $bill_date; + } + + public function set_bill_type($bill_type) + { + $this->bill_type = $bill_type; + $this->bizContentarr['bill_type'] = $bill_type; + } + + public function set_tar_type($tar_type) + { + $this->tar_type = $tar_type; + $this->bizContentarr['tar_type'] = $tar_type; + } + +} + +/* End of file WxpayQueryContentBuilder.php */ + +?>