netgescon-day0/app/Support/StabileContext.php

393 lines
12 KiB
PHP
Executable File

<?php
namespace App\Support;
use App\Models\Fornitore;
use App\Models\FornitoreDipendente;
use App\Models\Stabile;
use App\Models\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class StabileContext
{
public const SESSION_KEY = 'netgescon.stabile_attivo_id';
/**
* @return array<int, string>
*/
public static function legacyCodeCandidates(?Stabile $stabile): array
{
if (! $stabile instanceof Stabile) {
return [];
}
$rawCandidates = [
trim((string) ($stabile->codice_stabile ?? '')),
trim((string) ($stabile->old_id ?? '')),
trim((string) ($stabile->cod_stabile ?? '')),
];
$candidates = [];
foreach ($rawCandidates as $candidate) {
if ($candidate === '') {
continue;
}
$candidates[] = $candidate;
$noZero = ltrim($candidate, '0');
if ($noZero !== '' && $noZero !== $candidate) {
$candidates[] = $noZero;
}
}
return array_values(array_unique($candidates));
}
public static function preferredLegacyCode(?Stabile $stabile): ?string
{
$candidates = self::legacyCodeCandidates($stabile);
return $candidates[0] ?? null;
}
public static function setFromStabile(Stabile $stabile, ?User $user = null): bool
{
$user = $user ?? Auth::user();
if ($user instanceof User) {
return self::setActiveStabileId($user, (int) $stabile->id);
}
session([self::SESSION_KEY => (int) $stabile->id]);
return true;
}
public static function resolveActiveStabileId(User $user): ?int
{
$allowed = self::accessibleStabili($user)->pluck('id')->map(fn($v) => (int) $v)->values();
if ($allowed->isEmpty()) {
session()->forget(self::SESSION_KEY);
return null;
}
$sessionId = session(self::SESSION_KEY);
if (is_numeric($sessionId)) {
$sessionId = (int) $sessionId;
if ($allowed->contains($sessionId)) {
return $sessionId;
}
}
// Persistenza: prova a ripristinare l'ultimo stabile usato dall'utente.
$persistedId = self::getPersistedStabileId($user);
if ($persistedId && $allowed->contains($persistedId)) {
session([self::SESSION_KEY => $persistedId]);
return $persistedId;
}
$preferredSupplierStabileId = self::resolvePreferredSupplierStabileId($user, $allowed->all());
if ($preferredSupplierStabileId && $allowed->contains($preferredSupplierStabileId)) {
session([self::SESSION_KEY => $preferredSupplierStabileId]);
return $preferredSupplierStabileId;
}
$default = (int) config('netgescon.defaults.default_stabile_id', 0);
if ($default > 0 && $allowed->contains($default)) {
session([self::SESSION_KEY => $default]);
return $default;
}
$first = (int) $allowed->first();
session([self::SESSION_KEY => $first]);
return $first;
}
private static function getPersistedStabileId(User $user): ?int
{
if (! Schema::hasColumn('users', 'last_stabile_id')) {
return null;
}
$candidate = $user->getAttribute('last_stabile_id');
if (! is_numeric($candidate)) {
$candidate = DB::table('users')->where('id', (int) $user->id)->value('last_stabile_id');
}
return is_numeric($candidate) ? (int) $candidate : null;
}
/**
* @return Collection<int, Stabile>
*/
public static function accessibleStabili(User $user): Collection
{
// Super-admin / admin: tutto
if ($user->hasAnyRole(['super-admin', 'admin'])) {
return Stabile::query()->attivi()->orderBy('codice_stabile')->get();
}
$hasCollaboratorePivot = Schema::hasTable('collaboratore_stabile');
// Amministratore: per amministratore_id
if ($user->hasRole('amministratore') && $user->amministratore) {
$owned = Stabile::query()
->attivi()
->byAmministratore($user->amministratore->id)
->get();
// Supporta anche assegnazioni esplicite (stesso pivot dei collaboratori).
$assigned = $hasCollaboratorePivot
? $user->stabiliAssegnati()->where('stabili.attivo', true)->get()
: collect();
return $owned
->merge($assigned)
->unique('id')
->sortBy(fn(Stabile $s) => (string) $s->codice_stabile)
->values();
}
// Collaboratore: via pivot
if ($user->hasRole('collaboratore')) {
if (! $hasCollaboratorePivot) {
return collect();
}
return $user->stabiliAssegnati()->where('attivo', true)->orderBy('codice_stabile')->get();
}
if ($user->hasRole('fornitore')) {
$supplier = self::resolveSupplierForUser($user);
if (! $supplier instanceof Fornitore) {
return collect();
}
$stableIds = self::resolveSupplierAccessibleStableIds($user, $supplier);
if ($stableIds === []) {
return collect();
}
return Stabile::query()
->attivi()
->whereIn('id', $stableIds)
->orderBy('codice_stabile')
->get();
}
// Condomino / fornitore: per ora nessun accesso “stabili gestiti”
return collect();
}
/**
* @return array<int>
*/
private static function resolveSupplierAccessibleStableIds(User $user, Fornitore $supplier): array
{
$explicitStableIds = [];
try {
$explicitStableIds = array_merge($explicitStableIds, $user->stabiliAssegnati()
->pluck('stabili.id')
->map(fn($value): int => (int) $value)
->all());
} catch (\Throwable) {
// ignore collaborator-style explicit assignments for supplier users
}
if (Schema::hasTable('fornitore_stabile_impostazioni')) {
$explicitStableIds = array_merge($explicitStableIds, DB::table('fornitore_stabile_impostazioni')
->where('fornitore_id', (int) $supplier->id)
->pluck('stabile_id')
->map(fn($value): int => (int) $value)
->all());
}
$explicitStableIds = self::normalizeStableIds($explicitStableIds);
if ($explicitStableIds !== []) {
return $explicitStableIds;
}
$taxCodeMatchedIds = self::resolveSupplierStableIdsFromTaxCodes($supplier);
if ($taxCodeMatchedIds !== []) {
return $taxCodeMatchedIds;
}
$historicalStableIds = [];
foreach (['fatture_elettroniche', 'contabilita_fatture_fornitori'] as $table) {
if (! Schema::hasTable($table)) {
continue;
}
$historicalStableIds = array_merge($historicalStableIds, DB::table($table)
->where('fornitore_id', (int) $supplier->id)
->whereNotNull('stabile_id')
->pluck('stabile_id')
->map(fn($value): int => (int) $value)
->all());
}
return self::normalizeStableIds($historicalStableIds);
}
/**
* @return array<int>
*/
private static function resolveSupplierStableIdsFromTaxCodes(Fornitore $supplier): array
{
$taxCodes = collect([
trim((string) ($supplier->partita_iva ?? '')),
trim((string) ($supplier->codice_fiscale ?? '')),
])->filter()->unique()->values()->all();
if ($taxCodes === []) {
return [];
}
return self::normalizeStableIds(Stabile::query()
->attivi()
->where(function ($query) use ($taxCodes): void {
$query->whereIn('codice_fiscale', $taxCodes)
->orWhereIn('cod_fisc_amministratore', $taxCodes);
})
->pluck('id')
->map(fn($value): int => (int) $value)
->all());
}
/**
* @param array<int, mixed> $stableIds
* @return array<int>
*/
private static function normalizeStableIds(array $stableIds): array
{
return array_values(array_unique(array_filter(
array_map(static fn($value): int => (int) $value, $stableIds),
static fn(int $value): bool => $value > 0
)));
}
private static function resolvePreferredSupplierStabileId(User $user, array $allowedIds): ?int
{
if (! $user->hasRole('fornitore') || $allowedIds === []) {
return null;
}
$supplier = self::resolveSupplierForUser($user);
if (! $supplier instanceof Fornitore) {
return null;
}
$taxCodes = collect([
trim((string) ($supplier->partita_iva ?? '')),
trim((string) ($supplier->codice_fiscale ?? '')),
])->filter()->unique()->values()->all();
if ($taxCodes === []) {
return null;
}
return Stabile::query()
->attivi()
->whereIn('id', array_values(array_unique(array_map('intval', $allowedIds))))
->where(function ($query) use ($taxCodes): void {
$query->whereIn('codice_fiscale', $taxCodes)
->orWhereIn('cod_fisc_amministratore', $taxCodes);
})
->orderBy('codice_stabile')
->value('id');
}
private static function resolveSupplierForUser(User $user): ?Fornitore
{
$email = mb_strtolower(trim((string) $user->email));
if ($email !== '') {
$supplier = Fornitore::query()
->whereRaw('LOWER(email) = ?', [$email])
->orderByDesc('id')
->first();
if ($supplier instanceof Fornitore) {
return $supplier;
}
}
$dipendente = FornitoreDipendente::query()
->where('attivo', true)
->where(function ($query) use ($user, $email): void {
$query->where('user_id', (int) $user->id);
if ($email !== '') {
$query->orWhereRaw('LOWER(email) = ?', [$email]);
}
})
->orderByDesc('id')
->first();
if (! $dipendente instanceof FornitoreDipendente) {
return null;
}
return Fornitore::query()->find((int) $dipendente->fornitore_id);
}
public static function getActiveStabileId(?User $user = null): ?int
{
if ($user) {
return self::resolveActiveStabileId($user);
}
$sessionId = session(self::SESSION_KEY);
if (is_numeric($sessionId)) {
return (int) $sessionId;
}
$default = (int) config('netgescon.defaults.default_stabile_id', 0);
if ($default > 0) {
return $default;
}
if ($user) {
return self::accessibleStabili($user)->first()?->id;
}
return null;
}
public static function getActiveStabile(?User $user = null): ?Stabile
{
$id = self::getActiveStabileId($user);
if (! $id) {
return null;
}
if ($user) {
return self::accessibleStabili($user)->firstWhere('id', $id);
}
return Stabile::query()->find($id);
}
public static function setActiveStabileId(User $user, int $stabileId): bool
{
$allowed = self::accessibleStabili($user)->pluck('id')->map(fn($v) => (int) $v)->all();
if (! in_array($stabileId, $allowed, true)) {
return false;
}
session([self::SESSION_KEY => $stabileId]);
if (Schema::hasColumn('users', 'last_stabile_id')) {
try {
DB::table('users')->where('id', (int) $user->id)->update(['last_stabile_id' => $stabileId]);
} catch (\Throwable) {
// best-effort: non bloccare la sessione
}
}
return true;
}
}