Faza 6: Activity log + Kanban + Payroll + cleanup
══════ 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.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user