feat(forum): P1 topic coupons, P2 plate follow gateway, cash creator revenue
- Topic_Pay: soft/hard coupon validate, payable amount, free-after-discount, paid burn - Creator_Revenue: settle content/topic/plate_follow cash (type=order), keep shop path - Plate VIP1/VIP2 meta + resolve_plate_follow_pay_price via aksrt_get_user_vip_level - New AKSRT_Plate_Follow_Pay REST multi-gateway; remove Credits×100 money bypass - Frontend: cms-download plate_follow apiKind + forum-governance money cashier bridge
This commit is contained in:
1 parent
1a15ae7cea
commit
78d3189f8f
14 files changed
+1189
-169
No files matched your search
@@ -0,0 +1,626 @@
|
||||
<?php
|
||||
/**
|
||||
* AKSRT Plate Follow Pay — multi-gateway cashier for paid plate follow (cash only).
|
||||
*
|
||||
* Contract:
|
||||
* - modo = money plates only (points stay on purchase_plate_follow AJAX)
|
||||
* - product_type = plate_follow, product_id = plate_id
|
||||
* - order note.plate_follow_pay = 1
|
||||
* - paid → mark_plate_followed (idempotent)
|
||||
* - no coupons this phase
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class AKSRT_Plate_Follow_Pay {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance(): self {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
add_action('rest_api_init', [$this, 'register_routes']);
|
||||
add_action('aksrt_order_paid', [$this, 'on_order_paid'], 16, 2);
|
||||
}
|
||||
|
||||
public function register_routes(): void {
|
||||
register_rest_route('aksrt/v1', '/pay/plate-follow/(?P<id>\\d+)', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'rest_preview'],
|
||||
'permission_callback' => [$this, 'check_rest_nonce'],
|
||||
],
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'rest_purchase'],
|
||||
'permission_callback' => [$this, 'check_rest_nonce'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
public function check_rest_nonce(WP_REST_Request $request) {
|
||||
$nonce = $request->get_header('x-wp-nonce');
|
||||
if (!$nonce) {
|
||||
return new WP_Error('aksrt_rest_no_nonce', __('缺少安全令牌', 'aksrt'), ['status' => 403]);
|
||||
}
|
||||
if (!wp_verify_nonce($nonce, 'wp_rest')) {
|
||||
return new WP_Error('aksrt_rest_bad_nonce', __('安全令牌已过期,请刷新页面', 'aksrt'), ['status' => 403]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rest_preview(WP_REST_Request $request) {
|
||||
$plate_id = (int) $request['id'];
|
||||
$uid = get_current_user_id();
|
||||
$preview = $this->preview($plate_id, $uid);
|
||||
if (is_wp_error($preview)) {
|
||||
return $preview;
|
||||
}
|
||||
return new WP_REST_Response($preview, 200);
|
||||
}
|
||||
|
||||
public function rest_purchase(WP_REST_Request $request) {
|
||||
$plate_id = (int) $request['id'];
|
||||
$uid = get_current_user_id();
|
||||
if ($uid <= 0) {
|
||||
$post = get_post($plate_id);
|
||||
return new WP_Error('aksrt_need_login', __('请先登录后再关注。', 'aksrt'), [
|
||||
'status' => 401,
|
||||
'login_url' => wp_login_url($post ? get_permalink($post) : home_url('/')),
|
||||
]);
|
||||
}
|
||||
|
||||
$params = $request->get_json_params();
|
||||
if (!is_array($params)) {
|
||||
$params = $request->get_params();
|
||||
}
|
||||
|
||||
$payment_method = sanitize_key((string) ($params['payment_method'] ?? 'balance'));
|
||||
if ($payment_method === '' || $payment_method === 'cash') {
|
||||
$payment_method = 'balance';
|
||||
}
|
||||
|
||||
return $this->rest_wrap_result(
|
||||
$this->create_cash_order($plate_id, $uid, $payment_method)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $result
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
private function rest_wrap_result($result) {
|
||||
if (is_wp_error($result)) {
|
||||
return $result;
|
||||
}
|
||||
if (empty($result['success'])) {
|
||||
$code = sanitize_key((string) ($result['code'] ?? 'aksrt_pay_failed'));
|
||||
$status = (int) ($result['status'] ?? 400);
|
||||
return new WP_Error(
|
||||
$code !== '' ? $code : 'aksrt_pay_failed',
|
||||
(string) ($result['message'] ?? __('支付失败', 'aksrt')),
|
||||
array_merge(
|
||||
['status' => $status > 0 ? $status : 400],
|
||||
is_array($result['data'] ?? null) ? $result['data'] : []
|
||||
)
|
||||
);
|
||||
}
|
||||
return new WP_REST_Response($result, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function preview(int $plate_id, int $user_id = 0) {
|
||||
$assert = $this->assert_plate($plate_id);
|
||||
if (is_wp_error($assert)) {
|
||||
return $assert;
|
||||
}
|
||||
/** @var WP_Post $post */
|
||||
$post = $assert['post'];
|
||||
$uid = $user_id > 0 ? $user_id : get_current_user_id();
|
||||
|
||||
if ($uid <= 0) {
|
||||
return [
|
||||
'post_id' => $plate_id,
|
||||
'title' => get_the_title($post),
|
||||
'permalink' => get_permalink($post),
|
||||
'pay_modo' => '0',
|
||||
'pay_type' => 'plate_follow',
|
||||
'pay_type_label' => __('付费关注', 'aksrt'),
|
||||
'amount' => 0,
|
||||
'base' => 0,
|
||||
'list_amount' => 0,
|
||||
'payable' => 0,
|
||||
'currency' => '¥',
|
||||
'amount_label' => '',
|
||||
'base_label' => '',
|
||||
'list_amount_label' => '',
|
||||
'is_free' => false,
|
||||
'has_paid_access' => false,
|
||||
'need_login' => true,
|
||||
'allow_guest' => false,
|
||||
'need_vip' => false,
|
||||
'need_purchase' => true,
|
||||
'logged_in' => false,
|
||||
'balance' => 0,
|
||||
'balance_enough' => false,
|
||||
'payment_methods' => [],
|
||||
'login_url' => wp_login_url(get_permalink($post)),
|
||||
'vip_url' => home_url('/'),
|
||||
'credits_url' => home_url('/'),
|
||||
'coupon_allowed' => false,
|
||||
'coupon_desc' => '',
|
||||
'coupon_code' => '',
|
||||
'coupon' => null,
|
||||
'coupon_error' => '',
|
||||
'coupon_discount' => 0,
|
||||
'coupon_discount_label' => '',
|
||||
'rebate_discount' => 0,
|
||||
'rebate_discount_label' => '',
|
||||
'points_deduction_allowed' => false,
|
||||
'card_pass_allowed' => false,
|
||||
'price_type' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$priced = $this->resolve_price($plate_id, $uid);
|
||||
if (($priced['modo'] ?? 'money') === 'points') {
|
||||
return new WP_Error('aksrt_wrong_modo', __('该版块仅支持积分关注。', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
$amount = round((float) ($priced['amount'] ?? 0), 2);
|
||||
$base = round((float) ($priced['base'] ?? $amount), 2);
|
||||
$is_free = !empty($priced['is_free']) || $amount <= 0;
|
||||
$has_followed = $this->user_has_followed($uid, $plate_id);
|
||||
|
||||
$balance = 0;
|
||||
if (class_exists('AKSRT_Credits')) {
|
||||
$balance = (int) AKSRT_Credits::balance($uid);
|
||||
}
|
||||
|
||||
$methods = function_exists('aksrt_list_cash_payment_methods')
|
||||
? aksrt_list_cash_payment_methods(true)
|
||||
: [['id' => 'balance', 'name' => __('站内余额', 'aksrt')]];
|
||||
|
||||
$amount_label = $is_free
|
||||
? __('免费', 'aksrt')
|
||||
: sprintf('¥%s', number_format($amount, 2, '.', ''));
|
||||
$base_label = sprintf('¥%s', number_format($base, 2, '.', ''));
|
||||
|
||||
return [
|
||||
'post_id' => $plate_id,
|
||||
'title' => get_the_title($post),
|
||||
'permalink' => get_permalink($post),
|
||||
'pay_modo' => '0',
|
||||
'pay_type' => 'plate_follow',
|
||||
'pay_type_label' => __('付费关注', 'aksrt'),
|
||||
'amount' => $amount,
|
||||
'base' => $base,
|
||||
'list_amount' => $amount,
|
||||
'list_amount_label' => $amount_label,
|
||||
'payable' => $amount,
|
||||
'currency' => '¥',
|
||||
'amount_label' => $amount_label,
|
||||
'base_label' => $base_label,
|
||||
'is_free' => $is_free,
|
||||
'has_paid_access' => $has_followed,
|
||||
'paid_order' => null,
|
||||
'pending_order' => null,
|
||||
'need_login' => false,
|
||||
'allow_guest' => false,
|
||||
'need_vip' => false,
|
||||
'need_purchase' => !$has_followed && !$is_free,
|
||||
'logged_in' => true,
|
||||
'balance' => $balance,
|
||||
'balance_enough' => true,
|
||||
'payment_methods' => $methods,
|
||||
'login_url' => wp_login_url(get_permalink($post)),
|
||||
'vip_url' => home_url('/'),
|
||||
'credits_url' => home_url('/'),
|
||||
'coupon_allowed' => false,
|
||||
'coupon_desc' => '',
|
||||
'coupon_code' => '',
|
||||
'coupon' => null,
|
||||
'coupon_error' => '',
|
||||
'coupon_discount' => 0,
|
||||
'coupon_discount_label' => '',
|
||||
'rebate_discount' => 0,
|
||||
'rebate_discount_label' => '',
|
||||
'points_deduction_allowed' => false,
|
||||
'card_pass_allowed' => false,
|
||||
'price_type' => '',
|
||||
'vip_level' => (int) ($priced['vip_level'] ?? 0),
|
||||
'is_vip_price' => !empty($priced['is_vip_price']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function create_cash_order(int $plate_id, int $user_id, string $payment_method = 'balance') {
|
||||
if ($user_id <= 0) {
|
||||
return new WP_Error('aksrt_need_login', __('请先登录后再关注。', 'aksrt'), ['status' => 401]);
|
||||
}
|
||||
|
||||
$assert = $this->assert_plate($plate_id);
|
||||
if (is_wp_error($assert)) {
|
||||
return $assert;
|
||||
}
|
||||
/** @var WP_Post $post */
|
||||
$post = $assert['post'];
|
||||
|
||||
if ($this->user_has_followed($user_id, $plate_id)) {
|
||||
return new WP_Error('aksrt_already_followed', __('已关注该版块。', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
$priced = $this->resolve_price($plate_id, $user_id);
|
||||
if (($priced['modo'] ?? 'money') === 'points') {
|
||||
return new WP_Error('aksrt_wrong_modo', __('该版块仅支持积分关注。', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
$amount = round((float) ($priced['amount'] ?? 0), 2);
|
||||
$base = round((float) ($priced['base'] ?? $amount), 2);
|
||||
$is_free = !empty($priced['is_free']) || $amount <= 0;
|
||||
|
||||
if ($is_free) {
|
||||
return $this->create_free_paid_order($plate_id, $user_id, $post, $priced);
|
||||
}
|
||||
|
||||
if ($amount <= 0) {
|
||||
return new WP_Error('aksrt_price_unset', __('价格未设置', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
if (!class_exists('AKSRT_Order') || !class_exists('AKSRT_Order_Repository')) {
|
||||
return new WP_Error('aksrt_pay_unavailable', __('支付系统不可用。', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
|
||||
$payment_method = sanitize_key($payment_method);
|
||||
if ($payment_method === '') {
|
||||
$payment_method = 'balance';
|
||||
}
|
||||
|
||||
$pending = $this->find_pending_order($user_id, $plate_id);
|
||||
$can_resume = $pending && abs((float) ($pending['amount'] ?? 0) - $amount) < 0.001;
|
||||
|
||||
if ($can_resume) {
|
||||
$order_number = (string) ($pending['order_number'] ?? '');
|
||||
$order = $pending;
|
||||
} else {
|
||||
$note = wp_json_encode([
|
||||
'plate_follow_pay' => 1,
|
||||
'plate_id' => $plate_id,
|
||||
'pay_modo' => '0',
|
||||
'vip_level' => (int) ($priced['vip_level'] ?? 0),
|
||||
'base' => $base,
|
||||
'list_amount' => $amount,
|
||||
'amount' => $amount,
|
||||
'payable' => $amount,
|
||||
'ip_address' => function_exists('aksrt_pay_client_ip') ? aksrt_pay_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$order_number = AKSRT_Order_Repository::get_instance()->create([
|
||||
'user_id' => $user_id,
|
||||
'product_type' => AKSRT_Domain_Model::ORDER_PRODUCT_PLATE_FOLLOW,
|
||||
'product_id' => $plate_id,
|
||||
'amount' => $amount,
|
||||
'currency' => 'CNY',
|
||||
'status' => AKSRT_Order::STATUS_PENDING,
|
||||
'payment_method' => $payment_method,
|
||||
'note' => is_string($note) ? $note : '',
|
||||
'expires_at' => gmdate('Y-m-d H:i:s', time() + 30 * MINUTE_IN_SECONDS),
|
||||
]);
|
||||
|
||||
if ($order_number === '') {
|
||||
return new WP_Error('aksrt_order_create_failed', __('创建订单失败。', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
|
||||
$order = AKSRT_Order_Repository::get_instance()->get($order_number);
|
||||
if (!$order) {
|
||||
return new WP_Error('aksrt_order_create_failed', __('创建订单失败。', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
}
|
||||
|
||||
$order['subject'] = sprintf(
|
||||
/* translators: %s: plate title */
|
||||
__('付费关注版块「%s」', 'aksrt'),
|
||||
get_the_title($post)
|
||||
);
|
||||
$order['payment_method'] = $payment_method;
|
||||
$order['amount'] = $amount;
|
||||
|
||||
if (!class_exists('AKSRT_Payment_Gateway')) {
|
||||
return new WP_Error('aksrt_pay_unavailable', __('支付网关不可用。', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
|
||||
$gateway_manager = AKSRT_Payment_Gateway::get_instance();
|
||||
$gateway = $gateway_manager->get_gateway($payment_method);
|
||||
if (!$gateway) {
|
||||
return new WP_Error('aksrt_gateway_unavailable', __('当前支付方式不可用。', 'aksrt'), [
|
||||
'status' => 400,
|
||||
'order_number' => $order_number,
|
||||
]);
|
||||
}
|
||||
if (method_exists($gateway, 'is_configured') && !$gateway->is_configured()) {
|
||||
return new WP_Error('aksrt_gateway_unconfigured', __('该支付方式尚未配置,请联系站长。', 'aksrt'), [
|
||||
'status' => 400,
|
||||
'order_number' => $order_number,
|
||||
]);
|
||||
}
|
||||
|
||||
$payment_result = $gateway->create_payment($order);
|
||||
if (empty($payment_result['success'])) {
|
||||
$msg = (string) ($payment_result['message'] ?? __('支付失败。', 'aksrt'));
|
||||
$code = ($payment_method === 'balance' && (str_contains($msg, '余额') || str_contains($msg, '不足')))
|
||||
? 'aksrt_balance_insufficient'
|
||||
: 'aksrt_pay_failed';
|
||||
return new WP_Error($code, $msg, [
|
||||
'status' => 402,
|
||||
'order_number' => $order_number,
|
||||
]);
|
||||
}
|
||||
|
||||
$code_url = (string) ($payment_result['payment_data']['code_url'] ?? '');
|
||||
$payment_url = (string) ($payment_result['payment_url'] ?? '');
|
||||
if ($payment_url !== '' || $code_url !== '') {
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'redirect' => true,
|
||||
'payment_url' => $payment_url,
|
||||
'qr_content' => $code_url,
|
||||
'order_number' => $order_number,
|
||||
'amount' => $amount,
|
||||
'pay_modo' => '0',
|
||||
'message' => $payment_result['message'] ?? __('请在新页面完成支付。', 'aksrt'),
|
||||
'reload' => false,
|
||||
'poll' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$paid = AKSRT_Order::get_instance()->update_status($order_number, AKSRT_Order::STATUS_PAID, [
|
||||
'payment_method' => $payment_method,
|
||||
'payment_transaction_id' => sanitize_text_field((string) ($payment_result['transaction_id'] ?? '')),
|
||||
'note' => __('用户完成版块付费关注支付。', 'aksrt'),
|
||||
]);
|
||||
if (!$paid) {
|
||||
return new WP_Error('aksrt_order_confirm_failed', __('订单确认失败。', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
|
||||
$this->mark_followed($user_id, $plate_id);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'order_number' => $order_number,
|
||||
'amount' => $amount,
|
||||
'pay_modo' => '0',
|
||||
'message' => $payment_result['message'] ?? __('关注成功', 'aksrt'),
|
||||
'reload' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function on_order_paid(string $order_number, array $paid_order): void {
|
||||
$product_type = sanitize_key((string) ($paid_order['product_type'] ?? ''));
|
||||
if ($product_type !== AKSRT_Domain_Model::ORDER_PRODUCT_PLATE_FOLLOW) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plate_id = (int) ($paid_order['product_id'] ?? 0);
|
||||
$user_id = (int) ($paid_order['user_id'] ?? 0);
|
||||
if ($plate_id <= 0 || $user_id <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$meta = $this->decode_order_note_meta($paid_order);
|
||||
if (empty($meta['plate_follow_pay'])) {
|
||||
$post = get_post($plate_id);
|
||||
if (!($post instanceof WP_Post) || $post->post_type !== 'aksrt_forum_plate') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->mark_followed($user_id, $plate_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{post:WP_Post}|WP_Error
|
||||
*/
|
||||
private function assert_plate(int $plate_id) {
|
||||
$post = get_post($plate_id);
|
||||
if (!($post instanceof WP_Post) || $post->post_type !== 'aksrt_forum_plate') {
|
||||
return new WP_Error('aksrt_invalid', __('版块不存在', 'aksrt'), ['status' => 404]);
|
||||
}
|
||||
if ($post->post_status !== 'publish') {
|
||||
return new WP_Error('aksrt_invalid', __('版块不可关注', 'aksrt'), ['status' => 404]);
|
||||
}
|
||||
|
||||
if (!$this->is_follow_pay_enabled($plate_id)) {
|
||||
return new WP_Error('aksrt_not_paid', __('该版块未开启付费关注', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
$modo = sanitize_key((string) (get_post_meta($plate_id, '_aksrt_follow_pay_modo', true) ?: 'money'));
|
||||
if ($modo === 'points') {
|
||||
return new WP_Error('aksrt_wrong_modo', __('该版块仅支持积分关注。', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
return ['post' => $post];
|
||||
}
|
||||
|
||||
private function is_follow_pay_enabled(int $plate_id): bool {
|
||||
if (class_exists('AKSRT_Forum') && method_exists('AKSRT_Forum', 'is_plate_follow_pay_enabled')) {
|
||||
return (bool) AKSRT_Forum::get_instance()->is_plate_follow_pay_enabled($plate_id);
|
||||
}
|
||||
return (int) get_post_meta($plate_id, '_aksrt_follow_pay', true) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{amount:float,modo:string,is_vip_price:bool,is_free:bool,label:string,base:float,vip_level:int}
|
||||
*/
|
||||
private function resolve_price(int $plate_id, int $user_id): array {
|
||||
if (class_exists('AKSRT_Forum') && method_exists('AKSRT_Forum', 'resolve_plate_follow_pay_price')) {
|
||||
return AKSRT_Forum::get_instance()->resolve_plate_follow_pay_price($plate_id, $user_id);
|
||||
}
|
||||
return [
|
||||
'amount' => max(0.0, (float) get_post_meta($plate_id, '_aksrt_follow_pay_price', true)),
|
||||
'modo' => 'money',
|
||||
'is_vip_price' => false,
|
||||
'is_free' => false,
|
||||
'label' => '',
|
||||
'base' => max(0.0, (float) get_post_meta($plate_id, '_aksrt_follow_pay_price', true)),
|
||||
'vip_level' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
private function user_has_followed(int $user_id, int $plate_id): bool {
|
||||
if ($user_id <= 0 || $plate_id <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (class_exists('AKSRT_Forum') && method_exists('AKSRT_Forum', 'is_user_following_plate')) {
|
||||
return (bool) AKSRT_Forum::get_instance()->is_user_following_plate($user_id, $plate_id);
|
||||
}
|
||||
$follow_list = get_user_meta($user_id, 'aksrt_follow_plate', true);
|
||||
if (!is_array($follow_list)) {
|
||||
return false;
|
||||
}
|
||||
return in_array($plate_id, array_map('intval', $follow_list), true);
|
||||
}
|
||||
|
||||
private function mark_followed(int $user_id, int $plate_id): void {
|
||||
if (class_exists('AKSRT_Forum') && method_exists('AKSRT_Forum', 'mark_plate_followed')) {
|
||||
AKSRT_Forum::get_instance()->mark_plate_followed($user_id, $plate_id);
|
||||
return;
|
||||
}
|
||||
if ($user_id <= 0 || $plate_id <= 0) {
|
||||
return;
|
||||
}
|
||||
$follow_list = get_user_meta($user_id, 'aksrt_follow_plate', true);
|
||||
if (!is_array($follow_list)) {
|
||||
$follow_list = [];
|
||||
}
|
||||
$follow_list[] = $plate_id;
|
||||
update_user_meta($user_id, 'aksrt_follow_plate', array_values(array_unique(array_map('intval', $follow_list))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
private function create_free_paid_order(int $plate_id, int $user_id, WP_Post $post, array $priced) {
|
||||
if (!class_exists('AKSRT_Order') || !class_exists('AKSRT_Order_Repository')) {
|
||||
$this->mark_followed($user_id, $plate_id);
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'order_number' => '',
|
||||
'amount' => 0,
|
||||
'pay_modo' => '0',
|
||||
'free' => true,
|
||||
'message' => __('VIP 免费关注成功', 'aksrt'),
|
||||
'reload' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$note = wp_json_encode([
|
||||
'plate_follow_pay' => 1,
|
||||
'plate_id' => $plate_id,
|
||||
'pay_modo' => '0',
|
||||
'vip_level' => (int) ($priced['vip_level'] ?? 0),
|
||||
'base' => (float) ($priced['base'] ?? 0),
|
||||
'list_amount' => 0,
|
||||
'amount' => 0,
|
||||
'payable' => 0,
|
||||
'free' => 1,
|
||||
'ip_address' => function_exists('aksrt_pay_client_ip') ? aksrt_pay_client_ip() : (string) ($_SERVER['REMOTE_ADDR'] ?? ''),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
$order_number = AKSRT_Order_Repository::get_instance()->create([
|
||||
'user_id' => $user_id,
|
||||
'product_type' => AKSRT_Domain_Model::ORDER_PRODUCT_PLATE_FOLLOW,
|
||||
'product_id' => $plate_id,
|
||||
'amount' => 0.0,
|
||||
'currency' => 'CNY',
|
||||
'status' => AKSRT_Order::STATUS_PENDING,
|
||||
'payment_method' => 'free',
|
||||
'note' => is_string($note) ? $note : '',
|
||||
'expires_at' => gmdate('Y-m-d H:i:s', time() + 30 * MINUTE_IN_SECONDS),
|
||||
]);
|
||||
|
||||
if ($order_number === '') {
|
||||
$this->mark_followed($user_id, $plate_id);
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'order_number' => '',
|
||||
'amount' => 0,
|
||||
'free' => true,
|
||||
'message' => __('VIP 免费关注成功', 'aksrt'),
|
||||
'reload' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
AKSRT_Order::get_instance()->update_status($order_number, AKSRT_Order::STATUS_PAID, [
|
||||
'payment_method' => 'free',
|
||||
'payment_transaction_id' => 'free_' . $order_number,
|
||||
'note' => __('VIP 免费关注版块。', 'aksrt'),
|
||||
]);
|
||||
$this->mark_followed($user_id, $plate_id);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'order_number' => $order_number,
|
||||
'amount' => 0,
|
||||
'pay_modo' => '0',
|
||||
'free' => true,
|
||||
'message' => __('VIP 免费关注成功', 'aksrt'),
|
||||
'reload' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function find_pending_order(int $user_id, int $plate_id): ?array {
|
||||
if ($user_id <= 0 || $plate_id <= 0 || !class_exists('AKSRT_Order_Repository')) {
|
||||
return null;
|
||||
}
|
||||
$orders = AKSRT_Order_Repository::get_instance()->get_user_orders($user_id, [
|
||||
'product_type' => AKSRT_Domain_Model::ORDER_PRODUCT_PLATE_FOLLOW,
|
||||
'status' => AKSRT_Domain_Model::ORDER_STATUS_PENDING,
|
||||
'limit' => 20,
|
||||
'offset' => 0,
|
||||
]);
|
||||
foreach ($orders as $order) {
|
||||
if ((int) ($order['product_id'] ?? 0) !== $plate_id) {
|
||||
continue;
|
||||
}
|
||||
$meta = $this->decode_order_note_meta($order);
|
||||
if (!empty($meta['plate_follow_pay'])) {
|
||||
return $order;
|
||||
}
|
||||
return $order;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function decode_order_note_meta(array $order): array {
|
||||
$note = (string) ($order['note'] ?? '');
|
||||
if ($note === '') {
|
||||
return [];
|
||||
}
|
||||
$decoded = json_decode($note, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user