From 40f36c88893843b27ab2726e28ec487a209e3993 Mon Sep 17 00:00:00 2001 From: chen Date: Mon, 28 Sep 2026 11:06:35 +0800 Subject: [PATCH] =?UTF-8?q?fix(settle):=20=E6=81=A2=E5=A4=8D=E6=94=B6?= =?UTF-8?q?=E7=9B=8A=E4=B8=AD=E5=BF=83=E4=B8=8E=E5=85=91=E6=8D=A2=E5=88=B8?= =?UTF-8?q?=E9=87=8A=E6=94=BE=E4=B8=BA=E5=8E=9F=E6=97=A5=E7=BB=93=E7=BB=93?= =?UTF-8?q?=E7=AE=97=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/shopro/console/PartnerSettle.php | 44 +++++++++---------- .../shopro/service/partner/VoucherService.php | 4 +- tests/verify_minute_settle_spec.js | 17 ++++--- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/addons/shopro/console/PartnerSettle.php b/addons/shopro/console/PartnerSettle.php index de2f0ec..680c675 100644 --- a/addons/shopro/console/PartnerSettle.php +++ b/addons/shopro/console/PartnerSettle.php @@ -14,19 +14,19 @@ class PartnerSettle extends Command protected function configure() { $this->setName('shopro:partner:settle') - ->addOption('date', 'd', Option::VALUE_OPTIONAL, '结算日期 Y-m-d,指定日期时执行传统日结') + ->addOption('date', 'd', Option::VALUE_OPTIONAL, '结算日期 Y-m-d,默认昨天') ->addOption('rerun', 'r', Option::VALUE_NONE, '删除当天日结后重算') - ->addOption('daily', null, Option::VALUE_NONE, '强制执行昨天标准日结') + ->addOption('minute', 'm', Option::VALUE_NONE, '执行分钟级增量结算与兑换券释放(联调测试用)') ->addOption('compensate', 'c', Option::VALUE_NONE, '执行未结算订单自动对账与补偿发放') ->addOption('check', null, Option::VALUE_NONE, '收益中心与队列运行健康度体检诊断') - ->setDescription('收益中心结算(默认1分钟dmepa增量结算与兑换券释放,支持指定日期日结及未结算补偿)'); + ->setDescription('收益中心日结(DMEPA/馆县均分/兑换券释放,默认每日结算昨天)'); } protected function execute(Input $input, Output $output) { $date = $input->getOption('date'); $rerun = (bool) $input->getOption('rerun'); - $isDaily = (bool) $input->getOption('daily'); + $isMinute = (bool) $input->getOption('minute'); $isCompensate = (bool) $input->getOption('compensate'); $isCheck = (bool) $input->getOption('check'); @@ -46,34 +46,34 @@ class PartnerSettle extends Command return 0; } - // 3. 指定日期或强制日结模式(前置自动执行补偿,确保无漏单) - if ($date || $isDaily || $rerun) { - $settleDate = $date ?: date('Y-m-d', strtotime('-1 day')); - $output->writeln('partner daily settle start ' . $settleDate . ($rerun ? ' rerun' : '')); + // 3. 显式指定分钟级调度模式(联调调试测试) + if ($isMinute) { + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle start'); try { - // 日结前置:扫描并补偿未结算即时奖订单,避免影响大盘 GMV 统计与分红池 - $compensateReport = (new PartnerCompensateService())->compensateAll(100); - if (!empty($compensateReport['success_count'])) { - $output->writeln(" [✓] 日结前置补偿已完成: 成功补发 {$compensateReport['success_count']} 笔订单即时奖"); - } - - $report = (new DailySettleService())->run($date, $rerun); - $output->writeln('partner daily settle done: ' . json_encode($report ? $report->toArray() : [], JSON_UNESCAPED_UNICODE)); + $result = (new DailySettleService())->runMinute(); + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle done: ' . json_encode($result, JSON_UNESCAPED_UNICODE)); return 0; } catch (\Exception $e) { - $output->writeln('partner daily settle fail: ' . $e->getMessage()); + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle fail: ' . $e->getMessage()); return 1; } } - // 4. 默认执行 1 分钟dmepa增量结算与兑换券释放 - $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle start'); + // 4. 默认原标准日结模式(每日凌晨结算昨天,支持 -d 指定日期与 -r 重跑) + $settleDate = $date ?: date('Y-m-d', strtotime('-1 day')); + $output->writeln('partner daily settle start ' . $settleDate . ($rerun ? ' rerun' : '')); try { - $result = (new DailySettleService())->runMinute(); - $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle done: ' . json_encode($result, JSON_UNESCAPED_UNICODE)); + // 日结前置:扫描并补偿未结算即时奖订单,避免影响大盘 GMV 统计与分红池 + $compensateReport = (new PartnerCompensateService())->compensateAll(100); + if (!empty($compensateReport['success_count'])) { + $output->writeln(" [✓] 日结前置补偿已完成: 成功补发 {$compensateReport['success_count']} 笔订单即时奖"); + } + + $report = (new DailySettleService())->run($date, $rerun); + $output->writeln('partner daily settle done: ' . json_encode($report ? $report->toArray() : [], JSON_UNESCAPED_UNICODE)); return 0; } catch (\Exception $e) { - $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle fail: ' . $e->getMessage()); + $output->writeln('partner daily settle fail: ' . $e->getMessage()); return 1; } } diff --git a/addons/shopro/service/partner/VoucherService.php b/addons/shopro/service/partner/VoucherService.php index 60f6111..5f8bc6d 100644 --- a/addons/shopro/service/partner/VoucherService.php +++ b/addons/shopro/service/partner/VoucherService.php @@ -144,8 +144,8 @@ class VoucherService return null; } $daily = round($total / $days, 2); - // 临时模式:当天立即生效起算,支持 1 分钟释放联调 - $startDate = date('Y-m-d', $this->orderTime($order)); + // 生产标准模式:下单次日生效起算,按 365 天线性释放 + $startDate = date('Y-m-d', strtotime('+1 day', $this->orderTime($order))); $plan = VoucherPlan::create([ 'user_id' => $buyerId, diff --git a/tests/verify_minute_settle_spec.js b/tests/verify_minute_settle_spec.js index 95e1400..d7c1309 100644 --- a/tests/verify_minute_settle_spec.js +++ b/tests/verify_minute_settle_spec.js @@ -27,8 +27,8 @@ test('VoucherService 包含 releaseMinute() 分钟级释放方法', () => { assert(voucherContent.includes('function releaseMinute()'), '必须定义 releaseMinute()'); }); -test('VoucherService 包含立即生效起算逻辑', () => { - assert(voucherContent.includes("date('Y-m-d', $this->orderTime($order))"), '起算日期当天立即生效'); +test('VoucherService 包含标准次日起算逻辑', () => { + assert(voucherContent.includes("date('Y-m-d', strtotime('+1 day', $this->orderTime($order)))"), '起算日期下单次日生效起算'); }); test('VoucherService 分钟释放使用 NULL 结算日规避唯一索引冲突', () => { @@ -71,15 +71,14 @@ const partnerSettlePath = path.resolve(__dirname, '../addons/shopro/console/Part assert(fs.existsSync(partnerSettlePath), 'PartnerSettle.php 文件存在'); const cmdContent = fs.readFileSync(partnerSettlePath, 'utf-8'); -test('PartnerSettle 默认执行 runMinute() 分钟级调度', () => { - assert(cmdContent.includes('runMinute()'), '默认调用 runMinute()'); - assert(cmdContent.includes('partner minute settle done'), '输出分钟级执行结果日志'); +test('PartnerSettle 默认执行标准日结模式(结算昨天)', () => { + assert(cmdContent.includes("partner daily settle start"), '默认执行标准日结'); + assert(cmdContent.includes("run($date, $rerun)"), '默认调用 DailySettleService::run()'); }); -test('PartnerSettle 保留 --date / --rerun / --daily 传统日结兼容', () => { - assert(cmdContent.includes("$input->getOption('date')"), '兼容 -d/--date 参数'); - assert(cmdContent.includes("$input->getOption('rerun')"), '兼容 -r/--rerun 参数'); - assert(cmdContent.includes("$input->getOption('daily')"), '兼容 --daily 参数'); +test('PartnerSettle 支持 --minute 显式触发分钟调度', () => { + assert(cmdContent.includes("$input->getOption('minute')"), '支持 -m/--minute 参数'); + assert(cmdContent.includes("runMinute()"), '支持按需调用 runMinute()'); }); console.log('\n--------------------------------------------------------');