From ada43d222a481da7e660a79df76ff51b60d68489 Mon Sep 17 00:00:00 2001 From: Ovidiu U Date: Fri, 3 Apr 2026 18:53:42 +0100 Subject: [PATCH] feat: FuelPriceService station upsert with tagging Co-Authored-By: Claude Sonnet 4.6 --- app/Services/FuelPriceService.php | 41 +++++++++++ tests/Unit/Services/FuelPriceServiceTest.php | 72 ++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/app/Services/FuelPriceService.php b/app/Services/FuelPriceService.php index 5b34d6e..6dd831d 100644 --- a/app/Services/FuelPriceService.php +++ b/app/Services/FuelPriceService.php @@ -2,6 +2,7 @@ namespace App\Services; +use App\Models\Station; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; @@ -25,4 +26,44 @@ class FuelPriceService return $response->json('data.access_token'); }); } + + /** @param array> $apiStations */ + public function upsertStations(array $apiStations): void + { + $now = now(); + $rows = []; + + foreach ($apiStations as $data) { + $station = new Station([ + 'node_id' => $data['node_id'], + 'trading_name' => $data['trading_name'], + 'brand_name' => $data['brand_name'] ?? null, + 'is_same_trading_and_brand' => $data['is_same_trading_and_brand_name'] ?? false, + 'is_supermarket' => false, + 'is_motorway_service_station' => $data['is_motorway_service_station'] ?? false, + 'is_supermarket_service_station' => $data['is_supermarket_service_station'] ?? false, + 'temporary_closure' => $data['temporary_closure'] ?? false, + 'permanent_closure' => $data['permanent_closure'] ?? false, + 'permanent_closure_date' => $data['permanent_closure_date'] ?? null, + 'public_phone_number' => $data['public_phone_number'] ?? null, + 'address_line_1' => $data['location']['address_line_1'] ?? null, + 'address_line_2' => $data['location']['address_line_2'] ?? null, + 'city' => $data['location']['city'] ?? null, + 'county' => $data['location']['county'] ?? null, + 'country' => $data['location']['country'] ?? null, + 'postcode' => $data['location']['postcode'], + 'lat' => $data['location']['latitude'], + 'lng' => $data['location']['longitude'], + 'amenities' => $data['amenities'] ?? [], + 'opening_times' => $data['opening_times'] ?? null, + 'fuel_types' => $data['fuel_types'] ?? [], + 'last_seen_at' => $now, + ]); + + $this->taggingService->tag($station); + $rows[] = $station->getAttributes(); + } + + Station::upsert($rows, ['node_id'], array_keys($rows[0] ?? [])); + } } diff --git a/tests/Unit/Services/FuelPriceServiceTest.php b/tests/Unit/Services/FuelPriceServiceTest.php index 169f909..8d0e9ee 100644 --- a/tests/Unit/Services/FuelPriceServiceTest.php +++ b/tests/Unit/Services/FuelPriceServiceTest.php @@ -1,5 +1,6 @@ toBe('cached-token'); Http::assertNothingSent(); }); + +it('upserts stations from API batch response', function (): void { + $apiStations = [ + [ + 'node_id' => 'abc123', + 'trading_name' => 'Village Garage', + 'brand_name' => 'Village Garage', + 'is_same_trading_and_brand_name' => true, + 'is_motorway_service_station' => false, + 'is_supermarket_service_station' => false, + 'temporary_closure' => false, + 'permanent_closure' => false, + 'permanent_closure_date' => null, + 'public_phone_number' => null, + 'location' => [ + 'address_line_1' => '1 High Street', + 'address_line_2' => null, + 'city' => 'London', + 'county' => null, + 'country' => 'England', + 'postcode' => 'SW1A 1AA', + 'latitude' => 51.5, + 'longitude' => -0.1, + ], + 'amenities' => [], + 'opening_times'=> null, + 'fuel_types' => ['E10', 'E5'], + ], + ]; + + $this->service->upsertStations($apiStations); + + $station = Station::find('abc123'); + expect($station)->not->toBeNull() + ->and($station->trading_name)->toBe('Village Garage') + ->and($station->postcode)->toBe('SW1A 1AA') + ->and((float) $station->lat)->toBe(51.5) + ->and($station->is_supermarket)->toBeFalse(); +}); + +it('tags supermarket stations during upsert', function (): void { + $apiStations = [[ + 'node_id' => 'tesco1', + 'trading_name' => 'TESCO', + 'brand_name' => 'TESCO', + 'is_same_trading_and_brand_name' => true, + 'is_motorway_service_station' => false, + 'is_supermarket_service_station' => true, + 'temporary_closure' => false, + 'permanent_closure' => false, + 'permanent_closure_date' => null, + 'public_phone_number' => null, + 'location' => [ + 'address_line_1' => '1 Tesco Way', + 'address_line_2' => null, + 'city' => 'Bristol', + 'county' => null, + 'country' => 'England', + 'postcode' => 'BS1 1AA', + 'latitude' => 51.45, + 'longitude' => -2.6, + ], + 'amenities' => [], + 'opening_times'=> null, + 'fuel_types' => ['E10'], + ]]; + + $this->service->upsertStations($apiStations); + + expect(Station::find('tesco1')->is_supermarket)->toBeTrue(); +});