feat(partner): 完善马豆实时动态汇率与精度自适应,支持交易数据清理与汇率重置

这个提交包含在:
chen
2026-09-18 07:59:50 +08:00
父节点 ac8c45bdad
当前提交 7c10864be2
共有 60 个文件被更改,包括 2691 次插入 和 490 次删除

查看文件

@@ -111,6 +111,7 @@ class Shopro extends Addons
'addons\shopro\console\PartnerInstall',
'addons\shopro\console\PartnerDemo',
'addons\shopro\console\PartnerAccept',
'addons\shopro\console\PartnerClean',
]);
}

查看文件

@@ -0,0 +1,179 @@
<?php
namespace addons\shopro\console;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\console\input\Option;
use think\Db;
/**
* 清理订单数据、分销分润记录、日结快照日志,并将马豆汇率回归初始状态
*/
class PartnerClean extends Command
{
protected function configure()
{
$this->setName('shopro:partner:clean')
->addOption('force', 'f', Option::VALUE_NONE, '强制执行,不提示确认')
->addOption('with-wallet-log', 'w', Option::VALUE_NONE, '同时清理分佣与订单相关的佣金钱包流水日志')
->setDescription('清理所有订单、分销分润、日结日志,重置马豆与汇率回初始值');
}
protected function execute(Input $input, Output $output)
{
$force = (bool) $input->getOption('force');
$withWallet = (bool) $input->getOption('with-wallet-log');
$output->writeln("========================================================");
$output->writeln(" 收益中心交易数据清理与马豆汇率重置程序");
$output->writeln("========================================================");
if (!$force) {
$output->writeln("【警告】此操作将清空所有商城订单、分销记录、分润流水并重置马豆汇率!");
$output->writeln("如需执行,请增加参数 --force 或 -f,例如:");
$output->writeln("php think shopro:partner:clean --force");
return 1;
}
$prefix = config('database.prefix') ?: 'fa_';
$output->writeln("当前数据库前缀: [{$prefix}]");
Db::startTrans();
try {
// 1. 清理商城订单及关联子表
$orderTables = [
'shopro_order',
'shopro_order_item',
'shopro_order_action',
'shopro_order_aftersale',
'shopro_order_aftersale_log',
'shopro_order_express',
'shopro_order_invoice',
'shopro_order_item_stock',
];
$output->writeln("\n>>> 1. 正在清理商城订单及交易明细...");
foreach ($orderTables as $tbl) {
$fullTable = $prefix . $tbl;
if ($this->tableExists($fullTable)) {
Db::execute("TRUNCATE TABLE `{$fullTable}`");
$output->writeln(" [OK] 清空表 `{$fullTable}`");
}
}
// 2. 清理分销与合伙人收益流水表
$rewardTables = [
'shopro_partner_reward', // 二开收益中心全量分润流水
'shopro_commission_order', // 分销订单关联表
'shopro_commission_reward', // 原分销奖励明细
'shopro_commission_log', // 分销变动日志
];
$output->writeln("\n>>> 2. 正在清理分销订单与收益分润记录...");
foreach ($rewardTables as $tbl) {
$fullTable = $prefix . $tbl;
if ($this->tableExists($fullTable)) {
Db::execute("TRUNCATE TABLE `{$fullTable}`");
$output->writeln(" [OK] 清空表 `{$fullTable}`");
}
}
// 3. 清理日结对账、马豆大盘汇率快照与兑换券释放计划
$dailyTables = [
'shopro_partner_rate_log', // 马豆大盘汇率历史快照日志(清空后大盘汇率无历史,自动按 0 单重算)
'shopro_partner_daily_report', // 每日日结对账日报表
'shopro_partner_voucher_plan', // 兑换券释放计划表
'shopro_partner_voucher_log', // 兑换券释放明细流水
];
$output->writeln("\n>>> 3. 正在清理日结对账、汇率快照与兑换券计划...");
foreach ($dailyTables as $tbl) {
$fullTable = $prefix . $tbl;
if ($this->tableExists($fullTable)) {
Db::execute("TRUNCATE TABLE `{$fullTable}`");
$output->writeln(" [OK] 清空表 `{$fullTable}`");
}
}
// 4. 重置分销商资产状态(马豆归零、推三返一序号归零、兑换券归零、收益归零)
$output->writeln("\n>>> 4. 正在重置分销商(Agent)资产指标...");
$agentTable = $prefix . 'shopro_commission_agent';
if ($this->tableExists($agentTable)) {
Db::execute("UPDATE `{$agentTable}` SET
`madow` = 0.00000000,
`direct_order_seq` = 0,
`voucher_total` = 0.00,
`voucher_released` = 0.00,
`voucher_used` = 0.00,
`total_income` = 0.00,
`commission` = 0.00,
`total_consume` = 0.00,
`last_self_order_time` = NULL");
$output->writeln(" [OK] 已将所有分销商持仓马豆、推三返一序号、兑换券及累计收益重置归零");
}
// 5. 重置用户表钱包分销佣金与累计消费额
$output->writeln("\n>>> 5. 正在重置会员用户(User)交易与佣金数据...");
$userTable = $prefix . 'user';
if ($this->tableExists($userTable)) {
Db::execute("UPDATE `{$userTable}` SET
`commission` = 0.00,
`total_consume` = 0.00,
`order_count` = 0");
$output->writeln(" [OK] 已将所有会员钱包佣金、累计消费、订单计数重置归零");
}
// 6. 可选清理钱包流水表中佣金相关的记录
if ($withWallet) {
$walletLogTable = $prefix . 'shopro_user_wallet_log';
if ($this->tableExists($walletLogTable)) {
Db::execute("DELETE FROM `{$walletLogTable}` WHERE `wallet_type` = 'commission' OR `event` IN ('reward_income', 'reward_back', 'order_pay', 'order_refund')");
$output->writeln(" [OK] 已清理佣金钱包及订单相关流水日志");
}
}
Db::commit();
$output->writeln("\n[SUCCESS] 数据库交易与分润记录清理完毕!事务已成功提交。");
} catch (\Exception $e) {
Db::rollback();
$output->writeln("\n[FAIL] 清理过程中发生异常,事务已回滚: " . $e->getMessage());
return 1;
}
// 7. 清理缓存中汇率与收益中心配置
$output->writeln("\n>>> 6. 正在清除马豆汇率缓存与系统配置缓存...");
cache('partner_madow_current_rate', null);
cache('partner_rules', null);
if (function_exists('rmdirs')) {
@rmdirs(RUNTIME_PATH . 'cache');
@rmdirs(RUNTIME_PATH . 'temp');
}
$output->writeln(" [OK] 马豆即时汇率缓存已清理");
// 8. 校验回归初始汇率
$rateService = new \addons\shopro\service\partner\RateService();
$resetRate = $rateService->currentRate();
$resetN = $rateService->countN();
$formattedRate = number_format($resetRate, 8, '.', '');
$output->writeln("\n========================================================");
$output->writeln(" 重置后指标核对:");
$output->writeln(" 合格订单总数 N : {$resetN} 单 (应为 0)");
$output->writeln(" 当前大盘汇率 : {$formattedRate} 元/豆 (回归初始基准值 0.00000075)");
$output->writeln("========================================================\n");
return 0;
}
protected function tableExists($table)
{
try {
$check = Db::query("SHOW TABLES LIKE '{$table}'");
return !empty($check);
} catch (\Exception $e) {
return false;
}
}
}

查看文件

@@ -56,43 +56,47 @@ class Commission
*/
public function orderPaidAfter($params)
{
// 订单支付成功
$order = $params['order'];
try {
// 订单支付成功
$order = $params['order'];
// 积分商品订单不参与分销
if ($order['type'] === 'score') return;
// 积分商品订单不参与分销
if ($order['type'] === 'score') return;
$user = $params['user'];
$user = $params['user'];
$agent = new AgentService($user);
$agent = new AgentService($user);
// 绑定用户关系
$agent->bindUserRelation('pay');
// 绑定用户关系
$agent->bindUserRelation('pay');
// 先记录分佣 再处理记录业绩、升级等情况
$items = $order ? $order['items'] : [];
// 先记录分佣 再处理记录业绩、升级等情况
$items = $order ? $order['items'] : [];
foreach ($items as $item) {
if (isset($item['ext']['is_commission']) && !$item['ext']['is_commission']) continue;
foreach ($items as $item) {
if (isset($item['ext']['is_commission']) && !$item['ext']['is_commission']) continue;
$commission = new OrderService($item);
// 检查能否分销
if (!$commission->checkAndSetCommission()) continue;
// 添加分销订单
$commissionOrder = $commission->createCommissionOrder();
$commission = new OrderService($item);
// 检查能否分销
if (!$commission->checkAndSetCommission()) continue;
// 添加分销订单
$commissionOrder = $commission->createCommissionOrder();
if (!$commissionOrder) continue;
if (!$commissionOrder) continue;
// 执行佣金计划
$commission->runCommissionPlan($commissionOrder);
// 支付后拨款
(new RewardService('paid'))->runCommissionRewardByOrder($commissionOrder);
// 执行佣金计划
$commission->runCommissionPlan($commissionOrder);
// 支付后拨款
(new RewardService('paid'))->runCommissionRewardByOrder($commissionOrder);
}
// 创建分销商
$agent->createNewAgent();
// 分销商数据统计&升级(异步执行)
$agent->createAsyncAgentUpgrade();
} catch (\Throwable $e) {
format_log_error($e, 'Commission.orderPaidAfter', '原生分销监听处理异常: ' . $e->getMessage());
}
// 创建分销商
$agent->createNewAgent();
// 分销商数据统计&升级(异步执行)
$agent->createAsyncAgentUpgrade();
}
// 线下付款后

查看文件

@@ -35,6 +35,7 @@ class Partner
$service = new PartnerRewardService();
if ($service->isQualified($order)) {
\addons\shopro\service\partner\RateService::clearCache();
$userId = $order['user_id'] ?? ($params['user']['id'] ?? 0);
if ($userId) {
$agent = new AgentService($userId);

查看文件

@@ -84,6 +84,11 @@ class IdentityService
public static function formatMadow($value)
{
$floatVal = (float) $value;
// 当存在小于 1 豆且大于 0 的微量马豆时,自适应保留有效小数(最多4位),避免直接抹零显示为 0 豆
if ($floatVal > 0 && $floatVal < 1) {
return rtrim(rtrim(number_format($floatVal, 4, '.', ''), '0'), '.');
}
return number_format((float) $value, 0, '.', '');
}

查看文件

@@ -104,10 +104,12 @@ class PartnerConfig
'venue_share' => $venue . '加权奖励',
'county_share' => $county . '加权奖励',
'madow_share' => '每日贡献马豆',
'admin_madow' => '管理员调整马豆',
'voucher_grant' => '消费补贴发放',
'voucher_release' => '消费补贴到账',
'voucher_consume' => '消费券抵扣',
'voucher_consume_refund' => '消费券退款退还',
'admin_voucher' => '管理员调整兑换券',
];
}

查看文件

@@ -11,21 +11,33 @@ use app\admin\model\shopro\commission\CommissionGoods;
*/
class RateService
{
public function currentRate()
/**
* 获取大盘当前即时生效汇率(基于全网合格订单 N 实时动态计算,短缓存 120 秒保障高并发读性能)
*
* @param bool $forceRefresh 是否强制穿透缓存实时重算
* @return float
*/
public function currentRate($forceRefresh = false)
{
$latest = RateLog::order('id', 'desc')->find();
if ($latest && (float) $latest->rate > 0) {
return (float) $latest->rate;
}
$cached = cache('partner_madow_current_rate');
if ($cached !== null && $cached !== false && (float) $cached > 0) {
return (float) $cached;
if (!$forceRefresh) {
$cached = cache('partner_madow_current_rate');
if ($cached !== null && $cached !== false && (float) $cached > 0) {
return (float) $cached;
}
}
$rate = $this->calcRate($this->countN());
cache('partner_madow_current_rate', $rate, 300);
cache('partner_madow_current_rate', $rate, 120);
return $rate;
}
/**
* 主动清除当前马豆汇率缓存(订单支付、退款或后台调整时调用)
*/
public static function clearCache()
{
cache('partner_madow_current_rate', null);
}
public function calcRate($n = null)
{
$n = $n === null ? $this->countN() : intval($n);