217 lines
6.4 KiB
PHP
217 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class VinDecoderService
|
|
{
|
|
private const NHTSA_API_BASE = 'https://vpic.nhtsa.dot.gov/api';
|
|
|
|
/**
|
|
* Decode VIN using NHTSA API
|
|
*/
|
|
public function decodeVin(string $vin): array
|
|
{
|
|
try {
|
|
// Clean and validate VIN format
|
|
$vin = strtoupper(trim($vin));
|
|
|
|
if (strlen($vin) !== 17) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'VIN must be exactly 17 characters long.',
|
|
'data' => null
|
|
];
|
|
}
|
|
|
|
// Make API request to NHTSA
|
|
$response = Http::timeout(10)->get(self::NHTSA_API_BASE . "/vehicles/DecodeVin/{$vin}", [
|
|
'format' => 'json'
|
|
]);
|
|
|
|
if (!$response->successful()) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'Failed to connect to VIN decoder service.',
|
|
'data' => null
|
|
];
|
|
}
|
|
|
|
$data = $response->json();
|
|
|
|
if (empty($data['Results'])) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'No vehicle data found for this VIN.',
|
|
'data' => null
|
|
];
|
|
}
|
|
|
|
// Parse the results
|
|
$vehicleData = $this->parseVinResults($data['Results']);
|
|
|
|
return [
|
|
'success' => true,
|
|
'error' => null,
|
|
'data' => $vehicleData
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('VIN Decoder Error: ' . $e->getMessage());
|
|
|
|
return [
|
|
'success' => false,
|
|
'error' => 'An error occurred while decoding the VIN. Please try again.',
|
|
'data' => null
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse NHTSA API results into usable vehicle data
|
|
*/
|
|
private function parseVinResults(array $results): array
|
|
{
|
|
$vehicleData = [
|
|
'make' => null,
|
|
'model' => null,
|
|
'year' => null,
|
|
'engine_type' => null,
|
|
'transmission' => null,
|
|
'body_class' => null,
|
|
'fuel_type' => null,
|
|
'drive_type' => null,
|
|
'error_codes' => []
|
|
];
|
|
|
|
// Initialize engine-related variables
|
|
$cylinders = null;
|
|
$displacement = null;
|
|
$engineConfig = null;
|
|
|
|
foreach ($results as $result) {
|
|
$variable = $result['Variable'] ?? '';
|
|
$value = $result['Value'] ?? '';
|
|
$errorCode = $result['ErrorCode'] ?? '';
|
|
|
|
// Skip empty values
|
|
if (empty($value) || $value === 'Not Applicable' || $value === 'N/A') {
|
|
continue;
|
|
}
|
|
|
|
// Collect error codes
|
|
if (!empty($errorCode) && $errorCode !== '0') {
|
|
$vehicleData['error_codes'][] = $result['ErrorText'] ?? 'Unknown error';
|
|
continue;
|
|
}
|
|
|
|
// Map NHTSA fields to our vehicle data
|
|
switch ($variable) {
|
|
case 'Make':
|
|
$vehicleData['make'] = $value;
|
|
break;
|
|
case 'Model':
|
|
$vehicleData['model'] = $value;
|
|
break;
|
|
case 'Model Year':
|
|
$vehicleData['year'] = (int) $value;
|
|
break;
|
|
case 'Engine Number of Cylinders':
|
|
$cylinders = $value;
|
|
break;
|
|
case 'Displacement (L)':
|
|
$displacement = $value;
|
|
break;
|
|
case 'Engine Configuration':
|
|
$engineConfig = $value;
|
|
break;
|
|
case 'Fuel Type - Primary':
|
|
$vehicleData['fuel_type'] = $value;
|
|
break;
|
|
case 'Transmission Style':
|
|
$vehicleData['transmission'] = $value;
|
|
break;
|
|
case 'Body Class':
|
|
$vehicleData['body_class'] = $value;
|
|
break;
|
|
case 'Drive Type':
|
|
$vehicleData['drive_type'] = $value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Build engine description from available data
|
|
$engineParts = array_filter([
|
|
$displacement ? $displacement . 'L' : null,
|
|
$cylinders ? $cylinders . '-cyl' : null,
|
|
$engineConfig ?? null,
|
|
$vehicleData['fuel_type'] ?? null
|
|
]);
|
|
|
|
if (!empty($engineParts)) {
|
|
$vehicleData['engine_type'] = implode(' ', $engineParts);
|
|
}
|
|
|
|
return $vehicleData;
|
|
}
|
|
|
|
/**
|
|
* Get vehicle makes for dropdown
|
|
*/
|
|
public function getVehicleMakes(): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(10)->get(self::NHTSA_API_BASE . '/vehicles/GetMakesForVehicleType/car', [
|
|
'format' => 'json'
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
$makes = collect($data['Results'] ?? [])
|
|
->pluck('MakeName')
|
|
->filter()
|
|
->sort()
|
|
->values()
|
|
->all();
|
|
|
|
return $makes;
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('Error fetching vehicle makes: ' . $e->getMessage());
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Get vehicle models for a specific make and year
|
|
*/
|
|
public function getModelsForMakeAndYear(string $make, int $year): array
|
|
{
|
|
try {
|
|
$response = Http::timeout(10)->get(self::NHTSA_API_BASE . "/vehicles/GetModelsForMakeYear/make/{$make}/modelyear/{$year}", [
|
|
'format' => 'json'
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
$data = $response->json();
|
|
$models = collect($data['Results'] ?? [])
|
|
->pluck('Model_Name')
|
|
->filter()
|
|
->unique()
|
|
->sort()
|
|
->values()
|
|
->all();
|
|
|
|
return $models;
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::error('Error fetching vehicle models: ' . $e->getMessage());
|
|
}
|
|
|
|
return [];
|
|
}
|
|
}
|