chore(pay): close residual zibll edge contracts for content pay
Expand coupon scope to content categories, document points_deduction as runtime-off like zibll, reject card_pass on content cashier, and pass shop/content context into coupon validate.
This commit is contained in:
@@ -79,12 +79,12 @@ export const creditsSchema = {
|
||||
},
|
||||
{
|
||||
key: 'deduction',
|
||||
title: '积分抵扣',
|
||||
title: '积分抵扣(预留)',
|
||||
icon: 'fas fa-percent',
|
||||
fields: [
|
||||
{ key: 'points_deduction_s', label: '启用积分抵扣', type: 'switch', default: false },
|
||||
{ key: 'points_deduction_rate', label: '抵扣比例(%)', type: 'number', default: 100, min: 1, max: 100, dependsOn: { key: 'points_deduction_s', value: true } },
|
||||
{ key: 'points_deduction_max', label: '最大抵扣比例(%)', type: 'number', default: 50, min: 1, max: 100, dependsOn: { key: 'points_deduction_s', value: true } },
|
||||
{ key: 'points_deduction_s', label: '启用积分抵扣', type: 'switch', default: false, help: '对齐 zibll:运行时暂未启用(zibpay_is_allow_points_deduction 恒为 false)。字段保留供后续接收银台现金单抵扣。' },
|
||||
{ key: 'points_deduction_rate', label: '积分换算比例', type: 'number', default: 100, min: 1, max: 10000, dependsOn: { key: 'points_deduction_s', value: true }, help: 'zibll 语义:points_deduction_rate = 多少积分抵 1 元(示例 30 表示 30 积分=1 元)。当前未参与下单计算。' },
|
||||
{ key: 'points_deduction_max', label: '最大抵扣比例(%)', type: 'number', default: 50, min: 1, max: 100, dependsOn: { key: 'points_deduction_s', value: true }, help: '预留:最多可抵订单金额的百分比。当前未参与下单计算。' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -432,10 +432,10 @@ class AKSRT_Admin_Schema_Users {
|
||||
['key' => 'points_service_charge', 'label' => '转账手续费(%)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 50],
|
||||
['key' => 'points_transfer_min', 'label' => '最低转账金额', 'type' => 'number', 'default' => 1, 'min' => 1, 'max' => 9999],
|
||||
]],
|
||||
['key' => 'deduction', 'title' => '积分抵扣', 'fields' => [
|
||||
['key' => 'points_deduction_s', 'label' => '启用积分抵扣', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'points_deduction_rate', 'label' => '抵扣比例(%)', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 100],
|
||||
['key' => 'points_deduction_max', 'label' => '最大抵扣比例(%)', 'type' => 'number', 'default' => 50, 'min' => 1, 'max' => 100],
|
||||
['key' => 'deduction', 'title' => '积分抵扣(预留)', 'fields' => [
|
||||
['key' => 'points_deduction_s', 'label' => '启用积分抵扣', 'type' => 'switch', 'default' => false, 'help' => '对齐 zibll:运行时暂未启用。字段保留供后续接收银台现金单抵扣。'],
|
||||
['key' => 'points_deduction_rate', 'label' => '积分换算比例', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 10000, 'help' => '多少积分抵 1 元(zibll points_deduction_rate)。当前未参与下单。'],
|
||||
['key' => 'points_deduction_max', 'label' => '最大抵扣比例(%)', 'type' => 'number', 'default' => 50, 'min' => 1, 'max' => 100, 'help' => '预留:最多可抵订单金额百分比。当前未参与下单。'],
|
||||
]],
|
||||
['key' => 'card_pass', 'title' => '积分卡密兑换', 'fields' => [
|
||||
['key' => 'points_pass_exchange_s', 'label' => '启用积分卡密兑换', 'type' => 'switch', 'default' => false],
|
||||
|
||||
@@ -552,6 +552,13 @@ class AKSRT_Content_Pay {
|
||||
'payable' => round($payable, 2),
|
||||
'rebate_price' => round($rebate_price, 2),
|
||||
],
|
||||
// zibll: points_deduction runtime hard-off; card_pass not a content payment method.
|
||||
'points_deduction_allowed' => function_exists('aksrt_is_allow_points_deduction')
|
||||
? (bool) aksrt_is_allow_points_deduction('content')
|
||||
: false,
|
||||
'card_pass_allowed' => function_exists('aksrt_is_content_card_pass_pay_allowed')
|
||||
? (bool) aksrt_is_content_card_pass_pay_allowed($post)
|
||||
: false,
|
||||
'price_type' => $price_type,
|
||||
];
|
||||
}
|
||||
@@ -687,9 +694,16 @@ class AKSRT_Content_Pay {
|
||||
return new WP_Error('aksrt_wrong_modo', __('该内容仅支持积分支付。', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
|
||||
// Card pass cannot stack coupon (zibll).
|
||||
// Card pass cannot stack coupon (zibll). Content cashier does not sell via card_pass.
|
||||
$payment_method = sanitize_key($payment_method);
|
||||
if ($payment_method === 'card_pass') {
|
||||
if (!function_exists('aksrt_is_content_card_pass_pay_allowed') || !aksrt_is_content_card_pass_pay_allowed($post)) {
|
||||
return new WP_Error(
|
||||
'aksrt_card_pass_not_allowed',
|
||||
__('内容购买不支持卡密支付,请在用户中心使用卡密兑换余额/会员/积分。', 'aksrt'),
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
$coupon_code = '';
|
||||
}
|
||||
|
||||
@@ -1170,8 +1184,9 @@ class AKSRT_Content_Pay {
|
||||
}
|
||||
} else {
|
||||
$result = AKSRT_Coupon::get_instance()->validate($coupon_code, $pay, [
|
||||
'user_id' => max(0, $user_id),
|
||||
'user_id' => max(0, $user_id),
|
||||
'product_ids' => [(int) $post->ID],
|
||||
'context' => 'content',
|
||||
]);
|
||||
if (empty($result['valid'])) {
|
||||
$err = new WP_Error(
|
||||
|
||||
@@ -161,30 +161,42 @@ class AKSRT_Coupon {
|
||||
}
|
||||
}
|
||||
|
||||
// Product scope check
|
||||
// Product / content scope check.
|
||||
// Supports shop product cats and content post cats.
|
||||
if (!empty($coupon['product_scope']) && !empty($args['product_ids'])) {
|
||||
$scope = is_array($coupon['product_scope']) ? $coupon['product_scope'] : json_decode($coupon['product_scope'], true);
|
||||
if (is_array($scope) && !empty($scope)) {
|
||||
$scope_type = (string) ($scope['type'] ?? '');
|
||||
$scope_ids = array_map('intval', (array) ($scope['ids'] ?? []));
|
||||
$scope_type = sanitize_key((string) ($scope['type'] ?? ''));
|
||||
$scope_ids = array_map('intval', (array) ($scope['ids'] ?? []));
|
||||
$product_ids = array_map('intval', (array) $args['product_ids']);
|
||||
$taxonomies = array_values(array_filter(array_map('sanitize_key', (array) ($scope['taxonomies'] ?? []))));
|
||||
if ($taxonomies === []) {
|
||||
// content context prefers category; shop admin may pass aksrt_product_cat.
|
||||
$context = sanitize_key((string) ($args['context'] ?? ''));
|
||||
$taxonomies = ($context === 'content')
|
||||
? ['category']
|
||||
: ['aksrt_product_cat', 'category'];
|
||||
}
|
||||
|
||||
if ($scope_type === 'include' && empty(array_intersect($product_ids, $scope_ids))) {
|
||||
return ['valid' => false, 'message' => '该优惠码不适用于当前商品'];
|
||||
return ['valid' => false, 'message' => __('该优惠码不适用于当前商品', 'aksrt')];
|
||||
}
|
||||
if ($scope_type === 'exclude' && !empty(array_intersect($product_ids, $scope_ids))) {
|
||||
return ['valid' => false, 'message' => '该优惠码不适用于当前商品'];
|
||||
return ['valid' => false, 'message' => __('该优惠码不适用于当前商品', 'aksrt')];
|
||||
}
|
||||
if ($scope_type === 'category') {
|
||||
if (in_array($scope_type, ['category', 'content_category', 'post_category'], true)) {
|
||||
$matched = false;
|
||||
foreach ($product_ids as $pid) {
|
||||
$cats = wp_get_post_terms($pid, 'aksrt_product_cat', ['fields' => 'ids']);
|
||||
if (!is_wp_error($cats) && !empty(array_intersect($cats, $scope_ids))) {
|
||||
$matched = true;
|
||||
break;
|
||||
foreach ($taxonomies as $tax) {
|
||||
$cats = wp_get_post_terms($pid, $tax, ['fields' => 'ids']);
|
||||
if (!is_wp_error($cats) && !empty(array_intersect(array_map('intval', (array) $cats), $scope_ids))) {
|
||||
$matched = true;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$matched) {
|
||||
return ['valid' => false, 'message' => '该优惠码不适用于当前商品分类'];
|
||||
return ['valid' => false, 'message' => __('该优惠码不适用于当前分类', 'aksrt')];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,10 @@ class AKSRT_Shop_Checkout_Service {
|
||||
$shipping_profile = $this->resolve_shipping_quote($product_views, $shipping_method);
|
||||
|
||||
$coupon_code = sanitize_text_field((string) ($payload['coupon_code'] ?? ''));
|
||||
$coupon_result = $this->resolve_coupon_discount($coupon_code, $subtotal + $shipping_profile['fee']);
|
||||
$product_ids = array_values(array_unique(array_map(static function ($row) {
|
||||
return (int) ($row['product_id'] ?? $row['id'] ?? 0);
|
||||
}, $product_views)));
|
||||
$coupon_result = $this->resolve_coupon_discount($coupon_code, $subtotal + $shipping_profile['fee'], $product_ids);
|
||||
if (!$coupon_result['success']) {
|
||||
return $coupon_result;
|
||||
}
|
||||
@@ -306,7 +309,7 @@ class AKSRT_Shop_Checkout_Service {
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private function resolve_coupon_discount(string $coupon_code, float $order_amount): array {
|
||||
private function resolve_coupon_discount(string $coupon_code, float $order_amount, array $product_ids = []): array {
|
||||
if ($coupon_code === '') {
|
||||
return ['success' => true, 'discount' => 0.0, 'coupon' => []];
|
||||
}
|
||||
@@ -315,7 +318,11 @@ class AKSRT_Shop_Checkout_Service {
|
||||
return ['success' => false, 'message' => __('优惠券系统不可用。', 'aksrt')];
|
||||
}
|
||||
|
||||
$result = AKSRT_Coupon::get_instance()->validate($coupon_code, $order_amount);
|
||||
$result = AKSRT_Coupon::get_instance()->validate($coupon_code, $order_amount, [
|
||||
'user_id' => get_current_user_id(),
|
||||
'product_ids' => array_values(array_filter(array_map('intval', $product_ids))),
|
||||
'context' => 'shop',
|
||||
]);
|
||||
if (empty($result['valid'])) {
|
||||
return ['success' => false, 'message' => $result['message'] ?? __('优惠券不可用。', 'aksrt')];
|
||||
}
|
||||
|
||||
@@ -559,6 +559,38 @@ if (!function_exists('aksrt_get_post_rebate_discount')) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether cash checkout may use points deduction (zibll points_deduction).
|
||||
*
|
||||
* zibll: zibpay_is_allow_points_deduction() always returns false ("暂未启用").
|
||||
* Keep the same contract: schema/UI may exist, runtime is hard-off unless filter overrides.
|
||||
*/
|
||||
if (!function_exists('aksrt_is_allow_points_deduction')) {
|
||||
function aksrt_is_allow_points_deduction(string $context = 'content'): bool {
|
||||
// Mirror zibll hard-off first.
|
||||
$allowed = false;
|
||||
if (class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'get_all')) {
|
||||
$all = AKSRT_Settings::get_all();
|
||||
// Even if switch on, default remains false like zibll until product enables it.
|
||||
if (!empty($all['points_deduction_s']) && class_exists('AKSRT_Settings') && method_exists('AKSRT_Settings', 'credits_enabled') && AKSRT_Settings::credits_enabled()) {
|
||||
$allowed = false; // still disabled at runtime
|
||||
}
|
||||
}
|
||||
return (bool) apply_filters('aksrt_is_allow_points_deduction', $allowed, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Content cashier does not accept card_pass payment_method.
|
||||
* Card-pass for balance/VIP/points is user-center redeem (zibll order types 4/8/9),
|
||||
* not content pay types (reading/download/gallery/video).
|
||||
*/
|
||||
if (!function_exists('aksrt_is_content_card_pass_pay_allowed')) {
|
||||
function aksrt_is_content_card_pass_pay_allowed($post = null): bool {
|
||||
return (bool) apply_filters('aksrt_is_content_card_pass_pay_allowed', false, $post);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 状态判断
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user