Vehicle model now implements HasMedia + InteractsWithMedia and
registers a 'photos' collection. VehicleResource form gets a
SpatieMediaLibraryFileUpload section (collapsible, max 6 photos,
imageEditor enabled).
Dashboard already checks vehicle->getFirstMediaUrl('photos') first
and falls back to the WO's photos, so uploading here immediately
populates the vehicle card on the dashboard without any view changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Broad sweep across the whole codebase:
- Blade views (39 files, 315 wraps): tag-text and title/placeholder/alt
attributes wrapped with {{ __() }}. Excludes scripts, styles, @php,
@verbatim, {{ }}, {!! !!}, comments to avoid touching interpolations.
- PHP (54 files, 179 wraps): array 'key' => 'RO value' patterns and
list items with diacritics wrapped with __(). Reverted __() inside
const arrays (PHP disallows non-constant expressions).
- Added 269 new keys to lang/{ru,en}.json (identity fallback for
unknowns → 161 human RU + 163 EN translations added for the most
common enums, stages, roles, statuses, payment methods, vehicle
categories, warehouse, portal, form actions.
Missing translations fall back to RO so the UI never breaks. All 306
tests pass; view cache compiles cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Convert static $modelLabel/$pluralModelLabel/$title to getter methods
- Wrap ->label()/->placeholder()/->helperText()/->description()/->title()/->body() args
- Wrap Section::make()/Fieldset::make()/Notification::make()->title() args
- Fix RelationManagers::getTitle() signature to match parent (Model, string)
- Fix Pages::getTitle() to instance method (BasePage::getTitle is non-static)
- Extend lang/ru.json + lang/en.json with 700+ common terms; identity fallback for the rest
- Remove duplicate getters in 5 resources that had manual getModelLabel already
All 306 tests pass. Missing translations fall back to the RO key so the UI never breaks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User screenshots showed the tenant admin panel (Filament) had sidebar
labels stuck in Romanian even when switching to Russian: 'Cereri',
'Calendar vizual', 'Atelierul meu', 'KPI mecanici', 'Fișe lucru',
'Norme-ore', 'Tehnicieni', 'Șabloane servicii', 'Depozite', 'Scaner',
'Depozit', 'VIN-căutare', 'Furnizori', 'Achiziții', 'Procentaj',
'Coeficienți preț', plus all group headers.
Root cause: every Filament Resource and Page had static properties
'protected static ?string $navigationLabel = "Fișe lucru"' — string
literals baked into class definitions. Static properties don't run
through the translation layer.
Fix in two parts:
1. New translation files with 52 label keys + 12 group keys:
- lang/ro/nav.php — Romanian (identity)
- lang/ru/nav.php — full Russian translations (Заказ-наряды,
Автомобили, Клиенты, Календарь, Моя мастерская, Механики KPI,
Настройки, etc.)
- lang/en/nav.php — English translations (Work orders, Vehicles,
Clients, Calendar, My workshop, Mechanic KPI, Settings, etc.)
Keyed by the Romanian original so lookups map 1:1 —
'nav.label.Fișe lucru' returns 'Заказ-наряды' in RU, 'Work orders'
in EN, 'Fișe lucru' in RO.
2. Python transformer converted 54 files:
- 33 Filament Tenant Resources
- 15 Filament Tenant Pages
- 4 Filament Central Resources
- 1 Filament Central Page
- 1 Widget
Each 'protected static ?string $navigationLabel = "X";' became
'public static function getNavigationLabel(): string { return
__("nav.label.X"); }'. Same treatment for $navigationGroup.
Cleanup: 6 resources already had manually-added getNavigationLabel
methods from an earlier partial effort — those used flat JSON keys
(__("Cereri")) that never resolved. Deduped so only the nav.label.*
version remains.
Untouched (intentional):
- $modelLabel / $pluralModelLabel (used in breadcrumbs and headings —
still hardcoded, next tier of work)
- Section titles, column headers, form field labels (medium priority)
- $navigationSort (numeric, no translation needed)
- $navigationIcon (icon reference)
Suite: 306 passed (853 assertions). Unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contextual multipliers layered on top of base MarkupRule pricing, applied
per work-order line based on vehicle, client and urgency.
Schema:
- pricing_coefficients (multiplier, conditions JSON, priority, stackable)
- vehicles.vehicle_class (sedan/suv/commercial/hybrid/ev/premium)
- clients.is_vip
- work_orders.urgency (normal/urgent/express)
PricingEngine::quote(Part, Vehicle?, Client?, urgency):
- base = MarkupRule on buy_price (fallback sell_price or buy×1.30)
- context: class (explicit or inferred hybrid/ev from fuel), age, vip, urgency
- stackable coefficients all multiply; non-stackable take only the highest
- returns {base, final, applied[]} breakdown
PricingCoefficient::matches(ctx) — classes/age range/vip/urgency conditions
(empty = always applies).
Filament:
- PricingCoefficientResource with condition builder (classes, age, vip, urgency)
- vehicle_class select, client is_vip toggle, WO urgency select
- "Preț inteligent" action on WO parts shows breakdown + applies sell_price
Tests (6 new):
- base-only without coefficients; age coefficient gating; VIP; express urgency;
stackable multiply vs non-stackable highest-wins; hybrid inferred from fuel
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 3-step onboarding wizard at /app/onboarding (auto-redirected via
RequireOnboarding middleware on first login per tenant)
- Empty states with icon + heading + description on Client, Vehicle,
WorkOrder, Lead, Part lists
- Docs: operations/{api,i18n,2fa,monitoring}.md, stack/reverb.md
- Updated 00-index.md and journal.md with status of all 15 items
Layout components (Section, Grid, Tabs, etc.) au fost mutate din
Filament\Forms\Components în Filament\Schemas\Components.
Forms\Components păstrează doar field-urile (TextInput, Select, etc.).
Forms\Get s-a mutat în Schemas\Components\Utilities\Get.
Filament v5 a unificat actions într-un singur namespace Filament\Actions.
Tables\Actions\EditAction et al. nu mai există → fix global pe toate resources.