积分与余额账务系统硬切重构

This commit is contained in:
2026-08-24 15:59:11 +08:00
parent ca12226b39
commit 5cae5b5c93
159 changed files with 7275 additions and 4718 deletions
+208 -108
View File
@@ -17,19 +17,19 @@ trait PayOrders {
* @param string $order_number
* @param array $paid_order
*/
public function on_order_paid(string $order_number, array $paid_order): void {
public function fulfill_paid_order(string $order_number, array $paid_order) {
$product_type = sanitize_key((string) ($paid_order['product_type'] ?? ''));
if ($product_type !== \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE) {
return;
return true;
}
$post_id = (int) ($paid_order['product_id'] ?? 0);
if ($post_id <= 0) {
return;
return true;
}
// Only count normal posts for content purchases.
$post = get_post($post_id);
if (!($post instanceof \WP_Post) || $post->post_type !== 'post') {
return;
return true;
}
if (function_exists('aksrt_bump_content_sales_volume')) {
aksrt_bump_content_sales_volume($post_id, 1);
@@ -53,21 +53,31 @@ trait PayOrders {
}
// Consume coupon + write affiliate commission (cash content only; idempotent).
$this->finalize_content_order_side_effects($order_number, $paid_order);
$side_effects = $this->finalize_content_order_side_effects($order_number, $paid_order);
if (is_wp_error($side_effects)) {
return $side_effects;
}
if (class_exists('\AKSRT\Payment\OrderRepository')) {
$completed = \AKSRT\Payment\OrderRepository::get_instance()->update_status(
$order_number,
\AKSRT\Payment\Order::STATUS_COMPLETED,
['note' => __('内容权益已发放。', 'aksrt')]
);
if ($completed && class_exists('\AKSRT\Payment\CreatorRevenue')) {
if (!$completed) {
return new \WP_Error('aksrt_content_fulfillment_failed', __('内容权益发放失败。', 'aksrt'), ['status' => 500]);
}
if (class_exists('\AKSRT\Payment\CreatorRevenue')) {
$completed_order = array_merge($paid_order, [
'order_number' => $order_number,
'status' => \AKSRT\Payment\Order::STATUS_COMPLETED,
]);
\AKSRT\Payment\CreatorRevenue::get_instance()->create_from_paid_order($completed_order);
}
$revenue_id = \AKSRT\Payment\CreatorRevenue::get_instance()->create_from_paid_order($completed_order);
if ($revenue_id < 0) {
return new \WP_Error('aksrt_creator_revenue_conflict', __('同一订单的收益载荷不一致。', 'aksrt'), ['status' => 409]);
}
}
}
return true;
}
@@ -75,25 +85,29 @@ trait PayOrders {
/**
* On paid: burn coupon (if any) and create affiliate rebate log.
*/
private function finalize_content_order_side_effects(string $order_number, array $order): void {
private function finalize_content_order_side_effects(string $order_number, array $order) {
$meta = $this->decode_order_note_meta($order);
if (empty($meta['content_pay'])) {
return;
return true;
}
// Points: no coupon burn / no cash commission.
if (($meta['pay_modo'] ?? '') === 'points') {
return;
return true;
}
$buyer_id = (int) ($order['user_id'] ?? 0);
// Coupon burn (shared helper; idempotent via coupon_usage.order_number).
if (function_exists('aksrt_burn_order_coupon')) {
aksrt_burn_order_coupon($order_number, $meta, $buyer_id);
$coupon = is_array($meta['coupon'] ?? null) ? $meta['coupon'] : [];
$coupon_code = (string) ($coupon['code'] ?? $meta['coupon_code'] ?? '');
if ($coupon_code !== '' && !aksrt_burn_order_coupon($order_number, $meta, $buyer_id)) {
return new \WP_Error('aksrt_coupon_consume_failed', __('优惠券核销失败。', 'aksrt'), ['status' => 409]);
}
}
// Affiliate commission is recorded exactly once by CommissionLedger on
// the canonical aksrt_order_paid event. No order-side legacy writes.
// Affiliate commission is written by the order transition transaction.
return true;
}
@@ -121,7 +135,7 @@ trait PayOrders {
*
* @return array|\WP_Error
*/
public function create_and_pay_points(int $post_id, int $user_id, string $price_type = '') {
public function create_and_pay_points(int $post_id, int $user_id, string $price_type = '', string $operation_key = '') {
$assert = $this->assert_purchasable($post_id, $user_id, $price_type);
if (is_wp_error($assert)) {
return $assert;
@@ -132,7 +146,7 @@ trait PayOrders {
return new \WP_Error('aksrt_wrong_modo', __('该内容不支持积分支付。', 'aksrt'), ['status' => 400]);
}
$amount = (int) ceil((float) ($priced['amount'] ?? 0));
$amount = $this->parse_asset_minor($priced['amount'] ?? 0, 'points');
if ($amount <= 0) {
return [
'success' => true,
@@ -144,13 +158,14 @@ trait PayOrders {
];
}
if (!class_exists('\AKSRT\Payment\Order') || !class_exists('\AKSRT\Credits\Credits')) {
if (!class_exists('\AKSRT\Payment\Order')) {
return new \WP_Error('aksrt_pay_unavailable', __('支付系统不可用。', 'aksrt'), ['status' => 500]);
}
$balance = \AKSRT\Credits\Credits::balance($user_id);
$ledger = \AKSRT\Ledger\LedgerService::get_instance();
$balance = $ledger->balance($user_id, \AKSRT\Ledger\AssetType::POINTS);
if ($balance < $amount) {
return new \WP_Error('aksrt_credits_insufficient', __('积分不足,暂时无法支付。', 'aksrt'), [
return new \WP_Error('aksrt_points_insufficient', __('积分不足,暂时无法支付。', 'aksrt'), [
'status' => 402,
'balance' => $balance,
'cost' => $amount,
@@ -163,69 +178,93 @@ trait PayOrders {
'post_id' => $post_id,
'price_type' => $price_type,
'vip_level' => (int) ($priced['vip_level'] ?? 0),
'base' => (float) ($priced['base'] ?? $amount),
'base' => $this->parse_asset_minor($priced['base'] ?? $amount, 'points'),
'amount' => $amount,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$order_number = \AKSRT\Payment\OrderRepository::get_instance()->create([
'user_id' => $user_id,
'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE,
'product_id' => $post_id,
'amount' => (float) $amount,
'currency' => 'points',
'status' => \AKSRT\Payment\Order::STATUS_PENDING,
'payment_method' => 'points',
'note' => is_string($note) ? $note : '',
'expires_at' => \AKSRT\Settings\PaymentRuntime::get_order_expiry_at(),
]);
$repo = \AKSRT\Payment\OrderRepository::get_instance();
$existing = $operation_key !== '' ? $repo->get_by_request_key($operation_key) : null;
$is_new_order = !is_array($existing);
if (is_array($existing)) {
$existing_meta = $this->decode_order_note_meta($existing);
if ((int) ($existing['user_id'] ?? 0) !== $user_id
|| sanitize_key((string) ($existing['product_type'] ?? '')) !== \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE
|| (int) ($existing['product_id'] ?? 0) !== $post_id
|| (string) ($existing['currency'] ?? '') !== 'points'
|| (int) ($existing['amount'] ?? 0) !== $amount
|| sanitize_key((string) ($existing['payment_method'] ?? '')) !== 'points'
|| (string) ($existing_meta['price_type'] ?? '') !== $price_type
) {
return new \WP_Error('aksrt_ledger_idempotency_conflict', __('相同操作标识已用于其他购买请求。', 'aksrt'), ['status' => 409]);
}
$order_number = (string) $existing['order_number'];
} else {
$order_number = $repo->allocate_order_number();
}
if ($order_number === '') {
return new \WP_Error('aksrt_order_create_failed', __('创建订单失败。', 'aksrt'), ['status' => 500]);
}
$guard = static function () use ($is_new_order, $order_number, $user_id, $post_id, $amount) {
if ($is_new_order) {
return true;
}
global $wpdb;
$table = \AKSRT\Core\DBMigrator::table('order');
$current = $wpdb->get_row($wpdb->prepare("SELECT user_id, product_id, amount, currency, status FROM {$table} WHERE order_number = %s FOR UPDATE", $order_number), ARRAY_A);
if (!is_array($current)
|| (int) ($current['user_id'] ?? 0) !== $user_id
|| (int) ($current['product_id'] ?? 0) !== $post_id
|| (int) ($current['amount'] ?? 0) !== $amount
|| (string) ($current['currency'] ?? '') !== 'points'
|| !in_array((string) ($current['status'] ?? ''), [\AKSRT\Payment\Order::STATUS_CREATED, \AKSRT\Payment\Order::STATUS_PENDING], true)
) {
return new \WP_Error('aksrt_order_confirm_failed', __('订单状态或金额已变化。', 'aksrt'), ['status' => 409]);
}
return true;
};
$lock = class_exists('\AKSRT\Payment\PaymentAttemptLock')
? \AKSRT\Payment\PaymentAttemptLock::acquire($order_number)
: false;
if ($lock === false) {
return new \WP_Error('aksrt_pay_locked', __('该订单正在发起支付,请稍后重试。', 'aksrt'), ['status' => 409]);
}
try {
$deducted = \AKSRT\Credits\Credits::deduct(
$user_id,
$amount,
'content_points_pay',
['type' => 'post', 'id' => $post_id, 'order' => $order_number],
sprintf(__('积分购买《%s》', 'aksrt'), get_the_title($post_id))
);
if (is_wp_error($deducted) || $deducted === false) {
\AKSRT\Payment\Order::get_instance()->update_status($order_number, \AKSRT\Payment\Order::STATUS_CANCELLED, [
'note' => __('积分扣除失败,自动取消', 'aksrt'),
]);
$msg = is_wp_error($deducted) ? $deducted->get_error_message() : __('积分扣除失败。', 'aksrt');
return new \WP_Error('aksrt_credits_deduct_failed', $msg ?: __('积分扣除失败。', 'aksrt'), ['status' => 400]);
}
$paid = \AKSRT\Payment\Order::get_instance()->update_status($order_number, \AKSRT\Payment\Order::STATUS_PAID, [
$deducted = $ledger->debit(
$user_id,
\AKSRT\Ledger\AssetType::POINTS,
$amount,
$operation_key,
'content_points_pay',
['type' => 'order', 'key' => $order_number],
sprintf(__('积分购买《%s》', 'aksrt'), get_the_title($post_id)),
$user_id,
['post_id' => $post_id],
static function () use ($is_new_order, $repo, $order_number, $operation_key, $user_id, $post_id, $amount, $note) {
if ($is_new_order) {
$created = $repo->create([
'order_number' => $order_number,
'user_id' => $user_id,
'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE,
'product_id' => $post_id,
'amount' => $amount,
'currency' => 'points',
'status' => \AKSRT\Payment\Order::STATUS_PENDING,
'payment_method' => 'points',
'note' => is_string($note) ? $note : '',
'expires_at' => \AKSRT\Settings\PaymentRuntime::get_order_expiry_at(),
'request_key' => $operation_key,
]);
if ($created !== $order_number) {
return new \WP_Error('aksrt_order_create_failed', __('创建订单失败。', 'aksrt'), ['status' => 500]);
}
}
$paid = \AKSRT\Payment\Order::get_instance()->update_status($order_number, \AKSRT\Payment\Order::STATUS_PAID, [
'payment_method' => 'points',
'payment_transaction_id' => 'points_' . $order_number,
'note' => sprintf(__('积分支付 %d 积分。', 'aksrt'), $amount),
'require_transition' => true,
]);
if (!$paid) {
\AKSRT\Credits\Credits::add(
$user_id,
$amount,
'content_points_pay_refund',
['type' => 'post', 'id' => $post_id, 'order' => $order_number],
sprintf(__('购买失败退款:%s', 'aksrt'), get_the_title($post_id))
);
return new \WP_Error('aksrt_order_confirm_failed', __('订单确认失败,已尝试退回积分。', 'aksrt'), ['status' => 500]);
}
} finally {
\AKSRT\Payment\PaymentAttemptLock::release($order_number, $lock);
]);
return $paid ? true : new \WP_Error('aksrt_order_confirm_failed', __('订单确认失败。', 'aksrt'), ['status' => 500]);
},
$guard
);
if (is_wp_error($deducted)) {
return $deducted;
}
return [
@@ -234,7 +273,9 @@ trait PayOrders {
'order_number' => $order_number,
'amount' => $amount,
'pay_modo' => 'points',
'balance' => \AKSRT\Credits\Credits::balance($user_id),
'balance' => $ledger->balance($user_id, \AKSRT\Ledger\AssetType::POINTS),
'transaction_id' => $deducted->transaction_id,
'replayed' => $deducted->replayed,
'message' => __('支付成功', 'aksrt'),
'reload' => true,
],
@@ -248,7 +289,7 @@ trait PayOrders {
*
* @return array|\WP_Error
*/
public function create_cash_order(int $post_id, int $user_id, string $payment_method = 'balance', string $price_type = '', string $coupon_code = '') {
public function create_cash_order(int $post_id, int $user_id, string $payment_method = 'balance', string $price_type = '', string $coupon_code = '', string $operation_key = '') {
$assert = $this->assert_purchasable($post_id, $user_id, $price_type);
if (is_wp_error($assert)) {
return $assert;
@@ -279,15 +320,20 @@ trait PayOrders {
return $discounted;
}
$amount = round((float) ($discounted['payable'] ?? 0), 2);
$list_amount = round((float) ($discounted['list_amount'] ?? $amount), 2);
$rebate_discount = round((float) ($discounted['rebate_discount'] ?? 0), 2);
$coupon_discount = round((float) ($discounted['coupon_discount'] ?? 0), 2);
$amount_minor = max(0, (int) ($discounted['payable_minor'] ?? 0));
$list_minor = max(0, (int) ($discounted['list_minor'] ?? $amount_minor));
$rebate_discount_minor = max(0, (int) ($discounted['rebate_discount_minor'] ?? 0));
$coupon_discount_minor = max(0, (int) ($discounted['coupon_discount_minor'] ?? 0));
$amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($amount_minor);
$list_amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($list_minor);
$rebate_discount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($rebate_discount_minor);
$coupon_discount = \AKSRT\Ledger\AssetAmount::decimal_from_minor($coupon_discount_minor);
$coupon_meta = is_array($discounted['coupon'] ?? null) ? $discounted['coupon'] : [];
$referrer_id = (int) ($discounted['referrer_id'] ?? 0);
$rebate_price = round((float) ($discounted['rebate_price'] ?? 0), 2);
$rebate_price_minor = max(0, (int) ($discounted['rebate_price_minor'] ?? 0));
$rebate_price = \AKSRT\Ledger\AssetAmount::decimal_from_minor($rebate_price_minor);
if ($amount <= 0) {
if ($amount_minor <= 0) {
// Free after discount (or free content): create 0-paid order for access + burn coupon.
if (!class_exists('\AKSRT\Payment\Order') || !class_exists('\AKSRT\Payment\OrderRepository')) {
return new \WP_Error('aksrt_pay_unavailable', __('支付系统不可用。', 'aksrt'), ['status' => 500]);
@@ -298,50 +344,71 @@ trait PayOrders {
'post_id' => $post_id,
'price_type' => $price_type,
'vip_level' => (int) ($priced['vip_level'] ?? 0),
'base' => (float) ($priced['base'] ?? $list_amount),
'base' => $this->asset_value($this->parse_asset_minor($priced['base'] ?? $list_amount, '0'), '0'),
'list_amount' => $list_amount,
'rebate_discount' => $rebate_discount,
'coupon_discount' => $coupon_discount,
'discount' => $coupon_discount,
'coupon' => $coupon_meta,
'coupon_code' => (string) ($coupon_meta['code'] ?? $coupon_code),
'amount' => 0,
'payable' => 0,
'amount' => '0.00',
'payable' => '0.00',
'referrer_id' => $referrer_id,
'rebate_price' => 0,
'rebate_price' => '0.00',
'ip_address' => function_exists('aksrt_pay_client_ip') ? aksrt_pay_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''),
'guest' => $user_id <= 0 ? 1 : 0,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$order_number = \AKSRT\Payment\OrderRepository::get_instance()->create([
$repo = \AKSRT\Payment\OrderRepository::get_instance();
$existing = $operation_key !== '' ? $repo->get_by_request_key($operation_key) : null;
$replayed = is_array($existing);
if (is_array($existing)) {
if ((int) ($existing['user_id'] ?? 0) !== max(0, $user_id)
|| sanitize_key((string) ($existing['product_type'] ?? '')) !== \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE
|| (int) ($existing['product_id'] ?? 0) !== $post_id
|| sanitize_key((string) ($existing['payment_method'] ?? '')) !== 'free'
|| (string) ($existing['amount'] ?? '') !== '0.00'
) {
return new \WP_Error('aksrt_ledger_idempotency_conflict', __('相同操作标识已用于其他内容请求。', 'aksrt'), ['status' => 409]);
}
$order_number = (string) $existing['order_number'];
} else {
$order_number = $repo->create([
'user_id' => max(0, $user_id),
'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE,
'product_id' => $post_id,
'amount' => 0.0,
'amount' => '0.00',
'currency' => 'CNY',
'status' => \AKSRT\Payment\Order::STATUS_PENDING,
'payment_method' => 'free',
'note' => is_string($note) ? $note : '',
'expires_at' => \AKSRT\Settings\PaymentRuntime::get_order_expiry_at(),
]);
'request_key' => $operation_key,
]);
}
if ($order_number === '') {
return new \WP_Error('aksrt_order_create_failed', __('创建订单失败。', 'aksrt'), ['status' => 500]);
}
$paid = \AKSRT\Payment\Order::get_instance()->update_status($order_number, \AKSRT\Payment\Order::STATUS_PAID, [
'payment_method' => 'free',
'payment_transaction_id' => 'free_' . $order_number,
'note' => __('优惠后无需支付。', 'aksrt'),
]);
if (!$paid) {
return new \WP_Error('aksrt_order_confirm_failed', __('订单确认失败。', 'aksrt'), ['status' => 500]);
}
$status = is_array($existing) ? (string) ($existing['status'] ?? '') : '';
if (!in_array($status, [\AKSRT\Payment\Order::STATUS_PAID, \AKSRT\Payment\Order::STATUS_DELIVERED, \AKSRT\Payment\Order::STATUS_COMPLETED], true)) {
$paid = \AKSRT\Payment\Order::get_instance()->update_status($order_number, \AKSRT\Payment\Order::STATUS_PAID, [
'payment_method' => 'free',
'payment_transaction_id' => 'free_' . $order_number,
'note' => __('优惠后无需支付。', 'aksrt'),
]);
if (!$paid) {
return new \WP_Error('aksrt_order_confirm_failed', __('订单确认失败。', 'aksrt'), ['status' => 500]);
}
}
return [
'success' => true,
'data' => [
'order_number' => $order_number,
'amount' => 0,
'amount' => '0.00',
'pay_modo' => '0',
'free' => true,
'transaction_id' => 'free_' . $order_number,
'replayed' => $replayed,
'message' => __('无需支付,已可访问。', 'aksrt'),
'reload' => true,
],
@@ -358,21 +425,31 @@ trait PayOrders {
if ($user_id <= 0 && in_array($payment_method, ['balance', 'points'], true)) {
$payment_method = 'alipay';
}
$amount_decimal = $amount;
$coupon_code_norm = (string) ($coupon_meta['code'] ?? $coupon_code);
// Resume existing pending content order for this post when amount + coupon match (logged-in only).
$pending = $user_id > 0 ? $this->find_pending_content_order($user_id, $post_id) : null;
// A retry resolves only through its request key; a new operation never reuses another pending order.
$pending = $operation_key !== '' ? \AKSRT\Payment\OrderRepository::get_instance()->get_by_request_key($operation_key) : null;
$can_resume = false;
if ($pending && abs((float) ($pending['amount'] ?? 0) - $amount) < 0.001) {
if (is_array($pending)) {
$pending_meta = $this->decode_order_note_meta($pending);
$pending_coupon = (string) ($pending_meta['coupon_code'] ?? '');
if (is_array($pending_meta['coupon'] ?? null)) {
$pending_coupon = (string) ($pending_meta['coupon']['code'] ?? $pending_coupon);
}
if ($pending_coupon === $coupon_code_norm) {
$can_resume = true;
}
$can_resume = (int) ($pending['user_id'] ?? 0) === max(0, $user_id)
&& sanitize_key((string) ($pending['product_type'] ?? '')) === \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE
&& (int) ($pending['product_id'] ?? 0) === $post_id
&& (string) ($pending['amount'] ?? '') === $amount_decimal
&& strtoupper((string) ($pending['currency'] ?? '')) === 'CNY'
&& sanitize_key((string) ($pending['payment_method'] ?? '')) === $payment_method
&& (string) ($pending_meta['price_type'] ?? '') === $price_type
&& (int) ($pending_meta['post_id'] ?? 0) === $post_id
&& $pending_coupon === $coupon_code_norm;
if (!$can_resume) {
return new \WP_Error('aksrt_ledger_idempotency_conflict', __('相同操作标识已用于其他内容购买请求。', 'aksrt'), ['status' => 409]);
}
}
if ($can_resume) {
$order_number = (string) ($pending['order_number'] ?? '');
@@ -384,15 +461,15 @@ trait PayOrders {
'post_id' => $post_id,
'price_type' => $price_type,
'vip_level' => (int) ($priced['vip_level'] ?? 0),
'base' => (float) ($priced['base'] ?? $list_amount),
'base' => $this->asset_value($this->parse_asset_minor($priced['base'] ?? $list_amount, '0'), '0'),
'list_amount' => $list_amount,
'rebate_discount' => $rebate_discount,
'coupon_discount' => $coupon_discount,
'discount' => $coupon_discount,
'coupon' => $coupon_meta,
'coupon_code' => $coupon_code_norm,
'amount' => $amount,
'payable' => $amount,
'amount' => $amount_decimal,
'payable' => $amount_decimal,
'referrer_id' => $referrer_id,
'rebate_price' => $rebate_price,
'ip_address' => function_exists('aksrt_pay_client_ip') ? aksrt_pay_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''),
@@ -403,12 +480,13 @@ trait PayOrders {
'user_id' => max(0, $user_id),
'product_type' => \AKSRT\Core\DomainModel::ORDER_PRODUCT_RESOURCE,
'product_id' => $post_id,
'amount' => $amount,
'amount' => $amount_decimal,
'currency' => 'CNY',
'status' => \AKSRT\Payment\Order::STATUS_PENDING,
'payment_method' => $payment_method,
'note' => is_string($note) ? $note : '',
'expires_at' => \AKSRT\Settings\PaymentRuntime::get_order_expiry_at(),
'request_key' => $operation_key,
]);
if ($order_number === '') {
@@ -425,6 +503,23 @@ trait PayOrders {
if ($payment_method === '') {
$payment_method = $user_id > 0 ? 'balance' : 'alipay';
}
if ($can_resume && in_array((string) ($order['status'] ?? ''), [\AKSRT\Payment\Order::STATUS_PAID, \AKSRT\Payment\Order::STATUS_DELIVERED, \AKSRT\Payment\Order::STATUS_COMPLETED], true)) {
$ledger_key = \AKSRT\Ledger\OperationKey::deterministic('order-payment', [$order_number]);
$history = \AKSRT\Ledger\LedgerQuery::get_instance()->history(['operation_key' => $ledger_key, 'page' => 1, 'per_page' => 1]);
return [
'success' => true,
'data' => [
'order_number' => $order_number,
'amount' => $amount_decimal,
'pay_modo' => '0',
'transaction_id' => (int) ($history['items'][0]['id'] ?? 0),
'replayed' => true,
'balance' => \AKSRT\Ledger\LedgerService::get_instance()->balance_decimal($user_id),
'message' => __('支付成功', 'aksrt'),
'reload' => true,
],
];
}
$order['subject'] = sprintf(
/* translators: %s: post title */
@@ -433,7 +528,7 @@ trait PayOrders {
);
$order['payment_method'] = $payment_method;
// Ensure gateway uses discounted amount.
$order['amount'] = $amount;
$order['amount'] = $amount_decimal;
if (!class_exists('\AKSRT\Payment\Gateway')) {
return new \WP_Error('aksrt_pay_unavailable', __('支付网关不可用。', 'aksrt'), ['status' => 500]);
@@ -455,7 +550,7 @@ trait PayOrders {
return new \WP_Error(
(string) ($payment_result['code'] ?? 'aksrt_pay_failed'),
(string) ($payment_result['message'] ?? __('支付失败。', 'aksrt')),
['status' => 402, 'order_number' => $order_number]
['status' => (int) ($payment_result['status'] ?? 400), 'order_number' => $order_number]
);
}
@@ -467,11 +562,13 @@ trait PayOrders {
'payment_url' => (string) ($payment_result['payment_url'] ?? ''),
'qr_content' => (string) ($payment_result['qr_content'] ?? ''),
'order_number' => $order_number,
'amount' => $amount,
'amount' => $amount_decimal,
'pay_modo' => '0',
'message' => $payment_result['message'],
'reload' => false,
'poll' => true,
'transaction_id' => 0,
'replayed' => false,
],
];
}
@@ -480,8 +577,11 @@ trait PayOrders {
'success' => true,
'data' => [
'order_number' => $order_number,
'amount' => $amount,
'amount' => $amount_decimal,
'pay_modo' => '0',
'transaction_id' => (int) ($payment_result['ledger_transaction_id'] ?? 0),
'replayed' => !empty($payment_result['replayed']),
'balance' => $user_id > 0 ? \AKSRT\Ledger\LedgerService::get_instance()->balance_decimal($user_id) : '0.00',
'message' => $payment_result['message'],
'reload' => true,
],