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>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Tenant;
|
||||
|
||||
use App\Models\Concerns\BelongsToTenant;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
|
||||
class BodyshopJob extends Model implements HasMedia
|
||||
{
|
||||
use BelongsToTenant, InteractsWithMedia, SoftDeletes;
|
||||
|
||||
public const TYPES = [
|
||||
'body_repair' => 'Tinichigerie',
|
||||
'pdr' => 'PDR (fără vopsire)',
|
||||
'painting' => 'Vopsitorie',
|
||||
'detailing' => 'Detailing',
|
||||
'ceramic' => 'Ceramică',
|
||||
'ppf' => 'Folie PPF',
|
||||
'polishing' => 'Polish',
|
||||
];
|
||||
|
||||
public const STATUSES = [
|
||||
'estimate' => 'Deviz',
|
||||
'approved' => 'Aprobat',
|
||||
'in_progress' => 'În lucru',
|
||||
'done' => 'Finalizat',
|
||||
'delivered' => 'Predat',
|
||||
'cancelled' => 'Anulat',
|
||||
];
|
||||
|
||||
public const INSURANCE_STATUSES = [
|
||||
'submitted' => 'Depus',
|
||||
'approved' => 'Aprobat',
|
||||
'rejected' => 'Respins',
|
||||
'paid' => 'Plătit',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'company_id', 'work_order_id', 'client_id', 'vehicle_id',
|
||||
'number', 'type', 'status',
|
||||
'is_insurance', 'insurer', 'policy_no', 'claim_no', 'insurance_status',
|
||||
'estimate_amount', 'approved_amount', 'notes',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_insurance' => 'boolean',
|
||||
'estimate_amount' => 'decimal:2',
|
||||
'approved_amount' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('photos_before');
|
||||
$this->addMediaCollection('photos_after');
|
||||
}
|
||||
|
||||
public function client(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Client::class);
|
||||
}
|
||||
|
||||
public function vehicle(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Vehicle::class);
|
||||
}
|
||||
|
||||
public function workOrder(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(WorkOrder::class);
|
||||
}
|
||||
|
||||
public function damagePoints(): HasMany
|
||||
{
|
||||
return $this->hasMany(DamagePoint::class);
|
||||
}
|
||||
|
||||
public static function generateNumber(int $companyId): string
|
||||
{
|
||||
$year = date('y');
|
||||
$count = static::withoutGlobalScopes()
|
||||
->where('company_id', $companyId)
|
||||
->whereYear('created_at', date('Y'))
|
||||
->count();
|
||||
return sprintf('BS-%s-%04d', $year, $count + 1);
|
||||
}
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::creating(function (self $job) {
|
||||
if (empty($job->number)) {
|
||||
$job->number = static::generateNumber(
|
||||
$job->company_id ?: app(\App\Tenancy\TenantManager::class)->currentId()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user