4b3201ca1c
═══ Workload heatmap (Încărcare STO) ═══ - /app/workload custom Page (group Analiză) - Săptămână (Lu-Du) × posturi → matrice ore programate - Heatmap colorat: verde→galben→roșu pe ratio capacity (10h/zi) - Navigare săpt anterior/curent/următor - Programări fără pod → row '— fără pod —' separat ═══ Site PSauto (landing public) ═══ - / pe tenant subdomain → resources/views/site/landing.blade.php - Hero cu logo + nume + slogan; gradient theme color - Servicii (din settings.services) — grid card-uri - Locație/contact + program lucru standardizat - Mărci suportate (din settings.cars) - CTA: phone + email - Footer cu tenant name + powered by AutoCRM ═══ VIN search ═══ - VinDecoder service: WMI hardcoded (24 producători EU/Asia/USA) + year codes (2001-2026) — pure offline, fără API extern - /app/vin-search Page (group Depozit) cu: • Input VIN cu uppercase + monospace • Decode → producător/țară/an/serial • Match VIN-uri din baza Vehicles • Search piese din catalog (live debounce 300ms) - Rezultatele linkează la editor Vehicle/Part Total tenant routes: 102.
60 lines
2.5 KiB
PHP
60 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
class VinDecoder
|
|
{
|
|
/** WMI (first 3 chars of VIN) → manufacturer/country (subset relevant for European cars). */
|
|
public const WMI = [
|
|
'WBA' => ['BMW', 'Germany'], 'WBS' => ['BMW M', 'Germany'],
|
|
'WAU' => ['Audi', 'Germany'], 'WA1' => ['Audi SUV', 'Germany'],
|
|
'WVW' => ['Volkswagen', 'Germany'], 'WV1' => ['VW Comm', 'Germany'], 'WV2' => ['VW Bus', 'Germany'],
|
|
'WP0' => ['Porsche', 'Germany'], 'WP1' => ['Porsche SUV', 'Germany'],
|
|
'WDB' => ['Mercedes-Benz', 'Germany'], 'WDC' => ['Mercedes SUV', 'Germany'], 'WDD' => ['Mercedes AMG', 'Germany'],
|
|
'TMB' => ['Skoda', 'Czechia'],
|
|
'JF1' => ['Subaru', 'Japan'], 'JS3' => ['Suzuki', 'Japan'],
|
|
'JT1' => ['Toyota', 'Japan'], 'JTD' => ['Toyota Hybrid', 'Japan'],
|
|
'JHM' => ['Honda', 'Japan'], '1HG' => ['Honda US', 'USA'],
|
|
'KMH' => ['Hyundai', 'Korea'], 'KNA' => ['Kia', 'Korea'],
|
|
'VF1' => ['Renault', 'France'], 'VF3' => ['Peugeot', 'France'], 'VF7' => ['Citroen', 'France'],
|
|
'ZFA' => ['Fiat', 'Italy'], 'ZAR' => ['Alfa Romeo', 'Italy'],
|
|
'WF0' => ['Ford EU', 'Germany'], '1FA' => ['Ford US', 'USA'],
|
|
'YV1' => ['Volvo', 'Sweden'],
|
|
'W0L' => ['Opel', 'Germany'],
|
|
];
|
|
|
|
/** 10th VIN char (model year). */
|
|
public const YEAR_CODES = [
|
|
'A' => 2010, 'B' => 2011, 'C' => 2012, 'D' => 2013, 'E' => 2014, 'F' => 2015,
|
|
'G' => 2016, 'H' => 2017, 'J' => 2018, 'K' => 2019, 'L' => 2020, 'M' => 2021,
|
|
'N' => 2022, 'P' => 2023, 'R' => 2024, 'S' => 2025, 'T' => 2026,
|
|
'1' => 2001, '2' => 2002, '3' => 2003, '4' => 2004, '5' => 2005,
|
|
'6' => 2006, '7' => 2007, '8' => 2008, '9' => 2009,
|
|
];
|
|
|
|
public function decode(string $vin): array
|
|
{
|
|
$vin = strtoupper(trim($vin));
|
|
if (strlen($vin) < 11) {
|
|
return ['valid' => false, 'error' => 'VIN trebuie să aibă cel puțin 11 caractere.'];
|
|
}
|
|
|
|
$wmi = substr($vin, 0, 3);
|
|
$manufacturer = self::WMI[$wmi] ?? null;
|
|
$yearChar = $vin[9] ?? null;
|
|
$year = self::YEAR_CODES[$yearChar] ?? null;
|
|
|
|
// Heuristic: 70s/80s/90s vs 2000s+ — model year alone is ambiguous,
|
|
// we just return what we can.
|
|
return [
|
|
'valid' => $manufacturer !== null,
|
|
'vin' => $vin,
|
|
'wmi' => $wmi,
|
|
'manufacturer' => $manufacturer[0] ?? '?',
|
|
'country' => $manufacturer[1] ?? '?',
|
|
'serial' => substr($vin, 11),
|
|
'year' => $year,
|
|
];
|
|
}
|
|
}
|