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;
+ }
+
}