Car-Repairs-Shop/app/Services/VinDecoderService.php
sackey e839d40a99
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Initial commit
2025-07-30 17:15:50 +00:00

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 [];
}
}