diff --git a/app/Services/PostcodeService.php b/app/Services/PostcodeService.php index 7c27a2b..9489e98 100644 --- a/app/Services/PostcodeService.php +++ b/app/Services/PostcodeService.php @@ -47,6 +47,11 @@ class PostcodeService return $result; } + private function normalisePostcode(string $value): string + { + return strtoupper(preg_replace('/\s+/', '', $value)); + } + private function isFullPostcode(string $query): bool { return (bool) preg_match('/^[A-Z]{1,2}[0-9][0-9A-Z]?\s*[0-9][A-Z]{2}$/i', $query); @@ -59,7 +64,7 @@ class PostcodeService private function lookupLocalPostcode(string $postcode): ?LocationResult { - $normalised = strtoupper(preg_replace('/\s+/', '', $postcode)); + $normalised = $this->normalisePostcode($postcode); $row = Postcode::find($normalised); @@ -105,7 +110,7 @@ class PostcodeService private function lookupPostcode(string $postcode): ?LocationResult { - $normalised = strtoupper(preg_replace('/\s+/', '', $postcode)); + $normalised = $this->normalisePostcode($postcode); $url = self::BASE_URL.'/postcodes/'.$normalised; try { @@ -117,12 +122,23 @@ class PostcodeService $data = $response->json('result'); - return new LocationResult( + $result = new LocationResult( query: $postcode, displayName: $data['postcode'], lat: $data['latitude'], lng: $data['longitude'], ); + + Postcode::updateOrCreate( + ['postcode' => $normalised], + [ + 'outcode' => substr($normalised, 0, strlen($normalised) - 3), + 'lat' => $data['latitude'], + 'lng' => $data['longitude'], + ], + ); + + return $result; } catch (Throwable $e) { Log::error('PostcodeService: postcode lookup failed', [ 'postcode' => $postcode, @@ -147,12 +163,22 @@ class PostcodeService $data = $response->json('result'); - return new LocationResult( + $result = new LocationResult( query: $outcode, displayName: $data['outcode'], lat: $data['latitude'], lng: $data['longitude'], ); + + Outcode::updateOrCreate( + ['outcode' => $normalised], + [ + 'lat' => $data['latitude'], + 'lng' => $data['longitude'], + ], + ); + + return $result; } catch (Throwable $e) { Log::error('PostcodeService: outcode lookup failed', [ 'outcode' => $outcode, diff --git a/tests/Unit/Services/PostcodeServiceTest.php b/tests/Unit/Services/PostcodeServiceTest.php index 464ef8e..f3bc4ea 100644 --- a/tests/Unit/Services/PostcodeServiceTest.php +++ b/tests/Unit/Services/PostcodeServiceTest.php @@ -216,3 +216,48 @@ it('resolves an outcode from local DB without calling HTTP', function (): void { Http::assertNothingSent(); }); + +// --- HTTP fallback persistence --- + +it('persists a full postcode resolved via HTTP fallback', function (): void { + Http::fake([ + '*/postcodes/SW1A1AA' => Http::response([ + 'status' => 200, + 'result' => [ + 'postcode' => 'SW1A 1AA', + 'latitude' => 51.501009, + 'longitude' => -0.141588, + ], + ]), + ]); + + $this->service->resolve('SW1A 1AA'); + + $row = Postcode::find('SW1A1AA'); + + expect($row)->not->toBeNull() + ->and($row->outcode)->toBe('SW1A') + ->and((float) $row->lat)->toBe(51.501009) + ->and((float) $row->lng)->toBe(-0.141588); +}); + +it('persists an outcode resolved via HTTP fallback', function (): void { + Http::fake([ + '*/outcodes/PE7' => Http::response([ + 'status' => 200, + 'result' => [ + 'outcode' => 'PE7', + 'latitude' => 52.536397, + 'longitude' => -0.210181, + ], + ]), + ]); + + $this->service->resolve('PE7'); + + $row = Outcode::find('PE7'); + + expect($row)->not->toBeNull() + ->and((float) $row->lat)->toBe(52.536397) + ->and((float) $row->lng)->toBe(-0.210181); +});