CaiWuXiTong/modules/EcommerceFinance/Console/SyncJushuitanShipping.php
limeng 067102ab15 feat(发货数据): 商品来源改为出库实发(发货数据视图),对齐工作平台
- 商品来源从「下单商品 jst_OrderItem」改为「出库实发商品」:按出库单 io_id
  关联发货数据视图 Jst_SendData_View_extension 取实发条码/数量,jst_OrderItem/dws
  仅作兜底。消除组合/多规格包裹的多吐行与数量错误。
- 长宽高/体积/供应商/重量优先取自发货视图(体积=长×宽×高,整箱算一次)。
- 导出明细:多条码(逗号拼接)按条码拆条,数量/体积按条码数均摊,合并求和后与整行一致。
- 去除以 @ 开头、去@后已存在的重复单号(换单/重拉产生)。
- 发货单查询改为按主键翻页 + PHP 窗口过滤,避免 send_time 无索引全表扫。
- 逐天预载 dws,进度回调输出扫描/命中进度。

新增命令:jst:dump(导出对比CSV)、jst:row(抽查单号)、jst:dedup-at(去@重复)。

9.1-9.16 全量对比:共有 19.3 万包裹,数量/名称/条码/体积/供应商等字段一致率 99.9%;
导出明细件数结构 99.87% 一致。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014nvGZkg27YMEdhRy6EiUwf
2026-09-23 17:02:53 +08:00

59 lines
2.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Modules\EcommerceFinance\Services\Jushuitan\ShippingReplicaSynchronizer;
/**
* 发货数据同步:从经营分析副本库(operations_replica)直读聚水潭发货明细,清洗进本地展示表。
*
* php artisan jushuitan:sync-shipping --from=2026-09-01 --to=2026-09-17 # 按发货时间窗口拉全量
* php artisan jushuitan:sync-shipping --days=3 # 滚动最近 3 天(每日调度用)
* php artisan jushuitan:sync-shipping # 最近 2000 条(快速看效果)
*
* 按 id 去重 upsert,任何时候补拉早期区间都不会重复。
*/
class SyncJushuitanShipping extends Command
{
protected $signature = 'jushuitan:sync-shipping {--from=} {--to=} {--days=} {--limit=2000}';
protected $description = '从经营分析副本库直读聚水潭发货明细,清洗写入 caiwu 发货数据表';
public function handle(): int
{
@ini_set('memory_limit', '1536M');
@set_time_limit(0);
$from = $this->option('from') ? Carbon::parse($this->option('from')) : null;
$to = $this->option('to') ? Carbon::parse($this->option('to')) : null;
// --days=N:滚动最近 N 天(含今天)。显式 --from/--to 优先。
if (! $from && ! $to && $this->option('days')) {
$days = max((int) $this->option('days'), 1);
$from = now()->startOfDay()->subDays($days - 1);
$to = now()->startOfDay()->addDay();
}
$limit = (int) ($this->option('limit') ?: 2000);
$range = ($from && $to) ? $from->toDateString() . ' ~ ' . $to->toDateString() : '最近 ' . $limit . ' 条';
$this->info('开始从副本库同步发货明细(' . $range . ')...');
$progress = function (string $msg): void {
$this->info(' ' . $msg);
if (function_exists('fflush')) {
@fflush(STDOUT);
}
};
try {
$result = ShippingReplicaSynchronizer::make()->sync($from, $to, $limit, $progress);
} catch (\Throwable $e) {
$this->error('同步失败:' . $e->getMessage());
return self::FAILURE;
}
$this->info('完成:写入 ' . ($result['processed'] ?? 0) . ' 条发货明细。');
return self::SUCCESS;
}
}