06696727dd
══════ Activity log (Spatie) ══════ - spatie/laravel-activitylog v5 instalat - Migration cu company_id pentru tenant scoping - Trait Auditable (App\Models\Concerns\Auditable): - LogOptions cu logFillable + logOnlyDirty + dontSubmitEmptyLogs - tapActivity auto-fill company_id + causer - Descrieri RO (creat/modificat/șters/restaurat) - Aplicat pe: Client, Vehicle, Lead, Deal, WorkOrder, Payment, Expense - ActivityResource (group Admin → Jurnal activitate) - Listă read-only, scope pe tenant, filtre by description/today ══════ Kanban Work Orders ══════ - Custom Filament page la /app/kanban (group Service) - 6 coloane (new → diagnosis → agreement → in_work → awaiting_parts → ready) - Drag-drop nativ HTML5 cu wire:click moveCard() - Cards arată: număr fișă, client, auto, plate, master, total - Link 'Deschide' direct la editare WO ══════ Payroll (Salarii) ══════ Schema: - employee_profiles: user_id, position, base_salary, works_pct, parts_pct - payroll_runs: period (YYYY-MM), base, works_revenue/pct, parts_margin/pct, bonus, fines, advance, total auto-calculat - payroll_adjustments: bonus/fine/advance per period PayrollCalculator service: - compute($userId, $period) — calculează auto: - Manopere finalizate de mecanic în luna respectivă (sum total) - Marja pieselor montate de el (sell-buy * qty) - Bonus + fines + advance from adjustments - Total = base + works% + parts% + bonus - fines - advance Resources Filament (group Finanțe): - EmployeeProfileResource: profil cu % comisioane - PayrollRunResource: salarii cu action 'Calculează luna curentă' (toți userii) + per-row 'Recalculează'; Sum summary pe total - PayrollAdjustmentResource: gestionare bonus/penalizări/avansuri ══════ Cleanup ══════ - Șterse toate /__debug, /__seed, /__try-login, /__force-login, /__whoami, /__coolify-check (security) - Routes/web.php conține doar / redirect, /manifest.json, /sw.js Total Filament tenant routes: 92.
80 lines
2.9 KiB
PHP
80 lines
2.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Tenant\EmployeeProfile;
|
|
use App\Models\Tenant\PayrollAdjustment;
|
|
use App\Models\Tenant\PayrollRun;
|
|
use App\Models\Tenant\WorkOrderPart;
|
|
use App\Models\Tenant\WorkOrderWork;
|
|
use Carbon\Carbon;
|
|
|
|
class PayrollCalculator
|
|
{
|
|
/**
|
|
* Compute (or upsert) the payroll run for a given user + month.
|
|
* Period format: YYYY-MM.
|
|
*/
|
|
public function compute(int $userId, string $period, bool $persist = true): PayrollRun
|
|
{
|
|
$start = Carbon::createFromFormat('Y-m', $period)->startOfMonth();
|
|
$end = (clone $start)->endOfMonth();
|
|
|
|
$profile = EmployeeProfile::where('user_id', $userId)->first();
|
|
$base = (float) ($profile?->base_salary ?? 0);
|
|
$worksPct = (float) ($profile?->works_pct ?? 0);
|
|
$partsPct = (float) ($profile?->parts_pct ?? 0);
|
|
|
|
// Manopere finalizate de utilizator în perioadă.
|
|
$worksRevenue = (float) WorkOrderWork::where('master_id', $userId)
|
|
->where('status', 'done')
|
|
->whereBetween('updated_at', [$start, $end])
|
|
->sum('total');
|
|
$worksPctAmount = round($worksRevenue * $worksPct / 100, 2);
|
|
|
|
// Marja pe piesele montate de utilizator (nu există FK direct, aprox via work_order.master_id)
|
|
$partsMargin = (float) WorkOrderPart::where('status', 'installed')
|
|
->whereBetween('updated_at', [$start, $end])
|
|
->whereHas('workOrder', fn ($q) => $q->where('master_id', $userId))
|
|
->get()
|
|
->sum(fn ($p) => ((float) $p->sell_price - (float) $p->buy_price) * (float) $p->qty);
|
|
$partsPctAmount = round($partsMargin * $partsPct / 100, 2);
|
|
|
|
// Bonus / penalizări / avans pe perioadă.
|
|
$adjustments = PayrollAdjustment::where('user_id', $userId)
|
|
->where('period', $period)
|
|
->get();
|
|
$bonus = (float) $adjustments->where('type', 'bonus')->sum('amount');
|
|
$fines = (float) $adjustments->where('type', 'fine')->sum('amount');
|
|
$advance = (float) $adjustments->where('type', 'advance')->sum('amount');
|
|
|
|
$total = round(
|
|
$base + $worksPctAmount + $partsPctAmount + $bonus - $fines - $advance,
|
|
2
|
|
);
|
|
|
|
$attrs = [
|
|
'base' => $base,
|
|
'works_revenue' => $worksRevenue,
|
|
'works_pct_amount' => $worksPctAmount,
|
|
'parts_margin' => $partsMargin,
|
|
'parts_pct_amount' => $partsPctAmount,
|
|
'bonus' => $bonus,
|
|
'fines' => $fines,
|
|
'advance' => $advance,
|
|
'total' => max(0, $total),
|
|
];
|
|
|
|
if (! $persist) {
|
|
return new PayrollRun(['user_id' => $userId, 'period' => $period] + $attrs);
|
|
}
|
|
|
|
$run = PayrollRun::updateOrCreate(
|
|
['user_id' => $userId, 'period' => $period, 'company_id' => app(\App\Tenancy\TenantManager::class)->currentId()],
|
|
$attrs
|
|
);
|
|
|
|
return $run;
|
|
}
|
|
}
|