diff --git a/webht/third_party/pay/controllers/AlipayTradeService.php b/webht/third_party/pay/controllers/AlipayTradeService.php index 76058e55..eeb1ca5c 100644 --- a/webht/third_party/pay/controllers/AlipayTradeService.php +++ b/webht/third_party/pay/controllers/AlipayTradeService.php @@ -908,6 +908,7 @@ class AlipayTradeService extends CI_Controller public function download_billfile($date=NULL) { ignore_user_abort(true); + bcscale(2); $request = new AlipayDataDataserviceBillDownloadurlQueryRequest(); $date = $date===NULL ? date("Y-m-d", strtotime("-1 day")) : $date; $file_name = FCPATH.'download_statement\settlement_files\alipay\\' . $this->merchant_account . $date . ".zip"; diff --git a/webht/third_party/pay/controllers/PaymentService.php b/webht/third_party/pay/controllers/PaymentService.php index 801cb91d..90f8178e 100644 --- a/webht/third_party/pay/controllers/PaymentService.php +++ b/webht/third_party/pay/controllers/PaymentService.php @@ -757,25 +757,49 @@ class PaymentService extends CI_Controller { * 检查PayPal是否达到最低汇率的额度 * * 达到120万美元, 发邮件提醒 * 15号之后开始检查 - * + * 换美元汇率: https://www.chinahighlights.com/api/cht/currency/getCurrencydata.php **/ public function check_paypal_limit() { + $this->load->helper('file'); if (date('d') < '15') { return false; } + $this_month = date('Y-m-02'); + $today = date('Y-m-d'); + $next_month = date('Y-m-15', strtotime('+1 month', strtotime($this_month))); + $cache_file = md5('next_check_paypal_limit_date'); + $filename = APPPATH . 'cache/' . $cache_file . '.txt'; + if (!is_dir(APPPATH . 'cache/')) { + mkdir(APPPATH . 'cache/', 0755, TRUE); + } + $read_next_check = read_file($filename); + if ($today < $read_next_check) { + echo 'Next Check Date: ' . $read_next_check . '
'; + return false; + } + // 从前端取 外币换美元的汇率 + $currency_rate_url = 'https://www.chinahighlights.com/api/cht/currency/getCurrencydata.php'; + $all_rate_str = get_url_contents($currency_rate_url); + $all_rate = json_decode($all_rate_str, true); + $to_usd_rate = array_values(array_filter($all_rate['data'], function ($item) { + return $item['currency'] && $item['to'] == 'USD'; + })); + $year = date('Y', time()); $month = date('m', time()); $start = date('Y-m-d', strtotime("{$year}-{$month}-02")); $end = date('Y-m-d', strtotime('+1 month', strtotime($start))); // ? PayPal使用太平洋时间? GMT时间? // * 从本月2 号开始, 到下个月2号. - $summary = $this->account_model->query_paypal_note_summary($start, $end); + $summary = $this->account_model->query_paypal_note_summary($start, $end, $to_usd_rate); $if_got_line = $summary[0]['running_total'] > 120*10000; $current_total = number_format(bcdiv($summary[0]['running_total'], (1*10000)), 2); if ( ! $if_got_line) { + echo '

当前总额: ' . $current_total . ' 万 USD

'; return false; } + write_file($filename, $next_month); // 达到了 120 万美元, 就发邮件, 提醒切换渠道 $time_set = date('Y-m-d_H_i_s'); $fromName = 'PayPal 额度提醒'; @@ -783,10 +807,45 @@ class PaymentService extends CI_Controller { $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"). ".
"; + $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; + } + + /** + * 检查PayPal的费率 + * + **/ + public function check_paypal_rate() + { + if (date('d') !== '2') { + echo '不是2号,不检查'; + return false; + } + $list = $this->note_model->query_paypal_current_rate(); + $has_gt_rate = array_some($list, function($ele) { return $ele['OPN_paymentSource'] === 'paypal' ? $ele['calc_rate'] > 0.032 : false; }); + if (!$has_gt_rate) { + return false; + } + $BCDC_I = array_search('paypal', array_column($list, 'OPN_paymentSource')); + $current_BCDC = $list[$BCDC_I]['calc_rate']*100; + $ACDC = array_values(array_filter($list, function($ele) { return $ele['OPN_paymentSource'] !== 'paypal'; })); + $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); + $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 641c4e4a..69b50fdc 100644 --- a/webht/third_party/pay/controllers/WxpayService.php +++ b/webht/third_party/pay/controllers/WxpayService.php @@ -95,13 +95,21 @@ class WxpayService extends CI_Controller { } // async_curl($this->config->item('send_notify_url', 'wxpay')); async_curl('https://www.mycht.cn/webht.php/apps/pay/alipaytradeservice/get_billfile'); - async_curl('https://www.mycht.cn/download_statement/download_files.php', 30); // iPaylinks日账单 + // async_curl('https://www.mycht.cn/download_statement/download_files.php', 30); // iPaylinks日账单 + // 检查PayPal的额度 + async_get('https://www.mycht.cn/webht.php/apps/pay/paymentservice/check_paypal_limit'); /** * 每月20号发送退款给财务 */ if (date('d')==='20') { async_curl('https://www.mycht.cn/webht.php/apps/pay/paymentservice/refund_finance_notify'); } + /** + * 每月2号: 检查PayPal的费率 + */ + if (date('d')==='2') { + async_get('https://www.mycht.cn/webht.php/apps/pay/paymentservice/check_paypal_rate'); + } return; } diff --git a/webht/third_party/pay/helpers/payment_helper.php b/webht/third_party/pay/helpers/payment_helper.php index 6c0f9485..a6dd6476 100644 --- a/webht/third_party/pay/helpers/payment_helper.php +++ b/webht/third_party/pay/helpers/payment_helper.php @@ -358,6 +358,121 @@ function get_url_contents($url) return $result; } +/** + * 发一个异步的请求 + * @param string $url + * @param mixed $data + * @param array $headers + */ +function async_post_json($url, $data = '', $headers = []) { + $parts = parse_url($url); + $host = $parts['host']; + $path = isset($parts['path']) ? $parts['path'] : '/'; + $port = isset($parts['port']) ? $parts['port'] : 80; + $scheme = isset($parts['scheme']) ? $parts['scheme'] : 'http'; + $query = isset($parts['query']) ? '?' . $parts['query'] : ''; + + // $post_string = http_build_query($data); + $post_string = json_encode($data); + $request_headers = [ + "POST $path$query HTTP/1.1", + "Host: $host", + "Content-Type: application/json", + "Content-Length: " . strlen($post_string), + "Connection: close", + ]; + foreach ($headers as $header) { + $request_headers[] = $header; + } + $request_headers[] = ""; // Add a blank line to separate headers from body + $request = implode("\r\n", $request_headers) . "\r\n" . $post_string; + + if ($scheme === 'https') { + $port = 443; + $host = 'ssl://' . $host; + } + + $fp = fsockopen($host, $port, $errno, $errstr, 1); + log_message('error','test: ' . __METHOD__ . ': ' . __LINE__ . ' open' . PHP_EOL . var_export($request, 1)); + if (!$fp) { + log_message('error', "Webhook failed: $errstr ($errno)"); + return false; + } else { + fwrite($fp, $request); + fclose($fp); + return true; + } +} + +/** + * 发一个异步的请求 Get + * @param string $url + * @param mixed $query_params + * @param array $headers + */ +function async_get($url, $query_params = [], $headers = []) { + $parts = parse_url($url); + $host = $parts['host']; + $path = isset($parts['path']) ? $parts['path'] : '/'; + $port = isset($parts['port']) ? $parts['port'] : 80; + $scheme = isset($parts['scheme']) ? $parts['scheme'] : 'http'; + $base_query = isset($parts['query']) ? $parts['query'] : ''; + + $query_string = ''; + if (!empty($query_params)) { + $query_string = http_build_query($query_params); + if (!empty($base_query)) { + $query_string = $base_query . '&' . $query_string; + } + } else { + $query_string = $base_query; + } + + $full_url = $path; + if (!empty($query_string)) { + $full_url .= '?' . $query_string; + } + + $request_headers = [ + "GET $full_url HTTP/1.1", + "Host: $host", + "Connection: close", + ]; + + foreach ($headers as $header) { + $request_headers[] = $header; + } + + $request_headers[] = ""; + $request = implode("\r\n", $request_headers); + + if ($scheme === 'https') { + $port = 443; + $host = 'ssl://' . $host; + } + + $fp = fsockopen($host, $port, $errno, $errstr, 1); + log_message('error','test: ' . __METHOD__ . ': ' . __LINE__ . ' open' . PHP_EOL . var_export($request, 1)); + if (!$fp) { + // error_log("Webhook failed: $errstr ($errno)"); + log_message('error', "Webhook failed: $errstr ($errno)"); + return false; + } else { + fwrite($fp, $request); + fclose($fp); + return true; + } +} + +function array_some($array, $condition) { + foreach ($array as $element) { + if ($condition($element)) { + return true; + } + } + return false; +} + /** * 连连支付 * @uses LianlianService 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 6d2bceec..21560bfd 100644 --- a/webht/third_party/pay/models/Online_payment_account_model.php +++ b/webht/third_party/pay/models/Online_payment_account_model.php @@ -615,17 +615,8 @@ class Online_payment_account_model extends CI_Model { return $this->HT->query($sql, $note_sn); } - function query_paypal_note_summary($start, $end) { - $sql = "SELECT pn_mc_currency - ,round(sum(pn_mc_gross), 3) AS _sum_currency - ,round(sum(pn_mc_gross)*to_usd,3) as _sum_usd - ,SUM(sum(pn_mc_gross)*to_usd) OVER () AS running_total - FROM ( - SELECT pn_txn_id - ,pn_invoice - ,cast(pn_mc_gross AS FLOAT) AS pn_mc_gross - ,pn_mc_currency - ,case pn_mc_currency when 'USD' then 1 + function query_paypal_note_summary($start, $end, $to_usd_rate=[]) { + $rates_sql = "case pn_mc_currency when 'USD' then 1 when 'AUD' then 0.63 when 'CAD' then 0.70 when 'CHF' then 1.13 @@ -636,7 +627,26 @@ class Online_payment_account_model extends CI_Model { when 'SGD' then 0.75 when 'NZD' then 0.57 else 1 - end as to_usd + end "; + if (!empty($to_usd_rate)) { + $rates_sql = " case pn_mc_currency when 'USD' then 1 "; + $rates_sql .= "\n when 'CHF' then 1.13 "; + $rates_sql .= "\n when 'NZD' then 0.57 "; + foreach ($to_usd_rate as $key => $ele) { + $rates_sql .= $ele['currency'] ? "\n when '{$ele['from']}' then {$ele['currency']} " : ""; + } + $rates_sql .= " else 1 end "; + } + $sql = "SELECT pn_mc_currency + ,round(sum(pn_mc_gross), 3) AS _sum_currency + ,round(sum(pn_mc_gross)*to_usd,3) as _sum_usd + ,SUM(sum(pn_mc_gross)*to_usd) OVER () AS running_total + FROM ( + SELECT pn_txn_id + ,pn_invoice + ,cast(pn_mc_gross AS FLOAT) AS pn_mc_gross + ,pn_mc_currency + ,$rates_sql as to_usd ,pn_payer_email ,pn_payer ,pn_payment_date @@ -645,12 +655,11 @@ class Online_payment_account_model extends CI_Model { ,ROW_NUMBER() OVER ( PARTITION BY pn_txn_id ORDER BY pn_sn DESC ) AS rn FROM paypal_note p1 WHERE p1.pn_send = 'send' - -- AND p1.pn_datetime BETWEEN '2025-03-02' AND '2025-03-15' AND p1.pn_datetime BETWEEN '{$start}' AND '{$end}' ) cn GROUP BY cn.pn_mc_currency, to_usd order by pn_mc_currency "; - $ret = $paypal_sum = $this->HT->query($sql)->result_array(); + $ret = $this->HT->query($sql)->result_array(); return $ret; } 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 aeb3ce0f..bebe4964 100644 --- a/webht/third_party/pay/models/Online_payment_note_model.php +++ b/webht/third_party/pay/models/Online_payment_note_model.php @@ -589,5 +589,23 @@ class Online_payment_note_model extends CI_Model { return; } + public function query_paypal_current_rate() { + $sql = "SELECT TOP 10 opn.OPN_payFee + ,opn.OPN_payAmount + ,opn.OPN_netAmount + ,opn.OPN_paymentSource + ,opn.OPN_fundSource + ,round(((0 - cast(opn_payfee AS FLOAT) - 0.3) / cast(OPN_payAmount AS FLOAT)), 4) AS calc_rate + -- ,opn.* + FROM OnlinePaymentNote AS opn + WHERE OPN_accountMethod = 15002 + AND opn.OPN_transactionResult = 'completed' + AND cast(OPN_payAmount AS FLOAT) > 100 + AND opn.OPN_paymentSource IS NOT NULL + ORDER BY opn.OPN_completeTime DESC"; + $ret = $this->info->query($sql)->result_array(); + return $ret; + } + }