Files
Vasyka 5e255b7b40 Stage 10 — Bodyshop / PDR / Detailing: damage map + insurance + photos
Completes the 18-stage roadmap (17/18 fully functional, 18 partial).

Schema:
- bodyshop_jobs (type body_repair/pdr/painting/detailing/ceramic/ppf/polishing,
  status workflow, insurance case fields, estimate/approved amounts)
- damage_points (zone, kind, severity) — the damage map

Models:
- BodyshopJob (HasMedia: photos_before/photos_after), auto number BS-YY-NNNN
- DamagePoint with ZONES/KINDS/SEVERITIES

Filament (new "Tinichigerie" nav group):
- BodyshopJobResource: type/status, collapsible insurance section (conditional
  fields), before/after photo upload, estimate/approved amounts
- DamagePointsRelationManager (zone + kind + colour-coded severity)
- Table with type badge, insurance flag, damage count; nav badge = open jobs

Tests (5 new):
- auto number; damage points relation; insurance fields persist;
  detailing types supported; tenant isolation

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 06:49:47 +00:00

83 lines
3.0 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\BodyshopJob;
use App\Models\Tenant\Client;
use App\Models\Tenant\DamagePoint;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class BodyshopTest extends TestCase
{
use RefreshDatabase;
private Company $company;
protected function setUp(): void
{
parent::setUp();
$this->company = $this->makeCompany('body');
}
public function test_number_auto_generated(): void
{
$job = BodyshopJob::create(['type' => 'painting', 'status' => 'estimate']);
$this->assertStringStartsWith('BS-', $job->number);
}
public function test_damage_points_relation(): void
{
$job = BodyshopJob::create(['type' => 'body_repair', 'status' => 'estimate']);
DamagePoint::create(['bodyshop_job_id' => $job->id, 'zone' => 'Capotă', 'kind' => 'Lovitură', 'severity' => 'severe']);
DamagePoint::create(['bodyshop_job_id' => $job->id, 'zone' => 'Ușă FS', 'kind' => 'Zgârietură', 'severity' => 'minor']);
$this->assertEquals(2, $job->damagePoints()->count());
$this->assertEquals('severe', $job->damagePoints()->where('zone', 'Capotă')->first()->severity);
}
public function test_insurance_fields_persist(): void
{
$job = BodyshopJob::create([
'type' => 'body_repair', 'status' => 'approved',
'is_insurance' => true, 'insurer' => 'MoldAsig',
'policy_no' => 'POL-123', 'claim_no' => 'CLM-999',
'insurance_status' => 'submitted',
'estimate_amount' => 12000, 'approved_amount' => 11500,
]);
$fresh = $job->fresh();
$this->assertTrue($fresh->is_insurance);
$this->assertEquals('MoldAsig', $fresh->insurer);
$this->assertEquals('CLM-999', $fresh->claim_no);
$this->assertEquals(11500.0, (float) $fresh->approved_amount);
}
public function test_detailing_types_supported(): void
{
foreach (['ceramic', 'ppf', 'polishing', 'detailing', 'pdr'] as $type) {
$job = BodyshopJob::create(['type' => $type, 'status' => 'estimate']);
$this->assertArrayHasKey($job->type, BodyshopJob::TYPES);
}
}
public function test_bodyshop_jobs_isolated_per_tenant(): void
{
BodyshopJob::create(['type' => 'painting', 'status' => 'estimate']);
$other = $this->makeCompany('otherbody');
app(TenantManager::class)->setCurrent($other);
$this->assertEquals(0, BodyshopJob::count());
}
private function makeCompany(string $slug): Company
{
$plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]);
$company = Company::create(['plan_id' => $plan->id, 'slug' => $slug, 'name' => ucfirst($slug), 'status' => 'active']);
app(TenantManager::class)->setCurrent($company);
return $company;
}
}