diff --git a/app/Console/Commands/ImportPostcodes.php b/app/Console/Commands/ImportPostcodes.php index cfa6c7d..78968d6 100644 --- a/app/Console/Commands/ImportPostcodes.php +++ b/app/Console/Commands/ImportPostcodes.php @@ -41,8 +41,25 @@ final class ImportPostcodes extends Command } $headerCounts = array_count_values(array_map('strtolower', $header)); + $columns = array_change_key_case(array_flip($header), CASE_LOWER); - foreach (['pcd', 'lat', 'long'] as $required) { + $pcdColumn = null; + + foreach (['pcd', 'pcds', 'pcd7', 'pcd8'] as $candidate) { + if (isset($columns[$candidate])) { + $pcdColumn = $candidate; + break; + } + } + + if ($pcdColumn === null) { + $this->error('Missing required postcode column (expected one of: pcd, pcds, pcd7, pcd8).'); + fclose($handle); + + return self::FAILURE; + } + + foreach ([$pcdColumn, 'lat', 'long'] as $required) { if (($headerCounts[$required] ?? 0) > 1) { $this->error("Column '{$required}' appears more than once — refusing to import."); fclose($handle); @@ -51,9 +68,7 @@ final class ImportPostcodes extends Command } } - $columns = array_change_key_case(array_flip($header), CASE_LOWER); - - foreach (['pcd', 'lat', 'long'] as $required) { + foreach (['lat', 'long'] as $required) { if (! isset($columns[$required])) { $this->error("Missing required column '{$required}'."); fclose($handle); @@ -82,7 +97,7 @@ final class ImportPostcodes extends Command continue; } - $pcd = strtoupper(preg_replace('/\s+/', '', (string) $row[$columns['pcd']])); + $pcd = strtoupper(preg_replace('/\s+/', '', (string) $row[$columns[$pcdColumn]])); if ($pcd === '' || strlen($pcd) < 5) { continue; diff --git a/tests/Feature/Console/ImportPostcodesTest.php b/tests/Feature/Console/ImportPostcodesTest.php index 3d60e68..22e44ed 100644 --- a/tests/Feature/Console/ImportPostcodesTest.php +++ b/tests/Feature/Console/ImportPostcodesTest.php @@ -63,6 +63,22 @@ CSV; ->and(Postcode::find('BT11AA'))->toBeNull(); }); +it('accepts ArcGIS ONSPD exports that use PCD7 instead of PCD', function (): void { + $csv = <<<'CSV' +OBJECTID,PCD7,PCD8,PCDS,DOTERM,LAT,LONG,x,y +1,"SW1A 1AA","SW1A 1AA","SW1A 1AA","",51.501009,-0.141588,529090,179645 +2,"M1 1AD","M1 1AD","M1 1AD","",53.480957,-2.237428,384730,398295 +CSV; + + $path = writeOnspdFixture($csv); + + $this->artisan('postcodes:import', ['--file' => $path])->assertSuccessful(); + + expect(Postcode::count())->toBe(2) + ->and(Postcode::find('SW1A1AA')->outcode)->toBe('SW1A') + ->and(Postcode::find('M11AD')->outcode)->toBe('M1'); +}); + it('derives outcode centroids as the average of member postcodes', function (): void { $csv = <<<'CSV' pcd,pcds,doterm,lat,long