Compare commits
3 Commits
ca5e7a62ae
...
4727881e05
| Author | SHA1 | Date |
|---|---|---|
|
|
4727881e05 | |
|
|
73dc9ca3c3 | |
|
|
a9acdacf80 |
|
|
@ -19,6 +19,7 @@ function yoone_moneris_store_payment_data($order, $result, $request) {
|
|||
} elseif (is_array($result) && isset($result['payment_method'])) {
|
||||
$pm = (string) $result['payment_method'];
|
||||
}
|
||||
error_log('【Yoone Moneris Blocks】订单处理 hook,payment_method=' . ($pm ?: '未提供'));
|
||||
if ('yoone_moneris' !== $pm) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -34,9 +35,13 @@ function yoone_moneris_store_payment_data($order, $result, $request) {
|
|||
} else {
|
||||
$payload = is_array($data) ? $data : array();
|
||||
}
|
||||
error_log('【Yoone Moneris Blocks】解析 payment_method_data:' . print_r($payload, true));
|
||||
if (! empty($payload)) {
|
||||
$order->update_meta_data('_yoone_moneris_pm_data', $payload);
|
||||
$order->save();
|
||||
error_log('【Yoone Moneris Blocks】已保存 Blocks 支付数据到订单 _yoone_moneris_pm_data');
|
||||
} else {
|
||||
error_log('【Yoone Moneris Blocks】未收到有效的 payment_method_data');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -293,11 +293,13 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
if ($selected_token_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 新卡:需要确保卡片字段完整
|
||||
$card = $this->get_posted_card();
|
||||
error_log('【Yoone Moneris】validate_fields 读取到卡片字段:' . print_r($card, true));
|
||||
if (empty($card['number']) || empty($card['exp_month']) || empty($card['exp_year']) || empty($card['cvc'])) {
|
||||
wc_add_notice(__('请填写完整的银行卡信息。' . $card, 'yoone-moneris'), 'error');
|
||||
wc_add_notice(__('请填写完整的银行卡信息。', 'yoone-moneris'), 'error');
|
||||
error_log('【Yoone Moneris】validate_fields 缺少字段:number=' . (empty($card['number']) ? '空' : '已填') . ' exp_month=' . (empty($card['exp_month']) ? '空' : $card['exp_month']) . ' exp_year=' . (empty($card['exp_year']) ? '空' : $card['exp_year']) . ' cvc=' . (empty($card['cvc']) ? '空' : '已填'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -329,9 +331,13 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
*/
|
||||
protected function get_posted_card()
|
||||
{
|
||||
// 记录原始支付方式选择
|
||||
$raw_pm = isset($_POST['payment_method']) ? wc_clean(wp_unslash($_POST['payment_method'])) : '';
|
||||
error_log('【Yoone Moneris】get_posted_card payment_method=' . ($raw_pm ?: '未提交') . ' 当前网关=' . $this->id);
|
||||
// 如果当前提交并非选择我们网关,直接返回空卡数据,避免误读其他网关字段
|
||||
$pm = isset($_POST['payment_method']) ? wc_clean(wp_unslash($_POST['payment_method'])) : '';
|
||||
$pm = $raw_pm;
|
||||
if ($pm && $pm !== $this->id) {
|
||||
error_log('【Yoone Moneris】get_posted_card 非本网关提交,返回空卡数据');
|
||||
return array('number' => '', 'exp_month' => '', 'exp_year' => '', 'cvc' => '');
|
||||
}
|
||||
|
||||
|
|
@ -377,6 +383,8 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
'card_cvc',
|
||||
));
|
||||
|
||||
error_log('【Yoone Moneris】get_posted_card 原始读取:number=' . (isset($number) ? ('len=' . strlen((string)$number)) : '未读') . ' expiry_raw=' . ($expiry_raw ?: '空') . ' cvc=' . ($cvc ? ('len=' . strlen((string)$cvc)) : '空'));
|
||||
|
||||
// 如果没有组合有效期,尝试读取分拆的 月/年 字段
|
||||
$exp_month = $read_post(array(
|
||||
$this->id . '-exp-month',
|
||||
|
|
@ -396,6 +404,7 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
'card-expiry-year',
|
||||
'expiry_year',
|
||||
));
|
||||
error_log('【Yoone Moneris】get_posted_card 原始读取:exp_month=' . ($exp_month ?: '空') . ' exp_year=' . ($exp_year ?: '空'));
|
||||
|
||||
// 规范化:仅保留数字
|
||||
$number = preg_replace('/\D+/', '', (string) $number);
|
||||
|
|
@ -420,6 +429,9 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
$exp_year = '20' . $exp_year;
|
||||
}
|
||||
|
||||
$masked = $number ? str_repeat('*', max(strlen($number) - 4, 0)) . substr($number, -4) : '';
|
||||
error_log('【Yoone Moneris】get_posted_card 规范化:card=' . ($masked ?: '空') . ' len=' . strlen($number) . ' exp_month=' . ($exp_month ?: '空') . ' exp_year=' . ($exp_year ?: '空') . ' cvc_len=' . ($cvc ? strlen($cvc) : 0));
|
||||
|
||||
return array(
|
||||
'number' => $number,
|
||||
'exp_month' => $exp_month,
|
||||
|
|
@ -441,10 +453,15 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
// 当用户选择“已保存的卡”,此字段会传递一个 token 的 ID;当选择“使用新卡”,该字段值为 'new'。
|
||||
// 注意:此字段由 Woo 默认信用卡表单生成,适用于经典结账;如果使用 Blocks 结账,需要对应 Blocks 集成来产生等效数据。
|
||||
$field = 'wc-' . $this->id . '-payment-token';
|
||||
if (isset($_POST[$field])) {
|
||||
$posted = wc_clean(wp_unslash($_POST[$field]));
|
||||
error_log('【Yoone Moneris】get_selected_token_id 提交字段 ' . $field . ' = ' . $posted);
|
||||
}
|
||||
if (isset($_POST[$field]) && 'new' !== $_POST[$field]) {
|
||||
// 将提交的令牌 ID 转为整数,后续用 WC_Payment_Tokens::get( $id ) 读取具体令牌对象
|
||||
return absint($_POST[$field]);
|
||||
}
|
||||
error_log('【Yoone Moneris】get_selected_token_id 未选择已保存令牌或选择了新卡');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -484,15 +501,29 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
*/
|
||||
protected function create_wc_token($res, $user_id)
|
||||
{
|
||||
error_log('【yoone moneris 】创建 WC 支付令牌,tokenize_card 返回结果' . print_r($res, true));
|
||||
$token = new WC_Payment_Token_CC();
|
||||
// 兼容 data_key 命名
|
||||
if (empty($res['token']) && ! empty($res['data_key'])) {
|
||||
$res['token'] = $res['data_key'];
|
||||
error_log('【Yoone Moneris】create_wc_token 使用 data_key 作为 token');
|
||||
}
|
||||
$token->set_token($res['token']);
|
||||
$token->set_gateway_id($this->id);
|
||||
$token->set_user_id($user_id);
|
||||
$token->set_last4(substr(preg_replace('/\D+/', '', (string) $res['last4'] ?? ''), -4) ?: '0000');
|
||||
$token->set_expiry_month(preg_replace('/\D+/', '', (string) ($res['exp_month'] ?? '')) ?: '01');
|
||||
$token->set_expiry_year(preg_replace('/\D+/', '', (string) ($res['exp_year'] ?? '')) ?: (date('Y') + 1));
|
||||
// 设置卡类型(若有),避免 Woo 对必填字段校验失败
|
||||
if (! empty($res['brand'])) {
|
||||
$token->set_card_type((string) $res['brand']);
|
||||
}
|
||||
$token->save();
|
||||
return $token->get_id();
|
||||
$tid = $token->get_id();
|
||||
if (! $tid) {
|
||||
error_log('【Yoone Moneris】create_wc_token 保存失败:WC_Token 未生成 ID,检查必填字段。');
|
||||
}
|
||||
return $tid;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -504,17 +535,22 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
*/
|
||||
public function process_payment($order_id)
|
||||
{
|
||||
error_log('【Yoone Moneris】process_payment 开始,order_id=' . $order_id);
|
||||
$order = wc_get_order($order_id);
|
||||
if (! $order) {
|
||||
error_log('【Yoone Moneris】无法获取订单对象,终止');
|
||||
return array('result' => 'fail');
|
||||
}
|
||||
$user_id = $order->get_user_id();
|
||||
|
||||
// 支持 Blocks:若从 Store API 捕获到支付数据,优先使用该数据
|
||||
$blocks_data = is_object($order) && method_exists($order, 'get_meta') ? (array) $order->get_meta('_yoone_moneris_pm_data') : array();
|
||||
$pm_meta = $order->get_meta('_yoone_moneris_pm_data', true);
|
||||
if (! empty($pm_meta)) {
|
||||
error_log('【Yoone Moneris】订单存在 Blocks/Store API 支付数据 _yoone_moneris_pm_data=' . print_r($pm_meta, true));
|
||||
} else {
|
||||
error_log('【Yoone Moneris】订单未找到 _yoone_moneris_pm_data 元数据');
|
||||
}
|
||||
|
||||
// 选择已保存的令牌或创建新令牌
|
||||
$selected_token_id = $this->get_selected_token_id();
|
||||
if (! $selected_token_id && ! empty($blocks_data['saved_token_id']) && 'new' !== $blocks_data['saved_token_id']) {
|
||||
$selected_token_id = absint($blocks_data['saved_token_id']);
|
||||
}
|
||||
$token_string = '';
|
||||
|
||||
if ($selected_token_id) {
|
||||
|
|
@ -527,31 +563,40 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
}
|
||||
} else {
|
||||
// 创建新令牌(占位)
|
||||
$card = $this->get_posted_card();
|
||||
// 若 Blocks 提供了卡片数据,使用其值覆盖经典表单读取结果
|
||||
if (! empty($blocks_data)) {
|
||||
$normalize = function($v){ return preg_replace('/\D+/', '', (string) $v); };
|
||||
$number = isset($blocks_data['number']) ? $normalize($blocks_data['number']) : '';
|
||||
$cvc = isset($blocks_data['cvc']) ? $normalize($blocks_data['cvc']) : '';
|
||||
$exp_month = isset($blocks_data['exp_month']) ? $normalize($blocks_data['exp_month']) : '';
|
||||
$exp_year = isset($blocks_data['exp_year']) ? $normalize($blocks_data['exp_year']) : '';
|
||||
if (strlen($exp_year) === 2) { $exp_year = '20' . $exp_year; }
|
||||
// 优先使用 Blocks/Store API 保存到订单的支付数据
|
||||
$card = array();
|
||||
if (is_array($pm_meta) && ! empty($pm_meta)) {
|
||||
$card = array(
|
||||
'number' => $number ?: $card['number'],
|
||||
'exp_month' => $exp_month ?: $card['exp_month'],
|
||||
'exp_year' => $exp_year ?: $card['exp_year'],
|
||||
'cvc' => $cvc ?: $card['cvc'],
|
||||
'number' => preg_replace('/\D+/', '', (string) ($pm_meta['number'] ?? '')),
|
||||
'exp_month' => preg_replace('/\D+/', '', (string) ($pm_meta['exp_month'] ?? '')),
|
||||
'exp_year' => preg_replace('/\D+/', '', (string) ($pm_meta['exp_year'] ?? '')),
|
||||
'cvc' => preg_replace('/\D+/', '', (string) ($pm_meta['cvc'] ?? '')),
|
||||
);
|
||||
error_log('【Yoone Moneris】使用 Blocks/Store API 数据作为卡片来源:' . print_r($card, true));
|
||||
}
|
||||
if (empty($card['number']) || empty($card['exp_month']) || empty($card['exp_year']) || empty($card['cvc'])) {
|
||||
// 退回到经典结账表单的 POST 字段
|
||||
$card = $this->get_posted_card();
|
||||
error_log('【Yoone Moneris】使用经典结账 POST 字段作为卡片来源:' . print_r($card, true));
|
||||
}
|
||||
$res = $this->api()->tokenize_card($card);
|
||||
error_log('【Yoone Moneris】tokenize_card 返回=' . print_r($res, true));
|
||||
if (empty($res['success'])) {
|
||||
wc_add_notice(__('令牌化失败:', 'yoone-moneris') . $res['error'], 'error');
|
||||
error_log('【Yoone Moneris】令牌化失败:' . ($res['error'] ?? '未知错误'));
|
||||
return array('result' => 'fail');
|
||||
}
|
||||
// 兼容 data_key 命名
|
||||
if (empty($res['token']) && ! empty($res['data_key'])) {
|
||||
$res['token'] = $res['data_key'];
|
||||
error_log('【Yoone Moneris】tokenize_card 返回使用 data_key 作为 token');
|
||||
}
|
||||
$token_string = $res['token'];
|
||||
error_log('【Yoone Moneris】新令牌创建成功,token_len=' . strlen($token_string) . ' last4=' . ($res['last4'] ?? ''));
|
||||
// 保存到用户
|
||||
if ($user_id) {
|
||||
$wc_token_id = $this->create_wc_token($res + ['exp_month' => $card['exp_month'], 'exp_year' => $card['exp_year']], $user_id);
|
||||
error_log('【Yoone Moneris】已保存令牌到用户,wc_token_id=' . $wc_token_id . ' user_id=' . $user_id);
|
||||
$order->add_payment_token($wc_token_id);
|
||||
}
|
||||
}
|
||||
|
|
@ -559,15 +604,19 @@ class Yoone_Gateway_Moneris extends WC_Payment_Gateway_CC
|
|||
// 首笔扣款
|
||||
$amount = $order->get_total();
|
||||
$currency = $order->get_currency();
|
||||
error_log('【Yoone Moneris】准备扣款:amount=' . $amount . ' currency=' . $currency . ' order_id=' . $order_id);
|
||||
$charge = $this->api()->charge_token($token_string, $amount, $currency, $order_id);
|
||||
error_log('【Yoone Moneris】charge_token 返回=' . print_r($charge, true));
|
||||
if (empty($charge['success'])) {
|
||||
wc_add_notice(__('支付失败:', 'yoone-moneris') . ($charge['error'] ?? ''), 'error');
|
||||
error_log('【Yoone Moneris】支付失败:' . ($charge['error'] ?? '未知错误'));
|
||||
return array('result' => 'fail');
|
||||
}
|
||||
|
||||
// 标记订单已支付
|
||||
$order->payment_complete($charge['transaction_id'] ?? '');
|
||||
$order->add_order_note(sprintf('Moneris 首付成功,交易号:%s', $charge['transaction_id'] ?? 'N/A'));
|
||||
error_log('【Yoone Moneris】支付成功,transaction_id=' . ($charge['transaction_id'] ?? ''));
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
$this->http_method = isset( $config['http_method'] ) ? strtoupper( (string) $config['http_method'] ) : $this->http_method;
|
||||
$this->timeout = isset( $config['timeout'] ) ? absint( $config['timeout'] ) : $this->timeout;
|
||||
}
|
||||
yoone_moneris_log_debug( 'Moneris API 配置', array(
|
||||
error_log( 'Moneris API 配置' . print_r( array(
|
||||
'store_id' => $this->store_id,
|
||||
'sandbox' => $this->sandbox,
|
||||
'country_code' => $this->country_code,
|
||||
|
|
@ -61,7 +61,7 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
'path_override'=> $this->path_override,
|
||||
'http_method' => $this->http_method,
|
||||
'timeout' => $this->timeout,
|
||||
) );
|
||||
) ,true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -88,7 +88,11 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
'cvdValue' => preg_replace( '/\D+/', '', (string) $card['cvc'] ),
|
||||
);
|
||||
}
|
||||
$num = isset($card['number']) ? preg_replace('/\D+/', '', (string) $card['number']) : '';
|
||||
$masked = $num ? str_repeat('*', max(strlen($num) - 4, 0)) . substr($num, -4) : '';
|
||||
error_log('【Yoone Moneris API】tokenize_card 请求:last4=' . ($num ? substr($num, -4) : '') . ' len=' . strlen($num) . ' expdate=' . $payload['expdate'] . ' cryptType=' . $payload['cryptType']);
|
||||
$res = $this->send_moneris_xml( 'res_add_cc', $payload );
|
||||
error_log('$res11111111'. print_r($res, true));
|
||||
if ( $res['ok'] ) {
|
||||
return array(
|
||||
'success' => true,
|
||||
|
|
@ -117,21 +121,51 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
if ( empty( $this->store_id ) || empty( $this->api_token ) ) {
|
||||
return array( 'success' => false, 'error' => 'Missing Moneris credentials' );
|
||||
}
|
||||
// 为避免重复 orderId 导致主机拒绝,生成唯一订单 ID
|
||||
if ( ! function_exists( 'yoone_moneris_unique_order_id' ) ) {
|
||||
require_once __DIR__ . '/utils/orderid.php';
|
||||
}
|
||||
$unique_order_id = yoone_moneris_unique_order_id( $order_id );
|
||||
$type = $capture ? 'res_purchase_cc' : 'res_preauth_cc';
|
||||
$payload = array(
|
||||
'dataKey' => (string) $token,
|
||||
'orderId' => (string) $order_id,
|
||||
'orderId' => (string) $unique_order_id,
|
||||
'amount' => $this->format_amount( $amount ),
|
||||
'cryptType' => $this->crypt_type,
|
||||
);
|
||||
error_log('【Yoone Moneris API】charge_token 请求:type=' . $type . ' token_len=' . strlen($token) . ' amount=' . $payload['amount'] . ' currency=' . $currency . ' orderId=' . $unique_order_id . ' (源Woo订单ID=' . $order_id . ')');
|
||||
$res = $this->send_moneris_xml( $type, $payload );
|
||||
if ( $res['ok'] ) {
|
||||
return array(
|
||||
'success' => true,
|
||||
'transaction_id' => (string) ( $res['receipt']['txnNumber'] ?? '' ),
|
||||
'order_id_used' => $unique_order_id,
|
||||
'retry' => false,
|
||||
);
|
||||
}
|
||||
return array( 'success' => false, 'error' => (string) $res['error'] );
|
||||
// 如果出现系统错误,尝试一次自动重试(更换新的唯一 orderId)
|
||||
$err_msg = isset($res['error']) ? (string)$res['error'] : '';
|
||||
$is_system_error = stripos($err_msg, 'SYSTEM ERROR') !== false;
|
||||
if ( $is_system_error ) {
|
||||
$retry_order_id = yoone_moneris_unique_order_id( $order_id );
|
||||
$payload['orderId'] = (string) $retry_order_id;
|
||||
error_log('【Yoone Moneris API】检测到 SYSTEM ERROR,准备重试一次。新的 orderId=' . $retry_order_id);
|
||||
// 短暂延时,避免立即重复错误
|
||||
usleep(300 * 1000);
|
||||
$res_retry = $this->send_moneris_xml( $type, $payload );
|
||||
if ( $res_retry['ok'] ) {
|
||||
return array(
|
||||
'success' => true,
|
||||
'transaction_id' => (string) ( $res_retry['receipt']['txnNumber'] ?? '' ),
|
||||
'order_id_used' => $retry_order_id,
|
||||
'retry' => true,
|
||||
);
|
||||
}
|
||||
// 记录重试失败
|
||||
error_log('【Yoone Moneris API】重试仍失败:' . (string) ($res_retry['error'] ?? 'Unknown'));
|
||||
return array( 'success' => false, 'error' => (string) ($res_retry['error'] ?? $err_msg) );
|
||||
}
|
||||
return array( 'success' => false, 'error' => (string) $err_msg );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -176,6 +210,7 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
if ( ! $endpoint ) {
|
||||
return array( 'ok' => false, 'error' => 'Endpoint not configured' );
|
||||
}
|
||||
error_log('【Yoone Moneris API】发送 XML:type=' . $type . ' endpoint=' . $endpoint);
|
||||
|
||||
// 构建请求体
|
||||
$body = array(
|
||||
|
|
@ -189,6 +224,13 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
|
||||
$xml = $this->array_to_moneris_xml( array( 'request' => $body ) );
|
||||
|
||||
// 日志:打印部分已脱敏的 XML 以便排查格式问题(掩码 pan、data_key、api_token)
|
||||
$xml_log = $xml;
|
||||
$xml_log = preg_replace('/<pan>[^<]*<\/pan>/', '<pan>****</pan>', $xml_log);
|
||||
$xml_log = preg_replace('/<data_key>[^<]*<\/data_key>/', '<data_key>****</data_key>', $xml_log);
|
||||
$xml_log = preg_replace('/<api_token>[^<]*<\/api_token>/', '<api_token>****</api_token>', $xml_log);
|
||||
error_log('【Yoone Moneris API】请求 XML(脱敏)前 400 字符:' . substr($xml_log, 0, 400));
|
||||
|
||||
$args = array(
|
||||
'method' => $this->http_method ?: 'POST',
|
||||
'timeout' => $this->timeout,
|
||||
|
|
@ -203,26 +245,33 @@ class Yoone_Moneris_API implements Yoone_Moneris_API_Interface {
|
|||
// 仅支持 POST
|
||||
$resp = wp_remote_post( $endpoint, $args );
|
||||
if ( is_wp_error( $resp ) ) {
|
||||
error_log('【Yoone Moneris API】HTTP 错误:' . $resp->get_error_message());
|
||||
return array( 'ok' => false, 'error' => $resp->get_error_message() );
|
||||
}
|
||||
$code = wp_remote_retrieve_response_code( $resp );
|
||||
$raw = wp_remote_retrieve_body( $resp );
|
||||
if ( $code < 200 || $code >= 300 ) {
|
||||
error_log('【Yoone Moneris API】HTTP 非 2xx:code=' . $code . ' body=' . substr($raw, 0, 200));
|
||||
return array( 'ok' => false, 'error' => 'HTTP ' . $code . ' ' . $raw );
|
||||
}
|
||||
|
||||
// 解析 XML
|
||||
$parsed = $this->parse_moneris_xml( $raw );
|
||||
// 打印部分响应原文,便于调试
|
||||
error_log('【Yoone Moneris API】响应原文前 300 字符:' . substr($raw, 0, 300));
|
||||
if ( ! $parsed['parsed'] ) {
|
||||
error_log('【Yoone Moneris API】XML 解析失败:' . ($parsed['error'] ?? 'Unknown'));
|
||||
return array( 'ok' => false, 'error' => 'Parse error: ' . ( $parsed['error'] ?? 'Unknown' ) );
|
||||
}
|
||||
$receipt = $parsed['receipt'];
|
||||
$approved = $this->is_approved( $receipt );
|
||||
if ( ! $approved ) {
|
||||
$message = isset( $receipt['message'] ) ? $receipt['message'] : ( $receipt['Message'] ?? 'Declined' );
|
||||
error_log('【Yoone Moneris API】交易未批准:ResponseCode=' . ($receipt['responseCode'] ?? $receipt['response_code'] ?? '') . ' message=' . $message);
|
||||
return array( 'ok' => false, 'error' => $message );
|
||||
}
|
||||
|
||||
error_log('【Yoone Moneris API】交易批准:ResponseCode=' . ($receipt['responseCode'] ?? $receipt['response_code'] ?? '') . ' txnNumber=' . ($receipt['txnNumber'] ?? $receipt['txn_number'] ?? ''));
|
||||
error_log('receipt'. print_r($receipt,true));
|
||||
return array( 'ok' => true, 'receipt' => $receipt );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用于 Moneris 的唯一订单 ID(避免重复 orderId 导致主机拒绝)。
|
||||
*
|
||||
* 规则:<原始订单ID>-<毫秒时间戳>-<四位随机数>
|
||||
* 示例:1234-1730835123456-4821
|
||||
*
|
||||
* 注意:Moneris 对 orderId 的长度是有限制的(通常不超过 50 字符)。本实现控制在合理长度范围内。
|
||||
* 如需自定义格式,可在此函数中调整。
|
||||
*
|
||||
* @param int|string $order_id WooCommerce 订单 ID
|
||||
* @return string 唯一订单 ID 字符串
|
||||
*/
|
||||
function yoone_moneris_unique_order_id( $order_id ) {
|
||||
// 毫秒级时间戳
|
||||
$ms = (int) floor( microtime( true ) * 1000 );
|
||||
// 四位随机数
|
||||
$rand = mt_rand( 1000, 9999 );
|
||||
// 仅保留数字和字母,避免特殊字符
|
||||
$base = preg_replace( '/[^a-zA-Z0-9_-]/', '', (string) $order_id );
|
||||
// 拼接唯一后缀
|
||||
$unique = $base . '-' . $ms . '-' . $rand;
|
||||
// 限长保护(最多 50 字符)
|
||||
if ( strlen( $unique ) > 50 ) {
|
||||
// 若过长,截断前半部分(保留后缀)
|
||||
$unique = substr( $base, 0, max( 1, 50 - ( 1 + strlen( (string) $ms ) + 1 + 4 ) ) ) . '-' . $ms . '-' . $rand;
|
||||
}
|
||||
return $unique;
|
||||
}
|
||||
Loading…
Reference in New Issue