Merge pull request 'feat(payment): finish Zibll key contract and wire checkout gateways' (#55) from worktree-payment-finish into main

Reviewed-on: CYL/wordpress-theme-aksrt#55
This commit is contained in:
2026-07-11 17:57:41 +08:00
16 changed files with 298 additions and 228 deletions
@@ -49,6 +49,17 @@ export const paymentSection = {
canonicalDomain: 'payment', canonicalDomain: 'payment',
section: 'vip', section: 'vip',
}), }),
schemaPage({
key: 'payment-order',
name: 'PaymentOrder',
label: '订单设置',
route: '/payment/order',
status: 'available',
title: '订单设置',
desc: '订单前缀、有效期、展示字段和状态文案。',
canonicalDomain: 'payment',
section: 'order',
}),
customPage({ customPage({
key: 'payment-revenue', key: 'payment-revenue',
name: 'PaymentRevenue', name: 'PaymentRevenue',
@@ -84,6 +95,28 @@ export const paymentSection = {
canonicalDomain: 'payment', canonicalDomain: 'payment',
section: 'charge-card', section: 'charge-card',
}), }),
schemaPage({
key: 'payment-card-pass',
name: 'PaymentCardPass',
label: '卡密设置',
route: '/payment/card-pass',
status: 'available',
title: '卡密设置',
desc: '充值卡类型、卡号规则与兑换文案。',
canonicalDomain: 'payment',
section: 'card-pass',
}),
schemaPage({
key: 'payment-withdrawal',
name: 'PaymentWithdrawal',
label: '提现策略',
route: '/payment/withdrawal',
status: 'available',
title: '提现策略',
desc: '最低提现、手续费与说明文案(提现工单在商城提现管理)。',
canonicalDomain: 'payment',
section: 'withdrawal',
}),
customPage({ customPage({
key: 'payment-rebate', key: 'payment-rebate',
name: 'PaymentRebate', name: 'PaymentRebate',
@@ -1,16 +0,0 @@
<template>
<PaymentSectionPage
section="affiliate"
title="推广返佣"
desc="配置返佣比例、归因窗口和返佣说明。"
note="返佣逻辑复用用户邀请体系作为链路入口,订单归因和结算自动衔接当前策略字段。"
:links="[
{ label: '用户签到/邀请', path: '/users/signin' },
{ label: '创作分成', path: '/payment/revenue' },
]"
/>
</template>
<script setup>
import PaymentSectionPage from '@/pages/payment/PaymentSectionPage.vue'
</script>
@@ -1,16 +0,0 @@
<template>
<PaymentSectionPage
section="recharge"
title="余额充值"
desc="配置充值模式、套餐结构和帮助文案。"
note="当前支持人工确认与测试联调;接入真实网关时复用同一组字段。"
:links="[
{ label: '下载/付费内容中心', path: '/payment/paid' },
{ label: '收款接口', path: '/payment/gateway' },
]"
/>
</template>
<script setup>
import PaymentSectionPage from '@/pages/payment/PaymentSectionPage.vue'
</script>
@@ -1,16 +0,0 @@
<template>
<PaymentSectionPage
section="vip"
title="VIP会员"
desc=”配置会员名称、展示徽标和套餐结构。”
note=”角色免扣下载的运行逻辑在”下载/付费内容中心”中生效;此处管理会员套餐和权益说明。”
:links="[
{ label: '下载/付费内容中心', path: '/payment/paid' },
{ label: '创作分成', path: '/payment/revenue' },
]"
/>
</template>
<script setup>
import PaymentSectionPage from '@/pages/payment/PaymentSectionPage.vue'
</script>
@@ -21,7 +21,6 @@ export const affiliateSchema = {
pay_rebate_text_details_title: '', pay_rebate_text_details_title: '',
pay_rebate_text_details: '', pay_rebate_text_details: '',
pay_rebate_text_discount: '', pay_rebate_text_discount: '',
payment_affiliate_note: '返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。',
}, },
groups: [ groups: [
{ {
@@ -20,6 +20,7 @@ export const paymentSchemas = {
affiliate: affiliateSchema, affiliate: affiliateSchema,
gateway: gatewaySchema, gateway: gatewaySchema,
order: orderSchema, order: orderSchema,
'card-pass': cardPassSchema,
cardPass: cardPassSchema, cardPass: cardPassSchema,
withdrawal: withdrawalSchema, withdrawal: withdrawalSchema,
} }
@@ -2,7 +2,7 @@ export const rechargeSchema = {
key: 'payment.recharge', key: 'payment.recharge',
title: '余额充值', title: '余额充值',
icon: 'fas fa-charging-station', icon: 'fas fa-charging-station',
description: '配置测试充值、手动确认和充值套餐结构。', description: '配置余额充值套餐、转账与积分兑换。',
defaults: { defaults: {
pay_balance_s: true, pay_balance_s: true,
pay_balance_desc: '', pay_balance_desc: '',
@@ -31,7 +31,6 @@ export const rechargeSchema = {
icon: 'fas fa-wallet', icon: 'fas fa-wallet',
fields: [ fields: [
{ key: 'pay_balance_s', label: '启用余额功能', type: 'switch', default: true }, { key: 'pay_balance_s', label: '启用余额功能', type: 'switch', default: true },
{ key: 'payment_recharge_mode', label: '充值模式', type: 'radio', default: 'manual_review', options: [{ label: '人工确认', value: 'manual_review' }, { label: '测试网关', value: 'test_gateway' }], dependsOn: { key: 'pay_balance_s', value: true } },
{ key: 'pay_balance_desc', label: '充值说明', type: 'textarea', default: '', dependsOn: { key: 'pay_balance_s', value: true } }, { key: 'pay_balance_desc', label: '充值说明', type: 'textarea', default: '', dependsOn: { key: 'pay_balance_s', value: true } },
{ key: 'pay_auto_to_balance', label: '自动到账到余额', type: 'switch', default: true, dependsOn: { key: 'pay_balance_s', value: true } }, { key: 'pay_auto_to_balance', label: '自动到账到余额', type: 'switch', default: true, dependsOn: { key: 'pay_balance_s', value: true } },
], ],
@@ -42,7 +41,6 @@ export const rechargeSchema = {
icon: 'fas fa-box-open', icon: 'fas fa-box-open',
fields: [ fields: [
{ key: 'pay_balance_product', label: '套餐列表', type: 'textarea', default: '30|30|入门包\n98|108|推荐包', help: '每行一个套餐:支付金额|到账金额|标题', dependsOn: { key: 'pay_balance_s', value: true } }, { key: 'pay_balance_product', label: '套餐列表', type: 'textarea', default: '30|30|入门包\n98|108|推荐包', help: '每行一个套餐:支付金额|到账金额|标题', dependsOn: { key: 'pay_balance_s', value: true } },
{ key: 'payment_recharge_help', label: '帮助文案', type: 'textarea', default: '当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', dependsOn: { key: 'pay_balance_s', value: true } },
], ],
}, },
{ {
@@ -57,23 +57,18 @@ class AKSRT_Admin_Schema_Payment {
'option_key' => 'aksrt_settings', 'option_key' => 'aksrt_settings',
'groups' => [ 'groups' => [
['key' => 'basic', 'title' => '充值开关', 'fields' => [ ['key' => 'basic', 'title' => '充值开关', 'fields' => [
['key' => 'pay_balance_s', 'label' => '启用余额充值', 'type' => 'switch', 'default' => true], ['key' => 'pay_balance_s', 'label' => '启用余额功能', 'type' => 'switch', 'default' => true],
['key' => 'payment_recharge_mode', 'label' => '充值模式', 'type' => 'select', 'default' => 'manual_review', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true], 'options' => [
['label' => '人工审核', 'value' => 'manual_review'],
['label' => '自动到账', 'value' => 'auto'],
]],
['key' => 'pay_balance_desc', 'label' => '充值说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_desc', 'label' => '充值说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'pay_auto_to_balance', 'label' => '自动到账到余额', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_auto_to_balance', 'label' => '自动到账到余额', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
]], ]],
['key' => 'packages', 'title' => '充值套餐', 'fields' => [ ['key' => 'packages', 'title' => '充值套餐', 'fields' => [
['key' => 'pay_balance_product', 'label' => '套餐列表', 'type' => 'textarea', 'default' => "30|30|入门包\n98|108|推荐包", 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_product', 'label' => '套餐列表', 'type' => 'textarea', 'default' => "30|30|入门包\n98|108|推荐包", 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'payment_recharge_help', 'label' => '帮助文案', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
]], ]],
['key' => 'product', 'title' => '充值产品', 'fields' => [ ['key' => 'product', 'title' => '充值产品', 'fields' => [
['key' => 'payment_recharge_product', 'label' => '充值产品', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_product_name', 'label' => '充值产品', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'payment_recharge_price', 'label' => '充值价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_price', 'label' => '充值价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'payment_recharge_tag', 'label' => '价格标签', 'type' => 'input', 'default' => '元', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_tag', 'label' => '价格标签', 'type' => 'input', 'default' => '元', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'payment_recharge_tag_class', 'label' => '标签样式', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_tag_class', 'label' => '标签样式', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'pay_balance_product_custom_s', 'label' => '自定义金额', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_product_custom_s', 'label' => '自定义金额', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
['key' => 'pay_balance_product_custom_limit', 'label' => '自定义金额限制', 'type' => 'number', 'default' => 9999, 'min' => 1, 'max' => 99999, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]], ['key' => 'pay_balance_product_custom_limit', 'label' => '自定义金额限制', 'type' => 'number', 'default' => 9999, 'min' => 1, 'max' => 99999, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
]], ]],
@@ -88,9 +83,9 @@ class AKSRT_Admin_Schema_Payment {
['key' => 'pay_balance_pass_charge_only_password', 'label' => '仅密码免扣', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'pay_balance_pass_charge_s', 'value' => true]], ['key' => 'pay_balance_pass_charge_only_password', 'label' => '仅密码免扣', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'pay_balance_pass_charge_s', 'value' => true]],
]], ]],
['key' => 'exchange', 'title' => '积分兑换', 'fields' => [ ['key' => 'exchange', 'title' => '积分兑换', 'fields' => [
['key' => 'payment_recharge_exchange_s', 'label' => '启用积分兑换', 'type' => 'switch', 'default' => false], ['key' => 'pay_balance_exchange_s', 'label' => '启用积分兑换', 'type' => 'switch', 'default' => false],
['key' => 'payment_recharge_exchange_rate', 'label' => '兑换比例', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 10000, 'dependsOn' => ['key' => 'payment_recharge_exchange_s', 'value' => true]], ['key' => 'pay_balance_exchange_rate', 'label' => '兑换比例', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 10000, 'dependsOn' => ['key' => 'pay_balance_exchange_s', 'value' => true]],
['key' => 'payment_recharge_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'payment_recharge_exchange_s', 'value' => true]], ['key' => 'pay_balance_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_exchange_s', 'value' => true]],
]], ]],
], ],
], ],
@@ -100,7 +95,7 @@ class AKSRT_Admin_Schema_Payment {
'version' => '1.0.0', 'version' => '1.0.0',
'option_key' => 'aksrt_settings', 'option_key' => 'aksrt_settings',
'groups' => [ 'groups' => [
['key' => 'basic', 'title' => '会员基础', 'fields' => [ ['key' => 'basic', 'title' => '会员等级', 'fields' => [
['key' => 'pay_user_vip_1_s', 'label' => '启用一级会员', 'type' => 'switch', 'default' => true], ['key' => 'pay_user_vip_1_s', 'label' => '启用一级会员', 'type' => 'switch', 'default' => true],
['key' => 'pay_user_vip_1_name', 'label' => '一级会员名称', 'type' => 'input', 'default' => '一级会员', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]], ['key' => 'pay_user_vip_1_name', 'label' => '一级会员名称', 'type' => 'input', 'default' => '一级会员', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_user_vip_2_s', 'label' => '启用二级会员', 'type' => 'switch', 'default' => true], ['key' => 'pay_user_vip_2_s', 'label' => '启用二级会员', 'type' => 'switch', 'default' => true],
@@ -109,14 +104,16 @@ class AKSRT_Admin_Schema_Payment {
]], ]],
['key' => 'packages', 'title' => '会员套餐', 'fields' => [ ['key' => 'packages', 'title' => '会员套餐', 'fields' => [
['key' => 'payment_vip_packages', 'label' => '套餐列表', 'type' => 'textarea', 'default' => "30|30|月卡\n365|365|年卡"], ['key' => 'payment_vip_packages', 'label' => '套餐列表', 'type' => 'textarea', 'default' => "30|30|月卡\n365|365|年卡"],
['key' => 'payment_vip_help', 'label' => '权益说明', 'type' => 'textarea', 'default' => ''],
]], ]],
['key' => 'benefit', 'title' => '会员权益', 'fields' => [ ['key' => 'benefit', 'title' => '下载权益', 'fields' => [
['key' => 'pay_download_limit', 'label' => '下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999], ['key' => 'pay_download_limit', 'label' => '普通用户下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999],
['key' => 'pay_download_speed', 'label' => '下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999], ['key' => 'pay_download_speed', 'label' => '普通用户下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'payment_vip_discount', 'label' => '折扣(%)', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 100], ['key' => 'pay_download_limit_vip_1', 'label' => '一级会员下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_vip_pass_charge_s', 'label' => '积分充值免扣', 'type' => 'switch', 'default' => false], ['key' => 'pay_download_speed_vip_1', 'label' => '一级会员下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_vip_pass_charge_desc', 'label' => '积分充值说明', 'type' => 'textarea', 'default' => ''], ['key' => 'pay_download_limit_vip_2', 'label' => '二级会员下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_download_speed_vip_2', 'label' => '二级会员下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_vip_pass_charge_s', 'label' => '会员卡密兑换', 'type' => 'switch', 'default' => false],
['key' => 'pay_vip_pass_charge_desc', 'label' => '卡密兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true]],
]], ]],
['key' => 'renew', 'title' => '续费设置', 'fields' => [ ['key' => 'renew', 'title' => '续费设置', 'fields' => [
['key' => 'vip_renew', 'label' => '允许续费', 'type' => 'switch', 'default' => true], ['key' => 'vip_renew', 'label' => '允许续费', 'type' => 'switch', 'default' => true],
@@ -134,14 +131,6 @@ class AKSRT_Admin_Schema_Payment {
['key' => 'vip_upgrade_desc', 'label' => '升级说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]], ['key' => 'vip_upgrade_desc', 'label' => '升级说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]],
['key' => 'vip_upgrade_product', 'label' => '升级产品', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]], ['key' => 'vip_upgrade_product', 'label' => '升级产品', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]],
]], ]],
['key' => 'price', 'title' => '价格设置', 'fields' => [
['key' => 'payment_vip_month_price', 'label' => '月卡价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'payment_vip_year_price', 'label' => '年卡价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'payment_vip_permanent_price', 'label' => '永久价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'payment_vip_unit_price', 'label' => '单位价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'payment_vip_unit_tag', 'label' => '单位标签', 'type' => 'input', 'default' => '元'],
['key' => 'payment_vip_jump_price', 'label' => '跳转价格', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
]],
], ],
], ],
'revenue' => [ 'revenue' => [
@@ -314,10 +303,10 @@ class AKSRT_Admin_Schema_Payment {
]], ]],
['key' => 'service', 'title' => '服务设置', 'fields' => [ ['key' => 'service', 'title' => '服务设置', 'fields' => [
['key' => 'pay_service', 'label' => '客服设置', 'type' => 'textarea', 'default' => ''], ['key' => 'pay_service', 'label' => '客服设置', 'type' => 'textarea', 'default' => ''],
['key' => 'payment_service_icon', 'label' => '客服图标', 'type' => 'icon', 'default' => ''], ['key' => 'pay_service_icon', 'label' => '客服图标', 'type' => 'icon', 'default' => ''],
['key' => 'payment_service_value', 'label' => '客服内容', 'type' => 'input', 'default' => ''], ['key' => 'pay_service_value', 'label' => '客服内容', 'type' => 'input', 'default' => ''],
['key' => 'payment_service_qq', 'label' => 'QQ客服', 'type' => 'input', 'default' => ''], ['key' => 'pay_service_qq', 'label' => 'QQ客服', 'type' => 'input', 'default' => ''],
['key' => 'payment_service_wechat', 'label' => '微信客服', 'type' => 'media', 'default' => ''], ['key' => 'pay_service_wechat', 'label' => '微信客服', 'type' => 'media', 'default' => ''],
]], ]],
], ],
], ],
+33 -15
View File
@@ -351,7 +351,13 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
public function is_configured(): bool { public function is_configured(): bool {
return class_exists('AKSRT_Credits'); if (!class_exists('AKSRT_Credits')) {
return false;
}
if (class_exists('AKSRT_Settings_Payment_Runtime')) {
return AKSRT_Settings_Payment_Runtime::is_gateway_enabled('balance');
}
return true;
} }
public function create_payment(array $order): array { public function create_payment(array $order): array {
@@ -362,6 +368,7 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
$user_id = (int) ($order['user_id'] ?? 0); $user_id = (int) ($order['user_id'] ?? 0);
$amount = (float) ($order['amount'] ?? 0); $amount = (float) ($order['amount'] ?? 0);
$credits_cost = (int) ceil($amount * 100); // 1 元 = 100 积分 $credits_cost = (int) ceil($amount * 100); // 1 元 = 100 积分
$order_number = (string) ($order['order_number'] ?? '');
$balance = AKSRT_Credits::balance($user_id); $balance = AKSRT_Credits::balance($user_id);
@@ -369,18 +376,23 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
return ['success' => false, 'message' => __('余额不足', 'aksrt')]; return ['success' => false, 'message' => __('余额不足', 'aksrt')];
} }
// Deduct credits $result = AKSRT_Credits::deduct(
$result = AKSRT_Credits::deduct($user_id, $credits_cost, 'order_payment', sprintf(__('订单 %s 支付', 'aksrt'), $order['order_number'] ?? '')); $user_id,
$credits_cost,
'order_payment',
['order' => $order_number],
sprintf(__('订单 %s 支付', 'aksrt'), $order_number)
);
if ($result) { if (is_wp_error($result)) {
return [ return ['success' => false, 'message' => $result->get_error_message() ?: __('扣款失败', 'aksrt')];
'success' => true,
'transaction_id' => 'BAL_' . ($order['order_number'] ?? time()),
'message' => __('余额支付成功', 'aksrt'),
];
} }
return ['success' => false, 'message' => __('扣款失败', 'aksrt')]; return [
'success' => true,
'transaction_id' => 'BAL_' . ($order_number !== '' ? $order_number : (string) time()),
'message' => __('余额支付成功', 'aksrt'),
];
} }
public function verify_callback(WP_REST_Request $request): array { public function verify_callback(WP_REST_Request $request): array {
@@ -418,12 +430,18 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
$user_id = (int) $order['user_id']; $user_id = (int) $order['user_id'];
$credits_refund = (int) ceil($amount * 100); $credits_refund = (int) ceil($amount * 100);
$result = AKSRT_Credits::add($user_id, $credits_refund, 'order_refund', sprintf(__('订单 %s 退款', 'aksrt'), $order_number)); $result = AKSRT_Credits::add(
$user_id,
$credits_refund,
'order_refund',
['order' => $order_number],
sprintf(__('订单 %s 退款', 'aksrt'), $order_number)
);
if (is_wp_error($result)) {
return ['success' => false, 'message' => $result->get_error_message() ?: __('退款失败', 'aksrt')];
}
if ($result) {
return ['success' => true, 'refund_id' => 'BAL_REF_' . $order_number, 'message' => __('退款成功', 'aksrt')]; return ['success' => true, 'refund_id' => 'BAL_REF_' . $order_number, 'message' => __('退款成功', 'aksrt')];
} }
return ['success' => false, 'message' => __('退款失败', 'aksrt')];
}
} }
@@ -20,6 +20,10 @@ class AKSRT_Alipay_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
public function is_configured(): bool { public function is_configured(): bool {
if (class_exists('AKSRT_Settings_Payment_Runtime')
&& !AKSRT_Settings_Payment_Runtime::is_gateway_enabled('alipay')) {
return false;
}
$config = $this->get_config(); $config = $this->get_config();
return !empty($config['app_id']) && !empty($config['private_key']) && !empty($config['alipay_public_key']); return !empty($config['app_id']) && !empty($config['private_key']) && !empty($config['alipay_public_key']);
} }
@@ -165,25 +169,20 @@ class AKSRT_Alipay_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
private function get_config(): array { private function get_config(): array {
// 优先从统一设置读取(schema 保存的 key) if (!class_exists('AKSRT_Settings')) {
if (class_exists('AKSRT_Settings')) { return [];
}
$all = AKSRT_Settings::get_all(); $all = AKSRT_Settings::get_all();
if (!empty($all['alipay_appid'])) {
return [ return [
'app_id' => $all['alipay_appid'] ?? '', 'app_id' => (string) ($all['alipay_appid'] ?? ''),
'private_key' => $all['alipay_privatekey'] ?? '', 'private_key' => (string) ($all['alipay_privatekey'] ?? ''),
'alipay_public_key' => $all['alipay_publickey'] ?? '', 'alipay_public_key' => (string) ($all['alipay_publickey'] ?? ''),
'return_url' => $all['alipay_return_url'] ?? '', 'return_url' => (string) ($all['alipay_return_url'] ?? ''),
'notify_url' => $all['alipay_notify_url'] ?? '', 'notify_url' => (string) ($all['alipay_notify_url'] ?? ''),
'payment_type' => $all['alipay_payment_type'] ?? 'page', 'payment_type' => (string) ($all['alipay_payment_type'] ?? 'page'),
'sign_type' => $all['alipay_sign_type'] ?? 'RSA2', 'sign_type' => (string) ($all['alipay_sign_type'] ?? 'RSA2'),
]; ];
} }
}
// 回退到独立 option
$settings = get_option('aksrt_payment_alipay', []);
return is_array($settings) ? $settings : [];
}
private function create_sdk(array $config): \Yurun\PaySDK\AlipayApp\SDK { private function create_sdk(array $config): \Yurun\PaySDK\AlipayApp\SDK {
$params = new \Yurun\PaySDK\AlipayApp\Params\PublicParams; $params = new \Yurun\PaySDK\AlipayApp\Params\PublicParams;
@@ -20,6 +20,10 @@ class AKSRT_PayPal_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
public function is_configured(): bool { public function is_configured(): bool {
if (class_exists('AKSRT_Settings_Payment_Runtime')
&& !AKSRT_Settings_Payment_Runtime::is_gateway_enabled('paypal')) {
return false;
}
$config = $this->get_config(); $config = $this->get_config();
return !empty($config['client_id']) && !empty($config['client_secret']); return !empty($config['client_id']) && !empty($config['client_secret']);
} }
@@ -128,22 +132,17 @@ class AKSRT_PayPal_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
private function get_config(): array { private function get_config(): array {
// 优先从统一设置读取(schema 保存的 key) if (!class_exists('AKSRT_Settings')) {
if (class_exists('AKSRT_Settings')) { return [];
}
$all = AKSRT_Settings::get_all(); $all = AKSRT_Settings::get_all();
if (!empty($all['paypal_client_id'])) {
return [ return [
'client_id' => $all['paypal_client_id'] ?? '', 'client_id' => (string) ($all['paypal_client_id'] ?? ''),
'client_secret' => $all['paypal_client_secret'] ?? '', 'client_secret' => (string) ($all['paypal_client_secret'] ?? ''),
'currency' => $all['paypal_currency'] ?? 'USD', 'currency' => (string) ($all['paypal_currency'] ?? 'USD'),
'mode' => !empty($all['paypal_sandbox']) ? 'sandbox' : 'live', 'mode' => !empty($all['paypal_sandbox']) ? 'sandbox' : 'live',
]; ];
} }
}
// 回退到独立 option
$settings = get_option('aksrt_payment_paypal', []);
return is_array($settings) ? $settings : [];
}
/** /**
* 捕获已批准的 PayPal 订单(v2 CAPTURE 必需步骤)。 * 捕获已批准的 PayPal 订单(v2 CAPTURE 必需步骤)。
@@ -20,6 +20,10 @@ class AKSRT_Stripe_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
public function is_configured(): bool { public function is_configured(): bool {
if (class_exists('AKSRT_Settings_Payment_Runtime')
&& !AKSRT_Settings_Payment_Runtime::is_gateway_enabled('stripe')) {
return false;
}
$config = $this->get_config(); $config = $this->get_config();
return !empty($config['secret_key']) && !empty($config['publishable_key']); return !empty($config['secret_key']) && !empty($config['publishable_key']);
} }
@@ -233,23 +237,18 @@ class AKSRT_Stripe_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
private function get_config(): array { private function get_config(): array {
// 优先从统一设置读取(schema 保存的 key) if (!class_exists('AKSRT_Settings')) {
if (class_exists('AKSRT_Settings')) { return [];
}
$all = AKSRT_Settings::get_all(); $all = AKSRT_Settings::get_all();
if (!empty($all['stripe_secret_key'])) {
return [ return [
'secret_key' => $all['stripe_secret_key'] ?? '', 'secret_key' => (string) ($all['stripe_secret_key'] ?? ''),
'publishable_key' => $all['stripe_publishable_key'] ?? '', 'publishable_key' => (string) ($all['stripe_publishable_key'] ?? ''),
'webhook_secret' => $all['stripe_webhook_secret'] ?? '', 'webhook_secret' => (string) ($all['stripe_webhook_secret'] ?? ''),
'currency' => $all['stripe_currency'] ?? 'usd', 'currency' => (string) ($all['stripe_currency'] ?? 'usd'),
'mode' => !empty($all['stripe_test_mode']) ? 'test' : 'live', 'mode' => !empty($all['stripe_test_mode']) ? 'test' : 'live',
]; ];
} }
}
// 回退到独立 option
$settings = get_option('aksrt_payment_stripe', []);
return is_array($settings) ? $settings : [];
}
private function create_client(array $config): void { private function create_client(array $config): void {
\Stripe\Stripe::setApiKey($config['secret_key']); \Stripe\Stripe::setApiKey($config['secret_key']);
@@ -20,6 +20,10 @@ class AKSRT_WechatPay_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
public function is_configured(): bool { public function is_configured(): bool {
if (class_exists('AKSRT_Settings_Payment_Runtime')
&& !AKSRT_Settings_Payment_Runtime::is_gateway_enabled('wechatpay')) {
return false;
}
$config = $this->get_config(); $config = $this->get_config();
return !empty($config['mch_id']) && !empty($config['key']); return !empty($config['mch_id']) && !empty($config['key']);
} }
@@ -206,25 +210,20 @@ class AKSRT_WechatPay_Gateway implements AKSRT_Payment_Gateway_Interface {
} }
private function get_config(): array { private function get_config(): array {
// 优先从统一设置读取(schema 保存的 key) if (!class_exists('AKSRT_Settings')) {
if (class_exists('AKSRT_Settings')) { return [];
}
$all = AKSRT_Settings::get_all(); $all = AKSRT_Settings::get_all();
if (!empty($all['wechat_merchantid'])) {
return [ return [
'mch_id' => $all['wechat_merchantid'] ?? '', 'mch_id' => (string) ($all['wechat_merchantid'] ?? ''),
'key' => $all['wechat_jsapi'] ?? '', 'key' => (string) ($all['wechat_jsapi'] ?? ''),
'appid' => $all['wechat_appid'] ?? '', 'appid' => (string) ($all['wechat_appid'] ?? ''),
'appsecret' => $all['wechat_appsecret'] ?? '', 'appsecret' => (string) ($all['wechat_appsecret'] ?? ''),
'cert_path' => $all['wechat_cert_path'] ?? '', 'cert_path' => (string) ($all['wechat_cert_path'] ?? ''),
'key_path' => $all['wechat_key_path'] ?? '', 'key_path' => (string) ($all['wechat_key_path'] ?? ''),
'payment_type' => $all['wechat_payment_type'] ?? 'native', 'payment_type' => (string) ($all['wechat_payment_type'] ?? 'native'),
]; ];
} }
}
// 回退到独立 option
$settings = get_option('aksrt_payment_wechatpay', []);
return is_array($settings) ? $settings : [];
}
private function create_sdk(array $config): \Yurun\PaySDK\Weixin\SDK { private function create_sdk(array $config): \Yurun\PaySDK\Weixin\SDK {
$params = new \Yurun\PaySDK\Weixin\Params\PublicParams; $params = new \Yurun\PaySDK\Weixin\Params\PublicParams;
@@ -1,15 +1,22 @@
<?php <?php
/** /**
* Payment settings runtime — Zibll-aligned option keys. * Payment settings runtime — Zibll-aligned + intentional AKSRT keys.
* *
* Canonical keys (aligned with Zibll option IDs where applicable): * Zibll-aligned (pay_*):
* - Order/display: pay_no_logged_in, pay_cookie_day, pay_no_logged_remind, * - Display/order guest: pay_no_logged_in, pay_cookie_day, pay_no_logged_remind,
* pay_box_position, pay_mark, pay_show_user, pay_show_paycount, * pay_box_position, pay_mark, pay_show_user, pay_show_paycount,
* pay_free_logged_show, pay_wait_float_s * pay_free_logged_show, pay_wait_float_s, pay_service
* - Balance: pay_balance_s, pay_auto_to_balance, pay_balance_transfer_* * - Balance: pay_balance_s, pay_auto_to_balance, pay_balance_product*,
* - VIP: pay_user_vip_1_s / pay_user_vip_2_s (+ names, download limits) * pay_balance_transfer_*, pay_balance_pass_charge_*, pay_balance_exchange_*
* - VIP: pay_user_vip_1/2_*, pay_download_limit*, pay_download_speed*,
* pay_vip_pass_charge_*
* - Income/rebate: pay_income_*, pay_rebate_*
* *
* Stored in aksrt_settings. No dual-read of legacy payment_* keys. * Intentional AKSRT-native (payment_* / card_pass_* / withdraw_*):
* - Paid/download ops, gateway toggles+credentials, order prefix/expiry/status texts
* - payment_vip_packages (line format), payment_revenue_*, payment_affiliate_* extras
*
* Stored in aksrt_settings only. No dual-read of dropped keys.
* *
* @package AKSRT * @package AKSRT
*/ */
@@ -72,25 +79,24 @@ class AKSRT_Settings_Payment_Runtime {
public static function get_payment_recharge_settings(): array { public static function get_payment_recharge_settings(): array {
$settings = AKSRT_Settings::get_all(); $settings = AKSRT_Settings::get_all();
$packages = (string) ($settings['pay_balance_product'] ?? $settings['payment_recharge_packages'] ?? "30|30|入门包\n98|108|推荐包"); $packages = (string) ($settings['pay_balance_product'] ?? "30|30|入门包\n98|108|推荐包");
if (is_array($settings['pay_balance_product'] ?? null)) { if (is_array($settings['pay_balance_product'] ?? null)) {
$packages = self::format_product_lines((array) $settings['pay_balance_product']); $packages = self::format_product_lines((array) $settings['pay_balance_product']);
} }
$help_text = trim((string) ($settings['pay_balance_desc'] ?? $settings['payment_recharge_help'] ?? '')); $desc = sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? ''));
return [ return [
'enabled' => !empty($settings['pay_balance_s']), 'enabled' => !empty($settings['pay_balance_s']),
'mode' => 'manual_review', 'desc' => $desc,
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? '')),
'auto_to_balance' => !isset($settings['pay_auto_to_balance']) || !empty($settings['pay_auto_to_balance']), 'auto_to_balance' => !isset($settings['pay_auto_to_balance']) || !empty($settings['pay_auto_to_balance']),
'packages_raw' => $packages, 'packages_raw' => $packages,
'package_count' => self::count_structured_lines($packages), 'package_count' => self::count_structured_lines($packages),
'help_text' => $help_text !== '' ? $help_text : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'), 'help_text' => $desc !== '' ? $desc : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'),
'product' => [ 'product' => [
'name' => '', 'name' => sanitize_text_field((string) ($settings['pay_balance_product_name'] ?? '')),
'price' => 0, 'price' => max(0, (float) ($settings['pay_balance_price'] ?? 0)),
'tag' => '元', 'tag' => sanitize_text_field((string) ($settings['pay_balance_tag'] ?? '元')),
'tag_class' => '', 'tag_class' => sanitize_text_field((string) ($settings['pay_balance_tag_class'] ?? '')),
'custom_s' => !isset($settings['pay_balance_product_custom_s']) || !empty($settings['pay_balance_product_custom_s']), 'custom_s' => !isset($settings['pay_balance_product_custom_s']) || !empty($settings['pay_balance_product_custom_s']),
'custom_limit' => max(1, min(99999, (int) ($settings['pay_balance_product_custom_limit'] ?? 9999))), 'custom_limit' => max(1, min(99999, (int) ($settings['pay_balance_product_custom_limit'] ?? 9999))),
], ],
@@ -105,9 +111,9 @@ class AKSRT_Settings_Payment_Runtime {
'only_password' => !empty($settings['pay_balance_pass_charge_only_password']), 'only_password' => !empty($settings['pay_balance_pass_charge_only_password']),
], ],
'exchange' => [ 'exchange' => [
'enabled' => false, 'enabled' => !empty($settings['pay_balance_exchange_s']),
'rate' => 100, 'rate' => max(1, min(10000, (int) ($settings['pay_balance_exchange_rate'] ?? 100))),
'desc' => '', 'desc' => sanitize_textarea_field((string) ($settings['pay_balance_exchange_desc'] ?? '')),
], ],
]; ];
} }
@@ -141,22 +147,22 @@ class AKSRT_Settings_Payment_Runtime {
} }
$packages = (string) ($settings['payment_vip_packages'] ?? "30|30|月卡\n365|365|年卡"); $packages = (string) ($settings['payment_vip_packages'] ?? "30|30|月卡\n365|365|年卡");
$help_text = trim((string) ($settings['pay_user_vip_desc'] ?? $settings['payment_vip_help'] ?? '')); $desc = sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? ''));
return [ return [
'enabled' => $enabled, 'enabled' => $enabled,
'name' => $vip1_enabled ? $name1 : $badge, 'name' => $vip1_enabled ? $name1 : $badge,
'badge_text' => $badge, 'badge_text' => $badge,
'desc' => sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? '')), 'desc' => $desc,
'packages_raw' => $packages, 'packages_raw' => $packages,
'package_count' => self::count_structured_lines($packages), 'package_count' => self::count_structured_lines($packages),
'help_text' => $help_text !== '' ? $help_text : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'), 'help_text' => $desc !== '' ? $desc : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'),
'levels' => [ 'levels' => [
1 => [ 1 => [
'enabled' => $vip1_enabled, 'enabled' => $vip1_enabled,
'name' => $name1, 'name' => $name1,
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? $settings['pay_download_limit'] ?? 0))), 'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? $settings['pay_download_speed'] ?? 0))), 'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? 0))),
], ],
2 => [ 2 => [
'enabled' => $vip2_enabled, 'enabled' => $vip2_enabled,
@@ -168,7 +174,6 @@ class AKSRT_Settings_Payment_Runtime {
'benefit' => [ 'benefit' => [
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))), 'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))), 'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))),
'discount' => 100,
'pass_charge' => !empty($settings['pay_vip_pass_charge_s']), 'pass_charge' => !empty($settings['pay_vip_pass_charge_s']),
'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')), 'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')),
], ],
@@ -184,14 +189,6 @@ class AKSRT_Settings_Payment_Runtime {
'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')), 'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')),
'product' => sanitize_text_field((string) ($settings['vip_upgrade_product'] ?? '')), 'product' => sanitize_text_field((string) ($settings['vip_upgrade_product'] ?? '')),
], ],
'price' => [
'month' => 0,
'year' => 0,
'permanent' => 0,
'unit' => 0,
'unit_tag' => '元',
'jump' => 0,
],
]; ];
} }
@@ -200,13 +197,13 @@ class AKSRT_Settings_Payment_Runtime {
*/ */
public static function get_payment_revenue_settings(): array { public static function get_payment_revenue_settings(): array {
$settings = AKSRT_Settings::get_all(); $settings = AKSRT_Settings::get_all();
$note = trim((string) ($settings['pay_income_desc_details'] ?? $settings['payment_revenue_note'] ?? '')); $note = trim((string) ($settings['payment_revenue_note'] ?? ''));
return [ return [
'enabled' => !empty($settings['pay_income_s']), 'enabled' => !empty($settings['pay_income_s']),
'share_ratio' => max(0, min(100, (int) ($settings['payment_revenue_share_ratio'] ?? 70))), 'share_ratio' => max(0, min(100, (int) ($settings['payment_revenue_share_ratio'] ?? 70))),
'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? $settings['payment_revenue_ratio_vip1'] ?? 0))), 'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? 0))),
'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? $settings['payment_revenue_ratio_vip2'] ?? 0))), 'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? 0))),
'settlement_threshold' => max(0, (int) ($settings['payment_revenue_settlement_threshold'] ?? 100)), 'settlement_threshold' => max(0, (int) ($settings['payment_revenue_settlement_threshold'] ?? 100)),
'cycle_days' => max(1, min(365, (int) ($settings['payment_revenue_cycle_days'] ?? 30))), 'cycle_days' => max(1, min(365, (int) ($settings['payment_revenue_cycle_days'] ?? 30))),
'points_rule' => sanitize_textarea_field((string) ($settings['payment_revenue_points_rule'] ?? '')), 'points_rule' => sanitize_textarea_field((string) ($settings['payment_revenue_points_rule'] ?? '')),
@@ -223,18 +220,18 @@ class AKSRT_Settings_Payment_Runtime {
*/ */
public static function get_payment_affiliate_settings(): array { public static function get_payment_affiliate_settings(): array {
$settings = AKSRT_Settings::get_all(); $settings = AKSRT_Settings::get_all();
$note = trim((string) ($settings['pay_rebate_text_desc'] ?? $settings['payment_affiliate_note'] ?? '')); $note = trim((string) ($settings['pay_rebate_text_desc'] ?? ''));
return [ return [
'enabled' => !empty($settings['pay_rebate_s']), 'enabled' => !empty($settings['pay_rebate_s']),
'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? $settings['payment_affiliate_ratio'] ?? 10))), 'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))),
'window_days' => max(1, min(365, (int) ($settings['payment_affiliate_window_days'] ?? 30))), 'window_days' => max(1, min(365, (int) ($settings['payment_affiliate_window_days'] ?? 30))),
'require_paid_order' => true, 'require_paid_order' => !isset($settings['payment_affiliate_require_paid_order']) || !empty($settings['payment_affiliate_require_paid_order']),
'self_s' => !isset($settings['pay_rebate_self_s']) || !empty($settings['pay_rebate_self_s']), 'self_s' => !isset($settings['pay_rebate_self_s']) || !empty($settings['pay_rebate_self_s']),
'show_users' => !isset($settings['pay_rebate_show_users']) || !empty($settings['pay_rebate_show_users']), 'show_users' => !isset($settings['pay_rebate_show_users']) || !empty($settings['pay_rebate_show_users']),
'note' => $note !== '' ? $note : __('返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。', 'aksrt'), 'note' => $note !== '' ? $note : __('返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。', 'aksrt'),
'user_ratio' => [ 'user_ratio' => [
'user' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))), 'user' => max(0, min(100, (int) ($settings['payment_affiliate_user_ratio'] ?? $settings['pay_rebate_ratio'] ?? 10))),
'vip1' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_1'] ?? 0))), 'vip1' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_1'] ?? 0))),
'vip2' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_2'] ?? 0))), 'vip2' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_2'] ?? 0))),
], ],
@@ -303,7 +300,7 @@ class AKSRT_Settings_Payment_Runtime {
} }
/** /**
* Order display / checkout policy (Zibll pay_* contract). * Order display / checkout policy (Zibll pay_* + AKSRT order ops).
* *
* @return array<string,mixed> * @return array<string,mixed>
*/ */
@@ -347,11 +344,11 @@ class AKSRT_Settings_Payment_Runtime {
'show_pay_time' => !isset($s['payment_show_pay_time']) || !empty($s['payment_show_pay_time']), 'show_pay_time' => !isset($s['payment_show_pay_time']) || !empty($s['payment_show_pay_time']),
'status_texts' => $status_texts, 'status_texts' => $status_texts,
'service' => [ 'service' => [
'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? $s['payment_service'] ?? '')), 'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? '')),
'icon' => sanitize_text_field((string) ($s['payment_service_icon'] ?? '')), 'icon' => sanitize_text_field((string) ($s['pay_service_icon'] ?? '')),
'value' => sanitize_text_field((string) ($s['payment_service_value'] ?? '')), 'value' => sanitize_text_field((string) ($s['pay_service_value'] ?? '')),
'qq' => sanitize_text_field((string) ($s['payment_service_qq'] ?? '')), 'qq' => sanitize_text_field((string) ($s['pay_service_qq'] ?? '')),
'wechat' => esc_url_raw((string) ($s['payment_service_wechat'] ?? '')), 'wechat' => esc_url_raw((string) ($s['pay_service_wechat'] ?? '')),
], ],
]; ];
} }
@@ -401,6 +398,36 @@ class AKSRT_Settings_Payment_Runtime {
]; ];
} }
/**
* Whether a registered adapter is admin-enabled.
* Maps gateway ids (wechatpay) to schema toggles (payment_wechat_enabled).
*/
public static function is_gateway_enabled(string $gateway_id): bool {
$settings = AKSRT_Settings::get_all();
$map = [
'alipay' => 'payment_alipay_enabled',
'wechatpay' => 'payment_wechat_enabled',
'paypal' => 'payment_paypal_enabled',
'stripe' => 'payment_stripe_enabled',
'balance' => 'payment_balance_enabled',
'card_pass' => 'payment_card_pass_enabled',
'xunhupay' => 'payment_xunhupay_enabled',
'xhpay' => 'payment_xhpay_enabled',
'payjs' => 'payment_payjs_enabled',
'epay' => 'payment_epay_enabled',
'vmq' => 'payment_vmq_enabled',
'codepay' => 'payment_codepay_enabled',
];
$key = $map[$gateway_id] ?? '';
if ($key === '') {
return false;
}
if ($gateway_id === 'balance') {
return !empty($settings['payment_balance_enabled']) && !empty($settings['pay_balance_s']);
}
return !empty($settings[$key]);
}
/** /**
* @param string[] $fallback * @param string[] $fallback
* @return string[] * @return string[]
@@ -122,6 +122,12 @@ class AKSRT_Shop_Checkout_Service {
'discount' => $data['discount'], 'discount' => $data['discount'],
]; ];
$expiry_minutes = 30;
if (class_exists('AKSRT_Settings')) {
$order_settings = AKSRT_Settings::get_order_settings();
$expiry_minutes = max(5, min(1440, (int) ($order_settings['expiry'] ?? 30)));
}
$order_number = AKSRT_Order_Repository::get_instance()->create([ $order_number = AKSRT_Order_Repository::get_instance()->create([
'user_id' => $user_id, 'user_id' => $user_id,
'product_type' => 'shop_product', 'product_type' => 'shop_product',
@@ -130,7 +136,7 @@ class AKSRT_Shop_Checkout_Service {
'currency' => 'CNY', 'currency' => 'CNY',
'status' => AKSRT_Order::STATUS_PENDING, 'status' => AKSRT_Order::STATUS_PENDING,
'payment_method' => $payment_method, 'payment_method' => $payment_method,
'expires_at' => date('Y-m-d H:i:s', strtotime('+10 minutes')), 'expires_at' => date('Y-m-d H:i:s', strtotime('+' . $expiry_minutes . ' minutes')),
'note' => wp_json_encode($meta_payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'note' => wp_json_encode($meta_payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
]); ]);
@@ -246,14 +252,20 @@ class AKSRT_Shop_Checkout_Service {
return ['success' => false, 'message' => __('订单金额无效。', 'aksrt')]; return ['success' => false, 'message' => __('订单金额无效。', 'aksrt')];
} }
$balance = AKSRT_Credits::get_balance($user_id); $balance = AKSRT_Credits::balance($user_id);
if ($balance < $amount) { if ($balance < $amount) {
return ['success' => false, 'message' => sprintf(__('积分不足,需要 %d 积分,当前余额 %d。', 'aksrt'), $amount, $balance)]; return ['success' => false, 'message' => sprintf(__('积分不足,需要 %d 积分,当前余额 %d。', 'aksrt'), $amount, $balance)];
} }
$deducted = AKSRT_Credits::deduct($amount, $user_id, 'shop_points_pay', sprintf(__('积分购买订单 %s', 'aksrt'), $order_number)); $deducted = AKSRT_Credits::deduct(
if (!$deducted) { $user_id,
return ['success' => false, 'message' => __('积分扣除失败。', 'aksrt')]; $amount,
'shop_points_pay',
['order' => $order_number],
sprintf(__('积分购买订单 %s', 'aksrt'), $order_number)
);
if (is_wp_error($deducted)) {
return ['success' => false, 'message' => $deducted->get_error_message() ?: __('积分扣除失败。', 'aksrt')];
} }
$repo = AKSRT_Order_Repository::get_instance(); $repo = AKSRT_Order_Repository::get_instance();
@@ -74,25 +74,70 @@ class AKSRT_Shop_Product_Service {
} }
public function get_payment_method_options(): array { public function get_payment_method_options(): array {
return [ $methods = [];
'balance' => [
'value' => 'balance', if (class_exists('AKSRT_Payment_Gateway')) {
'label' => __('站内余额', 'aksrt'), foreach (AKSRT_Payment_Gateway::get_instance()->get_all() as $id => $gateway) {
'description' => __('即时完成支付并写回订单状态。', 'aksrt'), if (!method_exists($gateway, 'is_configured') || !$gateway->is_configured()) {
], continue;
'points' => [ }
$methods[$id] = [
'value' => $id,
'label' => method_exists($gateway, 'get_name') ? (string) $gateway->get_name() : $id,
'description' => $this->gateway_method_description((string) $id),
];
}
}
if (class_exists('AKSRT_Settings') && AKSRT_Settings::credits_enabled()) {
$methods['points'] = [
'value' => 'points', 'value' => 'points',
'label' => __('积分兑换', 'aksrt'), 'label' => __('积分兑换', 'aksrt'),
'description' => __('使用积分购买积分商品。', 'aksrt'), 'description' => __('使用积分购买积分商品。', 'aksrt'),
], ];
'manual_review' => [ }
$manual = true;
if (class_exists('AKSRT_Settings')) {
$gw = AKSRT_Settings::get_payment_gateway_settings();
$manual = !empty($gw['manual_review']) || ($gw['mode'] ?? '') === 'manual_review';
}
if ($manual) {
$methods['manual_review'] = [
'value' => 'manual_review', 'value' => 'manual_review',
'label' => __('人工确认', 'aksrt'), 'label' => __('人工确认', 'aksrt'),
'description' => __('保留待支付订单,后续由管理员确认。', 'aksrt'), 'description' => __('保留待支付订单,后续由管理员确认。', 'aksrt'),
],
]; ];
} }
if (empty($methods)) {
$methods['manual_review'] = [
'value' => 'manual_review',
'label' => __('人工确认', 'aksrt'),
'description' => __('保留待支付订单,后续由管理员确认。', 'aksrt'),
];
}
return $methods;
}
private function gateway_method_description(string $id): string {
switch ($id) {
case 'balance':
return __('即时完成支付并写回订单状态。', 'aksrt');
case 'alipay':
return __('跳转支付宝完成支付。', 'aksrt');
case 'wechatpay':
return __('微信扫码或跳转完成支付。', 'aksrt');
case 'paypal':
return __('跳转 PayPal 完成支付。', 'aksrt');
case 'stripe':
return __('跳转 Stripe Checkout 完成支付。', 'aksrt');
default:
return '';
}
}
public function get_shipping_method_options(): array { public function get_shipping_method_options(): array {
return [ return [
'express' => [ 'express' => [