public IList<StatoPatrimomialeDTO> GetSituazionePatrimoniale(int idEsercizio, DateTime? dataRiferimento)
        {
            try
            {
                var result = new List<StatoPatrimomialeDTO>();
                var listaDare = new Dictionary<string, EntrateUsciteDTO>();
                var listaAvere = new Dictionary<string, EntrateUsciteDTO>();

                var esercizio = _daoFactory.GetEsercizioDao().GetById(idEsercizio, false);
                if (dataRiferimento == null)
                    dataRiferimento = esercizio.DataChiusura;
                
                // ==================================================
                //  Altri conti Patrimoniali
                // ==================================================
                var foundDare = false;
                var foundAvere = false;
                var listaPatrimoniale = new Dictionary<string, EntrateUsciteDTO>();
                var contiPatrimoniali = _pianoContiService.GetConti(esercizio, "SituazionePatrimoniale");
                var idContiPatrimoniali = new List<int>(contiPatrimoniali.Count);
                idContiPatrimoniali.AddRange(contiPatrimoniali.Select(conto => conto.ID));
                var movimentiPatrimoniali = _movimentoContabileService.GetMovimentiByContiData(esercizio.CondominioRiferimento.ID, esercizio.DataApertura.GetValueOrDefault(), dataRiferimento.GetValueOrDefault(), idContiPatrimoniali);

                foreach (var movimento in movimentiPatrimoniali.OrderBy(item => item.Causale.Ordine))
                {
                    try
                    {
                        if (movimento.Causale.Codice != "OC")
                        {
                            var key = getKeyPatrimoniale(movimento);
                            EntrateUsciteDTO item;
                            if (listaPatrimoniale.Keys.Contains(key))
                                item = listaPatrimoniale[key];
                            else
                            {
                                item = new EntrateUsciteDTO
                                {
                                    CodiceConto = movimento.ContoRiferimento.Codice,
                                    DescrizioneConto = movimento.ContoRiferimento.Descrizione,
                                    IdConto = movimento.ContoRiferimento.ID,
                                    OrdineConto = movimento.ContoRiferimento.Ordine
                                };

                                if (movimento.SottoContoRiferimento != null)
                                {
                                    item.IdSottoConto = movimento.SottoContoRiferimento.ID;

                                    // Evitare per ora di differenziare gli importi per sottoconto bugid#6524
                                    //item.DescrizioneSottoConto = movimento.SottoContoRiferimento.GetDescrizione(movimento.Testata.EsercizioRiferimento, null, movimento);
                                }

                                if (movimento.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoBancario() || movimento.ContoRiferimento.Codice == _pianoContiService.GetCodiceContoCassa())
                                    item.Descrizione = item.DescrizioneConto;
                                else
                                    item.Descrizione = !string.IsNullOrEmpty(item.DescrizioneSottoConto) ? item.DescrizioneSottoConto : item.DescrizioneConto;

                                if (movimento.Causale.Codice == "AC" || movimento.Causale.Codice == "AB")
                                {
                                    // Per ora evito di stampare la dicitura "Saldo Iniziale"
                                    //item.Descrizione = "Saldo Iniziale - " + item.Descrizione;
                                    item.OrdineConto = -1;
                                }

                                listaPatrimoniale.Add(key, item);
                            }

                            var importo = movimento.GetImportoConSegno(false, true).GetValueOrDefault();
                            item.Importo += importo;
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nell'elaborazione di un singolo movimento contabile patrimoniale per la redazione della situazione patrimoniale - {0} - movimento:{1}", ex, Utility.GetMethodDescription(), movimento.ID.ToString(CultureInfo.InvariantCulture));
                        throw;
                    }
                }

                foreach (var kvp in listaPatrimoniale)
                {
                    if (kvp.Value.Importo > 0)
                    {
                        foundAvere = true;
                        listaAvere.Add(kvp.Key, kvp.Value);
                    }
                    else if (kvp.Value.Importo < 0)
                    {
                        foundDare = true;
                        kvp.Value.Importo = kvp.Value.Importo * -1;
                        listaDare.Add(kvp.Key, kvp.Value);
                    }
                }

                var listaDareOrdered = new Dictionary<string, EntrateUsciteDTO>(listaDare.Count);
                foreach (var kvp in listaDare.OrderBy(item => item.Value.OrdineConto))
                    listaDareOrdered.Add(kvp.Key, kvp.Value);

                var listaAvereOrdered = new Dictionary<string, EntrateUsciteDTO>(listaAvere.Count);
                foreach (var kvp in listaAvere.OrderBy(item => item.Value.OrdineConto))
                    listaAvereOrdered.Add(kvp.Key, kvp.Value);

                if (foundDare)
                listaDareOrdered.Add("SEP", new EntrateUsciteDTO());
                if (foundAvere)
                listaAvereOrdered.Add("SEP", new EntrateUsciteDTO());

                // ==================================================
                //  Esercizio aperto devo calcolare il risultato economico degli straordinari
                // ==================================================
                var importoEconomicoStraordinario = 0m;
                IList<MovimentoContabile> movimentiEconomiciStraordinario = new List<MovimentoContabile>();
                if (esercizio.Stato == StatoEsercizioEnum.Aperto)
                {
                    var eserciziStraordinari = _daoFactory.GetEsercizioDao().GetApertiByCondominio(esercizio.CondominioRiferimento.ID).Where(item => item.Gestione == GestioneEsercizioEnum.Straordinario).ToList();
                    foreach (var esercizioStraordinario in eserciziStraordinari)
                    {
                        var movimentiEconomiciSingoloStaordinario = _daoFactory.GetMovimentoContabileDao().GetByEsercizioEconomici(esercizioStraordinario, esercizio.DataApertura, dataRiferimento);
                        foreach (var movimentoContabile in movimentiEconomiciSingoloStaordinario)
                            movimentiEconomiciStraordinario.Add(movimentoContabile);
                        importoEconomicoStraordinario += movimentiEconomiciSingoloStaordinario.Sum(item => item.GetImportoConSegno(false, true)).GetValueOrDefault();
                    }
                }

                // ==================================================
                //  Crediti e Debiti v/condomini
                // ==================================================

                // -------------------------------------------------------------------
                //  Risultato di esercizio - Crediti v/condomini
                // -------------------------------------------------------------------
                var contiEconomici = _daoFactory.GetContoDao().GetContiEconomiciByCondominio(esercizio.CondominioRiferimento.ID);
                var idConti = new List<int>(contiEconomici.Count);
                idConti.AddRange(contiEconomici.Select(conto => conto.ID));

                var movimentiEconomici = _movimentoContabileService.GetMovimentiByContiData(esercizio.CondominioRiferimento.ID, esercizio.DataApertura.GetValueOrDefault(), dataRiferimento.GetValueOrDefault(), idConti);
                var importoEconomicoOrdinario = movimentiEconomici.Sum(item => item.GetImportoConSegno(false, true).GetValueOrDefault());
                var risultatoEconomico = importoEconomicoOrdinario - importoEconomicoStraordinario;

                // -------------------------------------------------------------------
                //  Debiti v/condomini (Quanto hanno effettivamente versato)
                // -------------------------------------------------------------------
                foundDare = false;
                foundAvere = false;
                var saldiCondomini = new Dictionary<int, EntrateUsciteDTO>();
                var contiCondomini = _daoFactory.GetContoDao().GetAllByCodice(esercizio.CondominioRiferimento.ID, _pianoContiService.GetCodiceContoVersamentiCondomini());
                var contoRateEmesse = _daoFactory.GetContoDao().GetByCodice(esercizio.ID, esercizio.CondominioRiferimento.ID, _pianoContiService.GetCodiceContoRateCondomini());

                if (contoRateEmesse == null)
                {
                    _log.FatalFormat("Non trovato conto rate emesse - {0} - esercizio:{1} - condominio:{2} - azienda:{3}", Utility.GetMethodDescription(), esercizio.ID, esercizio.CondominioRiferimento.ID, esercizio.CondominioRiferimento.Azienda.ID);
                    return new List<StatoPatrimomialeDTO>();
                }

                var idContiCondomini = new List<int>();
                idContiCondomini.AddRange(contiCondomini.Select(conto => conto.ID));
                idContiCondomini.Add(contoRateEmesse.ID);

                var movimentiCondomini = _movimentoContabileService.GetMovimentiByContiData(esercizio.CondominioRiferimento.ID, esercizio.DataApertura.GetValueOrDefault(), dataRiferimento.GetValueOrDefault(), idContiCondomini);

                // Elaboro i movimenti per esercizio per distinguere quelli dell'ordinario da quelli dello straordinario
                var movimentiPerEsercizio = movimentiCondomini.GroupBy(item => item.GetEsercizioRiferimento()).ToList();

                // Non è possibile che nell'intervallo di date esista più di un esercizio ordinario
                var numeroEserciziOrdinari = movimentiPerEsercizio.Count(item => item.Key.Gestione == GestioneEsercizioEnum.Ordinario);
                if (numeroEserciziOrdinari > 1)
                {
                    var esercizioErrato = movimentiPerEsercizio.FirstOrDefault(item => item.Key.ID != esercizio.ID).Key;
                    _log.ErrorFormat("Trovato più di un esercizio ordinario - {0} - esercizio:{1} - dataRiferimento:{2} - azienda:{3}", Utility.GetMethodDescription(), idEsercizio, dataRiferimento, esercizio.CondominioRiferimento.Azienda.ID);
                    throw new InvalidDataException($"Trovati dei movimenti contabili con data di registrazione esterna all'esercizio.{Environment.NewLine}Modificare la data di registrazione dei movimenti non presenti nell'intervallo di date: {esercizioErrato.DataApertura.GetValueOrDefault():d} - {esercizioErrato.DataChiusura.GetValueOrDefault():d}");
                }
                
                if (numeroEserciziOrdinari == 0 && risultatoEconomico != 0)
                {
                    var saldo = -risultatoEconomico;
                    saldiCondomini.Add(esercizio.ID,
                        saldo < 0
                            ? new EntrateUsciteDTO
                            {
                                Descrizione = $"Crediti v/condomini - esercizio:{esercizio.DisplayName}",
                                Importo = saldo,
                                OrdineConto = 800
                            }
                            : new EntrateUsciteDTO
                            {
                                Descrizione = $"Debiti v/condomini - esercizio:{esercizio.DisplayName}",
                                Importo = saldo,
                                OrdineConto = 800
                            });
                }

                foreach (var movimentoEsercizio in movimentiPerEsercizio.ToList())
                {
                    var saldo = (from item in movimentoEsercizio
                                 where item.Causale.Codice != "OC" && (dataRiferimento == null || item.Testata.DataRegistrazione <= dataRiferimento.GetValueOrDefault())
                                 select item).Sum(item => item.GetImportoConSegno(false, true).GetValueOrDefault());

                    // Solo per i movimenti dell'ordinario considero il risultato della situazione economica
                    if (movimentoEsercizio.Key.Gestione == GestioneEsercizioEnum.Ordinario)
                        saldo -= risultatoEconomico;

                    saldiCondomini.Add(movimentoEsercizio.Key.ID,
                        saldo < 0
                            ? new EntrateUsciteDTO
                            {
                                Descrizione = $"Crediti v/condomini - esercizio:{movimentoEsercizio.Key.DisplayName}",
                                Importo = saldo,
                                OrdineConto = 800
                            }
                            : new EntrateUsciteDTO
                            {
                                Descrizione = $"Debiti v/condomini - esercizio:{movimentoEsercizio.Key.DisplayName}",
                                Importo = saldo,
                                OrdineConto = 800
                            });
                }
                
                var firstDare = true;
                var firstAvere = true;
                decimal debitiVsCondomini = 0;
                decimal creditiVsCondomini = 0;
                var itemTotaleCondominiAvere = new EntrateUsciteDTO { Descrizione = "Debiti Vs/Condomini", OrdineConto = 999 };
                var itemTotaleCondominiDare = new EntrateUsciteDTO { Descrizione = "Crediti Vs/Condomini", OrdineConto = 999 };
                foreach (var kvp in saldiCondomini)
                {
                    if (kvp.Value.Importo > 0)
                    {
                        foundAvere = true;
                        if (firstAvere)
                        {
                            listaAvereOrdered.Add("DEBCOND", itemTotaleCondominiAvere);
                            firstAvere = false;
                        }
                        listaAvereOrdered.Add("DEBCOND&" + kvp.Key, kvp.Value);
                        debitiVsCondomini += kvp.Value.Importo;
                    }
                    else if (kvp.Value.Importo < 0)
                    {
                        foundDare = true;
                        if (firstDare)
                        {
                            listaDareOrdered.Add("CREDCOND", itemTotaleCondominiDare);
                            firstDare = false;
                        }
                        kvp.Value.Importo = kvp.Value.Importo * -1;
                        listaDareOrdered.Add("CREDCOND&" + kvp.Key, kvp.Value);
                        creditiVsCondomini += kvp.Value.Importo;
                    }
                }

                itemTotaleCondominiAvere.Importo = debitiVsCondomini;
                itemTotaleCondominiDare.Importo = creditiVsCondomini;

                if (foundDare)
                    listaDareOrdered.Add("SEPCOND", new EntrateUsciteDTO());
                if(foundAvere)
                    listaAvereOrdered.Add("SEPCOND", new EntrateUsciteDTO());

                // ==================================================
                //  Crediti e Debiti v/terzi
                // ==================================================
                foundDare = false;
                foundAvere = false;
                var contoFornitori = _daoFactory.GetContoDao().GetByCodice(esercizio.ID, esercizio.CondominioRiferimento.ID, _pianoContiService.GetCodiceContoFornitori());
                var conti = new List<int> {contoFornitori.ID};
                var movimentiFornitori = _movimentoContabileService.GetMovimentiByContiData(esercizio.CondominioRiferimento.ID, esercizio.DataApertura.GetValueOrDefault(), dataRiferimento.GetValueOrDefault(), conti);
                var saldiFornitori = new Dictionary<int,EntrateUsciteDTO>();

                foreach (var movimento in movimentiFornitori)
                {
                    try
                    {
                        if (movimento.Causale.Codice != "OC")
                        {
                            if (movimento.FornitoreRiferimento != null)
                            {
                                var importo = movimento.GetImportoSenzaSegno();
                                if (movimento.Segno == "D")
                                    importo = importo * -1;

                                EntrateUsciteDTO saldoFornitore;
                                if (saldiFornitori.ContainsKey(movimento.FornitoreRiferimento.ID))
                                    saldoFornitore = saldiFornitori[movimento.FornitoreRiferimento.ID];
                                else
                                {
                                    saldoFornitore = new EntrateUsciteDTO
                                    {
                                        IdConto = movimento.ContoRiferimento.ID,
                                        IdSottoConto = movimento.FornitoreRiferimento.ID,
                                        Descrizione = "   " + movimento.FornitoreRiferimento.DisplayName,
                                        Importo = 0,
                                        OrdineConto = 800
                                    };
                                    saldiFornitori.Add(movimento.FornitoreRiferimento.ID, saldoFornitore);
                                }
                                saldoFornitore.Importo += importo;
                            }
                            else
                            {
                                _log.WarnFormat("ATTENZIONE: Il movimento {0} del conto Fornitori non ha un fornitore di riferimento associato - {1}", movimento.ID, Utility.GetMethodDescription());
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nell'elaborazione di un singolo movimento per la redazione della situazione patrimoniale - FORNITORE - {0} - movimento:{1}", ex, Utility.GetMethodDescription(), movimento.ID);
                        throw;
                    }
                }

                firstDare = true;
                firstAvere = true;
                decimal debitiVsFornitori = 0;
                decimal creditiVsFornitori = 0;
                var itemTotaleFornitoriAvere = new EntrateUsciteDTO { IdConto = contoFornitori.ID, Descrizione = "Debiti Vs/Fornitori", OrdineConto = 999 };
                var itemTotaleFornitoriDare = new EntrateUsciteDTO { IdConto = contoFornitori.ID, Descrizione = "Crediti Vs/Fornitori", OrdineConto = 999 };
                foreach (var kvp in saldiFornitori)
                {
                    if (kvp.Value.Importo > 0)
                    {
                        foundAvere = true;
                        if (firstAvere)
                        {
                            listaAvereOrdered.Add("DEBFOR", itemTotaleFornitoriAvere);
                            firstAvere = false;
                        }
                        listaAvereOrdered.Add("DEBFOR&" + kvp.Key, kvp.Value);
                        debitiVsFornitori += kvp.Value.Importo;
                    }
                    else if (kvp.Value.Importo < 0)
                    {
                        foundDare = true;
                        if (firstDare)
                        {
                            listaDareOrdered.Add("CREDFOR", itemTotaleFornitoriDare);
                            firstDare = false;
                        }
                        kvp.Value.Importo = kvp.Value.Importo * -1;
                        listaDareOrdered.Add("CREDFOR&" + kvp.Key, kvp.Value);
                        creditiVsFornitori += kvp.Value.Importo;
                    }
                }
                itemTotaleFornitoriAvere.Importo = debitiVsFornitori;
                itemTotaleFornitoriDare.Importo = creditiVsFornitori;

                if(foundDare)
                    listaDareOrdered.Add("SEPFOR", new EntrateUsciteDTO());
                if (foundAvere)
                    listaAvereOrdered.Add("SEPFOR", new EntrateUsciteDTO());

                // ==================================================
                //  Chiusure Straordinari
                // ==================================================
                var movimentiChiusuraStraordinari = new List<MovimentoContabile>();
                var contiChiusuraStraordinario = _daoFactory.GetContoDao().GetAllByCodice(esercizio.CondominioRiferimento.ID, _pianoContiService.GetCodiceContoChiusuraTemporaneaStraordinari());
                if (contiChiusuraStraordinario.Count > 0)
                    movimentiChiusuraStraordinari.AddRange(_movimentoContabileService.GetMovimentiByContiData(esercizio.CondominioRiferimento.ID, esercizio.DataApertura.GetValueOrDefault(), dataRiferimento.GetValueOrDefault(), contiChiusuraStraordinario.Select(conto => conto.ID).ToList()).Where(item => item.Causale.Tipo == TipoCausaleContabileEnum.Chiusura).ToList());
                movimentiChiusuraStraordinari.AddRange(movimentiEconomiciStraordinario);

                var saldiChiusuraStraordinari = new Dictionary<int, EntrateUsciteDTO>();
                foreach (var movimento in movimentiChiusuraStraordinari)
                {
                    try
                    {
                        if (movimento.Causale.Codice != "OC")
                        {
                            var importo = movimento.GetImportoSenzaSegno();
                            if (movimento.Segno == "D")
                                importo = importo * -1;

                            EntrateUsciteDTO saldoStraordinario;
                            if (saldiChiusuraStraordinari.ContainsKey(movimento.Testata.EsercizioRiferimento.ID))
                                saldoStraordinario = saldiChiusuraStraordinari[movimento.Testata.EsercizioRiferimento.ID];
                            else
                            {
                                saldoStraordinario = new EntrateUsciteDTO
                                {
                                    IdConto = movimento.ContoRiferimento.ID,
                                    IdSottoConto = movimento.Testata.EsercizioRiferimento.ID,
                                    Descrizione = "   " + movimento.Testata.EsercizioRiferimento.DisplayName,
                                    Importo = 0,
                                    OrdineConto = 800
                                };
                                saldiChiusuraStraordinari.Add(movimento.Testata.EsercizioRiferimento.ID, saldoStraordinario);
                            }

                            saldoStraordinario.Importo += importo;
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nell'elaborazione di un singolo movimento per la redazione della situazione patrimoniale - CHIUSURA STRAORDINARI - {0} - movimento:{1}", ex, Utility.GetMethodDescription(), movimento.ID);
                        throw;
                    }
                }

                firstDare = true;
                firstAvere = true;
                var debitiChiusuraStraordinari = 0m;
                var creditiChiusuraStraordinari = 0m;
                var itemTotaleChiusuraStraordinariAvere = new EntrateUsciteDTO { Descrizione = "Costi sospesi Gestioni Straordinarie", OrdineConto = 999 };
                var itemTotaleChiusuraStraordinariDare = new EntrateUsciteDTO { Descrizione = "Costi sospesi Gestioni Straordinarie", OrdineConto = 999 };
                foreach (var kvp in saldiChiusuraStraordinari)
                {
                    if (kvp.Value.Importo > 0)
                    {
                        if (firstAvere)
                        {
                            listaAvereOrdered.Add("DEBCHIUSTRA", itemTotaleChiusuraStraordinariAvere);
                            firstAvere = false;
                        }
                        listaAvereOrdered.Add("DEBCHIUSTRA&" + kvp.Key, kvp.Value);
                        debitiChiusuraStraordinari += kvp.Value.Importo;
                    }
                    else if (kvp.Value.Importo < 0)
                    {
                        if (firstDare)
                        {
                            listaDareOrdered.Add("CREDCHIUSTRA", itemTotaleChiusuraStraordinariDare);
                            firstDare = false;
                        }
                        kvp.Value.Importo = kvp.Value.Importo * -1;
                        listaDareOrdered.Add("CREDCHIUSTRA&" + kvp.Key, kvp.Value);
                        creditiChiusuraStraordinari += kvp.Value.Importo;
                    }
                }

                itemTotaleChiusuraStraordinariAvere.Importo = debitiChiusuraStraordinari;
                itemTotaleChiusuraStraordinariDare.Importo = creditiChiusuraStraordinari;

                // ==========================================================================
                //  Elaborazione riepilogo
                // ==========================================================================
                try
                {
                    var length = listaDareOrdered.Values.Count;
                    if (listaAvereOrdered.Values.Count > length)
                        length = listaAvereOrdered.Count;
                        
                    IList<EntrateUsciteDTO> listaValoriDare = listaDareOrdered.Values.ToList();
                    IList<EntrateUsciteDTO> listaValoriAvere = listaAvereOrdered.Values.ToList();

                    decimal totaleAttivo = 0;
                    decimal totalePassivo = 0;

                    for (var i = 0; i < length; i++)
                    {
                        var item = new StatoPatrimomialeDTO();
                        if (i < listaDareOrdered.Count)
                        {
                            item.DescrizioneColonna1 = listaValoriDare[i].Descrizione;
                            item.ImportoColonna1 = listaValoriDare[i].Importo;
                            item.OrdineContoColonna1 = listaValoriDare[i].OrdineConto;
                            if(listaValoriDare[i].OrdineConto != 800)
                                totaleAttivo += item.ImportoColonna1;
                        }

                        if (i < listaAvereOrdered.Count)
                        {
                            item.DescrizioneColonna2 = listaValoriAvere[i].Descrizione;
                            item.ImportoColonna2 = listaValoriAvere[i].Importo;
                            item.OrdineContoColonna2 = listaValoriAvere[i].OrdineConto;
                            if (listaValoriAvere[i].OrdineConto != 800)
                                totalePassivo += item.ImportoColonna2;
                        }

                        result.Add(item);
                    }

                    var separatore = new StatoPatrimomialeDTO();
                    result.Add(separatore);

                    result.Add(new StatoPatrimomialeDTO
                    {
                        DescrizioneColonna1 = "TOTALE ATTIVITA'",
                        ImportoColonna1 = totaleAttivo,
                        OrdineContoColonna1 = 999,
                        DescrizioneColonna2 = "TOTALE PASSIVITA'",
                        ImportoColonna2 = totalePassivo,
                        OrdineContoColonna2 = 999
                    });


                    return result;
                }
                catch (Exception ex)
                {
                    _log.ErrorFormat("Errore inaspettato nell'elaborazione del riepilogo per la redazione della situazione patrimoniale - ELABORAZIONE RIEPILOGO - {0} - esercizio:{1} - dataRiferimento:{2}", ex, Utility.GetMethodDescription(), idEsercizio, dataRiferimento);
                    throw;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - {0} - esercizio:{1} - dataRiferimento:{2}", ex, Utility.GetMethodDescription(), idEsercizio, dataRiferimento);
                throw;
            }
        }
        public IList<StatoPatrimomialeDTO> GetSituazioneCassa(int idCondominio, int idEsercizio, DateTime? dataIniziale, DateTime? dataFinale)
        {
            try
            {
                var result = new List<StatoPatrimomialeDTO>();
                var listaDare = new Dictionary<string, EntrateUsciteDTO>();
                var listaAvere = new Dictionary<string, EntrateUsciteDTO>();

                var condominio = _daoFactory.GetCondominioDao().GetById(idCondominio, false);
                var esercizio = _daoFactory.GetEsercizioDao().GetById(idEsercizio, false);

                var conti = _pianoContiService.GetContiLiquidita(esercizio);
                var idConti = new List<int>(conti.Count);
                idConti.AddRange(conti.Select(conto => conto.ID));

                if (dataIniziale == null && esercizio != null)
                    dataIniziale = esercizio.DataApertura.GetValueOrDefault();

                if (dataFinale == null && esercizio != null)
                    dataFinale = esercizio.DataChiusura.GetValueOrDefault();

                var movimenti = _movimentoContabileService.GetMovimentiByContiData(condominio.ID, dataIniziale.GetValueOrDefault(), dataFinale.GetValueOrDefault(), idConti);

                // ==========================================================================
                //  Calcolo Importi Dare e Importi Avere
                // ==========================================================================
                foreach (var movimento in movimenti)
                {
                    try
                    {
                        if (movimento.Causale.Codice != "OC" && movimento.Causale.Codice != "C1")
                        {
                            var importo = movimento.GetImportoSenzaSegno();
                            var lista = movimento.Segno == "A" ? listaAvere : listaDare;

                            var key = getKey(movimento);
                            EntrateUsciteDTO item;
                            if (lista.Keys.Contains(key))
                                item = lista[key];
                            else
                            {
                                item = new EntrateUsciteDTO
                                {
                                    CodiceConto = movimento.ContoRiferimento.Codice,
                                    DescrizioneConto = movimento.ContoRiferimento.Descrizione,
                                    IdConto = movimento.ContoRiferimento.ID,
                                    OrdineConto = movimento.ContoRiferimento.Ordine
                                };

                                if (movimento.SottoContoRiferimento != null)
                                {
                                    item.IdSottoConto = movimento.SottoContoRiferimento.ID;
                                    item.DescrizioneSottoConto = movimento.SottoContoRiferimento.GetDescrizione(movimento.Testata.EsercizioRiferimento, null, movimento);
                                }

                                if (movimento.Causale.Codice == "RR")
                                    item.Descrizione = movimento.ContoRiferimento.Descrizione + " - " + movimento.Causale.Descrizione;
                                else if (movimento.Causale.Codice == "VR")
                                {
                                    item.Descrizione = movimento.Causale.Descrizione;
                                    item.OrdineConto = item.OrdineConto + 2;
                                }
                                else if (movimento.Causale.Codice == "SB")
                                {
                                    item.Descrizione = movimento.ContoRiferimento.Descrizione + " - " + movimento.Causale.Descrizione;
                                    item.OrdineConto = item.OrdineConto + 2;
                                }
                                else if (movimento.FornitoreRiferimento != null)
                                    item.Descrizione = "Pagamenti v/s " + movimento.FornitoreRiferimento.DisplayName;
                                else if (!string.IsNullOrEmpty(item.DescrizioneSottoConto))
                                    item.Descrizione = item.DescrizioneSottoConto;
                                else if (movimento.Causale.Codice == "PF")
                                {
                                    item.Descrizione = "Pagamenti v/s Fornitori";
                                    item.OrdineConto++;
                                }
                                else
                                {
                                    if (movimento.Causale.Codice == "AC" || movimento.Causale.Codice == "AB")
                                    {
                                        item.Descrizione = "Saldo iniziale ";
                                        item.OrdineConto = -1;
                                    }

                                    item.Descrizione += $"{movimento.Causale.Descrizione}: {item.DescrizioneConto}";
                                }

                                lista.Add(key, item);
                            }
                            item.Importo += importo;
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nell'elaborazione di un singolo movimento contabile per la redazione della situazione di cassa - {0} - movimento:{1}", ex, Utility.GetMethodDescription(), movimento.ID.ToString(CultureInfo.InvariantCulture));
                        throw;
                    }

                }

                // ==========================================================================
                //  Elaborazione riepilogo
                // ==========================================================================
                try
                {
                    var length = listaDare.Values.Count;
                    if (listaAvere.Values.Count > length)
                        length = listaAvere.Count;

                    IList<EntrateUsciteDTO> listaValoriDare = listaDare.Values.OrderBy(item => item.OrdineConto).ToList();
                    IList<EntrateUsciteDTO> listaValoriAvere = listaAvere.Values.OrderBy(item => item.OrdineConto).ToList();

                    for (var i = 0; i < length; i++)
                    {
                        var item = new StatoPatrimomialeDTO();
                        if (i < listaDare.Values.Count)
                        {
                            item.CodiceContoColonna1 = listaValoriDare[i].CodiceConto;
                            item.CodiceSottoContoColonna1 = listaValoriDare[i].CodiceSottoConto;
                            item.DescrizioneColonna1 = listaValoriDare[i].Descrizione;
                            item.DescrizioneContoColonna1 = listaValoriDare[i].DescrizioneConto;
                            item.DescrizioneSottoContoColonna1 = listaValoriDare[i].DescrizioneSottoConto;
                            item.IdContoColonna1 = listaValoriDare[i].IdConto;
                            item.IdSottoContoColonna1 = listaValoriDare[i].IdSottoConto;
                            item.ImportoColonna1 = listaValoriDare[i].Importo;
                            item.OrdineContoColonna1 = listaValoriDare[i].OrdineConto;
                        }

                        if (i < listaAvere.Values.Count)
                        {
                            item.CodiceContoColonna2 = listaValoriAvere[i].CodiceConto;
                            item.CodiceSottoContoColonna2 = listaValoriAvere[i].CodiceSottoConto;
                            item.DescrizioneColonna2 = listaValoriAvere[i].Descrizione;
                            item.DescrizioneContoColonna2 = listaValoriAvere[i].DescrizioneConto;
                            item.DescrizioneSottoContoColonna2 = listaValoriAvere[i].DescrizioneSottoConto;
                            item.IdContoColonna2 = listaValoriAvere[i].IdConto;
                            item.IdSottoContoColonna2 = listaValoriAvere[i].IdSottoConto;
                            item.ImportoColonna2 = listaValoriAvere[i].Importo;
                            item.OrdineContoColonna2 = listaValoriAvere[i].OrdineConto;
                        }

                        result.Add(item);
                    }

                    var totaleEntrate = listaValoriDare.Sum(item => item.Importo);
                    var totaleUscite = listaValoriAvere.Sum(item => item.Importo);

                    var separatore = new StatoPatrimomialeDTO();
                    result.Add(separatore);

                    var itemTotali = new StatoPatrimomialeDTO
                    {
                        IdContoColonna1 = 999,
                        DescrizioneColonna1 = "Totale delle Entrate",
                        ImportoColonna1 = totaleEntrate,
                        DescrizioneColonna2 = "Totale delle Uscite",
                        ImportoColonna2 = totaleUscite
                    };
                    result.Add(itemTotali);

                    var itemAvanzoCassa = new StatoPatrimomialeDTO {IdContoColonna1 = 999};
                    var avanzo = totaleEntrate - totaleUscite;
                    if (avanzo > 0)
                    {
                        itemAvanzoCassa.DescrizioneColonna1 = "Saldo di liquidità";
                        itemAvanzoCassa.ImportoColonna1 = avanzo;
                        result.Add(itemAvanzoCassa);
                    }
                    else if(avanzo < 0)
                    {
                        itemAvanzoCassa.DescrizioneColonna2 = "Saldo di liquidità";
                        itemAvanzoCassa.ImportoColonna2 = avanzo * -1;
                        result.Add(itemAvanzoCassa);
                    }

                }
                catch (Exception ex)
                {
                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione di cassa - RIEPILOGO - {0} - condominio:{1} - esercizio:{2} - dataIniziale:{3} - dataFinale:{4}", ex, Utility.GetMethodDescription(), idCondominio, idEsercizio, dataIniziale.GetValueOrDefault(), dataFinale.GetValueOrDefault());
                    throw;
                }

                return result;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nella redazione della situazione di cassa - {0} - condominio:{1} - esercizio:{2} - dataIniziale:{3} - dataFinale:{4}", ex, Utility.GetMethodDescription(), idCondominio, idEsercizio, dataIniziale.GetValueOrDefault(), dataFinale.GetValueOrDefault());
                throw;
            }
        }