修复发货镜像字段校准与合并列表耗时 #283

Merged
WuYongJie merged 3 commits from fix/WuYongJie-shipping-release-repair-oct07 into main 2026-10-07 14:08:20 +08:00
5 changed files with 71 additions and 4 deletions

View File

@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
$connection = (string) config('jushuitan.connection', 'jushuitan_local');
// 旧迁移可能在目标表不存在时跳过,却已记为完成。用独立版本校准实际结构。
if (! Schema::connection($connection)->hasTable('jst_oms_shipping')) {
throw new RuntimeException('发货镜像表不存在,不能将合并字段迁移标为完成。');
}
$migration = require base_path('modules/EcommerceFinance/Database/Migrations/2026_10_05_000001_add_merged_cols_to_jst_oms_shipping.php');
$migration->up();
}
public function down(): void
{
// 字段属于原迁移;校准回滚保留原迁移及镜像数据。
}
};

View File

@ -61,7 +61,9 @@ class SyncJushuitanShipping extends Command
$expressRows = (int) ($result['processed'] ?? 0);
$autoRows = (int) ($result['autoship'] ?? 0);
$summary = sprintf('发货明细 %d 条,代发仓 %d 条,合计处理 %d 条明细', $expressRows, $autoRows, $expressRows + $autoRows);
$outboundRows = (int) ($result['outbound'] ?? 0);
$purchaseOutRows = (int) ($result['purchase_out'] ?? 0);
$summary = sprintf('发货明细 %d 条,代发仓 %d 条,销售出库补漏 %d 条,采购出库补漏 %d 条,合计处理 %d 条明细', $expressRows, $autoRows, $outboundRows, $purchaseOutRows, $expressRows + $autoRows + $outboundRows + $purchaseOutRows);
$packageSummary = isset($result['unique_packages'])
? sprintf('唯一包裹源键 %d 个,包裹记录处理 %d 次;', $result['unique_packages'], $result['packages'] ?? 0)
: '';

View File

@ -49,12 +49,18 @@ class ShippingOrderRepository
// 合并:按包裹(source_id)归并
$base = $this->filteredQuery($filters);
$total = (clone $base)->distinct()->count('source_id');
$pageKeys = (clone $base)->select('source_id')->selectRaw('MAX(ship_time) as ship_time')
->groupBy('source_id')->orderByDesc('ship_time')->orderByDesc('source_id')
->forPage($page, $perPage)->pluck('source_id')->all();
if ($pageKeys === []) {
return ['data' => [], 'total' => $total];
}
$rows = (clone $base)
->whereIn('source_id', $pageKeys)
->groupBy('source_id')
->selectRaw($this->mergedSelectRaw())
->orderByDesc('ship_time')
->orderByDesc('source_id')
->forPage($page, $perPage)
->get()->map(fn ($r) => (array) $r)->all();
return ['data' => $rows, 'total' => $total];
@ -157,7 +163,12 @@ class ShippingOrderRepository
if ($last !== null) {
$query->where('source_id', '>', $last);
}
$rows = $query->groupBy('source_id')->selectRaw($this->mergedSelectRaw())
$keys = (clone $query)->select('source_id')->distinct()
->orderBy('source_id')->limit($batchSize)->pluck('source_id')->all();
if ($keys === []) {
return;
}
$rows = $query->whereIn('source_id', $keys)->groupBy('source_id')->selectRaw($this->mergedSelectRaw())
->orderBy('source_id')->limit($batchSize)->get()->all();
if ($rows === []) {
return;

View File

@ -0,0 +1,31 @@
<?php
namespace Tests\Unit\EcommerceFinance;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class ShippingMergedColumnsMigrationTest extends TestCase
{
public function test_reconciliation_repairs_missing_columns_and_can_run_again(): void
{
$schema = DB::connection('business_mirror')->getSchemaBuilder();
$columns = ['m_name', 'm_volume_cm3', 'm_length_cm', 'm_width_cm', 'm_height_cm'];
$schema->table('jst_oms_shipping', fn ($table) => $table->dropColumn($columns));
$migration = require base_path('database/migrations/2026_10_07_150000_reconcile_shipping_merged_columns.php');
$migration->up();
$migration->up();
foreach ($columns as $column) {
$this->assertTrue($schema->hasColumn('jst_oms_shipping', $column));
}
}
public function test_missing_target_is_reported_instead_of_marked_complete(): void
{
DB::connection('business_mirror')->getSchemaBuilder()->drop('jst_oms_shipping');
$migration = require base_path('database/migrations/2026_10_07_150000_reconcile_shipping_merged_columns.php');
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('发货镜像表不存在');
$migration->up();
}
}

View File

@ -844,7 +844,7 @@ class ShippingReplicaSynchronizerTest extends TestCase
$this->artisan('jushuitan:sync-shipping', [
'--from' => '2026-09-01', '--to' => '2026-09-05', '--skip-freight' => true,
])->expectsOutputToContain('唯一包裹源键 2 个,包裹记录处理 2 次;发货明细 1 条,代发仓 1 条,合计处理 2 条明细')
])->expectsOutputToContain('唯一包裹源键 2 个,包裹记录处理 2 次;发货明细 1 条,代发仓 1 条,销售出库补漏 0 条,采购出库补漏 0 条,合计处理 2 条明细')
->assertExitCode(0);
}