public IList<MovimentoContabileBilancioDTO> GetDettaglioPartitario(IList<int> conti, IList<string> sottoconti, DateTime dataIniziale, DateTime dataFinale)
        {
            try
            {
                var result = new List<MovimentoContabileBilancioDTO>();

                if (conti.Count > 0 && dataIniziale > DateTime.MinValue && dataFinale > DateTime.MinValue)
                {
                    var contoRiferimento = _daoFactory.GetContoDao().Find(conti[0], false);
                    if (contoRiferimento != null)
                    {
                        var idCondominio = contoRiferimento.CondominioRiferimento.ID;

                        // ==================================================
                        //  Lettura Movimenti
                        // ==================================================
                        var dataInizialeSaldi = new DateTime(1900, 1, 1);
                        var esercizioUltimaChiusura = contoRiferimento.CondominioRiferimento.Esercizi.Where(item => item.DataApertura < dataIniziale && item.Gestione == GestioneEsercizioEnum.Ordinario && item.Stato == StatoEsercizioEnum.Chiuso).OrderByDescending(item => item.DataChiusura).FirstOrDefault();
                        if (esercizioUltimaChiusura != null)
                            dataInizialeSaldi = esercizioUltimaChiusura.DataChiusura.GetValueOrDefault().AddDays(1);
                        
                        var movimenti = _movimentoContabileService.GetMovimentiByContiData(idCondominio, dataInizialeSaldi, dataFinale, conti);
                        
                        // ==================================================
                        //  Saldi Iniziali 
                        // ==================================================
                        var saldi = getSaldiInizialiConti(dataIniziale, movimenti);

                        // ==================================================
                        //  Elaborazione Movimenti
                        // ==================================================
                        // -------------------------------------------
                        //  Raggruppo i movimenti per sottoconto
                        // -------------------------------------------
                        var movimentiRaggruppati = new Dictionary<string, IList<MovimentoContabile>>();
                        foreach (var movimento in movimenti.Where(item => item.Testata.DataRegistrazione.GetValueOrDefault() >= dataIniziale).OrderBy(item => item.Testata.DataRegistrazione).ThenBy(item => item.NumeroRegistrazione))
                        {
                            try
                            {
                                IList<MovimentoContabile> movimentiPerSottoconto;
                                var key = _movimentoContabileService.GetKeyContoSottoconto(movimento);
                                if (movimentiRaggruppati.ContainsKey(key))
                                    movimentiPerSottoconto = movimentiRaggruppati[key];
                                else
                                {
                                    movimentiPerSottoconto = new List<MovimentoContabile>();
                                    movimentiRaggruppati.Add(key, movimentiPerSottoconto);
                                }

                                movimentiPerSottoconto.Add(movimento);
                            }
                            catch (Exception ex)
                            {
                                _log.ErrorFormat("Errore inaspettato nella lettura del dettaglio del partitario - LETTURA PER RAGGRUPPAMENTO - {0} - movimento:{1}", ex, Utility.GetMethodDescription(), movimento.ID);
                                throw;
                            }
                        }

                        // -------------------------------------------
                        //  Raggruppo i movimenti per sottoconto
                        // -------------------------------------------
                        var saldiUtilizzati = new List<SaldoContoDTO>(saldi.Count);
                        foreach (var movimentiPerSottoconto in movimentiRaggruppati)
                        {
                            try
                            {
                                var keyContoSottoconto = movimentiPerSottoconto.Key.Split('&');
                                var idConto = int.Parse(keyContoSottoconto[0]);
                                var idSottoconto = int.Parse(keyContoSottoconto[1]);
                                var movimentoSaldo = movimentiPerSottoconto.Value[0];
                                MovimentoContabileBilancioDTO dtoSaldo = null;

                                decimal progressivo = 0;
                                if (dataIniziale != null)
                                {
                                    // Calcolo il saldo del sottoconto precedente
                                    var saldiDaUsare = saldi.Where(item => item.IdConto == idConto && item.IdSottoConto == idSottoconto).ToList();
                                    progressivo = saldiDaUsare.Sum(item => item.ImportoDare + item.ImportoAvere);
                                    saldiUtilizzati.AddRange(saldiDaUsare);

                                    dtoSaldo = new MovimentoContabileBilancioDTO
                                    {
                                        IdConto = movimentoSaldo.ContoRiferimento.ID,
                                        Conto = movimentoSaldo.ContoRiferimento.Descrizione,
                                        Esercizio = movimentoSaldo.Testata.EsercizioRiferimento.DisplayName,
                                        Condominio = movimentoSaldo.Testata.EsercizioRiferimento.CondominioRiferimento.Descrizione,
                                        Data = dataIniziale,
                                        ID = movimentoSaldo.ID,
                                        CodiceConto = movimentoSaldo.ContoRiferimento.Codice,
                                        OrdineConto = movimentoSaldo.ContoRiferimento.Ordine,
                                        Descrizione = "Saldo Iniziale",
                                        TipoConto = movimentoSaldo.ContoRiferimento.Tipo.ToString(),
                                        IdEsercizio = movimentoSaldo.Testata.EsercizioRiferimento.ID,
                                        IdAnnoGestionale =  movimentoSaldo.Testata.EsercizioRiferimento.AnnoGestionale?.ID ?? 0,
                                        Ordine = 0,
                                        Saldo = progressivo
                                    };

                                    if (progressivo > 0)
                                        dtoSaldo.ImportoDare = progressivo;
                                    else
                                        dtoSaldo.ImportoAvere = progressivo;

                                    result.Add(dtoSaldo);
                                }

                                foreach (var movimentoSottoconto in movimentiPerSottoconto.Value)
                                {
                                    try
                                    {
                                        var dto = new MovimentoContabileBilancioDTO
                                        {
                                            IdConto = movimentoSottoconto.ContoRiferimento.ID,
                                            Conto = movimentoSottoconto.ContoRiferimento.Descrizione,
                                            OrdineConto = movimentoSottoconto.ContoRiferimento.Ordine,
                                            NumeroRiga = movimentoSottoconto.NumeroRiga,
                                            NumeroRegistrazione = movimentoSottoconto.NumeroRegistrazione,
                                            Esercizio = movimentoSottoconto.Testata.EsercizioRiferimento.DisplayName,
                                            Condominio = movimentoSottoconto.Testata.EsercizioRiferimento.CondominioRiferimento.Descrizione,
                                            Note = movimentoSottoconto.Note,
                                            Data = movimentoSottoconto.Testata.DataRegistrazione.GetValueOrDefault(),
                                            ID = movimentoSottoconto.ID,
                                            CodiceConto = movimentoSottoconto.ContoRiferimento.Codice,
                                            Descrizione = movimentoSottoconto.GetDescrizione(),
                                            TipoConto = movimentoSottoconto.ContoRiferimento.Tipo.ToString(),
                                            IdEsercizio = movimentoSottoconto.Testata.EsercizioRiferimento.ID,
                                            IdAnnoGestionale =  movimentoSottoconto.Testata.EsercizioRiferimento.AnnoGestionale?.ID ?? 0
                                        };

                                        if (string.IsNullOrEmpty(dto.Descrizione))
                                            dto.Descrizione = movimentoSottoconto.Testata.Descrizione;
                                        if (string.IsNullOrEmpty(dto.Descrizione) &&
                                            movimentoSottoconto.SottoContoRiferimento != null)
                                            dto.Descrizione = movimentoSottoconto.SottoContoRiferimento.GetDescrizione(movimentoSottoconto.Testata.EsercizioRiferimento, null, movimentoSottoconto);

                                        if ((movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoBancario() ||
                                             movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoCassa() ||
                                             movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoAmministratoreAnticipi() ||
                                             movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoFornitoriAnticipi()) && movimentoSottoconto.FornitoreRiferimento != null)
                                            dto.Descrizione += " - " + movimentoSottoconto.FornitoreRiferimento.DisplayName;

                                        // ----------------------------------
                                        // Ordinamento
                                        // ----------------------------------
                                        switch (movimentoSottoconto.Causale.Codice)
                                        {
                                            case "AC":
                                            case "AB":
                                                dto.Ordine = 1;
                                                break;
                                            case "C1":
                                            case "OC":
                                                dto.Ordine = 3;
                                                break;
                                            default:
                                                dto.Ordine = 2;
                                                break;
                                        }

                                        // ----------------------------------
                                        // Sottoconto
                                        // ----------------------------------
                                        // Fornitore
                                        if (movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoFornitori())
                                        {
                                            if (movimentoSottoconto.FornitoreRiferimento != null)
                                            {
                                                dto.IdSottoConto = movimentoSottoconto.FornitoreRiferimento.ID;
                                                dto.SottoConto = movimentoSottoconto.FornitoreRiferimento.DisplayName;
                                            }
                                            else
                                            {
                                                dto.SottoConto = dto.Conto;
                                                dto.CodiceSottoConto = dto.CodiceConto + ".000";
                                            }
                                        }

                                        // Banca
                                        else if (movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoBancario())
                                        {
                                            var contoCorrente = movimentoSottoconto.ContoCorrenteBancario ??
                                                                movimentoSottoconto.Testata.EsercizioRiferimento.
                                                                    CondominioRiferimento.DatiBancariPrincipale;
                                            if (contoCorrente != null)
                                            {
                                                dto.IdSottoConto = contoCorrente.ID;
                                                dto.SottoConto = contoCorrente.DisplayName;
                                            }
                                        }

                                        // Condomini
                                        else if (movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoVersamentiCondomini() || movimentoSottoconto.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoRateCondomini())
                                        {
                                            if (movimentoSottoconto.CondominoRiferimento != null)
                                            {
                                                dto.IdSottoConto = movimentoSottoconto.CondominoRiferimento.ID;
                                                dto.SottoConto = movimentoSottoconto.CondominoRiferimento.DisplayName;
                                            }
                                            else
                                            {
                                                dto.SottoConto = dto.Conto;
                                                dto.CodiceSottoConto = dto.CodiceConto + ".000";
                                            }
                                        }

                                        // Altri
                                        else if (movimentoSottoconto.SottoContoRiferimento != null)
                                        {
                                            dto.IdSottoConto = movimentoSottoconto.SottoContoRiferimento.ID;
                                            dto.SottoConto = movimentoSottoconto.SottoContoRiferimento.GetDescrizione(movimentoSottoconto.Testata.EsercizioRiferimento, null, movimentoSottoconto);
                                            dto.CodiceSottoConto = movimentoSottoconto.SottoContoRiferimento.Codice;
                                        }

                                        // Sottoconto NON definito
                                        else
                                        {
                                            dto.SottoConto = dto.Conto;
                                            dto.CodiceSottoConto = dto.CodiceConto + ".000";
                                        }

                                        if (string.IsNullOrEmpty(dto.CodiceSottoConto))
                                            dto.CodiceSottoConto = $"{dto.CodiceConto}.{dto.IdSottoConto.GetValueOrDefault().ToString(CultureInfo.InvariantCulture).PadLeft(7, '0')}";

                                        // ----------------------------------
                                        // Identificativo Archiviazione
                                        // ----------------------------------
                                        if (movimentoSottoconto.DettaglioRiferimento != null)
                                            dto.IdentificativoArchiviazioneOttica = _archiviazioneOtticaService.GetIdentificativoArchiviazione(movimentoSottoconto.DettaglioRiferimento.SpesaRiferimento, true);
                                        else if (movimentoSottoconto.Testata.NumeroProtocollo > 0)
                                            dto.IdentificativoArchiviazioneOttica = _archiviazioneOtticaService.GetIdentificativoArchiviazione(movimentoSottoconto.Testata);

                                        // ----------------------------------
                                        // Importi
                                        // ----------------------------------
                                        if (movimentoSottoconto.Segno == "D")
                                            dto.ImportoDare = movimentoSottoconto.GetImportoSenzaSegno();
                                        else
                                            dto.ImportoAvere = movimentoSottoconto.GetImportoSenzaSegno()*-1;

                                        progressivo += dto.ImportoDare.GetValueOrDefault() +
                                                       dto.ImportoAvere.GetValueOrDefault();
                                        dto.Saldo = progressivo;

                                        if (dtoSaldo != null)
                                        {
                                            dtoSaldo.CodiceSottoConto = dto.CodiceSottoConto;
                                            dtoSaldo.IdSottoConto = dto.IdSottoConto;
                                            dtoSaldo.SottoConto = dto.SottoConto;
                                        }

                                        result.Add(dto);
                                    }
                                    catch (Exception ex)
                                    {
                                        _log.ErrorFormat("Errore inaspettato nella lettura del dettaglio del partitario - SINGOLO MOVIMENTO - {0} - sottoconto:{1} - conto:{1} - movimento:{2}", ex, Utility.GetMethodDescription(), idSottoconto, idConto, movimentoSottoconto.ID);
                                        throw;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                _log.ErrorFormat("Errore inaspettato nella lettura del dettaglio del partitario - RAGGRUPPAMENTO PER SOTTOCONTO - {0} - KEY:{1}", ex, Utility.GetMethodDescription(), movimentiPerSottoconto.Key);
                                throw;
                            }
                        }

                        // ==================================================
                        // Aggiungo i saldi non utilizzati
                        // ==================================================
                        var saldiNonUtilizzati = saldi.Except(saldiUtilizzati);
                        foreach (var saldoContoDTO in saldiNonUtilizzati)
                        {
                            var conto = _daoFactory.GetContoDao().GetById(saldoContoDTO.IdConto, false);
                            var dtoSaldo = new MovimentoContabileBilancioDTO
                            {
                                IdConto = conto.ID,
                                Conto = conto.Descrizione,
                                Esercizio = esercizioUltimaChiusura != null ? esercizioUltimaChiusura.DisplayName : string.Empty,
                                Condominio = contoRiferimento.CondominioRiferimento.Descrizione,
                                Data = dataIniziale,
                                ID = 0,
                                CodiceConto = conto.Codice,
                                OrdineConto = conto.Ordine,
                                Descrizione = "Saldo Iniziale",
                                TipoConto = conto.Tipo.ToString(),
                                IdEsercizio = esercizioUltimaChiusura?.ID ?? 0,
                                IdAnnoGestionale = esercizioUltimaChiusura?.AnnoGestionale.ID ?? 0,
                                Ordine = 0,
                                Saldo = saldoContoDTO.Saldo,
                                ImportoDare = saldoContoDTO.Saldo > 0 ? saldoContoDTO.Saldo : 0m,
                                ImportoAvere = saldoContoDTO.Saldo < 0 ? saldoContoDTO.Saldo : 0m
                            };
                            
                            // ----------------------------------
                            // Sottoconto
                            // ----------------------------------
                            // Fornitore
                            if (conto.Codice == _pianoContiService.GetCodiceContoFornitori())
                            {
                                var fornitore = _daoFactory.GetFornitoreDao().Find(saldoContoDTO.IdSottoConto, false);
                                if (fornitore != null)
                                {
                                    dtoSaldo.IdSottoConto = fornitore.ID;
                                    dtoSaldo.SottoConto = fornitore.DisplayName;
                                }
                            }

                            // Banca
                            else if (conto.Codice == _pianoContiService.GetCodiceContoBancario())
                            {
                                var contoCorrente = _daoFactory.GetDatiBancariCondominiDao().Find(saldoContoDTO.IdSottoConto, false);
                                if (contoCorrente != null)
                                {
                                    dtoSaldo.IdSottoConto = contoCorrente.ID;
                                    dtoSaldo.SottoConto = contoCorrente.DisplayName;
                                }
                            }
                                        
                            // Condomini
                            else if (conto.Codice == _pianoContiService.GetCodiceContoVersamentiCondomini())
                            {
                                var condomino = _daoFactory.GetSoggettoCondominioDao().Find(saldoContoDTO.IdSottoConto, false);
                                if (condomino != null)
                                {
                                    dtoSaldo.IdSottoConto = condomino.ID;
                                    dtoSaldo.SottoConto = condomino.DisplayName;
                                }
                            }

                            // Altri
                            else if (saldoContoDTO.IdSottoConto > 0)
                            {
                                var sottoconto = _daoFactory.GetSottoContoDao().Find(saldoContoDTO.IdSottoConto, false);
                                if (sottoconto != null)
                                {
                                    dtoSaldo.IdSottoConto = sottoconto.ID;
                                    dtoSaldo.SottoConto = sottoconto.Descrizione;
                                    dtoSaldo.CodiceSottoConto = sottoconto.Codice;
                                }
                                else
                                {
                                    _log.WarnFormat("Non trovato sottoconto - {0} - conto:{1} - sottoconto:{2}", Utility.GetMethodDescription(), conto.ID, saldoContoDTO.IdSottoConto);
                                }
                            }
    
                            // Sottoconto NON definito
                            else
                            {
                                dtoSaldo.SottoConto = conto.Descrizione;
                                dtoSaldo.CodiceSottoConto = conto.Codice + ".000";
                            }

                            if (string.IsNullOrEmpty(dtoSaldo.CodiceSottoConto))
                                dtoSaldo.CodiceSottoConto = dtoSaldo.CodiceConto + "." + dtoSaldo.IdSottoConto.GetValueOrDefault().ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');

                            result.Add(dtoSaldo);
                        }
                    }

                    // ==================================================
                    // Escludo i sottoconti non selezionati
                    // ==================================================
                    if (sottoconti != null && sottoconti.Count > 0)
                    {
                        var movimenti = new List<MovimentoContabileBilancioDTO>(result.Count);
                        foreach (var idConto in conti)
                        {
                            var conto = _daoFactory.GetContoDao().Find(idConto, false);
                            if (conto != null)
                            {
                                var sottocontiConto = sottoconti.Where(item => item.Contains($"{conto.Codice}.")).ToList();
                                movimenti.AddRange(!sottocontiConto.Any()
                                    ? result.Where(item => item.IdConto == idConto)
                                    : result.Where(item => item.IdConto == idConto && sottocontiConto.Any(sott => sott == item.CodiceSottoConto)).ToList());
                            }
                            else
                            {
                                _log.ErrorFormat("Non trovato conto - {0} - idConto:{1} - azienda:{2}", Utility.GetMethodDescription(), idConto, contoRiferimento.CondominioRiferimento.Azienda.ID);
                            }
                        }

                        result = movimenti;
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                var contiStr = conti.Aggregate(string.Empty, (current, i) => current + (i.ToString(CultureInfo.InvariantCulture) + ", "));
                _log.ErrorFormat("Errore inaspettato nella lettura del dettaglio del partitario - {0} - conti:{1} - dataIniziale:{2} - dataFinale:{3}", ex, Utility.GetMethodDescription(), contiStr, dataIniziale.ToShortDateString(), dataFinale.ToShortDateString());
                throw;
            }
        }
        public object Clone()
        {
            var movimento = new MovimentoContabileBilancioDTO
            {
                ID = ID,
                Data = Data,
                NumeroRiga = NumeroRiga,
                TipoConto = TipoConto,
                IdSpesa = IdSpesa,
                NumeroRegistrazione = NumeroRegistrazione,
                IdentificativoArchiviazioneOttica = IdentificativoArchiviazioneOttica,
                ImportoDare = ImportoDare,
                ImportoAvere = ImportoAvere,
                Saldo = Saldo,
                Descrizione = Descrizione,
                Note = Note,
                IdConto = IdConto,
                Conto = Conto,
                CodiceConto = CodiceConto,
                OrdineConto = OrdineConto,
                IdSottoConto = IdSottoConto,
                SottoConto = SottoConto,
                CodiceSottoConto = CodiceSottoConto,
                Condominio = Condominio,
                IdEsercizio = IdEsercizio,
                Esercizio = Esercizio,
                IdAnnoGestionale = IdAnnoGestionale,
                IdTestata = IdTestata,
                Ordine = Ordine
            };

            return movimento;
        }