public IList<SaldoContoDTO> GetSaldiConti(int idCondominio, int? idEsercizio, DateTime? dataIniziale, DateTime? dataFinale)
        {
            try
            {
                var result = new List<SaldoContoDTO>();

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

                Esercizio esercizio = null;
                if (idEsercizio != null)
                    esercizio = _daoFactory.GetEsercizioDao().GetById(idEsercizio.GetValueOrDefault(), false);

				// TODO: Considerare tutti i movimenti dalla ultima data di apertura dei conti patrimoniali, fino alla dataIniziale 
				// per calcolare il saldo iniziale

                if (dataIniziale == null && esercizio != null)
                    dataIniziale = esercizio.DataApertura.GetValueOrDefault();
                                    
                if (dataFinale == null && esercizio != null)
                    dataFinale = esercizio.DataChiusura.GetValueOrDefault();
                        
                // ==================================================
                //  Lettura Movimenti
                // ==================================================
                var movimenti = _movimentoContabileService.GetMovimentiByContiData(condominio.ID, dataIniziale.GetValueOrDefault(), dataFinale.GetValueOrDefault(), null);

                // ==================================================
                //  Raggruppo i movimenti per conto
                // ==================================================
                var movimentiGroupConto = from item in movimenti
                                          group item by item.ContoRiferimento into saldiConto
                                          select saldiConto;

                foreach (var movimentoConto in movimentiGroupConto)
                {
                    try
                    {

                        // -------------------------------------------------------------------
                        // Conto Fornitori, i sottoconti corrispondono ai fornitori
                        // -------------------------------------------------------------------
                        if (movimentoConto.Key.Codice == _pianoContiService.GetCodiceContoFornitori())
                        {
                            var movimentiGroupSottoconto = from item in movimentoConto
                                                           group item by item.FornitoreRiferimento into saldiContoFornitore
                                                           select saldiContoFornitore;

                            foreach (var movimentoContoFornitore in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = condominio.ID,
                                        CodiceSottoConto = movimentoConto.Key.Codice,
                                        TipoConto = movimentoConto.Key.Tipo.ToString(),
                                        ImportoDare = (from item in movimentoContoFornitore
                                                       where item.Segno == "D"
                                                       select item).Sum(item => item.GetImportoSenzaSegno()),
                                        ImportoAvere = (from item in movimentoContoFornitore
                                                        where item.Segno == "A"
                                                        select item).Sum(item => item.GetImportoSenzaSegno()) * -1
                                    };

                                    if (movimentoContoFornitore.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoFornitore.Key.ID;
                                        saldoConto.DescrizioneSottoConto = movimentoContoFornitore.Key.DisplayName;
                                        saldoConto.CodiceSottoConto += "." + movimentoContoFornitore.Key.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                    }
                                    else
                                    {
                                        _log.WarnFormat("Trovato movimento del conto fornitore senza indicazione del fornitore - {0} - conto:{1}", Utility.GetMethodDescription(), movimentoConto.Key.ID);
                                    }

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    var idStr = string.Empty;
                                    if (movimentoContoFornitore.Key != null)
                                        idStr = movimentoContoFornitore.Key.ID.ToString(CultureInfo.InvariantCulture);

                                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Fornitore - {0} - conto:{1} - fornitore:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, idStr, esercizio.ID);
                                    throw;
                                }
                            }
                        }

                        // -------------------------------------------------------------------
                        // Conto Banca, i sottoconti corrispondono ai conti correnti
                        // -------------------------------------------------------------------
                        else if (movimentoConto.Key.Codice == _pianoContiService.GetCodiceContoBancario())
                        {
                            foreach (var item in movimentoConto)
                            {
                                if (item.ContoCorrenteBancario == null)
                                    item.ContoCorrenteBancario = item.Testata.EsercizioRiferimento.CondominioRiferimento.DatiBancariPrincipale;
                            }

                            var movimentiGroupSottoconto = from item in movimentoConto
                                                           group item by item.ContoCorrenteBancario into saldiContoBanca
                                                           select saldiContoBanca;

                            foreach (var movimentoContoBanca in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = condominio.ID,
                                        TipoConto = movimentoConto.Key.Tipo.ToString()
                                    };

                                    if (movimentoContoBanca.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoBanca.Key.ID;
                                        saldoConto.DescrizioneSottoConto = movimentoContoBanca.Key.DisplayName;
                                        saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + movimentoContoBanca.Key.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                    }
                                    else
                                    {
                                        if (condominio.DatiBancariPrincipale != null)
                                        {
                                            saldoConto.IdSottoConto = condominio.DatiBancariPrincipale.ID;
                                            saldoConto.DescrizioneSottoConto = condominio.DatiBancariPrincipale.DisplayName;
                                            saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + condominio.DatiBancariPrincipale.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                        }
                                        else
                                            saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + string.Empty.PadLeft(7, '0');
                                    }

                                    saldoConto.ImportoDare = (from item in movimentoContoBanca
                                                              where item.Segno == "D"
                                                              select item).Sum(item => item.GetImportoSenzaSegno());
                                    saldoConto.ImportoAvere = (from item in movimentoContoBanca
                                                               where item.Segno == "A"
                                                               select item).Sum(item => item.GetImportoSenzaSegno()) * -1;

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    
                                    if (movimentoContoBanca.Key != null)
                                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Banca - {0} - conto:{1} - banca:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, movimentoContoBanca.Key.ID, esercizio.ID);
                                    else
                                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Banca - {0} - conto:{1} - banca:NULL - esercizio:{2}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, esercizio.ID);
                                    throw;
                                }

                            }
                        }

                        // -------------------------------------------------------------------
                        // Tutti gli altri casi prendo il vero sottoconto
                        // -------------------------------------------------------------------
                        else
                        {
                            var movimentiGroupSottoconto = from item in movimentoConto
                                                           group item by item.SottoContoRiferimento into saldiContoSottoconto
                                                           select saldiContoSottoconto;

                            foreach (var movimentoContoSottoconto in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = condominio.ID,
                                        TipoConto = movimentoConto.Key.Tipo.ToString()
                                    };

                                    if (movimentoContoSottoconto.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoSottoconto.Key.ID;
                                        saldoConto.CodiceSottoConto = movimentoContoSottoconto.Key.Codice;
                                        var movimento = movimentoContoSottoconto.FirstOrDefault();
                                        saldoConto.DescrizioneSottoConto = movimento != null ? movimentoContoSottoconto.Key.GetDescrizione(movimento.Testata.EsercizioRiferimento, null, movimento) : movimentoContoSottoconto.Key.Descrizione;
                                    }
                                    else
                                    {
                                        saldoConto.IdSottoConto = 0;
                                        saldoConto.DescrizioneSottoConto = saldoConto.DescrizioneConto;
                                        saldoConto.CodiceSottoConto = saldoConto.CodiceConto + ".000";
                                    }

                                    saldoConto.ImportoDare = (from item in movimentoContoSottoconto
                                                              where item.Segno == "D"
                                                              select item).Sum(item => item.GetImportoSenzaSegno());
                                    saldoConto.ImportoAvere = (from item in movimentoContoSottoconto
                                                               where item.Segno == "A"
                                                               select item).Sum(item => item.GetImportoSenzaSegno()) * -1;

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    if (movimentoContoSottoconto.Key != null)
                                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Sottoconto - {0} - conto:{1} - sottoconto:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, movimentoContoSottoconto.Key.ID, esercizio.ID);
                                    else
                                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Sottoconto - {0} - conto:{1} - sottoconto:NULL - esercizio:{2}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, esercizio.ID);
                                    throw;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Conto - {0} - conto:{1} - esercizio:{2}", ex, Utility.GetMethodDescription(), +movimentoConto.Key.ID, esercizio.ID);
                        throw;
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - {0} - condominio:{1} - esercizio:{2}", ex, Utility.GetMethodDescription(), idCondominio, idEsercizio.GetValueOrDefault());
                throw;
            }
        }
        private IList<SaldoContoDTO> getSaldiInizialiConti(DateTime data, IEnumerable<MovimentoContabile> movimentiCompleti)
        {
            try
            {
                var result = new List<SaldoContoDTO>();

                var movimenti = movimentiCompleti.Where(item => item.Testata.DataRegistrazione < data);

                // ==================================================
                //  Raggruppo i movimenti per conto
                // ==================================================
                var movimentiGroupConto = movimenti.GroupBy(item => item.ContoRiferimento).Select(saldiConto => saldiConto);
                foreach (var movimentoConto in movimentiGroupConto)
                {
                    try
                    {

                        // -------------------------------------------------------------------
                        // Conto Fornitori, i sottoconti corrispondono ai fornitori
                        // -------------------------------------------------------------------
                        if (movimentoConto.Key.Codice == _pianoContiService.GetCodiceContoFornitori())
                        {
                            var movimentiGroupSottoconto = movimentoConto.GroupBy(item => item.FornitoreRiferimento).Select(saldiContoFornitore => saldiContoFornitore);

                            foreach (var movimentoContoFornitore in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = movimentoConto.Key.CondominioRiferimento.ID,
                                        CodiceSottoConto = movimentoConto.Key.Codice,
                                        TipoConto = movimentoConto.Key.Tipo.ToString(),
                                        ImportoDare = (movimentoContoFornitore.Where(item => item.Segno == "D")).Sum(item => item.GetImportoSenzaSegno()),
                                        ImportoAvere = (movimentoContoFornitore.Where(item => item.Segno == "A")).Sum(item => item.GetImportoSenzaSegno()) * -1
                                    };

                                    if (movimentoContoFornitore.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoFornitore.Key.ID;
                                        saldoConto.DescrizioneSottoConto = movimentoContoFornitore.Key.DisplayName;
                                        saldoConto.CodiceSottoConto += "." + movimentoContoFornitore.Key.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                    }
                                    else
                                    {
                                        _log.WarnFormat("Trovato movimento del conto fornitore senza indicazione del fornitore - {0} - conto:{1}", Utility.GetMethodDescription(), movimentoConto.Key.ID);
                                    }

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    var idStr = string.Empty;
                                    if (movimentoContoFornitore.Key != null)
                                        idStr = movimentoContoFornitore.Key.ID.ToString(CultureInfo.InvariantCulture);

                                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Fornitore - {0} - conto:{1} - fornitore:{2}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, idStr);
                                    throw;
                                }
                            }
                        }

                        // -------------------------------------------------------------------
                        // Conto Versamenti, i sottoconti corrispondono ai condomini
                        // -------------------------------------------------------------------
                        else if (movimentoConto.Key.Codice == _pianoContiService.GetCodiceContoVersamentiCondomini())
                        {
                            var movimentiGroupSottoconto = movimentoConto.GroupBy(item => item.CondominoRiferimento).Select(saldiContoCondomini => saldiContoCondomini);

                            foreach (var movimentoContoCondomino in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = movimentoConto.Key.CondominioRiferimento.ID,
                                        CodiceSottoConto = movimentoConto.Key.Codice,
                                        TipoConto = movimentoConto.Key.Tipo.ToString(),
                                        ImportoDare = (movimentoContoCondomino.Where(item => item.Segno == "D")).Sum(item => item.GetImportoSenzaSegno()),
                                        ImportoAvere = (movimentoContoCondomino.Where(item => item.Segno == "A")).Sum(item => item.GetImportoSenzaSegno()) * -1
                                    };

                                    if (movimentoContoCondomino.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoCondomino.Key.ID;
                                        saldoConto.DescrizioneSottoConto = movimentoContoCondomino.Key.DisplayName;
                                        saldoConto.CodiceSottoConto += "." + movimentoContoCondomino.Key.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                    }
                                    else
                                    {
                                        var idMovimentoContabile = string.Empty;
                                        var movimentoContabile = movimentoConto.FirstOrDefault();
                                        if (movimentoContabile != null)
                                            idMovimentoContabile = movimentoContabile.ID.ToString();
                                        _log.WarnFormat("Trovato movimento del conto versamenti senza indicazione del condomino - {0} - conto:{1} - movimento:{2}", Utility.GetMethodDescription(), movimentoConto.Key.ID, idMovimentoContabile);
                                    }

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    var idStr = string.Empty;
                                    if (movimentoContoCondomino.Key != null)
                                        idStr = movimentoContoCondomino.Key.ID.ToString(CultureInfo.InvariantCulture);

                                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - Group per Condomino - {0} - conto:{1} - condomino:{2}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, idStr);
                                    throw;
                                }
                            }
                        }

                        // -------------------------------------------------------------------
                        // Conto Banca, i sottoconti corrispondono ai conti correnti
                        // -------------------------------------------------------------------
                        else if (movimentoConto.Key.Codice == _pianoContiService.GetCodiceContoBancario())
                        {
                            foreach (var item in movimentoConto)
                            {
                                if (item.ContoCorrenteBancario == null)
                                    item.ContoCorrenteBancario = item.Testata.EsercizioRiferimento.CondominioRiferimento.DatiBancariPrincipale;
                            }

                            var movimentiGroupSottoconto = movimentoConto.GroupBy(item => item.ContoCorrenteBancario).Select(saldiContoBanca => saldiContoBanca);

                            foreach (var movimentoContoBanca in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = movimentoConto.Key.CondominioRiferimento.ID,
                                        TipoConto = movimentoConto.Key.Tipo.ToString()
                                    };

                                    if (movimentoContoBanca.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoBanca.Key.ID;
                                        saldoConto.DescrizioneSottoConto = movimentoContoBanca.Key.DisplayName;
                                        saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + movimentoContoBanca.Key.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                    }
                                    else
                                    {
                                        if (movimentoConto.Key.CondominioRiferimento.DatiBancariPrincipale != null)
                                        {
                                            saldoConto.IdSottoConto = movimentoConto.Key.CondominioRiferimento.DatiBancariPrincipale.ID;
                                            saldoConto.DescrizioneSottoConto = movimentoConto.Key.CondominioRiferimento.DatiBancariPrincipale.DisplayName;
                                            saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + movimentoConto.Key.CondominioRiferimento.DatiBancariPrincipale.ID.ToString(CultureInfo.InvariantCulture).PadLeft(7, '0');
                                        }
                                        else
                                            saldoConto.CodiceSottoConto = movimentoConto.Key.Codice + "." + string.Empty.PadLeft(7, '0');
                                    }

                                    saldoConto.ImportoDare = (movimentoContoBanca.Where(item => item.Segno == "D")).Sum(item => item.GetImportoSenzaSegno());
                                    saldoConto.ImportoAvere = (movimentoContoBanca.Where(item => item.Segno == "A")).Sum(item => item.GetImportoSenzaSegno()) * -1;

                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - BANCA - {0} - conto:{0} - banca:{1}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, movimentoContoBanca.Key?.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>");
                                    throw;
                                }

                            }
                        }

                        // -------------------------------------------------------------------
                        // Tutti gli altri casi prendo il vero sottoconto
                        // -------------------------------------------------------------------
                        else
                        {
                            var movimentiGroupSottoconto = movimentoConto.GroupBy(item => item.SottoContoRiferimento).Select(saldiContoSottoconto => saldiContoSottoconto);
                            foreach (var movimentoContoSottoconto in movimentiGroupSottoconto)
                            {
                                try
                                {
                                    var saldoConto = new SaldoContoDTO
                                    {
                                        IdConto = movimentoConto.Key.ID,
                                        DescrizioneConto = movimentoConto.Key.Descrizione,
                                        CodiceConto = movimentoConto.Key.Codice,
                                        OrdineConto = movimentoConto.Key.Ordine,
                                        IdCondominio = movimentoConto.Key.CondominioRiferimento.ID,
                                        TipoConto = movimentoConto.Key.Tipo.ToString()
                                    };

                                    if (movimentoContoSottoconto.Key != null)
                                    {
                                        saldoConto.IdSottoConto = movimentoContoSottoconto.Key.ID;
                                        saldoConto.CodiceSottoConto = movimentoContoSottoconto.Key.Codice;
                                        var movimento = movimentoContoSottoconto.FirstOrDefault();
                                        saldoConto.DescrizioneSottoConto = movimento != null ? movimentoContoSottoconto.Key.GetDescrizione(movimento.Testata.EsercizioRiferimento, null, movimento) : movimentoContoSottoconto.Key.Descrizione;
                                    }
                                    else
                                    {
                                        saldoConto.IdSottoConto = movimentoConto.Key.ID;
                                        saldoConto.DescrizioneSottoConto = saldoConto.DescrizioneConto;
                                        saldoConto.CodiceSottoConto = saldoConto.CodiceConto + ".000";
                                    }

                                    saldoConto.ImportoDare = (movimentoContoSottoconto.Where(item => item.Segno == "D")).Sum(item => item.GetImportoSenzaSegno());
                                    saldoConto.ImportoAvere = (movimentoContoSottoconto.Where(item => item.Segno == "A")).Sum(item => item.GetImportoSenzaSegno()) * -1;
                                    saldoConto.Saldo = saldoConto.ImportoDare + saldoConto.ImportoAvere;

                                    result.Add(saldoConto);
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - SOTTOCONTO - {0} - conto:{1} - sottoconto:{2}", ex, Utility.GetMethodDescription(), movimentoConto.Key.ID, movimentoContoSottoconto.Key?.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>");
                                    throw;
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - CONTO - {0} - conto:{1}", ex, Utility.GetMethodDescription(), movimentoConto.Key?.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>");
                        throw;
                    }
                }

                return result;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nella redazione della situazione patrimoniale - {0} - data:{1}", ex, Utility.GetMethodDescription(), data);
                throw;
            }
        }