📋 Commit iniziale con: - ✅ Documentazione unificata in docs/ - ✅ Codice Laravel in netgescon-laravel/ - ✅ Script automazione in scripts/ - ✅ Configurazione sync rsync - ✅ Struttura organizzata e pulita 🔄 Versione: 2025.07.19-1644 🎯 Sistema pronto per Git distribuito
30 KiB
30 KiB
NETGESCON - GESTIONE DOCUMENTALE E PROTOCOLLI
📋 OVERVIEW
Sistema completo per la gestione documentale dell'amministratore condominiale con protocolli digitali, stampa etichette, archiviazione intelligente e passaggio di consegne automatizzato.
📁 SISTEMA GESTIONE DOCUMENTALE AVANZATO
🗂️ Archivio Digitale Centralizzato
Struttura Gerarchica Documenti
STABILE [Codice Stabile] - [Denominazione]
├── 📋 AMMINISTRAZIONE
│ ├── Contratti Amministrazione
│ ├── Delibere Assembleari
│ ├── Verbali Assemblee
│ ├── Comunicazioni Condomini
│ └── Corrispondenza Ufficiale
├── 💰 CONTABILITÀ
│ ├── Bilanci (Preventivo/Consuntivo)
│ ├── Libri Contabili
│ ├── Fatture Passive
│ ├── Ricevute/Quietanze
│ └── Documenti Fiscali
├── 🏢 TECNICO/MANUTENZIONI
│ ├── Progetti e Capitolati
│ ├── Preventivi Lavori
│ ├── Contratti Manutenzione
│ ├── Certificazioni Impianti
│ └── Pratiche Edilizie
├── 👥 CONDOMINI
│ ├── Anagrafica Proprietari
│ ├── Contratti Locazione
│ ├── Comunicazioni Private
│ ├── Morosità/Solleciti
│ └── Documenti Personali
├── 🏠 UNITÀ IMMOBILIARI
│ ├── Atti di Compravendita
│ ├── Planimetrie/Visure
│ ├── Autorizzazioni Uso
│ ├── Contratti Utenze
│ └── Perizie/Valutazioni
└── ⚖️ LEGALE/CONTROVERSIE
├── Contenziosi Attivi
├── Contenziosi Passivi
├── Pareri Legali
├── Decreti Ingiuntivi
└── Transazioni
Database Struttura Documenti
CREATE TABLE documenti_archivio (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
stabile_id BIGINT NOT NULL,
-- Identificativi documento
numero_protocollo VARCHAR(20) UNIQUE NOT NULL, -- PR-2025-001
data_protocollo DATE NOT NULL,
-- Categorizzazione
categoria_principale ENUM('amministrazione', 'contabilita', 'tecnico', 'condomini', 'unita', 'legale'),
categoria_secondaria VARCHAR(50),
categoria_terziaria VARCHAR(50),
-- Metadati documento
titolo VARCHAR(200) NOT NULL,
descrizione TEXT,
parole_chiave TEXT, -- Separata da virgole per ricerca
-- Tipologia e formato
tipo_documento ENUM('contratto', 'fattura', 'delibera', 'verbale', 'comunicazione', 'certificato', 'altro'),
formato_originale ENUM('pdf', 'doc', 'docx', 'xls', 'xlsx', 'img', 'altro'),
-- Archiviazione fisica
ubicazione_fisica VARCHAR(100), -- "Faldone 2025-A, Pos. 15"
codice_etichetta VARCHAR(20), -- Riferimento etichetta stampata
stato_fisico ENUM('presente', 'prestito', 'mancante', 'digitalizzato'),
-- Archiviazione digitale
percorso_file VARCHAR(500),
hash_file VARCHAR(64), -- SHA256 per integrità
dimensione_file BIGINT,
-- OCR e indicizzazione
testo_estratto_ocr LONGTEXT,
stato_ocr ENUM('pending', 'completed', 'failed', 'not_needed'),
confidence_ocr DECIMAL(5,2), -- Affidabilità OCR 0-100%
-- Relazioni
persona_id BIGINT NULL, -- Se riferito a persona specifica
unita_immobiliare_id BIGINT NULL, -- Se riferito a unità specifica
fornitore_id BIGINT NULL, -- Se riferito a fornitore
-- Scadenze e follow-up
data_scadenza DATE NULL,
giorni_preavviso_scadenza INT DEFAULT 30,
richiede_rinnovo BOOLEAN DEFAULT FALSE,
-- Sicurezza e privacy
livello_riservatezza ENUM('pubblico', 'riservato', 'confidenziale', 'segreto'),
accesso_limitato_ruoli JSON, -- Array ruoli autorizzati
-- Audit
creato_da_user_id BIGINT NOT NULL,
modificato_da_user_id BIGINT,
data_creazione TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_modifica TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- Note e commenti
note_interne TEXT,
commenti_storia JSON, -- Cronologia commenti/modifiche
FOREIGN KEY (stabile_id) REFERENCES stabili(id),
FOREIGN KEY (persona_id) REFERENCES persone(id),
FOREIGN KEY (unita_immobiliare_id) REFERENCES unita_immobiliari(id),
FOREIGN KEY (creato_da_user_id) REFERENCES users(id),
INDEX idx_protocollo (numero_protocollo),
INDEX idx_categoria (categoria_principale, categoria_secondaria),
INDEX idx_scadenze (data_scadenza),
FULLTEXT idx_ricerca (titolo, descrizione, parole_chiave, testo_estratto_ocr)
);
📄 Sistema OCR e Indicizzazione Automatica
Estrazione Automatica Metadati
class DocumentOCRService {
/**
* Elaborazione automatica documento caricato
*/
public function processDocument($documentId) {
$documento = DocumentoArchivio::find($documentId);
$filePath = storage_path('app/' . $documento->percorso_file);
// 1. Estrazione testo OCR
$testoEstratto = $this->estraiTestoOCR($filePath);
// 2. Riconoscimento tipologia documento
$tipoDocumento = $this->riconosciTipoDocumento($testoEstratto);
// 3. Estrazione dati specifici
$datiEstratti = $this->estraiDatiSpecifici($testoEstratto, $tipoDocumento);
// 4. Categorizzazione automatica
$categoria = $this->categorizzaAutomaticamente($testoEstratto, $datiEstratti);
// 5. Generazione parole chiave
$paroleChiave = $this->generaParoleChiave($testoEstratto, $datiEstratti);
// 6. Aggiornamento database
$documento->update([
'testo_estratto_ocr' => $testoEstratto,
'tipo_documento' => $tipoDocumento,
'categoria_principale' => $categoria['principale'],
'categoria_secondaria' => $categoria['secondaria'],
'parole_chiave' => implode(', ', $paroleChiave),
'stato_ocr' => 'completed'
]);
return $datiEstratti;
}
/**
* Riconoscimento tipologia documento da contenuto
*/
private function riconosciTipoDocumento($testo) {
$patterns = [
'fattura' => [
'fattura', 'n\.', 'iva', 'imponibile', 'totale',
'partita iva', 'codice fiscale'
],
'contratto' => [
'contratto', 'sottoscritto', 'parti', 'condizioni',
'durata', 'corrispettivo'
],
'delibera' => [
'delibera', 'assemblea', 'condominio', 'votazione',
'favorevoli', 'contrari', 'astenuti'
],
'verbale' => [
'verbale', 'riunione', 'presenti', 'ordine del giorno',
'discussione', 'decisioni'
],
'certificato' => [
'certificato', 'attestato', 'conformità', 'norma',
'rilasciato', 'validità'
]
];
$scores = [];
foreach ($patterns as $tipo => $keywords) {
$score = 0;
foreach ($keywords as $keyword) {
if (preg_match('/' . preg_quote($keyword, '/') . '/i', $testo)) {
$score++;
}
}
$scores[$tipo] = $score;
}
return array_keys($scores, max($scores))[0] ?? 'altro';
}
/**
* Estrazione dati specifici per tipologia
*/
private function estraiDatiSpecifici($testo, $tipo) {
switch ($tipo) {
case 'fattura':
return $this->estraiFattura($testo);
case 'contratto':
return $this->estraiContratto($testo);
case 'delibera':
return $this->estraiDelibera($testo);
default:
return [];
}
}
private function estraiFattura($testo) {
$dati = [];
// Numero fattura
if (preg_match('/n\.?\s*(\d+\/?\d*)/i', $testo, $matches)) {
$dati['numero_fattura'] = $matches[1];
}
// Data fattura
if (preg_match('/(\d{1,2}\/\d{1,2}\/\d{4})/', $testo, $matches)) {
$dati['data_fattura'] = $matches[1];
}
// Importo totale
if (preg_match('/totale[\s:]*€?\s*(\d+[,.]?\d*)/i', $testo, $matches)) {
$dati['importo_totale'] = str_replace(',', '.', $matches[1]);
}
// Partita IVA fornitore
if (preg_match('/p\.?\s*iva[\s:]*(\d{11})/i', $testo, $matches)) {
$dati['partita_iva'] = $matches[1];
}
return $dati;
}
}
🏷️ Sistema Stampa Etichette Automatizzato
Generazione Etichette Faldoni
class EtichettaService {
/**
* Genera etichetta per faldone/cartella
*/
public function generaEtichettaFaldone($stabileId, $categoria, $anno, $progressivo) {
$stabile = Stabile::find($stabileId);
$codiceEtichetta = $this->generaCodiceEtichetta($stabile, $categoria, $anno, $progressivo);
$etichettaData = [
'codice' => $codiceEtichetta,
'stabile' => [
'codice' => $stabile->codice_stabile,
'denominazione' => $stabile->denominazione,
'indirizzo' => $stabile->indirizzo_completo
],
'categoria' => $categoria,
'anno' => $anno,
'progressivo' => $progressivo,
'data_creazione' => now()->format('d/m/Y'),
'qr_code' => $this->generaQRCodeEtichetta($codiceEtichetta)
];
return $this->stampaEtichetta($etichettaData);
}
/**
* Template etichetta per faldone (formato Dymo/Brother)
*/
private function stampaEtichetta($data) {
$html = view('labels.faldone', $data)->render();
// Conversione in formato stampa (PDF o diretta stampante)
$pdf = app('dompdf.wrapper');
$pdf->loadHTML($html);
$pdf->setPaper([0, 0, 283.46, 141.73], 'portrait'); // 100x50mm
return $pdf->stream("etichetta-{$data['codice']}.pdf");
}
/**
* Genera codice etichetta standardizzato
*/
private function generaCodiceEtichetta($stabile, $categoria, $anno, $progressivo) {
$prefissoStabile = strtoupper(substr($stabile->codice_stabile, 0, 3));
$prefissoCategoria = $this->getPrefissoCategoria($categoria);
return sprintf(
'%s-%s-%d-%03d',
$prefissoStabile,
$prefissoCategoria,
$anno,
$progressivo
);
}
private function getPrefissoCategoria($categoria) {
$prefissi = [
'amministrazione' => 'ADM',
'contabilita' => 'CNT',
'tecnico' => 'TEC',
'condomini' => 'CON',
'unita' => 'UNI',
'legale' => 'LEG'
];
return $prefissi[$categoria] ?? 'GEN';
}
}
Template Etichetta Blade
{{-- resources/views/labels/faldone.blade.php --}}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
@page { margin: 0; }
body {
margin: 0;
padding: 8px;
font-family: Arial, sans-serif;
font-size: 10px;
line-height: 1.2;
width: 84mm;
height: 42mm;
border: 1px solid #000;
box-sizing: border-box;
}
.header {
text-align: center;
font-weight: bold;
font-size: 11px;
margin-bottom: 4px;
border-bottom: 1px solid #000;
padding-bottom: 2px;
}
.codice {
font-size: 14px;
font-weight: bold;
text-align: center;
margin: 4px 0;
}
.stabile {
font-weight: bold;
margin-bottom: 2px;
}
.dettagli {
display: flex;
justify-content: space-between;
margin-top: 4px;
font-size: 9px;
}
.qr-code {
float: right;
margin-left: 8px;
}
</style>
</head>
<body>
<div class="header">NETGESCON - ARCHIVIO DOCUMENTALE</div>
<div class="codice">{{ $codice }}</div>
<div class="content">
<div class="qr-code">
{!! QrCode::size(30)->generate($qr_code) !!}
</div>
<div class="stabile">
{{ $stabile['denominazione'] }}
</div>
<div>{{ $stabile['indirizzo'] }}</div>
<div style="margin-top: 4px;">
<strong>{{ strtoupper($categoria) }}</strong> - Anno {{ $anno }}
</div>
</div>
<div class="dettagli">
<span>Prog. {{ str_pad($progressivo, 3, '0', STR_PAD_LEFT) }}</span>
<span>{{ $data_creazione }}</span>
</div>
</body>
</html>
🔄 Sistema Passaggio Consegne Automatizzato
Generazione Pacchetto Consegne
class PassaggioConsegneService {
/**
* Genera pacchetto completo per passaggio amministratore
*/
public function generaPacchettoConsegne($stabileId, $amministratoreUscente, $amministratoreEntrante) {
$stabile = Stabile::find($stabileId);
$dataPassaggio = now();
// 1. Crea cartella di export
$cartellaPacchetto = $this->creaCcartellaPacchetto($stabile, $dataPassaggio);
// 2. Genera HTML browser locale
$this->generaBrowserLocale($stabile, $cartellaPacchetto);
// 3. Esporta database archivio
$this->esportaDatabaseArchivio($stabile, $cartellaPacchetto);
// 4. Copia documenti digitali
$this->copiaDocumentiDigitali($stabile, $cartellaPacchetto);
// 5. Genera inventario cartaceo
$this->generaInventarioCartaceo($stabile, $cartellaPacchetto);
// 6. Crea indice generale
$this->creaIndiceGenerale($stabile, $cartellaPacchetto);
// 7. Genera ZIP finale
return $this->comprmiPacchetto($cartellaPacchetto);
}
/**
* Genera sito HTML locale per consultazione offline
*/
private function generaBrowserLocale($stabile, $cartellaBase) {
$datiCompleti = $this->raccogliDatiCompleti($stabile);
// Struttura HTML statica
$struttura = [
'index.html' => $this->generaPaginaPrincipale($stabile, $datiCompleti),
'anagrafica.html' => $this->generaPaginaAnagrafica($datiCompleti['persone']),
'unita.html' => $this->generaPaginaUnita($datiCompleti['unita']),
'documenti.html' => $this->generaPaginaDocumenti($datiCompleti['documenti']),
'contabilita.html' => $this->generaPaginaContabilita($datiCompleti['contabilita']),
'fornitori.html' => $this->generaPaginaFornitori($datiCompleti['fornitori']),
'assets/style.css' => $this->generaCSS(),
'assets/script.js' => $this->generaJavaScript(),
'assets/data.json' => json_encode($datiCompleti, JSON_PRETTY_PRINT)
];
foreach ($struttura as $file => $contenuto) {
$percorso = $cartellaBase . '/browser_locale/' . $file;
$this->scriviFile($percorso, $contenuto);
}
}
/**
* Inventario completo archivio cartaceo
*/
private function generaInventarioCartaceo($stabile, $cartellaBase) {
$documenti = DocumentoArchivio::where('stabile_id', $stabile->id)
->where('stato_fisico', '!=', 'digitalizzato')
->orderBy('ubicazione_fisica')
->get();
$inventario = [
'intestazione' => [
'stabile' => $stabile->denominazione,
'data_inventario' => now()->format('d/m/Y H:i'),
'totale_documenti' => $documenti->count()
],
'sezioni' => []
];
// Raggruppa per ubicazione fisica
$documentiPerUbicazione = $documenti->groupBy('ubicazione_fisica');
foreach ($documentiPerUbicazione as $ubicazione => $docsUbicazione) {
$inventario['sezioni'][] = [
'ubicazione' => $ubicazione,
'totale_documenti' => $docsUbicazione->count(),
'documenti' => $docsUbicazione->map(function($doc) {
return [
'protocollo' => $doc->numero_protocollo,
'data' => $doc->data_protocollo->format('d/m/Y'),
'titolo' => $doc->titolo,
'categoria' => $doc->categoria_principale,
'etichetta' => $doc->codice_etichetta
];
})->toArray()
];
}
// Genera PDF inventario
$pdf = app('dompdf.wrapper');
$html = view('reports.inventario_cartaceo', $inventario)->render();
$pdf->loadHTML($html);
$pathPdf = $cartellaBase . '/inventario_cartaceo.pdf';
file_put_contents($pathPdf, $pdf->output());
return $pathPdf;
}
/**
* Indice generale del pacchetto
*/
private function creaIndiceGenerale($stabile, $cartellaBase) {
$indice = [
'stabile' => $stabile,
'data_generazione' => now(),
'contenuto_pacchetto' => [
'browser_locale' => 'Consultazione offline di tutti i dati',
'database' => 'Export database completo (SQL + Excel)',
'documenti_digitali' => 'Copia di tutti i documenti digitali',
'inventario_cartaceo' => 'Elenco completo documenti fisici',
'etichette' => 'Template per ristampa etichette'
],
'istruzioni' => [
'Per consultare i dati offline aprire: browser_locale/index.html',
'I documenti digitali sono nella cartella: documenti/',
'Il database può essere importato in MySQL',
'L\'inventario cartaceo elenca tutti i faldoni fisici'
]
];
$readme = view('passaggio_consegne.readme', $indice)->render();
file_put_contents($cartellaBase . '/README.html', $readme);
}
}
🔍 Sistema Ricerca Avanzata
Motore di Ricerca Full-Text
class RicercaDocumentiService {
/**
* Ricerca avanzata con filtri multipli
*/
public function ricercaAvanzata($parametri) {
$query = DocumentoArchivio::query();
// Ricerca full-text
if (!empty($parametri['testo'])) {
$query->whereRaw(
'MATCH(titolo, descrizione, parole_chiave, testo_estratto_ocr) AGAINST(? IN NATURAL LANGUAGE MODE)',
[$parametri['testo']]
);
}
// Filtri categoria
if (!empty($parametri['categoria'])) {
$query->where('categoria_principale', $parametri['categoria']);
}
// Filtri data
if (!empty($parametri['data_da'])) {
$query->where('data_protocollo', '>=', $parametri['data_da']);
}
if (!empty($parametri['data_a'])) {
$query->where('data_protocollo', '<=', $parametri['data_a']);
}
// Filtri scadenze
if (!empty($parametri['solo_scadenti'])) {
$query->where('data_scadenza', '<=', now()->addDays(30));
}
// Filtro ubicazione fisica
if (!empty($parametri['ubicazione'])) {
$query->where('ubicazione_fisica', 'LIKE', '%' . $parametri['ubicazione'] . '%');
}
return $query->with(['stabile', 'persona', 'unitaImmobiliare'])
->orderBy('data_protocollo', 'desc')
->paginate(20);
}
/**
* Suggerimenti ricerca intelligenti
*/
public function suggerimentiRicerca($termineIncompleto, $stabileId = null) {
$suggerimenti = [];
// Suggerimenti da titoli documenti
$titoliSuggiriti = DocumentoArchivio::where('stabile_id', $stabileId)
->where('titolo', 'LIKE', '%' . $termineIncompleto . '%')
->limit(5)
->pluck('titolo')
->unique()
->values();
// Suggerimenti da parole chiave
$paroleSuggerite = DocumentoArchivio::where('stabile_id', $stabileId)
->where('parole_chiave', 'LIKE', '%' . $termineIncompleto . '%')
->limit(5)
->pluck('parole_chiave')
->map(function($parole) use ($termineIncompleto) {
return collect(explode(',', $parole))
->map('trim')
->filter(function($parola) use ($termineIncompleto) {
return stripos($parola, $termineIncompleto) !== false;
});
})
->flatten()
->unique()
->take(5);
return [
'titoli' => $titoliSuggiriti,
'parole_chiave' => $paroleSuggerite
];
}
}
4. GESTIONE PROTOCOLLI AVANZATA
4.1 Sistema di Protocollo Interno
- Numerazione Automatica Documenti
- Protocollo in entrata/uscita
- Numerazione progressiva annuale
- Classificazione per tipologia
- Gestione fascicoli tematici
4.2 Ricerca Avanzata Documenti
- Search Engine Interno
- Ricerca full-text nei contenuti
- Filtri per data, tipologia, mittente
- Tag personalizzabili
- Ricerca per contenuto OCR
4.3 OCR e Indicizzazione Automatica
// Implementazione OCR per documenti
class DocumentOCRService {
public function processDocument($filePath) {
// OCR del documento
$text = $this->extractTextFromPDF($filePath);
// Estrazione automatica metadati
$metadata = $this->extractMetadata($text);
// Salvataggio in database per ricerca
DocumentIndex::create([
'documento_id' => $documento->id,
'contenuto_ocr' => $text,
'keywords' => $metadata['keywords'],
'data_estrazione' => now()
]);
}
private function extractMetadata($text) {
$keywords = [];
// Estrazione date
preg_match_all('/\d{2}\/\d{2}\/\d{4}/', $text, $dates);
// Estrazione numeri di protocollo
preg_match_all('/prot\.?\s*n\.?\s*(\d+)/i', $text, $protocols);
// Estrazione importi
preg_match_all('/€\s*(\d+[.,]\d{2})/', $text, $amounts);
return [
'keywords' => $keywords,
'dates' => $dates[0],
'protocols' => $protocols[1],
'amounts' => $amounts[1]
];
}
}
5. PASSAGGIO CONSEGNE DIGITALE
5.1 Sistema di Handover
- Moduli di Consegna Digitali
- Checklist personalizzabili
- Foto prima/dopo
- Firme digitali
- Timestamp automatici
5.2 Inventario Digitale
- Tracking Beni Mobili
- Inventario attrezzature
- Stato di conservazione
- Storia manutenzioni
- Responsabilità di custodia
5.3 Knowledge Base
// Sistema knowledge base per handover
class HandoverKnowledgeBase {
public function createHandoverPackage($stabileId, $tipoConsegna) {
$package = [
'documenti_essenziali' => $this->getDocumentiEssenziali($stabileId),
'chiavi_e_accessi' => $this->getChiaviEAccessi($stabileId),
'contatti_emergenza' => $this->getContattiEmergenza($stabileId),
'procedure_operative' => $this->getProcedureOperative($tipoConsegna),
'checklist' => $this->getChecklistConsegna($tipoConsegna)
];
return $package;
}
public function generateHandoverReport($handoverId) {
$handover = Handover::with(['checklist', 'photos', 'signatures'])->find($handoverId);
return view('reports.handover', [
'handover' => $handover,
'completionRate' => $this->calculateCompletionRate($handover),
'criticalIssues' => $this->identifyCriticalIssues($handover)
]);
}
}
6. IMPORTAZIONE DATI DA ALTRI GESTIONALI
6.1 Connettori Multi-Sistema
- Supporto Formati Multipli
- Database Access (.mdb/.accdb)
- File Excel (.xls/.xlsx)
- Database MySQL/PostgreSQL
- File CSV delimitati
- XML strutturati
- JSON da API REST
6.2 Mapping Intelligente
// Sistema di mapping automatico campi
class DataImportMapper {
private $commonMappings = [
'nome' => ['nome', 'name', 'cognome_nome', 'denominazione'],
'codice_fiscale' => ['cf', 'cod_fiscale', 'codice_fiscale', 'fiscal_code'],
'indirizzo' => ['via', 'indirizzo', 'address', 'strada'],
'telefono' => ['tel', 'telefono', 'phone', 'cellulare']
];
public function autoMapFields($sourceColumns, $targetTable) {
$mapping = [];
foreach($this->commonMappings as $targetField => $variants) {
foreach($variants as $variant) {
if(in_array($variant, $sourceColumns)) {
$mapping[$targetField] = $variant;
break;
}
}
}
return $mapping;
}
public function validateAndTransform($data, $mapping, $validationRules) {
$transformedData = [];
foreach($data as $row) {
$transformedRow = [];
foreach($mapping as $targetField => $sourceField) {
$value = $row[$sourceField] ?? null;
// Applicazione regole di trasformazione
$transformedRow[$targetField] = $this->transformValue($value, $targetField);
}
// Validazione Laravel
$validator = Validator::make($transformedRow, $validationRules);
if($validator->passes()) {
$transformedData[] = $transformedRow;
} else {
// Log errori per revisione manuale
$this->logValidationError($transformedRow, $validator->errors());
}
}
return $transformedData;
}
}
6.3 Wizard di Importazione
- Interfaccia Step-by-Step
- Upload e preview file
- Mapping automatico/manuale campi
- Validazione e preview dati
- Importazione con progress bar
- Report errori e successi
6.4 Gestione Conflitti
// Gestione conflitti durante importazione
class ConflictResolver {
public function resolveConflicts($importData, $existingData) {
$conflicts = [];
$resolutions = [];
foreach($importData as $record) {
$existing = $this->findExistingRecord($record, $existingData);
if($existing) {
$conflicts[] = [
'type' => 'duplicate',
'import_record' => $record,
'existing_record' => $existing,
'suggested_action' => $this->suggestAction($record, $existing)
];
}
}
return $conflicts;
}
private function suggestAction($import, $existing) {
// Logica per suggerire azione basata su differenze
$differences = array_diff_assoc($import, $existing->toArray());
if(empty($differences)) {
return 'skip'; // Identici
} elseif(count($differences) < 3) {
return 'update'; // Poche differenze, aggiorna
} else {
return 'review'; // Molte differenze, revisione manuale
}
}
}
🎯 ROADMAP IMPLEMENTAZIONE
Fase 1: Archivio Base (2-3 settimane)
- ✅ Database schema documenti con OCR
- ✅ Upload e categorizzazione automatica
- ✅ Sistema protocolli numerazione automatica
- ✅ Ricerca full-text base
Fase 2: Stampa e Fisico (1-2 settimane)
- ✅ Generazione etichette Dymo/Brother
- ✅ Template etichette personalizzabili
- ✅ Tracciamento ubicazioni fisiche
- ✅ Inventario automatico
Fase 3: OCR e AI (2-3 settimane)
- ✅ OCR integrazione (Tesseract/Google Vision)
- ✅ Riconoscimento automatico tipologie documento
- ✅ Estrazione dati intelligente
- ✅ Suggerimenti ricerca AI
Fase 4: Passaggio Consegne (1-2 settimane)
- ✅ Browser HTML locale
- ✅ Export completo dati
- ✅ Pacchetti automatici
- ✅ Inventari digitali
Fase 5: Importazione (1-2 settimane)
- ✅ Importatori multi-sorgente
- ✅ Mapping configurabile
- ✅ Validazione dati automatica
- ✅ Report importazione
Questa gestione documentale completa l'ecosistema NetGesCon con strumenti professionali per l'amministratore, rendendo il passaggio da cartaceo a digitale fluido e mantenendo la tracciabilità completa di tutti i documenti.