From 8e93e710248a2aa5885f5a9b7db128317ddad111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8F=E6=9C=A8?= <594326199@qq.com> Date: Tue, 13 Oct 2026 11:31:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=97=E9=93=BA=E8=BF=9D=E8=A7=84=E9=A2=84?= =?UTF-8?q?=E8=AD=A6=EF=BC=9A=E6=96=B0=E5=A2=9E=E8=BF=9D=E8=A7=84=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0=E4=B8=8E=E5=A4=84=E7=BD=AE=E6=96=B9=E5=BC=8F=E4=B8=A4?= =?UTF-8?q?=E5=88=97=EF=BC=88=E9=A1=B5=E9=9D=A2/=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E8=A1=A8/=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 页面在「违规分类」后新增「违规原因」「处置方式」,统一表头、导出、模板、导入同步支持 - 新迁移:统一表 store_violation_records 增加 violation_reason、disposition 两列 - 同步命令:上游视图补齐 violation_reason/disposition(或 reason/handling_method)后自动参与同步;未提供时不触碰这两列,导入补充的数据不会被每日同步清空 - 导入:违规原因/处置方式独立映射;仅提供违规原因时,违规分类按原因关键词自动归类 - 测试:StoreViolation*、NavigationTest 共 23 项通过(含新导入用例与列探测用例) --- app/Business/StoreViolationMapper.php | 3 + .../StoreViolationWorkbookImporter.php | 18 +++++- app/Console/Commands/SyncStoreViolations.php | 62 +++++++++++++++++-- app/Http/Controllers/Business/Pages.php | 10 +-- config/store_violations.php | 6 +- ...disposition_to_store_violation_records.php | 59 ++++++++++++++++++ .../financial-risk-control/index.blade.php | 6 +- .../Business/StoreViolationAlertPageTest.php | 59 ++++++++++++++++-- .../Business/StoreViolationMapperTest.php | 27 ++++++++ .../StoreViolationsSyncExtraColumnsTest.php | 33 ++++++++++ 10 files changed, 264 insertions(+), 19 deletions(-) create mode 100644 database/migrations/2026_10_13_130000_add_reason_and_disposition_to_store_violation_records.php create mode 100644 tests/Unit/Console/StoreViolationsSyncExtraColumnsTest.php diff --git a/app/Business/StoreViolationMapper.php b/app/Business/StoreViolationMapper.php index bbd41379..8f56da6e 100644 --- a/app/Business/StoreViolationMapper.php +++ b/app/Business/StoreViolationMapper.php @@ -72,6 +72,9 @@ class StoreViolationMapper 'shop_name' => mb_substr(trim((string) ($row['shop_name'] ?? '')), 0, 191), 'violation_type' => $content === '' ? null : mb_substr($content, 0, 500), 'violation_category' => $this->categoryForContent($content), + // 上游视图补齐这两列后由同步命令自动带出(见 SyncStoreViolations 的列探测)。 + 'violation_reason' => $this->normalizeLabel($row['violation_reason'] ?? null, 500), + 'disposition' => $this->normalizeLabel($row['disposition'] ?? null, 500), 'violation_no' => mb_substr(trim((string) ($row['violation_no'] ?? '')), 0, 100), 'violation_date' => $this->normalizeDate($row['violation_date'] ?? null), 'status' => $this->normalizeLabel($row['status'] ?? null, 64), diff --git a/app/Business/StoreViolationWorkbookImporter.php b/app/Business/StoreViolationWorkbookImporter.php index 43750e12..ebee242a 100644 --- a/app/Business/StoreViolationWorkbookImporter.php +++ b/app/Business/StoreViolationWorkbookImporter.php @@ -305,13 +305,25 @@ class StoreViolationWorkbookImporter $data['violation_type'] = $type === '' ? null : mb_substr($type, 0, 500); } + $reason = $has('violation_reason') ? trim((string) ($raw['violation_reason'] ?? '')) : null; + if ($has('violation_reason')) { + $data['violation_reason'] = $reason === '' ? null : mb_substr($reason, 0, 500); + } + + if ($has('disposition')) { + $disposition = trim((string) ($raw['disposition'] ?? '')); + $data['disposition'] = $disposition === '' ? null : mb_substr($disposition, 0, 500); + } + if ($has('violation_category')) { + $categorySource = ($type !== null && $type !== '') ? $type : (string) $reason; $category = trim((string) ($raw['violation_category'] ?? '')); $data['violation_category'] = $category === '' - ? $this->mapper->categoryForContent($type) + ? $this->mapper->categoryForContent($categorySource) : mb_substr($category, 0, 64); - } elseif ($has('violation_type')) { - $data['violation_category'] = $this->mapper->categoryForContent($type); + } elseif ($has('violation_type') || $has('violation_reason')) { + $categorySource = ($type !== null && $type !== '') ? $type : (string) $reason; + $data['violation_category'] = $this->mapper->categoryForContent($categorySource); } if ($has('violation_date')) { diff --git a/app/Console/Commands/SyncStoreViolations.php b/app/Console/Commands/SyncStoreViolations.php index f0491065..9dfa48f4 100644 --- a/app/Console/Commands/SyncStoreViolations.php +++ b/app/Console/Commands/SyncStoreViolations.php @@ -68,16 +68,27 @@ class SyncStoreViolations extends Command $skipped = 0; $read = 0; + // 违规原因/处置方式:上游视图补齐后自动参与同步;未提供时不触碰这两列, + // 避免每日同步把导入补充的数据清空。 + $extraColumns = $this->availableExtraColumns($pdo); + $updateColumns = $extraColumns === [] + ? StoreViolationRecordRepository::CRAWL_UPDATE_COLUMNS + : array_merge(StoreViolationRecordRepository::CRAWL_UPDATE_COLUMNS, array_keys($extraColumns)); + try { while (true) { // FreeTDS 可能按连接区域返回 date(例如 "Oct 4 2026 12:00:00:AM"), // 与镜像同步器保持一致:在源端转成 ISO 字符串再交给 PHP 解析。 - $sql = 'SELECT TOP ' . $batchSize - . ' id, shop_name, violation_no,' + $selectedColumns = ' id, shop_name, violation_no,' . ' CONVERT(varchar(10), violation_date, 23) AS violation_date,' . ' CONVERT(varchar(10), deadline, 23) AS deadline,' . ' violation_content, status, window_name, platform,' - . ' CONVERT(varchar(10), crawl_date, 23) AS crawl_date' + . ' CONVERT(varchar(10), crawl_date, 23) AS crawl_date'; + foreach ($extraColumns as $target => $sourceColumn) { + $selectedColumns .= ', ' . $sourceColumn . ' AS ' . $target; + } + + $sql = 'SELECT TOP ' . $batchSize . $selectedColumns . ' FROM rpt.crawl_shop_violation WHERE id > ?'; $params = [$lastId]; @@ -114,7 +125,7 @@ class SyncStoreViolations extends Command ]; } - $upserted += $repository->upsertRows($payload, StoreViolationRecordRepository::CRAWL_UPDATE_COLUMNS); + $upserted += $repository->upsertRows($payload, $updateColumns); } } catch (Throwable $exception) { report($exception); @@ -137,4 +148,47 @@ class SyncStoreViolations extends Command return self::SUCCESS; } + + /** @return array 统一表字段 => 上游视图列名 */ + private function availableExtraColumns(PDO $pdo): array + { + try { + $statement = $pdo->query( + "SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('rpt.crawl_shop_violation')" + ); + $names = $statement->fetchAll(PDO::FETCH_COLUMN); + $statement->closeCursor(); + } catch (Throwable) { + return []; + } + + return self::pickExtraColumns(array_map('strval', $names)); + } + + /** + * 从上游可用列名中挑选可同步的扩展列;列名以数据平台实际提供的为准。 + * + * @param list $availableColumns + * @return array + */ + public static function pickExtraColumns(array $availableColumns): array + { + $candidates = [ + 'violation_reason' => ['violation_reason', 'reason'], + 'disposition' => ['disposition', 'handling_method', 'disposal'], + ]; + + $available = array_map(static fn (string $name): string => strtolower($name), $availableColumns); + $selected = []; + foreach ($candidates as $target => $names) { + foreach ($names as $name) { + if (in_array($name, $available, true)) { + $selected[$target] = $name; + break; + } + } + } + + return $selected; + } } diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index d3a84d7c..3f7e7a9a 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -3231,7 +3231,7 @@ class Pages extends Controller $rowNumber++; } - foreach (['A' => 30, 'B' => 36, 'C' => 14, 'D' => 24, 'E' => 14, 'F' => 10, 'G' => 16, 'H' => 14, 'I' => 16, 'J' => 12] as $column => $width) { + foreach (['A' => 30, 'B' => 36, 'C' => 14, 'D' => 36, 'E' => 28, 'F' => 24, 'G' => 14, 'H' => 10, 'I' => 16, 'J' => 14, 'K' => 16, 'L' => 12] as $column => $width) { $sheet->getColumnDimension($column)->setWidth($width); } $sheet->freezePane('A2'); @@ -3257,7 +3257,7 @@ class Pages extends Controller $headers = array_map(static fn (array $column): string => (string) $column['label'], $columns); $sheet->fromArray($headers, null, 'A1'); $sheet->fromArray( - ['示例·某某旗舰店', '延迟发货/缺货无货', '发货履约', 'JD202610040001', '2026-10-04', 2, '待处理', '', '2026-10-11', '未处理'], + ['示例·某某旗舰店', '延迟发货/缺货无货', '发货履约', '订单存在揽收超时行为', '警告', 'JD202610040001', '2026-10-04', 2, '待处理', '', '2026-10-11', '未处理'], null, 'A2', ); @@ -3268,7 +3268,7 @@ class Pages extends Controller 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], ]); $sheet->getRowDimension(1)->setRowHeight(24); - foreach (['A' => 30, 'B' => 36, 'C' => 14, 'D' => 24, 'E' => 14, 'F' => 10, 'G' => 16, 'H' => 14, 'I' => 16, 'J' => 12] as $column => $width) { + foreach (['A' => 30, 'B' => 36, 'C' => 14, 'D' => 36, 'E' => 28, 'F' => 24, 'G' => 14, 'H' => 10, 'I' => 16, 'J' => 14, 'K' => 16, 'L' => 12] as $column => $width) { $sheet->getColumnDimension($column)->setWidth($width); } $sheet->freezePane('A2'); @@ -3281,6 +3281,8 @@ class Pages extends Controller ['违规单号', '必填。同一平台内唯一;已存在的单号会按文件内容更新(导入预览会逐行提示)。'], ['违规类型', '选填。平台显示的违规内容/类型,例如“延迟发货/缺货无货”。'], ['违规分类', '选填。留空时按违规类型关键词自动归类。'], + ['违规原因', '选填。平台展示的违规原因/详细说明。'], + ['处置方式', '选填。平台对违规的处置/处理方式。'], ['违规日期 / 处罚日期 / 申诉截止日期', '选填。格式 YYYY-MM-DD,例如 2026-10-04。'], ['扣分', '选填。数字,例如 2 或 0.5。'], ['状态', '选填。平台状态,例如“待处理”“超期未申诉”。'], @@ -3294,7 +3296,7 @@ class Pages extends Controller ]); $notes->getColumnDimension('A')->setWidth(34); $notes->getColumnDimension('B')->setWidth(72); - $notes->getStyle('B1:B11')->getAlignment()->setWrapText(true); + $notes->getStyle('B1:B13')->getAlignment()->setWrapText(true); (new Xlsx($spreadsheet))->save('php://output'); }, '店铺违规信息导入模板_' . now()->format('Ymd') . '.xlsx', [ diff --git a/config/store_violations.php b/config/store_violations.php index 1618e164..b4e647e7 100644 --- a/config/store_violations.php +++ b/config/store_violations.php @@ -16,6 +16,8 @@ return [ ['key' => 'shop_name', 'label' => '店铺名'], ['key' => 'violation_type', 'label' => '违规类型'], ['key' => 'violation_category', 'label' => '违规分类'], + ['key' => 'violation_reason', 'label' => '违规原因'], + ['key' => 'disposition', 'label' => '处置方式'], ['key' => 'violation_no', 'label' => '违规单号'], ['key' => 'violation_date', 'label' => '违规日期'], ['key' => 'points_deducted', 'label' => '扣分'], @@ -42,8 +44,10 @@ return [ // 导入表头别名 → 统一列键(不区分大小写、忽略空格) 'header_aliases' => [ 'shop_name' => ['店铺名', '店铺名称', '店铺', '商家名称', '商家', 'shop_name', 'shopname'], - 'violation_type' => ['违规类型', '违规内容', '违规行为', '违规原因', '违规描述', 'violation_type'], + 'violation_type' => ['违规类型', '违规内容', '违规行为', '违规描述', 'violation_type'], 'violation_category' => ['违规分类', '违规类别', '分类', 'violation_category'], + 'violation_reason' => ['违规原因', '违规说明', '违规详情', 'violation_reason', 'reason'], + 'disposition' => ['处置方式', '处置措施', '处置结果', '处理方式', 'disposition', 'handling_method'], 'violation_no' => ['违规单号', '违规编号', '违规id', '违规ID', '单号', 'violation_no'], 'violation_date' => ['违规日期', '违规时间', '违规发生时间', 'violation_date'], 'points_deducted' => ['扣分', '扣分数', '扣除分数', '罚分', 'points_deducted'], diff --git a/database/migrations/2026_10_13_130000_add_reason_and_disposition_to_store_violation_records.php b/database/migrations/2026_10_13_130000_add_reason_and_disposition_to_store_violation_records.php new file mode 100644 index 00000000..05ed9fc9 --- /dev/null +++ b/database/migrations/2026_10_13_130000_add_reason_and_disposition_to_store_violation_records.php @@ -0,0 +1,59 @@ +connection()); + + if (! $schema->hasTable('store_violation_records')) { + return; + } + + $missing = []; + foreach (['violation_reason', 'disposition'] as $column) { + if (! $schema->hasColumn('store_violation_records', $column)) { + $missing[] = $column; + } + } + + if ($missing === []) { + return; + } + + $schema->table('store_violation_records', function (Blueprint $table) use ($missing): void { + if (in_array('violation_reason', $missing, true)) { + $table->string('violation_reason', 500)->nullable()->after('violation_category'); + } + if (in_array('disposition', $missing, true)) { + $table->string('disposition', 500)->nullable()->after('violation_reason'); + } + }); + } + + public function down(): void + { + $schema = Schema::connection($this->connection()); + + if (! $schema->hasTable('store_violation_records')) { + return; + } + + foreach (['disposition', 'violation_reason'] as $column) { + if ($schema->hasColumn('store_violation_records', $column)) { + $schema->table('store_violation_records', function (Blueprint $table) use ($column): void { + $table->dropColumn($column); + }); + } + } + } +}; diff --git a/resources/views/business/pages/financial-risk-control/index.blade.php b/resources/views/business/pages/financial-risk-control/index.blade.php index e09776a2..ea7b6dce 100644 --- a/resources/views/business/pages/financial-risk-control/index.blade.php +++ b/resources/views/business/pages/financial-risk-control/index.blade.php @@ -543,6 +543,8 @@ 店铺名 违规类型 违规分类 + 违规原因 + 处置方式 违规单号 违规日期 扣分 @@ -559,6 +561,8 @@ {{ $record->shop_name ?: '-' }} {{ \Illuminate\Support\Str::limit((string) $record->violation_type, 40, '…') ?: '-' }} {{ $record->violation_category ?: '-' }} + {{ \Illuminate\Support\Str::limit((string) $record->violation_reason, 40, '…') ?: '-' }} + {{ \Illuminate\Support\Str::limit((string) $record->disposition, 30, '…') ?: '-' }} {{ $record->violation_no ?: '-' }} {{ $record->violation_date ?: '-' }} {{ $record->points_deducted === null ? '-' : rtrim(rtrim(number_format((float) $record->points_deducted, 2, '.', ''), '0'), '.') }} @@ -573,7 +577,7 @@ @empty - + @if ($error) {{ $error }} @elseif ($platformTotal === 0) diff --git a/tests/Feature/Business/StoreViolationAlertPageTest.php b/tests/Feature/Business/StoreViolationAlertPageTest.php index 18fac931..27e9a39e 100644 --- a/tests/Feature/Business/StoreViolationAlertPageTest.php +++ b/tests/Feature/Business/StoreViolationAlertPageTest.php @@ -37,6 +37,8 @@ class StoreViolationAlertPageTest extends FeatureTestCase $table->string('shop_name', 191)->default(''); $table->string('violation_type', 500)->nullable(); $table->string('violation_category', 64)->nullable(); + $table->string('violation_reason', 500)->nullable(); + $table->string('disposition', 500)->nullable(); $table->string('violation_no', 100); $table->date('violation_date')->nullable(); $table->decimal('points_deducted', 10, 2)->nullable(); @@ -69,21 +71,24 @@ class StoreViolationAlertPageTest extends FeatureTestCase DB::connection('business_mirror')->table('store_violation_records')->insert([ [ 'platform' => 'jd', 'shop_name' => '京东-亿家达全屋旗舰店', 'violation_type' => '延迟发货/缺货无货', - 'violation_category' => '发货履约', 'violation_no' => 'JD202610040001', 'violation_date' => '2026-10-04', + 'violation_category' => '发货履约', 'violation_reason' => '订单存在延迟发货、缺货无货', 'disposition' => '警告', + 'violation_no' => 'JD202610040001', 'violation_date' => '2026-10-04', 'points_deducted' => 2, 'status' => '待处理', 'penalty_date' => null, 'appeal_deadline' => '2026-10-11', 'handling_status' => '未处理', 'source' => 'crawl', 'crawl_date' => '2026-10-04', 'created_at' => '2026-10-05 08:00:00', 'updated_at' => '2026-10-05 08:00:00', ], [ 'platform' => 'jd', 'shop_name' => '京东-卓禾卧室家具旗舰店', 'violation_type' => '订单存在揽收超时行为', - 'violation_category' => '发货履约', 'violation_no' => 'JD202610040002', 'violation_date' => '2026-10-03', + 'violation_category' => '发货履约', 'violation_reason' => '订单存在揽收超时行为', 'disposition' => null, + 'violation_no' => 'JD202610040002', 'violation_date' => '2026-10-03', 'points_deducted' => null, 'status' => '超期未申诉', 'penalty_date' => '2026-10-05', 'appeal_deadline' => '2026-10-08', 'handling_status' => '处理中', 'source' => 'crawl', 'crawl_date' => '2026-10-04', 'created_at' => '2026-10-05 08:00:00', 'updated_at' => '2026-10-05 08:00:00', ], [ 'platform' => 'jingxi', 'shop_name' => '京喜-久伴吾家具京喜自营工厂店', 'violation_type' => '发票违规', - 'violation_category' => '发票与考核', 'violation_no' => 'JX202610040001', 'violation_date' => '2026-10-04', + 'violation_category' => '发票与考核', 'violation_reason' => null, 'disposition' => '维持原判', + 'violation_no' => 'JX202610040001', 'violation_date' => '2026-10-04', 'points_deducted' => null, 'status' => '已处置', 'penalty_date' => null, 'appeal_deadline' => null, 'handling_status' => '已处理', 'source' => 'crawl', 'crawl_date' => '2026-10-04', 'created_at' => '2026-10-05 08:00:00', 'updated_at' => '2026-10-05 08:00:00', @@ -117,11 +122,14 @@ class StoreViolationAlertPageTest extends FeatureTestCase ->assertSee('店铺名') ->assertSee('违规类型') ->assertSee('违规分类') + ->assertSee('违规原因') + ->assertSee('处置方式') ->assertSee('违规单号') ->assertSee('违规日期') ->assertSee('扣分') ->assertSee('申诉截止日期') ->assertSee('处理状态') + ->assertSee('订单存在延迟发货、缺货无货') ->assertSee('JD202610040001') ->assertSee('京东-亿家达全屋旗舰店') ->assertSee('data-platform-panel="jingxi"', false); @@ -166,13 +174,15 @@ class StoreViolationAlertPageTest extends FeatureTestCase file_put_contents($temp, $binary); $sheet = IOFactory::load($temp)->getActiveSheet(); - $headers = $sheet->rangeToArray('A1:J1')[0]; + $headers = $sheet->rangeToArray('A1:L1')[0]; $this->assertSame( - ['店铺名', '违规类型', '违规分类', '违规单号', '违规日期', '扣分', '状态', '处罚日期', '申诉截止日期', '处理状态'], + ['店铺名', '违规类型', '违规分类', '违规原因', '处置方式', '违规单号', '违规日期', '扣分', '状态', '处罚日期', '申诉截止日期', '处理状态'], $headers, ); - $this->assertSame('JD202610040001', $sheet->getCell('D2')->getValue()); + $this->assertSame('订单存在延迟发货、缺货无货', $sheet->getCell('D2')->getValue()); + $this->assertSame('警告', $sheet->getCell('E2')->getValue()); + $this->assertSame('JD202610040001', $sheet->getCell('F2')->getValue()); unlink($temp); } @@ -237,6 +247,43 @@ class StoreViolationAlertPageTest extends FeatureTestCase $response->assertSessionHasErrors('import'); } + public function test_import_maps_reason_and_disposition_columns(): void + { + $this->allowPage(); + + $file = $this->makeWorkbook([ + ['店铺名', '违规单号', '违规原因', '处置方式'], + ['京东-纪辰家具旗舰店', 'JD202610040088', '订单存在揽收超时行为', '警告;整改'], + ]); + + $preview = $this->loginAs()->post(route('business.store-violation-alert.import.preview'), [ + 'platform' => 'jd', + 'import' => $file, + ]); + + $preview->assertRedirect(); + $payload = $preview->getSession()->get('store_violation_preview'); + $this->assertIsArray($payload); + $this->assertSame(1, $payload['summary']['new']); + + $commit = $this->loginAs()->post(route('business.store-violation-alert.import.commit'), [ + 'preview_token' => $payload['token'], + ]); + $commit->assertRedirect(); + + $record = DB::connection('business_mirror') + ->table('store_violation_records') + ->where('platform', 'jd') + ->where('violation_no', 'JD202610040088') + ->first(); + + $this->assertNotNull($record); + $this->assertSame('订单存在揽收超时行为', $record->violation_reason); + $this->assertSame('警告;整改', $record->disposition); + // 未提供违规类型时,违规分类按违规原因关键词自动归类。 + $this->assertSame('发货履约', $record->violation_category); + } + /** @param list> $rows */ private function makeWorkbook(array $rows): UploadedFile { diff --git a/tests/Unit/Business/StoreViolationMapperTest.php b/tests/Unit/Business/StoreViolationMapperTest.php index e654ef30..e165fd45 100644 --- a/tests/Unit/Business/StoreViolationMapperTest.php +++ b/tests/Unit/Business/StoreViolationMapperTest.php @@ -71,6 +71,33 @@ class StoreViolationMapperTest extends TestCase $this->assertNull($this->mapper->normalizePoints('不扣分')); } + public function test_map_crawl_row_includes_reason_and_disposition_when_upstream_provides_them(): void + { + $base = [ + 'shop_name' => '京喜-久伴吾家具京喜自营工厂店', + 'violation_no' => '86522327', + 'violation_date' => '2026-09-30', + 'deadline' => '2026-10-07', + 'violation_content' => '订单存在揽收超时行为', + 'status' => '待处理', + 'window_name' => '京喜-久伴吾家具京喜自营工厂店_商家后台', + 'platform' => '京喜', + 'crawl_date' => '2026-10-04', + ]; + + $mapped = $this->mapper->mapCrawlRow($base + [ + 'violation_reason' => '订单存在揽收超时行为', + 'disposition' => '警告;扣2分', + ]); + $this->assertSame('订单存在揽收超时行为', $mapped['violation_reason']); + $this->assertSame('警告;扣2分', $mapped['disposition']); + + // 上游尚未提供两列时保持 null,避免同步误覆盖导入补充的数据。 + $legacy = $this->mapper->mapCrawlRow($base); + $this->assertNull($legacy['violation_reason']); + $this->assertNull($legacy['disposition']); + } + public function test_unrecognized_points_throw(): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/Unit/Console/StoreViolationsSyncExtraColumnsTest.php b/tests/Unit/Console/StoreViolationsSyncExtraColumnsTest.php new file mode 100644 index 00000000..3f301800 --- /dev/null +++ b/tests/Unit/Console/StoreViolationsSyncExtraColumnsTest.php @@ -0,0 +1,33 @@ +assertSame([], SyncStoreViolations::pickExtraColumns([ + 'id', 'shop_name', 'violation_no', 'violation_date', 'deadline', + 'violation_content', 'status', 'window_name', 'platform', 'crawl_date', + ])); + } + + public function test_picks_exact_and_alternative_column_names_case_insensitively(): void + { + $this->assertSame( + ['violation_reason' => 'violation_reason', 'disposition' => 'disposition'], + SyncStoreViolations::pickExtraColumns(['id', 'violation_reason', 'disposition']), + ); + + $this->assertSame( + ['violation_reason' => 'reason', 'disposition' => 'handling_method'], + SyncStoreViolations::pickExtraColumns(['Reason', 'HANDLING_METHOD']), + ); + } +}