feat(revenue): immediate commission credit with independent withdrawable pool
Aligns affiliate commission with the reference theme: commission is credited to a dedicated COMMISSION asset pool the moment an order is paid, removing the 7-day settlement freeze, the settlement cron, and the settlement_days setting. - Ledger: add AssetType::COMMISSION (isolated from the recharge balance wallet) - CommissionLedger: credit-on-record + opportunistic debt repayment; refunds claw back the full commission from the pool, carrying any shortfall as debt (aksrt_commission_debt) that future commission pays down first - Withdrawal: make asset-aware via a source discriminator (commission vs balance); each pool keeps independent daily limits, pending gate, and reject-refund. Balance withdrawal (recharge + creator income) is unchanged - Fix pay_rebate_self_s: honor self-commission at purchase time - Revenue card: show pool balance + 累计/已提现 (drop 待结算), debt when present - Schema 2.0.0 -> 2.1.0: add commission_debt, drop freeze columns
This commit is contained in:
1 parent
cded20ae02
commit
61667aa03c
22 files changed
+569
-268
No files matched your search
@@ -43,8 +43,12 @@ $withdraw_min = $normalize_balance($withdrawal['min_amount'] ?? '50')->decimal()
|
||||
|
||||
$commission_stats = class_exists('\AKSRT\Payment\CommissionLedger')
|
||||
? \AKSRT\Payment\CommissionLedger::get_instance()->overview($user_id)
|
||||
: ['total' => 0, 'pending' => 0, 'settled' => 0, 'wallet' => 0];
|
||||
$pending_commission = $normalize_balance($commission_stats['pending'] ?? '0')->decimal();
|
||||
: ['total' => 0, 'pool' => 0, 'withdrawn' => 0, 'debt' => 0];
|
||||
/* 佣金池提现的每日次数/额度:与余额提现相互独立,按 commission source 计。 */
|
||||
$commission_withdraw_usage = ['remaining_count' => 0, 'remaining_amount' => '0.00'];
|
||||
if ($withdraw_on && class_exists('\AKSRT\Payment\Withdrawal')) {
|
||||
$commission_withdraw_usage = \AKSRT\Payment\Withdrawal::get_instance()->daily_usage($user_id, $withdrawal, \AKSRT\Payment\Withdrawal::SOURCE_COMMISSION);
|
||||
}
|
||||
$commission_ratio = class_exists('\AKSRT\Settings\Settings')
|
||||
? (int) \AKSRT\Settings\Settings::affiliate_ratio_for_user($user_id)
|
||||
: 0;
|
||||
@@ -109,11 +113,24 @@ if ($commission_page > $commission_total_pages) {
|
||||
}
|
||||
$commission_items = (array) ($commission_view['items'] ?? []);
|
||||
$status_labels = [
|
||||
'pending' => __('待结算', 'aksrt'),
|
||||
'settled' => __('已结算', 'aksrt'),
|
||||
'cancelled' => __('已取消', 'aksrt'),
|
||||
'credited' => __('已入账', 'aksrt'),
|
||||
'cancelled' => __('已退款', 'aksrt'),
|
||||
];
|
||||
?>
|
||||
<?php
|
||||
$pool_amount = $format_amount($commission_stats['pool'] ?? 0);
|
||||
$total_amount = $format_amount($commission_stats['total'] ?? 0);
|
||||
$withdrawn_amount = $format_amount($commission_stats['withdrawn'] ?? 0);
|
||||
$debt_amount = $format_amount($commission_stats['debt'] ?? 0);
|
||||
$reward_panes = ['detail'];
|
||||
if ($affiliate_on) {
|
||||
$reward_panes[] = 'orders';
|
||||
}
|
||||
$reward_panes[] = 'users';
|
||||
$pane_is_active = static function (string $tab) use ($active_reward_tab): bool {
|
||||
return $active_reward_tab === $tab;
|
||||
};
|
||||
?>
|
||||
<div class="uc-revenue-panel" data-aksrt-revenue-page>
|
||||
<?php if ($affiliate_on) : ?>
|
||||
<section class="uc-commission-summary" aria-label="<?php esc_attr_e('佣金概览', 'aksrt'); ?>">
|
||||
@@ -127,9 +144,16 @@ $status_labels = [
|
||||
<article class="uc-commission-card uc-commission-card--balance">
|
||||
<div class="uc-commission-card__body">
|
||||
<span><?php esc_html_e('我的佣金', 'aksrt'); ?></span>
|
||||
<strong><small>¥</small><?php echo esc_html($format_amount($pending_commission)); ?></strong>
|
||||
<span><?php printf(esc_html__('累计佣金 ¥%s', 'aksrt'), esc_html($format_amount($commission_stats['total'] ?? 0))); ?></span>
|
||||
<strong><small>¥</small><?php echo esc_html($pool_amount); ?></strong>
|
||||
<p class="uc-commission-card__meta">
|
||||
<span><?php printf(esc_html__('累计佣金 ¥%s', 'aksrt'), esc_html($total_amount)); ?></span>
|
||||
<span><?php printf(esc_html__('已提现 ¥%s', 'aksrt'), esc_html($withdrawn_amount)); ?></span>
|
||||
<?php if (($commission_stats['debt'] ?? '0.00') !== '0.00') : ?><span class="uc-commission-card__debt"><?php printf(esc_html__('待偿欠款 ¥%s', 'aksrt'), esc_html($debt_amount)); ?></span><?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php if ($withdraw_on) : ?>
|
||||
<button type="button" class="uc-commission-card__action" data-aksrt-withdraw-open data-aksrt-withdraw-source="commission" data-withdraw-min="<?php echo esc_attr($withdraw_min); ?>" data-withdraw-remaining-amount="<?php echo esc_attr((string) ($commission_withdraw_usage['remaining_amount'] ?? '0.00')); ?>" data-withdraw-remaining-count="<?php echo esc_attr((string) ($commission_withdraw_usage['remaining_count'] ?? 0)); ?>"><?php esc_html_e('立即提现', 'aksrt'); ?><i class="fa fas fa-angle-right" aria-hidden="true"></i></button>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
@@ -139,61 +163,59 @@ $status_labels = [
|
||||
<span><?php echo esc_html($affiliate_on ? __('推广链接、佣金订单与推广用户', 'aksrt') : __('推广链接与推广用户', 'aksrt')); ?></span>
|
||||
</div>
|
||||
<nav class="uc-reward-tabs" aria-label="<?php esc_attr_e('收益明细', 'aksrt'); ?>">
|
||||
<a <?php echo $active_reward_tab === 'detail' ? 'aria-current="page"' : ''; ?> class="<?php echo $active_reward_tab === 'detail' ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('detail')); ?>"><?php esc_html_e('推广详情', 'aksrt'); ?></a>
|
||||
<?php if ($affiliate_on) : ?><a <?php echo $active_reward_tab === 'orders' ? 'aria-current="page"' : ''; ?> class="<?php echo $active_reward_tab === 'orders' ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders')); ?>"><?php esc_html_e('佣金明细', 'aksrt'); ?></a><?php endif; ?>
|
||||
<a <?php echo $active_reward_tab === 'users' ? 'aria-current="page"' : ''; ?> class="<?php echo $active_reward_tab === 'users' ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('users')); ?>"><?php esc_html_e('推广用户', 'aksrt'); ?></a>
|
||||
<a data-reward-tab="detail" <?php echo $pane_is_active('detail') ? 'aria-current="page"' : ''; ?> class="<?php echo $pane_is_active('detail') ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('detail')); ?>"><?php esc_html_e('推广详情', 'aksrt'); ?></a>
|
||||
<?php if ($affiliate_on) : ?><a data-reward-tab="orders" <?php echo $pane_is_active('orders') ? 'aria-current="page"' : ''; ?> class="<?php echo $pane_is_active('orders') ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders')); ?>"><?php esc_html_e('佣金明细', 'aksrt'); ?></a><?php endif; ?>
|
||||
<a data-reward-tab="users" <?php echo $pane_is_active('users') ? 'aria-current="page"' : ''; ?> class="<?php echo $pane_is_active('users') ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('users')); ?>"><?php esc_html_e('推广用户', 'aksrt'); ?></a>
|
||||
</nav>
|
||||
|
||||
<?php if ($active_reward_tab === 'detail') : ?>
|
||||
<div class="uc-reward-pane uc-reward-pane--detail" data-aksrt-revenue-page>
|
||||
<div class="uc-revenue-summary-list">
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--link">
|
||||
<span><?php esc_html_e('推广链接', 'aksrt'); ?></span>
|
||||
<input type="text" readonly data-affiliate-link value="<?php echo esc_attr($affiliate_link_url); ?>" aria-label="<?php esc_attr_e('推广链接', 'aksrt'); ?>">
|
||||
<button type="button" class="btn-primary btn-sm" data-affiliate-copy><?php esc_html_e('复制链接', 'aksrt'); ?></button>
|
||||
<?php if (!empty($affiliate['poster']['enabled'])) : ?><button type="button" class="btn-outline btn-sm" data-affiliate-poster hidden><?php esc_html_e('推广海报', 'aksrt'); ?></button><?php endif; ?>
|
||||
<small data-affiliate-feedback role="status" aria-live="polite"></small>
|
||||
</div>
|
||||
<?php if ($affiliate_on) : ?>
|
||||
<div class="uc-revenue-summary-row"><span><?php esc_html_e('佣金比例', 'aksrt'); ?></span><strong data-affiliate-ratio><?php echo esc_html((string) $commission_ratio); ?>%</strong></div>
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--total"><span><?php esc_html_e('累计佣金', 'aksrt'); ?></span><div><strong><?php printf(esc_html__('累计 %s 元', 'aksrt'), esc_html($format_amount($commission_stats['total'] ?? 0))); ?></strong><strong><?php printf(esc_html__('待结算 %s 元', 'aksrt'), esc_html($format_amount($commission_stats['pending'] ?? 0))); ?></strong></div></div>
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--explain"><span><?php echo esc_html($details_title); ?></span><div class="uc-reward-richtext"><?php echo wp_kses_post(wpautop($details_text)); ?></div></div>
|
||||
<?php endif; ?>
|
||||
<div class="uc-reward-pane uc-reward-pane--detail" data-reward-pane="detail"<?php echo $pane_is_active('detail') ? '' : ' hidden'; ?>>
|
||||
<div class="uc-revenue-summary-list">
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--link">
|
||||
<span><?php esc_html_e('推广链接', 'aksrt'); ?></span>
|
||||
<input type="text" readonly data-affiliate-link value="<?php echo esc_attr($affiliate_link_url); ?>" aria-label="<?php esc_attr_e('推广链接', 'aksrt'); ?>">
|
||||
<button type="button" class="btn-primary btn-sm" data-affiliate-copy><?php esc_html_e('复制链接', 'aksrt'); ?></button>
|
||||
<?php if (!empty($affiliate['poster']['enabled'])) : ?><button type="button" class="btn-outline btn-sm" data-affiliate-poster hidden><?php esc_html_e('推广海报', 'aksrt'); ?></button><?php endif; ?>
|
||||
<small data-affiliate-feedback role="status" aria-live="polite"></small>
|
||||
</div>
|
||||
<?php if ($affiliate_on) : ?>
|
||||
<div class="uc-revenue-summary-row"><span><?php esc_html_e('佣金比例', 'aksrt'); ?></span><strong data-affiliate-ratio><?php echo esc_html((string) $commission_ratio); ?>%</strong></div>
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--total"><span><?php esc_html_e('累计佣金', 'aksrt'); ?></span><div><strong><?php printf(esc_html__('累计 %s 元', 'aksrt'), esc_html($total_amount)); ?></strong><strong><?php printf(esc_html__('可提现 %s 元', 'aksrt'), esc_html($pool_amount)); ?></strong><strong><?php printf(esc_html__('已提现 %s 元', 'aksrt'), esc_html($withdrawn_amount)); ?></strong><?php if (($commission_stats['debt'] ?? '0.00') !== '0.00') : ?><strong><?php printf(esc_html__('待偿欠款 %s 元', 'aksrt'), esc_html($debt_amount)); ?></strong><?php endif; ?></div></div>
|
||||
<div class="uc-revenue-summary-row uc-revenue-summary-row--explain"><span><?php echo esc_html($details_title); ?></span><div class="uc-reward-richtext"><?php echo wp_kses_post(wpautop($details_text)); ?></div></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php elseif ($active_reward_tab === 'orders') : ?>
|
||||
<div class="uc-reward-pane">
|
||||
<div class="uc-reward-list-heading"><div><h4><?php esc_html_e('佣金订单', 'aksrt'); ?></h4><p><?php esc_html_e('每页显示 10 条佣金记录。', 'aksrt'); ?></p></div><strong><?php printf(esc_html__('%d 条', 'aksrt'), (int) ($commission_view['total'] ?? 0)); ?></strong></div>
|
||||
<?php if ($commission_items) : ?>
|
||||
<div class="uc-commission-list">
|
||||
<?php foreach ($commission_items as $item) :
|
||||
$status = sanitize_key((string) ($item['status'] ?? 'pending'));
|
||||
$source_user = !empty($item['source_user_id']) ? get_userdata((int) $item['source_user_id']) : null;
|
||||
$source_name = $source_user instanceof WP_User ? $source_user->display_name : __('推广用户', 'aksrt');
|
||||
?>
|
||||
<?php
|
||||
$commission_minor = $signed_balance_minor($item['original_amount'] ?? '0') + $signed_balance_minor($item['adjustment_total'] ?? '0');
|
||||
$commission_amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor(max(0, $commission_minor));
|
||||
?>
|
||||
<article class="uc-commission-row"><span class="uc-commission-row__icon"><i class="fa fas fa-file-alt" aria-hidden="true"></i></span><div class="uc-commission-row__main"><strong><?php echo esc_html($source_name); ?></strong><span><?php printf(esc_html__('订单 %s', 'aksrt'), esc_html((string) ($item['order_number'] ?? '-'))); ?></span><time><?php echo esc_html((string) ($item['created_at'] ?? '')); ?></time></div><div class="uc-commission-row__value"><strong><?php echo esc_html($format_amount($commission_amount)); ?></strong><span class="is-<?php echo esc_attr($status); ?>"><?php echo esc_html($status_labels[$status] ?? $status); ?></span></div></article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($commission_total_pages > 1) : ?><nav class="uc-reward-pagination" aria-label="<?php esc_attr_e('佣金明细分页', 'aksrt'); ?>"><?php for ($i = 1; $i <= $commission_total_pages; $i++) : ?><a class="<?php echo $i === $commission_page ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders', ['commission_page' => $i])); ?>"><?php echo esc_html((string) $i); ?></a><?php endfor; ?></nav><?php endif; ?>
|
||||
<?php else : ?><p class="uc-reward-empty"><?php esc_html_e('暂无佣金订单', 'aksrt'); ?></p><?php endif; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="uc-reward-pane">
|
||||
<div class="uc-reward-list-heading"><div><h4><?php esc_html_e('推广用户', 'aksrt'); ?></h4><p><?php esc_html_e('通过你的 ref 推广链接完成绑定的用户。', 'aksrt'); ?></p></div><strong><?php printf(esc_html__('%d 人', 'aksrt'), (int) ($user_view['total'] ?? 0)); ?></strong></div>
|
||||
<?php if (!empty($user_view['items'])) : ?>
|
||||
<div class="uc-revenue-user-list">
|
||||
<?php foreach ($user_view['items'] as $item) : ?>
|
||||
<article class="uc-revenue-user-row"><img src="<?php echo esc_url((string) ($item['avatar'] ?? '')); ?>" alt=""><div><strong><?php echo esc_html((string) ($item['name'] ?? __('推广用户', 'aksrt'))); ?></strong><small><?php echo esc_html((string) ($item['bound_at'] ?? '')); ?></small></div><span><?php esc_html_e('已绑定', 'aksrt'); ?></span></article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($user_total_pages > 1) : ?><nav class="uc-reward-pagination" aria-label="<?php esc_attr_e('推广用户分页', 'aksrt'); ?>"><?php for ($i = 1; $i <= $user_total_pages; $i++) : ?><a class="<?php echo $i === $user_page ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('users', ['user_page' => $i])); ?>"><?php echo esc_html((string) $i); ?></a><?php endfor; ?></nav><?php endif; ?>
|
||||
<?php else : ?><p class="uc-reward-empty"><?php esc_html_e('暂无推广用户', 'aksrt'); ?></p><?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($affiliate_on) : ?>
|
||||
<div class="uc-reward-pane" data-reward-pane="orders"<?php echo $pane_is_active('orders') ? '' : ' hidden'; ?>>
|
||||
<div class="uc-reward-list-heading"><div><h4><?php esc_html_e('佣金订单', 'aksrt'); ?></h4><p><?php esc_html_e('每页显示 10 条佣金记录。', 'aksrt'); ?></p></div><strong><?php printf(esc_html__('%d 条', 'aksrt'), (int) ($commission_view['total'] ?? 0)); ?></strong></div>
|
||||
<?php if ($commission_items) : ?>
|
||||
<div class="uc-commission-list">
|
||||
<?php foreach ($commission_items as $item) :
|
||||
$status = sanitize_key((string) ($item['status'] ?? 'pending'));
|
||||
$source_user = !empty($item['source_user_id']) ? get_userdata((int) $item['source_user_id']) : null;
|
||||
$source_name = $source_user instanceof WP_User ? $source_user->display_name : __('推广用户', 'aksrt');
|
||||
$commission_minor = $signed_balance_minor($item['original_amount'] ?? '0') + $signed_balance_minor($item['adjustment_total'] ?? '0');
|
||||
$commission_amount = \AKSRT\Ledger\AssetAmount::decimal_from_minor(max(0, $commission_minor));
|
||||
?>
|
||||
<article class="uc-commission-row"><span class="uc-commission-row__icon"><i class="fa fas fa-file-alt" aria-hidden="true"></i></span><div class="uc-commission-row__main"><strong><?php echo esc_html($source_name); ?></strong><span><?php printf(esc_html__('订单 %s', 'aksrt'), esc_html((string) ($item['order_number'] ?? '-'))); ?></span><time><?php echo esc_html((string) ($item['created_at'] ?? '')); ?></time></div><div class="uc-commission-row__value"><strong><?php echo esc_html($format_amount($commission_amount)); ?></strong><span class="is-<?php echo esc_attr($status); ?>"><?php echo esc_html($status_labels[$status] ?? $status); ?></span></div></article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($commission_total_pages > 1) : ?><nav class="uc-reward-pagination" aria-label="<?php esc_attr_e('佣金明细分页', 'aksrt'); ?>"><?php for ($i = 1; $i <= $commission_total_pages; $i++) : ?><a class="<?php echo $i === $commission_page ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('orders', ['commission_page' => $i])); ?>"><?php echo esc_html((string) $i); ?></a><?php endfor; ?></nav><?php endif; ?>
|
||||
<?php else : ?><p class="uc-reward-empty"><?php esc_html_e('暂无佣金订单', 'aksrt'); ?></p><?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="uc-reward-pane" data-reward-pane="users"<?php echo $pane_is_active('users') ? '' : ' hidden'; ?>>
|
||||
<div class="uc-reward-list-heading"><div><h4><?php esc_html_e('推广用户', 'aksrt'); ?></h4><p><?php esc_html_e('通过你的 ref 推广链接完成绑定的用户。', 'aksrt'); ?></p></div><strong><?php printf(esc_html__('%d 人', 'aksrt'), (int) ($user_view['total'] ?? 0)); ?></strong></div>
|
||||
<?php if (!empty($user_view['items'])) : ?>
|
||||
<div class="uc-revenue-user-list">
|
||||
<?php foreach ($user_view['items'] as $item) : ?>
|
||||
<article class="uc-revenue-user-row"><img src="<?php echo esc_url((string) ($item['avatar'] ?? '')); ?>" alt=""><div><strong><?php echo esc_html((string) ($item['name'] ?? __('推广用户', 'aksrt'))); ?></strong><small><?php echo esc_html((string) ($item['bound_at'] ?? '')); ?></small></div><span><?php esc_html_e('已绑定', 'aksrt'); ?></span></article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($user_total_pages > 1) : ?><nav class="uc-reward-pagination" aria-label="<?php esc_attr_e('推广用户分页', 'aksrt'); ?>"><?php for ($i = 1; $i <= $user_total_pages; $i++) : ?><a class="<?php echo $i === $user_page ? 'is-active' : ''; ?>" href="<?php echo esc_url($reward_url('users', ['user_page' => $i])); ?>"><?php echo esc_html((string) $i); ?></a><?php endfor; ?></nav><?php endif; ?>
|
||||
<?php else : ?><p class="uc-reward-empty"><?php esc_html_e('暂无推广用户', 'aksrt'); ?></p><?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<?php if ($withdraw_on) {
|
||||
|
||||
Reference in new issue
Block a user