public override IEnumerable<ReportRipartizioneBilancioDTO> GetDataSourceRipartizioneBilancioConsuntivo(int? idEsercizio, int? idCondominio, int? anno, int? detrazione, IList<int> idSpese, int? idStabile, int? idScala, bool ripartizioneProprietarioConduttore, bool accorpamentoUnita, TipoAccorpamentoRateEnum tipoAccorpamento, bool inversioneSaldi, bool calcoloPerSubentro, bool addebitiCondominio, bool addebitiDirettiStabileScala, IList<int> idSoggetti, bool dettaglioSottoConto = false)
        {
            try
            {
                var lista = new Dictionary<string, ReportRipartizioneBilancioDTO>();

                Esercizio esercizio = null;
                Condominio condominio = null;

                // =============================================================================================
                //  Allineo flag di ripartizione personalizzata
                // =============================================================================================
                if (idEsercizio != null)
                {
                    try
                    {
                        _daoFactory.GetMovimentoContabileDao().ExecuteQuery("AllineamentoRipartoPersonalizzato", new QueryParam("idEsercizio", idEsercizio.GetValueOrDefault()));
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore nella esecuzione dell'allineamento personalizzato - {0} - esercizio:{1}", ex, Utility.GetMethodDescription(), idEsercizio.GetValueOrDefault());
                    }
                }

                var detrazioneRicerca = _ripartizioneService.GetDetrazioneRicerca(detrazione.GetValueOrDefault());
                IList<Conto> contiChiusuraStraordinario = new List<Conto>();
                if (idEsercizio != null)
                {
                    esercizio = _daoFactory.GetEsercizioDao().Find(idEsercizio.Value, false);
                    if (esercizio == null)
                    {
                        _log.WarnFormat("Esercizio non più presente - {0} - esercizio:{1}", Utility.GetMethodDescription(), idEsercizio.GetValueOrDefault());
                        return new BindingList<ReportRipartizioneBilancioDTO>();
                    }

                    condominio = esercizio.CondominioRiferimento;
                    contiChiusuraStraordinario = getContiEconomiciChiusuraStraordinario(condominio.ID);
                }

                // =============================================================================================
                //  Per gli esercizi chiusi deve essere proposto, se possibile, lo storico
                // =============================================================================================
                if (esercizio != null && esercizio.Stato == StatoEsercizioEnum.Chiuso)
                {
                    var listaStorico = getStoricoRiparto(esercizio.ID, idStabile, idScala, false, TipoRendiconto.Consuntivo);
                    if (listaStorico.Any())
                    {
                        if (!inversioneSaldi)
                        {
                            foreach (var reportRipartizioneBilancioDTO in listaStorico)
                            {
                                if (reportRipartizioneBilancioDTO.OrdineConto == 9993 || reportRipartizioneBilancioDTO.OrdineConto == 9994)
                                    reportRipartizioneBilancioDTO.Importo = reportRipartizioneBilancioDTO.Importo * -1;
                            }
                        }

                        listaStorico = elaboraAccorpamento(listaStorico, tipoAccorpamento, condominio.GetSoggetti(esercizio.DataApertura.GetValueOrDefault(), null, null).ToList(), new Dictionary<int, IList<MillesimoDTO>>(), esercizio, null, null);
                        return elaboraRigheContiVuoti(listaStorico);
                    }
                }

                // =============================================================================================
                //  Ricalcolo i saldi solo se ho un esercizio precedente aperto
                // =============================================================================================
                if (esercizio != null)
                {
                    var esercizioPrecedente = esercizio.GetEsercizioPrecedente();
                    if (esercizioPrecedente != null && esercizioPrecedente.Stato == StatoEsercizioEnum.Aperto)
                        _saldoContabileService.TrasferimentoSaldiNuovoEsercizio(esercizio.ID, this, calcoloPerSubentro);
                }

                if (idCondominio != null)
                    condominio = _daoFactory.GetCondominioDao().GetById(idCondominio.Value, false);

                ImpostazioniAzienda impostazioni = null;
                IList<SoggettoCondominio> soggettiEsercizio = null;
                if (condominio != null)
                {
                    impostazioni = _daoFactory.GetImpostazioniAziendaDao().GetByAzienda(condominio.Azienda.ID);
                    soggettiEsercizio = esercizio != null ? _daoFactory.GetSoggettoCondominioDao().GetAttiviByEsercizio(esercizio, null) : _daoFactory.GetSoggettoCondominioDao().GetAttiviByCondominioAnno(condominio.ID, anno.GetValueOrDefault());
                }

                var conti = _daoFactory.GetContoDao().GetByCondominio(condominio.ID).ToDictionary(item => item.ID);

                // -------------------------------------------------------------------------------------------
                // TODO: Da eliminare quando saranno riscritti i subentri - bugid#8425 
                var soggettiEsercizioNoSubentri = new List<SoggettoCondominio>(soggettiEsercizio.Count);
                foreach (var soggettoCondominio in soggettiEsercizio)
                {
                    try
                    {
                        if (soggettoCondominio != null && soggettoCondominio.Tipo == TipoSoggetto.Proprietario || soggettoCondominio.DataInizio == null || (esercizio != null && soggettoCondominio.DataInizio.GetValueOrDefault() <= esercizio.DataApertura.GetValueOrDefault()) || (anno != null && soggettoCondominio.DataInizio.GetValueOrDefault().Year <= anno.Value))
                            soggettiEsercizioNoSubentri.Add(soggettoCondominio);
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore nella lettura dei soggetti per subentro - {0} - soggetto:{1} - esercizio:{2}", ex, Utility.GetMethodDescription(), soggettoCondominio?.ID, esercizio?.ID);
                    }
                }
                // -------------------------------------------------------------------------------------------

                IDictionary<int, IList<SoggettoCondominio>> soggettiAttivi = new Dictionary<int, IList<SoggettoCondominio>>();
                foreach (var soggettoCondominioUnita in soggettiEsercizioNoSubentri.GroupBy(item => item.UnitaImmobiliare))
                {
                    soggettiAttivi.Add(soggettoCondominioUnita.Key.ID, soggettoCondominioUnita.ToList());
                }

                IDictionary<int, SoggettoCondominio> soggettiAttiviIndex = new Dictionary<int, SoggettoCondominio>();
                foreach (var soggettoCondominio in soggettiEsercizioNoSubentri)
                {
                    soggettiAttiviIndex.Add(soggettoCondominio.ID, soggettoCondominio);
                }

                //====================================================================================
                //  Raggruppo gli importi dei movimenti per Conto, Sottoconto, Lotto, Stabile e Scala
                //====================================================================================
                var importiConto = new List<ImportiContoSottocontoDTO>();
                IList<IRipartizioneSpesa> movimenti;
                if (esercizio != null)
                {
                    movimenti = _daoFactory.GetMovimentoContabileDao().GetByEsercizioEconomiciBilancio(esercizio).Cast<IRipartizioneSpesa>().ToList();
                    movimenti = movimenti.Where(item => item.Causale.Codice != "ST" || contiChiusuraStraordinario.Contains(item.ContoRiferimento)).ToList();
                }
                else
                {
                    var whereSpese = string.Empty;
                    var parameters = new List<QueryParam>(3)
                    {
                        new QueryParam("condominio", condominio),
                        new QueryParam("anno", anno),
                        new QueryParam("detrazione", detrazioneRicerca)
                    };

                    if (idSpese != null && idSpese.Count > 0)
                    {
                        whereSpese += " AND SPE in(:spese) ";
                        parameters.Add(new QueryParam("spese", idSpese));
                    }

                    const string hql = "FROM MovimentoContabile MOV LEFT JOIN FETCH MOV.FornitoreRiferimento FOR LEFT JOIN FETCH FOR.PersonaRiferimento PERS LEFT JOIN FETCH PERS.IndirizzoResidenza.Comune COM LEFT JOIN FETCH MOV.ContoRiferimento CON JOIN FETCH MOV.DettaglioRiferimento DETT JOIN FETCH DETT.SpesaRiferimento SPE LEFT JOIN FETCH SPE.RipartizioneSpesa RIPSPE LEFT JOIN FETCH SPE.Scadenze SCA LEFT JOIN FETCH SCA.Pagamenti PAG LEFT JOIN FETCH SPE.Riscossioni RISC LEFT JOIN FETCH RISC.MovimentoContabile MOVRISC LEFT JOIN FETCH MOVRISC.Testata TESRISC WHERE RIPSPE IS NULL AND MOV.Importo is not null AND MOV.Testata.EsercizioRiferimento.CondominioRiferimento = :condominio AND SPE.Detrazione = :detrazione AND (year(PAG.Data) = :anno OR year(TESRISC.DataRegistrazione) = :anno) {0}";
                    movimenti = _daoFactory.GetMovimentoContabileDao().GetByQuery(string.Format(hql, whereSpese), parameters.ToArray()).Cast<IRipartizioneSpesa>().ToList();

                    // Aggiungo le ripartizione relative a spese inserite solo fiscalmente
                    if (detrazione != null)
                    {
                        const string hqlRipartzioni = "FROM RipartizioneSpesa RIPSPE LEFT JOIN FETCH RIPSPE.ContoRiferimento CON JOIN FETCH RIPSPE.Spesa SPE LEFT JOIN FETCH SPE.Scadenze SCA LEFT JOIN FETCH SCA.Pagamenti PAG WHERE RIPSPE.Importo is not null AND SPE.EsercizioRiferimento.CondominioRiferimento = :condominio AND SPE.Detrazione = :detrazione AND year(PAG.Data) = :anno {0}";
                        var ripartizioni = _daoFactory.GetRipartizioneSpesaDao().GetByQuery(string.Format(hqlRipartzioni, whereSpese), parameters.ToArray()).Cast<IRipartizioneSpesa>().ToList();
                        foreach (var ripartizioneSpesa in ripartizioni)
                        {
                            movimenti.Add(ripartizioneSpesa);
                        }
                    }
                }

                // NON considero le spese personali (NON sono soggette a riparto), le spese ripartite tramite letture del contatore (NON riparto lineare) e le spese con riparto personalizzato
                // ------------------------------------------------------------------------------------------------------------------------------------------------------
                // TODO: Intevenire qui per poter gestire un riparto in cui a livello di modello sono mescolati addebiti a singoli stabili, scale e unità immobiliari
                //       Per ogni scala, stabile e unità aggiungere un ImportiContoSottocontoDTO specifico ... fare molti test!
                // ------------------------------------------------------------------------------------------------------------------------------------------------------
                foreach (var movimentoContabile in movimenti.Where(item => !item.GetContoRiferimento(detrazione != null).IsSpesePersonali && !item.IsRipartoPersonalizzato && (!item.RipartoTramiteLetture || item.DettaglioRipartizione.Count == 0) && (item.Spesa == null || item.Spesa.Utenza == null || !item.Spesa.Utenza.IsAllowRipartoLetture())))
                {
                    if (addebitiDirettiStabileScala)
                    {
                        if (idStabile != null && !isAddebitatoStabile(movimentoContabile, idStabile.Value))
                            continue;

                        if (idScala != null && !isAddebitatoScala(movimentoContabile, idScala.Value))
                            continue;
                    }
                    else if (addebitiCondominio)
                    {
                        if (!string.IsNullOrEmpty(movimentoContabile.StabiliAddebito) || !string.IsNullOrEmpty(movimentoContabile.GruppiAddebito))
                            continue;
                    }

                    var contoRiferimento = movimentoContabile.GetContoRiferimento(detrazione != null);
                    var sottoContoRiferimento = movimentoContabile.SottoContoRiferimento;

                    int? idSottoConto = null;
                    if (sottoContoRiferimento != null)
                        idSottoConto = sottoContoRiferimento.ID;
                    else if(dettaglioSottoConto)
                        idSottoConto = movimentoContabile.ID*-1;

                    int? idContatoreRiferimento = null;
                    if (contoRiferimento.ContatoreRiferimento != null)
                        idContatoreRiferimento = contoRiferimento.ContatoreRiferimento.ID;

                    var stabili = new List<int>();
                    var scale = new List<int>();
                    if (!string.IsNullOrEmpty(movimentoContabile.StabiliAddebito))
                        stabili.AddRange(movimentoContabile.StabiliAddebito.Split('&').Select(int.Parse));
                    else if (!string.IsNullOrEmpty(movimentoContabile.GruppiAddebito))
                        scale.AddRange(movimentoContabile.GruppiAddebito.Split('&').Select(int.Parse));

                    if (stabili.Count > 0)
                    {
                        foreach (var id in stabili)
                        {
                            var importoConto = new ImportiContoSottocontoDTO
                            {
                                Conto = contoRiferimento.ID,
                                SottoConto = idSottoConto,
                                Stabile = id,
                                ContatoreRiferimento = idContatoreRiferimento,
                                ImportoProprieta = _ripartizioneService.GetImportoCompetenza(null, _daoFactory.GetPalazzinaDao().Find(id, false), movimentoContabile, null, null, TipoSoggetto.Proprietario, anno, detrazione),
                                ImportoConduzione = _ripartizioneService.GetImportoCompetenza(null, _daoFactory.GetPalazzinaDao().Find(id, false), movimentoContabile, null, null, TipoSoggetto.Conduttore, anno, detrazione)
                            };

                            addImporto(importoConto, importiConto);
                        }
                    }
                    else if (scale.Count > 0)
                    {
                        foreach (var id in scale)
                        {
                            var importoConto = new ImportiContoSottocontoDTO
                            {
                                Conto = contoRiferimento.ID,
                                SottoConto = idSottoConto,
                                Scala = id,
                                ContatoreRiferimento = idContatoreRiferimento,
                                ImportoProprieta = _ripartizioneService.GetImportoCompetenza(null, _daoFactory.GetGruppoStabileDao().Find(id, false), movimentoContabile, null, null, TipoSoggetto.Proprietario, anno, detrazione),
                                ImportoConduzione = _ripartizioneService.GetImportoCompetenza(null, _daoFactory.GetGruppoStabileDao().Find(id, false), movimentoContabile, null, null, TipoSoggetto.Conduttore, anno, detrazione)
                            };

                            addImporto(importoConto, importiConto);
                        }
                    }
                    else
                    {
                        var importoConto = new ImportiContoSottocontoDTO
                        {
                            Conto = contoRiferimento.ID,
                            SottoConto = idSottoConto,
                            ContatoreRiferimento = idContatoreRiferimento,
                            ImportoProprieta = _ripartizioneService.GetImportoCompetenza(movimentoContabile.GetImportoConSegno(detrazione != null).GetValueOrDefault(), movimentoContabile, TipoSoggetto.Proprietario, anno, detrazione),
                            ImportoConduzione = _ripartizioneService.GetImportoCompetenza(movimentoContabile.GetImportoConSegno(detrazione != null).GetValueOrDefault(), movimentoContabile, TipoSoggetto.Conduttore, anno, detrazione)
                        };

                        addImporto(importoConto, importiConto);
                    }
                }

                //====================================================================================
                //  Eseguo il riparto
                //====================================================================================
                var listaMillesimi = _daoFactory.GetMillesimoDao().GetByCondominio(condominio.ID);
                var millesimiGroupByUnita = listaMillesimi.GroupBy(item => item.UnitaRiferimento.ID).ToList();
                var millesimiGroupByConto = listaMillesimi.GroupBy(item => item.ContoRiferimento.ID).ToList();
                var riparto = new Dictionary<string, SpeseUnitaRipartoDTO>();
                var millesimiAttivi = new Dictionary<int, IList<MillesimoDTO>>();
                foreach (var importiContoSottocontoDTO in importiConto)
                {
                    if (importiContoSottocontoDTO.ContatoreRiferimento == null)
                    {
                        if (!listaMillesimi.Any() || listaMillesimi.Sum(item => item.Valore) == 0)
                            continue;

                        var spese = getRiparto(importiContoSottocontoDTO, millesimiGroupByConto, null, esercizio, dettaglioSottoConto);
                        addSpeseToRiparto(spese, riparto, dettaglioSottoConto);
                    }
                    else
                    {
                        var conto = _daoFactory.GetContoDao().GetById(importiContoSottocontoDTO.Conto, false);

                        List<int> stabili = null;
                        if (importiContoSottocontoDTO.Stabile != null)
                            stabili = new List<int> { importiContoSottocontoDTO.Stabile.GetValueOrDefault() };

                        List<int> scale = null;
                        if (importiContoSottocontoDTO.Scala != null)
                            scale = new List<int> { importiContoSottocontoDTO.Scala.GetValueOrDefault() };

                        IList<MillesimoDTO> millesimi;
                        if (millesimiAttivi.ContainsKey(conto.ID))
                            millesimi = millesimiAttivi[conto.ID];
                        else
                        {
                            millesimi = _millesimiService.GetByConto(conto, stabili, scale, esercizio);
                            millesimiAttivi.Add(conto.ID, millesimi);
                        }

                        var spese = getRiparto(conto, importiContoSottocontoDTO, millesimi, calcoloPerSubentro);
                        addSpeseToRiparto(spese, riparto, dettaglioSottoConto);
                    }
                }

                // Eseguo il riparto per le spese con riparto personalizzato ma che NON siano spese personali o spese ripartite tramite letture del contatore NON lineare (queste saranno considerate nel loop successivo)
                foreach (var movimentoContabile in movimenti.Where(item => item.IsRipartoPersonalizzato && !item.RipartoTramiteLetture && !item.GetContoRiferimento(detrazione != null).IsSpesePersonali && (item.Spesa?.Utenza == null || !item.Spesa.Utenza.IsAllowRipartoLetture())))
                {
                    var spese = getRiparto(movimentoContabile, millesimiGroupByConto, anno, detrazione, esercizio, dettaglioSottoConto);
                    addSpeseToRiparto(spese, riparto, dettaglioSottoConto);
                }

                // Aggiungo le spese personali (NON sono soggette a riparto) e le spese ripartite tramite letture del contatore
                foreach (var movimentoContabile in movimenti.Where(item => (item.DettaglioRipartizione.Count > 0) && (item.GetContoRiferimento(detrazione != null).IsSpesePersonali || item.RipartoTramiteLetture || (item.Spesa?.Utenza != null && item.Spesa.Utenza.IsAllowRipartoLetture()))))
                {
                    var contabile = movimentoContabile;

                    var spese = movimentoContabile.DettaglioRipartizione.Select(spesa => new SpeseUnitaRipartoDTO
                    {
                        ID = spesa.ID,
                        IdConto = contabile.GetContoRiferimento(detrazione != null).ID,
                        IdSottoConto = contabile.SottoContoRiferimento?.ID ?? contabile.ID * -1,
                        IdUnita = spesa.UnitaRiferimento?.ID,
                        IdSoggettoCondominio = spesa.SoggettoCondominio?.ID,
                        UnitaMisuraMillesimo = "PC",
                        ImportoConduttore = _ripartizioneService.GetImportoCompetenza(spesa, TipoSoggetto.Conduttore, anno, detrazione),
                        ImportoProprietario = _ripartizioneService.GetImportoCompetenza(spesa, TipoSoggetto.Proprietario, anno, detrazione)
                    });
                    addSpeseToRiparto(spese, riparto, dettaglioSottoConto);
                }

                //=====================================================================================================
                //  Elaborazione delle ripartizioni
                //=====================================================================================================
                foreach (var spesaAggregata in riparto.ToList())
                {
                    try
                    {
                        var spesa = spesaAggregata.Value;
                        var conto = conti.ContainsKey(spesa.IdConto) ? conti[spesa.IdConto] : _daoFactory.GetContoDao().GetById(spesa.IdConto, false);

                        SottoConto sottoconto = null;
                        if (dettaglioSottoConto && spesa.IdSottoConto > 0)
                            sottoconto = conto.SottoConti.FirstOrDefault(item => item.ID == spesa.IdSottoConto.Value);

                        UnitaImmobiliare unita = null;
                        SoggettoCondominio soggetto = null;

                        if (spesa.IdUnita != null)
                            unita = findUnitaImmobiliare(spesa.IdUnita.GetValueOrDefault(), soggettiAttivi);
                        if (spesa.IdSoggettoCondominio != null)
                            soggetto = findSoggettoCondominio(spesa.IdSoggettoCondominio.GetValueOrDefault(), soggettiAttiviIndex);

                        // -------------------------------------------------------
                        // Verifica se appartiene a scala e/o stabile selezionato
                        // -------------------------------------------------------
                        SoggettoCondominio proprietarioPrincipale = null;
                        SoggettoCondominio conduttorePrincipale = null;

                        // Se il soggetto è diverso da null individuo immediatamente il proprietario o il conduttore principale
                        if (soggetto != null)
                        {
                            unita = soggetto.UnitaImmobiliare;
                            if (!accorpamentoUnita)
                            {
                                switch (soggetto.Tipo)
                                {
                                    case TipoSoggetto.Proprietario:
                                        proprietarioPrincipale = soggetto;
                                        break;
                                    case TipoSoggetto.Conduttore:
                                        conduttorePrincipale = soggetto;
                                        break;
                                }
                            }
                        }

                        if (idStabile != null)
                        {
                            if (unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID != idStabile.Value)
                                continue;
                        }

                        if (idScala != null)
                        {
                            if (unita.GruppoStabileRiferimento.ID != idScala.Value)
                                continue;
                        }

                        // -------------------------
                        // Proprietario
                        // -------------------------
                        if (proprietarioPrincipale == null)
                        {
                            try
                            {
                                if (soggettiAttivi.ContainsKey(unita.ID))
                                {
                                    var proprietariPrincipali = (soggettiAttivi[unita.ID].Where(item =>
                                                item.Tipo == TipoSoggetto.Proprietario &&
                                                item.Principale.GetValueOrDefault())).ToList();

                                    if (proprietariPrincipali.Count > 1)
                                    {
                                        if (proprietariPrincipali.All(item => item.DataInizio == null) || proprietariPrincipali.All(item => item.DataFine == null))
                                            _log.DebugFormat("Trovato più di un PROPRIETARIO principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), spesa.IdUnita, idEsercizio);
                                    }
                                    proprietarioPrincipale = proprietariPrincipali.OrderByDescending(item => item.DataInizio.GetValueOrDefault()).FirstOrDefault(item => item.DataFine == null);
                                }
                            }
                            catch (Exception ex)
                            {
                                _log.ErrorFormat("Errore nella ricerca del proprietario principale - {0} - unita:{1}", ex, Utility.GetMethodDescription(), unita.ID);
                                throw;
                            }
                        }

                        if (conduttorePrincipale == null)
                        {
                            if (soggettiAttivi.ContainsKey(unita.ID))
                            {
                                var conduttoriPrincipale = (soggettiAttivi[unita.ID].Where(item =>
                                    item.Tipo == TipoSoggetto.Conduttore &&
                                    item.Principale.GetValueOrDefault())).ToList();

                                if (conduttoriPrincipale.Count > 1)
                                    _log.WarnFormat("Trovato più di un CONDUTTORE principale - {0} - idUnita:{1} - esercizio:{2}", Utility.GetMethodDescription(), spesa.IdUnita, idEsercizio);
                                conduttorePrincipale = conduttoriPrincipale.FirstOrDefault();
                            }
                        }

                        // Se il proprietario non è presente lo cerco tra tutti i proprietari
                        if (proprietarioPrincipale == null)
                        {
                            var dataLimite = DateTime.Today;
                            if (esercizio != null)
                                dataLimite = esercizio.DataChiusura.GetValueOrDefault();
                            else if (anno != null)
                                dataLimite = new DateTime(anno.GetValueOrDefault(), 12, 31);

                            proprietarioPrincipale = (unita.Proprietari.Where(item =>
                                item.DataInizio == null || item.DataInizio.Value < dataLimite)
                                .OrderByDescending(item => item.DataInizio.GetValueOrDefault())).FirstOrDefault();

                            if (proprietarioPrincipale != null && !soggettiAttiviIndex.ContainsKey(proprietarioPrincipale.ID))
                            {
                                if (soggettiAttivi.ContainsKey(proprietarioPrincipale.UnitaImmobiliare.ID))
                                    soggettiAttivi[proprietarioPrincipale.UnitaImmobiliare.ID].Add(proprietarioPrincipale);
                                else
                                    soggettiAttivi.Add(proprietarioPrincipale.UnitaImmobiliare.ID, new List<SoggettoCondominio>() { proprietarioPrincipale });
                            }
                        }

                        var importoProprieta = spesa.ImportoProprietario;

                        if (importoProprieta == null)
                        {
                            _log.ErrorFormat("ATTENZIONE: Importo a null - {0} - id:{1} - conto:{2} - soggetto:{3} - unità:{4}", Utility.GetMethodDescription(), spesa.ID, spesa.IdConto, spesa.IdSoggettoCondominio, spesa.IdUnita);
                            throw new InvalidDataException(
                                $"Per il conto '{conto.Descrizione}' la ripartizione personalizzata dell'unità immobiliare '{unita.Ordine} - {unita.Descrizione}' non è corretta.");
                        }

                        if (importoProprieta.GetValueOrDefault() != 0)
                        {
                            var soggProp = new List<ImportiDTO>();
                            if (spesa.IdUnita != null)
                            {
                                if (!accorpamentoUnita)
                                {
                                    // --------------------------------------------------------------------
                                    //  Individuo tutti i soggetti tra cui ripartire l'importo
                                    // --------------------------------------------------------------------
                                    var soggPropRip = (conto.SoggettiRipartizione.Where(itemSogg =>
                                            itemSogg.Soggetto.Tipo == TipoSoggetto.Proprietario &&
                                            itemSogg.Soggetto.UnitaImmobiliare.ID == spesa.IdUnita)).ToList();

                                    // In presenza di ripartizioni personalizzate occorre dividere l'importo addebito alla proprietà tra i diversi proprietari
                                    if (soggPropRip.Count > 0)
                                    {
                                        var totaleSoggPropRip = soggPropRip.Sum(item => item.PercentualeRipartizione);
                                        soggProp.AddRange(from sogg in soggPropRip
                                                          let soggettoRipartizione = sogg.Soggetto
                                                          select new ImportiDTO
                                                          {
                                                              Id = soggettoRipartizione.ID,
                                                              Importo = (importoProprieta.GetValueOrDefault() * sogg.PercentualeRipartizione) / totaleSoggPropRip
                                                          });
                                    }
                                    else if (soggPropRip.Count == 0)
                                    {
                                        var spesa1 = spesa;
                                        IList<SoggettoCondominio> proprietariAttivi = new List<SoggettoCondominio>();
                                        if (soggettiAttivi.ContainsKey(spesa1.IdUnita.GetValueOrDefault()))
                                            proprietariAttivi = soggettiAttivi[spesa1.IdUnita.GetValueOrDefault()].Where(item => item.Tipo == TipoSoggetto.Proprietario).ToList();
                                        else
                                            _log.WarnFormat("Non trovato nessun condomino per l'unità immobiliare - {0} - unità:{1} - condominio:{2} - azienda:{3}", Utility.GetMethodDescription(), spesa1.IdUnita, idCondominio, condominio.Azienda.ID);

                                        if (proprietariAttivi.Count == 0 && proprietarioPrincipale != null)
                                            proprietariAttivi.Add(proprietarioPrincipale);
                                        if (proprietariAttivi.Sum(item => item.PercentualeRiferimento) != 100)
                                        {
                                            if (proprietariAttivi.All(item => item.DataInizio == null) || proprietariAttivi.All(item => item.DataFine == null))
                                                _log.WarnFormat("ATTENZIONE: La somma della percentuale di riparto non è 100 - SPESE PROPRIETARI - {0} - unità:{1} - spesa:{2} - esercizio:{3}", Utility.GetMethodDescription(), spesa.IdUnita, spesa.ID, idEsercizio);

                                            if (proprietariAttivi.Count == 1)
                                                proprietariAttivi[0].PercentualeRiferimento = 100m;
                                        }

                                        soggProp.AddRange(proprietariAttivi.Select(soggAttivo => new ImportiDTO { Id = soggAttivo.ID, Importo = (importoProprieta.GetValueOrDefault() * soggAttivo.PercentualeRiferimento.GetValueOrDefault()) / 100 }));
                                    }
                                }
                                else
                                    soggProp.Add(new ImportiDTO(proprietarioPrincipale.ID, importoProprieta.GetValueOrDefault()));
                            }
                            else
                                soggProp.Add(new ImportiDTO(proprietarioPrincipale.ID, importoProprieta.GetValueOrDefault()));

                            foreach (var idSogg in soggProp)
                            {
                                try
                                {
                                    if (idSogg.Importo != 0 && proprietarioPrincipale != null)
                                    {
                                        var key = getKey(spesa.IdConto, spesa.IdSottoConto, proprietarioPrincipale.UnitaImmobiliare.ID, idSogg.Id, accorpamentoUnita, TipoSoggetto.Proprietario, dettaglioSottoConto);

                                        ReportRipartizioneBilancioDTO item;
                                        if (lista.ContainsKey(key))
                                            item = lista[key];
                                        else
                                        {
                                            item = new ReportRipartizioneBilancioDTO();
                                            lista.Add(key, item);
                                            item.Importo = 0;
                                            item.IdConto = spesa.IdConto;
                                            item.DisabilitaStampaMillesimi = conto.IsSpesePersonali || conto.DisabilitaMillesimiRiparto;

                                            var codice = string.Empty;
                                            if (conto.Codice != null)
                                                codice = conto.Codice;
                                            item.CodiceConto = codice;

                                            if (dettaglioSottoConto)
                                            {
                                                var codiceSottoConto = string.Empty;
                                                var descrizioneSottoConto = string.Empty;
                                                if (sottoconto != null)
                                                {
                                                    if (!string.IsNullOrEmpty(sottoconto.Codice))
                                                        codiceSottoConto = sottoconto.Codice;
                                                    descrizioneSottoConto = sottoconto.Descrizione;
                                                }
                                                else if (spesa.IdSottoConto < 0)
                                                {
                                                    var movimento = _daoFactory.GetMovimentoContabileDao().Find(spesa.IdSottoConto.GetValueOrDefault() * -1, false);
                                                    if (movimento != null)
                                                        descrizioneSottoConto = movimento.GetDescrizione();
                                                }

                                                item.IdSottoConto = spesa.IdSottoConto;
                                                item.CodiceSottoConto = codiceSottoConto;
                                                item.DescrizioneSottoConto = descrizioneSottoConto;
                                            }

                                            item.DescrizioneConto = !string.IsNullOrEmpty(conto.DescrizioneBilancio) && !dettaglioSottoConto
                                                ? conto.DescrizioneBilancio
                                                : conto.Descrizione;

                                            item.OrdineConto = conto.Ordine;
                                            item.IdUnitaImmobiliare = proprietarioPrincipale.UnitaImmobiliare.ID;
                                            item.TipoUnitaImmobiliare = unita.TipoUnitaImmobiliare.Descrizione;

                                            item.IdGruppoStabile = unita.GruppoStabileRiferimento.ID;
                                            item.DescrizioneGruppoStabile = unita.GruppoStabileRiferimento.Descrizione;
                                            item.OrdineGruppoStabile = unita.GruppoStabileRiferimento.Ordine;
                                            item.IdStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID;
                                            item.DescrizioneStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Descrizione;
                                            item.OrdineStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Ordine;
                                            item.OrdineUnitaImmobiliare = unita.Ordine.GetValueOrDefault();
                                            item.SubalternoUnitaImmobiliare = unita.Subalterno;
                                            item.PianoUnitaImmobiliare = unita.Piano;
                                            item.InternoUnitaImmobiliare = getInternoUnitaImmobiliare(unita);

                                            item.Millesimi = spesa.ValoreMillesimo;
                                            item.UnitaMisuraMillesimi = spesa.UnitaMisuraMillesimo;
                                            item.MillesimiProprieta = getUnitaMillProp(unita, millesimiGroupByUnita);

                                            if (!accorpamentoUnita)
                                            {
                                                var sogg = findSoggettoCondominio(idSogg.Id, soggettiAttiviIndex);
                                                item.Nominativo = sogg.DisplayName;
                                                item.IdPartecipante = sogg.ID;
                                                item.IdPersona = sogg.Persona.ID;
                                            }
                                            else
                                            {
                                                item.Nominativo = proprietarioPrincipale.UnitaImmobiliare.Descrizione;
                                                item.IdPartecipante = proprietarioPrincipale.ID;
                                                item.IdPersona = proprietarioPrincipale.Persona.ID;
                                            }

                                            item.DataUscitaPartecipante = getDataUscita(proprietarioPrincipale);
                                            item.OrdinePartecipante = 10;
                                            item.TipoNominativo = "PROP";
                                            item.TipoNominativoEffettivo = findSoggettoCondominio(item.IdPartecipante, soggettiAttiviIndex).Tipo.ToString().Substring(0, 1);
                                            item.NumeroColonne = 1;
                                        }

                                        item.Importo += idSogg.Importo;
                                    }
                                    else
                                    {
                                        if (proprietarioPrincipale == null)
                                        {
                                            throw new InvalidDataException($"Per l'unità immobiliare {unita.Ordine} non è presente un proprietario principale");
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - (SPESE - PROPRIETARI) - {0} - idSogg:{1}  - idSpesa:{2} - idEsercizio:{3}", ex, Utility.GetMethodDescription(), idSogg.Id, spesa.ID, idEsercizio);
                                    throw;
                                }
                            }
                        }

                        // -------------------------
                        // Conduttore
                        // -------------------------
                        if (spesa.ImportoConduttore.GetValueOrDefault() != 0)
                        {
                            var soggCond = new List<ImportiDTO>();
                            int idUnita;
                            if (spesa.IdUnita != null)
                            {
                                idUnita = spesa.IdUnita.GetValueOrDefault();
                                if (!accorpamentoUnita)
                                {
                                    var soggCondRip = (conto.SoggettiRipartizione.Where(itemSogg =>
                                                    itemSogg.Soggetto.Tipo == TipoSoggetto.Conduttore &&
                                                    itemSogg.Soggetto.UnitaImmobiliare.ID == spesa.IdUnita)).ToList();

                                    if (soggCondRip.Count > 0)
                                    {
                                        var totaleSoggCondRip = soggCondRip.Sum(item => item.PercentualeRipartizione);
                                        soggCond.AddRange(soggCondRip.Select(sogg => new ImportiDTO
                                        {
                                            Id = sogg.Soggetto.ID,
                                            Importo = (spesa.ImportoConduttore.GetValueOrDefault() * sogg.PercentualeRipartizione) / totaleSoggCondRip
                                        }));
                                    }
                                    else if (soggCondRip.Count == 0)
                                    {
                                        var conduttoriAttivi = (soggettiAttivi[spesa.IdUnita.GetValueOrDefault()].Where(item =>
                                                item.Tipo == TipoSoggetto.Conduttore &&
                                                item.PercentualeRiferimento > 0)).ToList();
                                        if (!conduttoriAttivi.Any())
                                        {
                                            var spesa1 = spesa;
                                            conduttoriAttivi = (soggettiAttivi[spesa1.IdUnita.GetValueOrDefault()].Where(item =>
                                                    item.Tipo == TipoSoggetto.Proprietario)).ToList();
                                        }

                                        if (conduttoriAttivi.Sum(item => item.PercentualeRiferimento) != 100)
                                        {
                                            _log.WarnFormat("ATTENZIONE: La somma della percentuale di riparto non è 100 - SPESE CONDUTTORI - {0} - unità:{1} - spesa:{2} - esercizio:{3}", Utility.GetMethodDescription(), spesa.IdUnita, spesa.ID, idEsercizio);
                                        }

                                        soggCond.AddRange(conduttoriAttivi.Select(soggAttivo => new ImportiDTO { Id = soggAttivo.ID, Importo = (spesa.ImportoConduttore.GetValueOrDefault() * soggAttivo.PercentualeRiferimento.GetValueOrDefault()) / 100 }));
                                    }
                                }
                                else if (proprietarioPrincipale != null)
                                    soggCond.Add(new ImportiDTO(proprietarioPrincipale.ID, spesa.ImportoConduttore.GetValueOrDefault()));
                            }
                            else
                            {
                                if (conduttorePrincipale == null)
                                {
                                    conduttorePrincipale =
                                        soggettiEsercizio.Where(
                                                item =>
                                                    item.UnitaImmobiliare.ID ==
                                                    proprietarioPrincipale.UnitaImmobiliare.ID &&
                                                    item.Tipo == TipoSoggetto.Conduttore)
                                            .OrderByDescending(item => item.Principale)
                                            .FirstOrDefault();
                                }

                                if (conduttorePrincipale == null)
                                    conduttorePrincipale = _daoFactory.GetSoggettoCondominioDao().Find(spesa.IdSoggettoCondominio.GetValueOrDefault(), false);
                                
                                if (conduttorePrincipale != null)
                                {
                                    soggCond.Add(new ImportiDTO(conduttorePrincipale.ID, spesa.ImportoConduttore.GetValueOrDefault()));
                                    idUnita = conduttorePrincipale.UnitaImmobiliare.ID;
                                }
                                else
                                    throw new InvalidDataException($"Per l'unità immobiliare {unita.Descrizione} il conduttore non è configurato correttamente.{Environment.NewLine}Si prega di verificare e rilanciare l'esecuzione.");
                            }

                            foreach (var idSogg in soggCond)
                            {
                                try
                                {
                                    if (idSogg.Importo != 0)
                                    {
                                        var key = getKey(spesa.IdConto, spesa.IdSottoConto, idUnita, idSogg.Id, accorpamentoUnita, TipoSoggetto.Conduttore, dettaglioSottoConto);

                                        ReportRipartizioneBilancioDTO item;
                                        if (lista.ContainsKey(key))
                                            item = lista[key];
                                        else
                                        {
                                            item = new ReportRipartizioneBilancioDTO();
                                            lista.Add(key, item);
                                            item.Importo = 0;
                                            item.IdConto = spesa.IdConto;
                                            item.DisabilitaStampaMillesimi = conto.IsSpesePersonali || conto.DisabilitaMillesimiRiparto;

                                            var codice = string.Empty;
                                            if (conto.Codice != null)
                                                codice = conto.Codice;
                                            item.CodiceConto = codice;

                                            item.DescrizioneConto = !string.IsNullOrEmpty(conto.DescrizioneBilancio) && !dettaglioSottoConto ? conto.DescrizioneBilancio : conto.Descrizione;
                                            item.OrdineConto = conto.Ordine;

                                            if (dettaglioSottoConto)
                                            {
                                                var codiceSottoConto = string.Empty;
                                                var descrizioneSottoConto = string.Empty;
                                                if (sottoconto != null)
                                                {
                                                    if (!string.IsNullOrEmpty(sottoconto.Codice))
                                                        codiceSottoConto = sottoconto.Codice;
                                                    descrizioneSottoConto = sottoconto.Descrizione;
                                                }
                                                else if (spesa.IdSottoConto < 0)
                                                {
                                                    var movimento = _daoFactory.GetMovimentoContabileDao().Find(spesa.IdSottoConto.GetValueOrDefault()*-1, false);
                                                    if (movimento != null)
                                                        descrizioneSottoConto = movimento.GetDescrizione();
                                                }

                                                item.IdSottoConto = spesa.IdSottoConto;
                                                item.CodiceSottoConto = codiceSottoConto;
                                                item.DescrizioneSottoConto = descrizioneSottoConto;
                                            }

                                            item.IdUnitaImmobiliare = idUnita;
                                            item.TipoUnitaImmobiliare = unita.TipoUnitaImmobiliare.Descrizione;

                                            item.IdGruppoStabile = unita.GruppoStabileRiferimento.ID;
                                            item.DescrizioneGruppoStabile = unita.GruppoStabileRiferimento.Descrizione;
                                            item.IdStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID;
                                            item.DescrizioneStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Descrizione;
                                            item.OrdineGruppoStabile = unita.GruppoStabileRiferimento.Ordine;
                                            item.OrdineStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Ordine;
                                            item.OrdineUnitaImmobiliare = unita.Ordine.GetValueOrDefault();
                                            item.InternoUnitaImmobiliare = getInternoUnitaImmobiliare(unita);
                                            item.SubalternoUnitaImmobiliare = unita.Subalterno;
                                            item.PianoUnitaImmobiliare = unita.Piano;
                                            item.Millesimi = spesa.ValoreMillesimo;
                                            item.UnitaMisuraMillesimi = spesa.UnitaMisuraMillesimo;
                                            item.MillesimiProprieta = getUnitaMillProp(unita, millesimiGroupByUnita);

                                            if (!accorpamentoUnita)
                                            {
                                                var sogg = findSoggettoCondominio(idSogg.Id, soggettiAttiviIndex);
                                                item.DataUscitaPartecipante = getDataUscita(sogg);
                                                item.Nominativo = sogg.DisplayName;
                                                item.IdPartecipante = sogg.ID;
                                                item.IdPersona = sogg.Persona.ID;
                                            }
                                            else
                                            {
                                                item.DataUscitaPartecipante = getDataUscita(proprietarioPrincipale);
                                                item.Nominativo = proprietarioPrincipale.UnitaImmobiliare.Descrizione;
                                                item.IdPartecipante = proprietarioPrincipale.ID;
                                                item.IdPersona = proprietarioPrincipale.Persona.ID;
                                            }

                                            item.OrdinePartecipante = 20;
                                            item.TipoNominativo = "COND";
                                            item.TipoNominativoEffettivo = ripartizioneProprietarioConduttore ? "C" : findSoggettoCondominio(item.IdPartecipante, soggettiAttiviIndex).Tipo.ToString().Substring(0, 1);

                                            item.NumeroColonne = 1;
                                        }

                                        item.Importo += idSogg.Importo;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - SPESE CONDUTTORI - {0} - soggetto:{1} - spesa:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), idSogg.Id, spesa.ID, idEsercizio);
                                    throw;
                                }
                            }
                        }

                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - (SPESE) - {0} - idSpesa:{1} - esercizio:{2} - anno:{3} - detrazione:{4}", ex, Utility.GetMethodDescription(), spesaAggregata.Value.ID, idEsercizio.GetValueOrDefault(), anno.GetValueOrDefault(), detrazione.GetValueOrDefault());
                        throw;
                    }
                }

                //==============================================================================================================
                //  Elaborazione SUBENTRI per avere una riga per ogni soggetto
                //==============================================================================================================
                elaboraSubentri(esercizio, accorpamentoUnita, lista, soggettiAttivi, conti, dettaglioSottoConto);

                //==============================================================================================================
                //  Calcolo totali spese
                //==============================================================================================================
                var totali = new Dictionary<string, ReportRipartizioneBilancioDTO>();
                foreach (var itemGroup in lista.Values.GroupBy(item => item.IdPartecipante.ToString().PadLeft(10, '0') + "&" + item.TipoNominativo))
                {
                    try
                    {
                        var itemSpesa = itemGroup.FirstOrDefault();
                        var totaleKey = getKey(0, null, itemSpesa.IdUnitaImmobiliare, itemSpesa.IdPartecipante, accorpamentoUnita, itemSpesa.TipoNominativo == "PROP" ? TipoSoggetto.Proprietario : TipoSoggetto.Conduttore, dettaglioSottoConto);

                        // Somma gli importi raggruppati per conto perchè deve arrotondare l'importo a livello di conto
                        var groupConto = itemGroup.GroupBy(item => item.IdConto);
                        var importoTotale = groupConto.Sum(itemGroupConto => Math.Round(itemGroupConto.Sum(item => item.Importo.GetValueOrDefault()), 2));

                        if (!totali.ContainsKey(totaleKey))
                        {
                            var itemTotale = getItemTotale(itemSpesa);
                            itemTotale.Importo = importoTotale;
                            totali.Add(totaleKey, itemTotale);
                        }
                        else
                        {
                            var itemTotale = totali[totaleKey];
                            itemTotale.Importo += importoTotale;
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore nel calcolo dei totali - SINGOLO TOTALE - {0} - key:{1}", ex, Utility.GetMethodDescription(), itemGroup.Key);
                        throw;
                    }
                }

                //==============================================================================================================
                //  SOLO se NON si tratta di un riparto per DETRAZIONE
                //==============================================================================================================
                if (esercizio != null)
                {
                    var versamenti = _versamentiCondominiService.GetImportoMovimentiVersatoByEsercizio(esercizio, idStabile, idScala);

                    //==============================================================================================================
                    //  Ripartizione delle differenze tra Rendiconto e Riparto
                    //==============================================================================================================
                    // Merge
                    var saldi = _daoFactory.GetSaldoSoggettoDao().GetByEsercizioStabileScala(esercizio, idStabile, idScala);
                    var saldiCalcolati = new Dictionary<int, ReportRipartizioneBilancioDTO>();
                    var versamentiCalcolati = new List<int>();
                    var totaliCalcolati = new List<ReportRipartizioneBilancioDTO>();

                    // Se il soggetto non è presente nei totali (quindi non ha nessuna spesa addebitata) lo aggiungo con un elemento FAKE (666), che poi
                    // provvederò a cancellare, per permettere l'inserimento degli elementi di saldo e versamenti
                    // ----------------------------------------------------------------------------------------------------------------------------------
                    // Saldi
                    foreach (var saldo in saldi)
                    {
                        try
                        {
                            totali = elaboraSoggetto(saldo.Soggetto, soggettiAttivi, totali, esercizio, accorpamentoUnita);
                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo (SALDI FAKE) - {0} - saldo:{1} - esercizio:{2}", ex, Utility.GetMethodDescription(), saldo.ID, idEsercizio);
                            throw;
                        }
                    }

                    // Versamenti
                    foreach (var item in versamenti)
                    {
                        try
                        {
                            var soggetto = findSoggettoCondominio(item.Id, soggettiAttiviIndex);

                            if (soggetto != null)
                            {
                                if (idStabile != null)
                                {
                                    if (soggetto.UnitaImmobiliare.GruppoStabileRiferimento.PalazzinaRiferimento.ID != idStabile.Value)
                                        continue;
                                }

                                if (idScala != null)
                                {
                                    if (soggetto.UnitaImmobiliare.GruppoStabileRiferimento.ID != idScala.Value)
                                        continue;
                                }

                                totali = elaboraSoggetto(soggetto, soggettiAttivi, totali, esercizio, accorpamentoUnita);
                            }
                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo (VERSAMENTI FAKE) - {0} - soggetto:{1} - importo:{2:c} - esercizio:{3}", ex, Utility.GetMethodDescription(), item.Id, item.Importo, idEsercizio);
                            throw;
                        }
                    }

                    //==============================================================================================================
                    //  Elaborazione dei totali + saldi e versamenti
                    //==============================================================================================================
                    var partecipantiElaborati = new List<int>();

                    // Leggo i versamenti successivi alla chiusura solo per gli esercizi ordinari
                    PianoRatealeDettaglio pianoRatealeDettaglio = null;
                    if (esercizio.Gestione == GestioneEsercizioEnum.Ordinario)
                    {
                        var esercizioSuccessivo = _daoFactory.GetEsercizioDao().GetEsercizioCompetenza(esercizio.CondominioRiferimento, esercizio.DataChiusura.GetValueOrDefault().AddDays(1));
                        if (esercizioSuccessivo != null)
                            pianoRatealeDettaglio = _daoFactory.GetPianoRatealeDettaglioDao().GetRataVersamentoDopoChiusura(esercizioSuccessivo);
                    }

                    foreach (var kvp in totali)
                    {
                        try
                        {
                            var soggetto = findSoggettoCondominio(kvp.Value.IdPartecipante, soggettiAttiviIndex);

                            // Può capitare in caso di subentro senza trasferimento di saldi e versamenti
                            lista.Add(kvp.Key, kvp.Value);

                            // ---------------------------------------------------------
                            // Saldo Anno Precedente
                            // ---------------------------------------------------------
                            var itemRiporto = new ReportRipartizioneBilancioDTO();
                            if (!saldiCalcolati.ContainsKey(kvp.Value.IdPartecipante))
                            {
                                // Inserisco il saldo solo se diverso da 0, oppure se è relativo al proprietario principale. (bugid#999)
                                // La riga del proprietario deve essere sempre presente anche se tutti gli importi sono a 0, il conduttore
                                // invece non deve essere presente se gli importi sono a 0
                                int? idPartecipante = kvp.Value.IdPartecipante;
                                int? idUnitaImmobiliare = null;
                                if (accorpamentoUnita)
                                {
                                    idPartecipante = null;
                                    idUnitaImmobiliare = kvp.Value.IdUnitaImmobiliare;
                                }
                                var saldo = getSaldoBySoggettoUnita(saldi, idPartecipante, idUnitaImmobiliare);
                                if ((saldo != null && saldo != 0) || (kvp.Value.TipoNominativo == "PROP" && soggetto.Principale.GetValueOrDefault()))
                                {
                                    itemRiporto = cloneItem(kvp.Value);
                                    itemRiporto.DescrizioneConto = "Saldo Esercizio Precedente";
                                    itemRiporto.OrdineConto = 9991;
                                    itemRiporto.CodiceConto = null;
                                    itemRiporto.DisabilitaStampaMillesimi = true;

                                    if (accorpamentoUnita)
                                    {
                                        var propPrincipale = (from item in soggettiAttivi[kvp.Value.IdUnitaImmobiliare]
                                                              where item.Tipo == TipoSoggetto.Proprietario && item.Principale.GetValueOrDefault()
                                                              orderby item.DataInizio.GetValueOrDefault() descending 
                                                              select item).FirstOrDefault();
                                        // Se il proprietario non è presente lo cerco tra tutti i proprietari
                                        if (propPrincipale == null)
                                        {
                                            propPrincipale = (from item in soggetto.UnitaImmobiliare.Proprietari
                                                              where item.DataInizio == null || item.DataInizio.Value < esercizio.DataChiusura
                                                              orderby item.DataInizio.GetValueOrDefault() descending
                                                              select item).FirstOrDefault();

                                            _log.DebugFormat("Non trovato proprietario principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), soggetto.UnitaImmobiliare.ID, idEsercizio.ToString());
                                        }

                                        itemRiporto.IdPartecipante = propPrincipale.ID;
                                        itemRiporto.IdPersona = propPrincipale.Persona.ID;
                                        itemRiporto.Nominativo = propPrincipale.UnitaImmobiliare.Descrizione;
                                    }

                                    itemRiporto.Importo = saldo != null ? saldo.Value : 0;

                                    var sogg = _daoFactory.GetSoggettoCondominioDao().GetById(itemRiporto.IdPartecipante, false);
                                    itemRiporto.TipoNominativo = (sogg.Tipo == TipoSoggetto.Proprietario) ? "PROP" : "COND";
                                    itemRiporto.TipoNominativoEffettivo = sogg.Tipo.ToString().Substring(0, 1);

                                    lista.Add(kvp.Key + "_RIPORTO", itemRiporto);
                                    saldiCalcolati.Add(kvp.Value.IdPartecipante, itemRiporto);
                                }
                            }

                            // ---------------------------------------------------------
                            // Versamenti
                            // ---------------------------------------------------------
                            var itemVersato = new ReportRipartizioneBilancioDTO();
                            if (!versamentiCalcolati.Contains(kvp.Value.IdPartecipante))
                            {
                                decimal versamento;
                                if (!accorpamentoUnita)
                                {
                                    var kvp1 = kvp;
                                    versamento = (versamenti.Where(item => item.Id == kvp1.Value.IdPartecipante)).Sum(item => item.Importo);
                                }
                                else
                                {
                                    var kvp1 = kvp;
                                    var soggettiUnita = soggettiAttivi[kvp1.Value.IdUnitaImmobiliare].Select(item => item.ID);
                                    versamento = (versamenti.Where(item => soggettiUnita.Contains(item.Id))).Sum(item => item.Importo);
                                }

                                // Inserisco il versamento solo se diverso da 0, oppure se è relativo al proprietario. (bugid#999)
                                // La riga del proprietario deve essere sempre presente anche se tutti gli importi sono a 0, il conduttore
                                // invece non deve essere presente se gli importi sono a 0
                                if (versamento != 0 || (kvp.Value.TipoNominativo == "PROP" && soggetto != null && soggetto.Principale.GetValueOrDefault()))
                                {
                                    itemVersato = cloneItem(kvp.Value);
                                    itemVersato.DescrizioneConto = "Versato";
                                    itemVersato.OrdineConto = 9992;
                                    itemVersato.CodiceConto = null;
                                    itemVersato.DisabilitaStampaMillesimi = true;

                                    if (accorpamentoUnita)
                                    {
                                        var propPrincipale = findProprietarioPrincipale(kvp.Value.IdUnitaImmobiliare, soggettiAttivi, soggetto.UnitaImmobiliare, esercizio);

                                        // Se il proprietario non è presente lo cerco tra tutti i proprietari
                                        if (propPrincipale == null)
                                        {
                                            propPrincipale = (soggetto.UnitaImmobiliare.Proprietari.Where(
                                                item => item.DataInizio == null || item.DataInizio.Value < esercizio.DataChiusura)
                                                .OrderByDescending(item => item.DataInizio.GetValueOrDefault())).FirstOrDefault();

                                            _log.DebugFormat("Non trovato proprietario principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), soggetto.UnitaImmobiliare.ID, idEsercizio.ToString());
                                        }
                                        itemVersato.IdPartecipante = propPrincipale.ID;
                                        itemVersato.IdPersona = propPrincipale.Persona.ID;
                                        itemVersato.Nominativo = propPrincipale.UnitaImmobiliare.Descrizione;
                                    }

                                    var sogg = _daoFactory.GetSoggettoCondominioDao().GetById(itemVersato.IdPartecipante, false);
                                    itemVersato.TipoNominativo = (sogg.Tipo == TipoSoggetto.Proprietario) ? "PROP" : "COND";
                                    itemVersato.TipoNominativoEffettivo = sogg.Tipo.ToString().Substring(0, 1);

                                    itemVersato.Importo = versamento;

                                    lista.Add(kvp.Key + "_VERSATO", itemVersato);
                                    versamentiCalcolati.Add(kvp.Value.IdPartecipante);
                                }
                            }

                            //----------------------------------------------------------
                            // Versamenti dopo la chiusura
                            //----------------------------------------------------------
                            if (pianoRatealeDettaglio != null && pianoRatealeDettaglio.RateSoggetti.Count > 0 && !partecipantiElaborati.Contains(kvp.Value.IdPartecipante))
                            {
                                var kvp1 = kvp;
                                partecipantiElaborati.Add(kvp.Value.IdPartecipante);
                                var itemVersamentoDopoChiusura = cloneItem(kvp.Value);
                                itemVersamentoDopoChiusura.DescrizioneConto = "Di cui Versamenti dopo la Chiusura";
                                itemVersamentoDopoChiusura.OrdineConto = 9995;
                                itemVersamentoDopoChiusura.CodiceConto = null;
                                itemVersamentoDopoChiusura.DisabilitaStampaMillesimi = true;

                                if (accorpamentoUnita)
                                {
                                    var propPrincipale = findProprietarioPrincipale(kvp.Value.IdUnitaImmobiliare, soggettiAttivi, soggetto.UnitaImmobiliare, esercizio);

                                    // Se il proprietario non è presente lo cerco tra tutti i proprietari
                                    if (propPrincipale == null)
                                    {
                                        propPrincipale = (soggetto.UnitaImmobiliare.Proprietari.Where(
                                            item => item.DataInizio == null || item.DataInizio.Value < esercizio.DataChiusura)
                                            .OrderByDescending(item => item.DataInizio.GetValueOrDefault())).FirstOrDefault();

                                        _log.WarnFormat("Non trovato proprietario principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), soggetto.UnitaImmobiliare.ID, idEsercizio);
                                    }
                                    itemVersamentoDopoChiusura.IdPartecipante = propPrincipale.ID;
                                    itemVersamentoDopoChiusura.IdPersona = propPrincipale.Persona.ID;
                                    itemVersamentoDopoChiusura.Nominativo = propPrincipale.UnitaImmobiliare.Descrizione;
                                }

                                var sogg = _daoFactory.GetSoggettoCondominioDao().GetById(itemVersamentoDopoChiusura.IdPartecipante, false);
                                itemVersamentoDopoChiusura.TipoNominativo = (sogg.Tipo == TipoSoggetto.Proprietario) ? "PROP" : "COND";
                                itemVersamentoDopoChiusura.TipoNominativoEffettivo = sogg.Tipo.ToString().Substring(0, 1);

                                itemVersamentoDopoChiusura.Importo = pianoRatealeDettaglio.RateSoggetti.Where(item => item.Soggetto.ID == kvp1.Value.IdPartecipante).Sum(item => item.Importo);
                                lista.Add(kvp.Key + "_VERSATODOPOCHIUSURA", itemVersamentoDopoChiusura);
                            }

                            // ---------------------------------------------------------
                            // Importi a Debito e a Credito
                            // ---------------------------------------------------------
                            var importoTotale = kvp.Value.Importo.Value + itemRiporto.Importo.GetValueOrDefault() - itemVersato.Importo.GetValueOrDefault();

                            // Solo se l'importo è <> 0 oppure se la riga è relativa al proprietario principale
                            if (importoTotale != 0 || (kvp.Value.TipoNominativo == "PROP" && soggetto != null && soggetto.Principale.GetValueOrDefault()))
                            {
                                var idSoggettoTotali = kvp.Value.IdPartecipante;
                                if (accorpamentoUnita)
                                {
                                    var propPrincipale = findProprietarioPrincipale(kvp.Value.IdUnitaImmobiliare, soggettiAttivi, soggetto.UnitaImmobiliare, esercizio);

                                    // Se il proprietario non è presente lo cerco tra tutti i proprietari
                                    if (propPrincipale == null)
                                    {
                                        propPrincipale = (soggetto.UnitaImmobiliare.Proprietari.Where(
                                            item => item.DataInizio == null || item.DataInizio.Value < esercizio.DataChiusura)
                                            .OrderByDescending(item => item.DataInizio.GetValueOrDefault())).FirstOrDefault();

                                        _log.DebugFormat("Non trovato proprietario principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), soggetto.UnitaImmobiliare.ID, idEsercizio.ToString());
                                    }
                                    idSoggettoTotali = propPrincipale.ID;
                                }

                                var importoDto = totaliCalcolati.SingleOrDefault(item => item.IdPartecipante == idSoggettoTotali);
                                if (importoDto == null)
                                {
                                    importoDto = cloneItem(kvp.Value);
                                    importoDto.Importo = importoTotale;
                                    totaliCalcolati.Add(importoDto);
                                }
                                else
                                    importoDto.Importo += importoTotale;
                            }

                            // se necessario inverto i saldi
                            if (impostazioni != null && impostazioni.InversioneSaldiRate)
                                itemRiporto.Importo = itemRiporto.Importo.GetValueOrDefault() * -1;
                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - SALDI E VERSAMENTI - {0} - unità:{1} - soggetto:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), kvp.Value.IdUnitaImmobiliare, kvp.Value.IdPartecipante, idEsercizio);
                            throw;
                        }
                    }

                    // ===================================================================
                    //  Rielaboro i totali calcolati
                    // ===================================================================
                    foreach (var itemTotale in totaliCalcolati)
                    {
                        var sogg = _daoFactory.GetSoggettoCondominioDao().GetById(itemTotale.IdPartecipante, false);

                        // Debito
                        var itemDebitoCredito = cloneItem(itemTotale);
                        itemDebitoCredito.CodiceConto = null;
                        itemDebitoCredito.Importo = itemTotale.Importo;
                        itemDebitoCredito.TipoNominativo = (sogg.Tipo == TipoSoggetto.Proprietario) ? "PROP" : "COND";
                        itemDebitoCredito.TipoNominativoEffettivo = sogg.Tipo.ToString().Substring(0, 1);

                        if (itemTotale.Importo > 0)
                        {
                            itemDebitoCredito.DescrizioneConto = "a Debito";
                            itemDebitoCredito.OrdineConto = 9993;
                        }
                        else
                        {
                            itemDebitoCredito.DescrizioneConto = "a Credito";
                            itemDebitoCredito.OrdineConto = 9994;
                        }

                        if (inversioneSaldi)
                            itemDebitoCredito.Importo = itemDebitoCredito.Importo * -1;

                        lista.Add(itemDebitoCredito.IdPartecipante + "_DEBITOCREDITO", itemDebitoCredito);
                    }
                }
                else
                {
                    //==============================================================================================================
                    //  Stampa detrazioni devo rielaborare i totali
                    //==============================================================================================================
                    foreach (var kvp in totali)
                    {
                        try
                        {
                            lista.Add(kvp.Key, kvp.Value);
                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - TOTALI IN STAMPA DETRAZIONI - {0} - unità:{1} - soggetto:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), kvp.Value.IdUnitaImmobiliare, kvp.Value.IdPartecipante, idEsercizio);
                            throw;
                        }
                    }
                }

                //==============================================================================================================
                //  Rielaboro lista finale
                //==============================================================================================================
                IList<ReportRipartizioneBilancioDTO> listaRiparto;
                try
                {
                    // Tolgo gli elementi FAKE aggiunti per permettere l'inserimento di tutti i saldi e versamenti
                    listaRiparto = lista.Values.Where(item => item.CodiceConto != "666").ToList();

                    // I Millesimi deve comparire solo sul primo soggetto per una stessa unità immmobiliare (bugid#1002)
                    var listaContoGroup = listaRiparto.GroupBy(item => item.IdConto).Select(contoGroup => contoGroup);
                    foreach (var itemGroup in listaContoGroup)
                    {
                        var listaUnitaGroup = itemGroup.GroupBy(item => item.IdUnitaImmobiliare).Select(unitaGroup => unitaGroup);
                        foreach (var unitaGroup in listaUnitaGroup)
                        {
                            var first = true;
                            foreach (var item in unitaGroup.OrderByDescending(item2 => item2.TipoNominativo).ThenBy(item2 => item2.Nominativo))
                            {
                                if (!first)
                                    item.Millesimi = null;
                                first = false;
                            }
                        }
                    }

                    //==============================================================================================================
                    //  Applico eventuali accorpamenti
                    //==============================================================================================================
                    if (!accorpamentoUnita)
                    {
                        var soggetti = new List<SoggettoCondominio>();
                        foreach (var kvp in soggettiAttivi)
                            soggetti.AddRange(kvp.Value.ToList());
                        listaRiparto = elaboraAccorpamento(listaRiparto, tipoAccorpamento, soggetti, millesimiAttivi, esercizio, null, null);
                    }
                }
                catch (Exception ex)
                {
                    _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - RIELABORAZIONE LISTA FINALE - {0} - esercizio:{1}", ex, Utility.GetMethodDescription(), idEsercizio);
                    throw;
                }

                //==============================================================================================================
                //  Elimino righe per conti vuoti
                //==============================================================================================================
                listaRiparto = elaboraRigheContiVuoti(listaRiparto);

                //==============================================================================================================
                //  Aggiungo colonna spese conduzione
                //==============================================================================================================
                var listaConduzione = listaRiparto.Where(item => item.OrdineConto < 9990 && item.TipoNominativo == "COND").GroupBy(item => item.IdPartecipante).ToList();
                foreach (var item in listaConduzione)
                {
                    var firstItem = item.FirstOrDefault();
                    if (firstItem != null)
                    {

                        // Debito
                        var itemConduzione = cloneItem(firstItem);
                        itemConduzione.IdConto = 0;
                        itemConduzione.CodiceConto = null;
                        itemConduzione.IdSottoConto = null;
                        itemConduzione.CodiceSottoConto = null;
                        itemConduzione.Importo = item.Sum(itemImporto => itemImporto.Importo);
                        itemConduzione.TipoNominativo = "COND";
                        itemConduzione.TipoNominativoEffettivo = firstItem.TipoNominativoEffettivo;
                        itemConduzione.DescrizioneConto = "Spese Conduzione";
                        itemConduzione.OrdineConto = 9996;

                        listaRiparto.Add(itemConduzione);
                        lista.Add(itemConduzione.IdPartecipante + "_CONDUZIONE", itemConduzione);
                    }
                }

                //==============================================================================================================
                //  ARROTONDAMENTO Importi generazione di una nuova riga di arrotondamenti
                //==============================================================================================================
                var importiNonArrotondati = new List<ReportRipartizioneBilancioDTO>();
                foreach (var reportRipartizioneBilancioDTO in listaRiparto.Where(item => item.OrdineConto < 9990))
                {
                    if (reportRipartizioneBilancioDTO.Importo != null)
                    {
                        var importoArrotondato = Math.Round(reportRipartizioneBilancioDTO.Importo.GetValueOrDefault(), 2);
                        var importoArrotondamento = reportRipartizioneBilancioDTO.Importo.GetValueOrDefault() - importoArrotondato;

                        var itemImportoArrotondato = importiNonArrotondati.FirstOrDefault(item => item.IdConto == reportRipartizioneBilancioDTO.IdConto && item.DescrizioneConto == reportRipartizioneBilancioDTO.DescrizioneConto);
                        if (itemImportoArrotondato == null)
                        {
                            itemImportoArrotondato = getItemArrotondamenti(reportRipartizioneBilancioDTO);
                            itemImportoArrotondato.Importo = importoArrotondamento;
                            importiNonArrotondati.Add(itemImportoArrotondato);
                        }
                        else
                            itemImportoArrotondato.Importo += importoArrotondamento;

                        reportRipartizioneBilancioDTO.Importo = importoArrotondato;
                    }
                }

                // Aggiungo anche il totale degli arrotondamenti
                var totaleArrotondamento = 0m;
                foreach (var reportRipartizioneBilancioDTO in importiNonArrotondati)
                {
                    reportRipartizioneBilancioDTO.Importo = Math.Round(reportRipartizioneBilancioDTO.Importo.GetValueOrDefault(), 2);
                    totaleArrotondamento += reportRipartizioneBilancioDTO.Importo.GetValueOrDefault();
                }

                if (totaleArrotondamento != 0)
                {
                    var itemImportoArrotondato = getItemArrotondamenti(importiNonArrotondati.FirstOrDefault());
                    itemImportoArrotondato.OrdineConto = 9990;
                    itemImportoArrotondato.IdConto = 0;
                    itemImportoArrotondato.DescrizioneConto = "Totale Spese";
                    itemImportoArrotondato.IdSottoConto = null;
                    itemImportoArrotondato.Importo = totaleArrotondamento;
                    importiNonArrotondati.Add(itemImportoArrotondato);

                    var itemImportoArrotondatoDebitoCredito = getItemArrotondamenti(importiNonArrotondati.FirstOrDefault());
                    itemImportoArrotondatoDebitoCredito.IdConto = 0;
                    itemImportoArrotondatoDebitoCredito.IdSottoConto = null;
                    itemImportoArrotondatoDebitoCredito.Importo = totaleArrotondamento;
                    if (inversioneSaldi)
                        itemImportoArrotondatoDebitoCredito.Importo = itemImportoArrotondatoDebitoCredito.Importo * -1;

                    if (totaleArrotondamento < 0)
                    {
                        itemImportoArrotondatoDebitoCredito.OrdineConto = 9994;
                        itemImportoArrotondatoDebitoCredito.DescrizioneConto = "a Credito";
                    }
                    else
                    {
                        itemImportoArrotondatoDebitoCredito.OrdineConto = 9993;
                        itemImportoArrotondatoDebitoCredito.DescrizioneConto = "a Debito";
                    }

                    importiNonArrotondati.Add(itemImportoArrotondatoDebitoCredito);
                }

                foreach (var reportRipartizioneBilancioDTO in importiNonArrotondati)
                {
                    listaRiparto.Add(reportRipartizioneBilancioDTO);
                }

                // ======================================================
                //  Add Empty items - Per una corretta visualizzazione
                //  nel report multicolonna
                // ======================================================
                if (!ripartizioneProprietarioConduttore && !dettaglioSottoConto)
                {
                    var emptyItems = getEmptyItems(listaRiparto);
                    foreach (var reportRipartizioneBilancioDTO in emptyItems)
                        listaRiparto.Add(reportRipartizioneBilancioDTO);
                }

                // ======================================================
                //  Rielaborazione millesimi
                // ======================================================
                elaborazioneMillesimi(listaRiparto);

                // ======================================================
                //  Rielaborazione nominativi
                // ======================================================
                elaborazioneNominativi(listaRiparto);

                // ======================================================
                //  Ritorno solo le righe dei condomini selezionati
                // ======================================================
                if (idSoggetti != null)
                    listaRiparto = listaRiparto.Where(item => (item.OrdineConto < 9990 || item.OrdineConto == 9991 || item.OrdineConto == 9992) && idSoggetti.Contains(item.IdPartecipante)).ToList();

                return listaRiparto.OrderBy(item => item.IdGruppoStabile);
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - {0} - esercizio:{1} - condominio:{2} - anno:{3} - detrazione:{4} - stabile:{5} - scala:{6} - ripartizioneProprietarioConduttore:{7} - accorpamentoUnita:{8} - inversioneSaldi:{9}", ex, Utility.GetMethodDescription(), idEsercizio, idCondominio.GetValueOrDefault(), anno.GetValueOrDefault(), detrazione.GetValueOrDefault(), idStabile.GetValueOrDefault(), idScala.GetValueOrDefault(), ripartizioneProprietarioConduttore, tipoAccorpamento, inversioneSaldi);
                throw;
            }
        }
        private IEnumerable<SpeseUnitaRipartoDTO> getRiparto(Conto conto, ImportiContoSottocontoDTO importo, ICollection<MillesimoDTO> millesimi, bool calcoloPerSubentro)
        {
            IEnumerable<MillesimoDTO> millesimiAttivi = new List<MillesimoDTO>(millesimi.Count);
            if (importo.Lotto == null && importo.Stabile == null && importo.Scala == null)
                millesimiAttivi = millesimi.Where(item => item.IdContoRiferimento == importo.Conto);
            else if (importo.Scala != null)
                millesimiAttivi = millesimi.Where(item => item.IdContoRiferimento == importo.Conto && item.IdGruppoRiferimento == importo.Scala.GetValueOrDefault());
            else if (importo.Stabile != null)
                millesimiAttivi = millesimi.Where(item => item.IdContoRiferimento == importo.Conto && item.IdStabileRiferimento == importo.Stabile.GetValueOrDefault());
            else if (importo.Lotto != null)
                millesimiAttivi = millesimi.Where(item => item.IdContoRiferimento == importo.Conto && item.IdLottoRiferimento == importo.Lotto.GetValueOrDefault());

            var totaleMillesimi = millesimiAttivi.Sum(item => item.Valore);
            IList<SpeseUnitaRipartoDTO> lista = new List<SpeseUnitaRipartoDTO>(millesimiAttivi.Count());

            // Controllare se i millesimi sono presenti bugid#3946
            if (totaleMillesimi == 0)
            {
                // Se sto calcolando per la conferma di un subentro non ritorno errori bugid#4152
                if (calcoloPerSubentro)
                    return lista;

                var messaggio = conto.ContatoreRiferimento == null ?
                    $"Il conto '{conto.Descrizione}' non ha millesimi non è possibile proseguire l'elaborazione"
                    : $"Per il conto '{conto.Descrizione}' non sono presenti letture relative al contatore lineare: '{conto.ContatoreRiferimento.Descrizione}'{Environment.NewLine}Non è possibile proseguire l'elaborazione";
                throw new InvalidDataException(messaggio);
            }

            foreach (var millesimo in millesimiAttivi)
            {
                // Se è definita devo usare la ripartizione specifica per conto
                // ---------------------------------------------------------------------------------
                var importoProprietario = (importo.ImportoProprieta * millesimo.Valore) / totaleMillesimi;
                var importoConduttore = (importo.ImportoConduzione * millesimo.Valore) / totaleMillesimi;
                var importi = getImportoProprietaConduzioneByUnita(conto, importoProprietario, importoConduttore, millesimo.IdUnitaRiferimento);

                var riparto = new SpeseUnitaRipartoDTO
                {
                    IdConto = importo.Conto,
                    IdUnita = millesimo.IdUnitaRiferimento,
                    ValoreMillesimo = millesimo.Valore,
                    UnitaMisuraMillesimo = millesimo.UnitaMisura,
                    ImportoProprietario = importi[0],
                    ImportoConduttore = importi[1]
                };
                lista.Add(riparto);
            }

            return lista;
        }
 private static void addImporto(ImportiContoSottocontoDTO importo, IList<ImportiContoSottocontoDTO> importi)
 {
     if (!importi.Contains(importo))
         importi.Add(importo);
     else
     {
         var oldImporto = importi[importi.IndexOf(importo)];
         oldImporto.ImportoConduzione += importo.ImportoConduzione;
         oldImporto.ImportoProprieta += importo.ImportoProprieta;
     }
 }
        private IEnumerable<SpeseUnitaRipartoDTO> getRiparto(ImportiContoSottocontoDTO importo, List<IGrouping<int, Millesimo>> millesimi, IEnumerable<ReportRipartizioneBilancioDTO> consuntivo, Esercizio esercizio, bool dettaglioSottoConto)
        {
            IEnumerable<Millesimo> millesimiAttivi = new List<Millesimo>(millesimi.Count);

            var millesimiConto = new List<Millesimo>();
            foreach (var item in millesimi.Where(item => item.Key == importo.Conto))
                millesimiConto.AddRange(item);

            if (importo.Lotto == null && importo.Stabile == null && importo.Scala == null)
                millesimiAttivi = millesimiConto.ToList();
            else if (importo.Scala != null)
                millesimiAttivi = millesimiConto.Where(item => item.UnitaRiferimento.GruppoStabileRiferimento.ID == importo.Scala.GetValueOrDefault());
            else if (importo.Stabile != null)
                millesimiAttivi = millesimiConto.Where(item => item.UnitaRiferimento.GruppoStabileRiferimento.PalazzinaRiferimento.ID == importo.Stabile.GetValueOrDefault());
            else if (importo.Lotto != null)
                millesimiAttivi = millesimiConto.Where(item => item.UnitaRiferimento.GruppoStabileRiferimento.PalazzinaRiferimento.LottoRiferimento.ID == importo.Lotto.GetValueOrDefault());

            IList<SpeseUnitaRipartoDTO> lista = new List<SpeseUnitaRipartoDTO>();

            // ===================================================================================================================
            //  Se il conto è senza millesimi, come millesimo uso il riparto del consuntivo se previsto (riparto tramite letture)
            // ===================================================================================================================
            IList<ImportiDTO> millesimiUnita = new List<ImportiDTO>();
            if (millesimiAttivi.Any())
            {
                foreach (var millesimo in millesimiAttivi)
                    millesimiUnita.Add(new ImportiDTO(millesimo.UnitaRiferimento.ID, millesimo.Valore.GetValueOrDefault()));
            }
            else if (consuntivo != null)
            {
                var millesimiConsuntivo = consuntivo.Where(item => item.IdConto == importo.Conto && item.IdUnitaImmobiliare > 0).GroupBy(item => item.IdUnitaImmobiliare).ToList();
                if (millesimiConsuntivo.Any())
                {
                    foreach (var kvp in millesimiConsuntivo)
                        millesimiUnita.Add(new ImportiDTO(kvp.Key, kvp.Sum(item => item.Importo.GetValueOrDefault())));
                }

                // Se non è presente il consuntivo deve calcolare i millesimi in base alle letture o altro criterio bugid#8729
                else
                {
                    var conto = _daoFactory.GetContoDao().Find(importo.Conto, false);
                    if (conto != null && esercizio != null)
                    {
                        var millesimiByConto = _millesimiService.GetByConto(conto, null, null, esercizio);
                        foreach (var millesimoDTO in millesimiByConto)
                        {
                            millesimiUnita.Add(new ImportiDTO(millesimoDTO.IdUnitaRiferimento, millesimoDTO.Valore.GetValueOrDefault()));
                        }
                    }
                }

            }

            var totaleMillesimi = millesimiUnita.Sum(item => item.Importo);
            if (totaleMillesimi != 0)
            {
                foreach (var millesimo in millesimiUnita)
                {
                    try
                    {
                        // Se è definita devo usare la ripartizione specifica per conto
                        // ---------------------------------------------------------------------------------
                        var importoProprietario = (importo.ImportoProprieta * millesimo.Importo) / totaleMillesimi;
                        var importoConduttore = (importo.ImportoConduzione * millesimo.Importo) / totaleMillesimi;
                        var importi = getImportoProprietaConduzioneByUnita(_daoFactory.GetContoDao().GetById(importo.Conto, false), importoProprietario, importoConduttore, millesimo.Id);

                        var riparto = new SpeseUnitaRipartoDTO
                        {
                            IdConto = importo.Conto,
                            IdSottoConto = importo.SottoConto,
                            IdUnita = millesimo.Id,
                            ValoreMillesimo = millesimo.Importo,
                            UnitaMisuraMillesimo = "PC",
                            ImportoProprietario = importi[0],
                            ImportoConduttore = importi[1],
                            IdStabileAddebito = importo.Scala,
                            IdGruppoStabileAddebito = importo.Stabile
                        };

                        if (dettaglioSottoConto)
                            riparto.IdSottoConto = importo.SottoConto;

                        lista.Add(riparto);
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore nella elaborazione dei millesimi - {0} - millesimo:{1}", ex, Utility.GetMethodDescription(), millesimo.Id);
                        throw;
                    }
                }
            }

            var importoRipartitoProprietario = lista.Sum(item => item.ImportoProprietario);
            var importoRipartitoConduttore = lista.Sum(item => item.ImportoConduttore);
            _log.DebugFormat("Totale ripartito - {0} - importoRipartitoProprietario:{1} - importoRipartitoConduttore:{2} - importo:{3}", Utility.GetMethodDescription(), importoRipartitoProprietario, importoRipartitoConduttore, importo);

            return lista;
        }
        private IList<ReportRipartizioneBilancioDTO> getReportItemsPreventivo(Esercizio esercizio, RendicontoAnnuale rendicontoDaUsare, IList<SoggettoCondominio> soggettiAttivi, int? idStabile, int? idScala, bool ripartizioneProprietarioConduttore, bool accorpamentoUnita, bool inversioneSaldi, bool calcoloPerSubentro, bool addebitiCondominio, bool addebitiDirettiStabileScala, bool dettaglioSottoConto)
        {
            var condominio = esercizio.CondominioRiferimento;
            var idEsercizio = esercizio.ID;
            var lista = new Dictionary<string, ReportRipartizioneBilancioDTO>();

            // =============================================================================================
            //  Se esiste devo proporre lo storico
            // =============================================================================================
            var listaStorico = getStoricoRiparto(idEsercizio, idStabile, idScala, addebitiDirettiStabileScala, TipoRendiconto.Preventivo);
            if (listaStorico.Any())
            {
                return listaStorico.Where(item => item.IdConto > 0).ToList();
            }
            else
            {
                // =============================================================================================
                //  Ricalcolo i saldi solo se ho un esercizio precedente aperto
                // =============================================================================================
                var esercizioPrecedente = esercizio.GetEsercizioPrecedente();
                if (esercizioPrecedente != null && esercizioPrecedente.Stato == StatoEsercizioEnum.Aperto)
                    _saldoContabileService.TrasferimentoSaldiNuovoEsercizio(esercizio.ID, this, calcoloPerSubentro);

                //====================================================================================
                //  Raggruppo gli importi del preventivo per Conto, Sottoconto, Lotto, Stabile e Scala
                //====================================================================================
                IList<ReportRipartizioneBilancioDTO> consuntivo = null;
                if (rendicontoDaUsare.Conti.Any(item => item.GetConto().IsRipartoLetture))
                {
                    // Il calcolo dal consuntivo, necessario per ripartire il preventivo se presente un conto a letture, deve sempre essere calcolato senza accorpamenti
                    // bugid#4171
                    if (esercizioPrecedente != null)
                        consuntivo = GetDataSourceRipartizioneBilancioConsuntivo(esercizioPrecedente.ID, null, null, null, null, idStabile, idScala, ripartizioneProprietarioConduttore, accorpamentoUnita, TipoAccorpamentoRateEnum.Nessuno, inversioneSaldi, calcoloPerSubentro, addebitiCondominio, addebitiDirettiStabileScala, null).ToList();
                }

                var importiConto = new List<ImportiContoSottocontoDTO>();
                foreach (var rendicontoAnnualeConto in rendicontoDaUsare.Conti.Where(item => !item.GetConto().IsSpesePersonali))
                {
                    if (!addebitiCondominio || !addebitiDirettiStabileScala || (rendicontoAnnualeConto.Stabile == null && rendicontoAnnualeConto.GruppoStabile == null))
                    {
                        if (!addebitiDirettiStabileScala ||
                            (
                                (idStabile == null || (rendicontoAnnualeConto.Stabile != null && rendicontoAnnualeConto.Stabile.ID == idStabile.GetValueOrDefault())) &&
                                (idScala == null || (rendicontoAnnualeConto.GruppoStabile != null && rendicontoAnnualeConto.GruppoStabile.ID == idScala.GetValueOrDefault()))
                            ))
                        {
                            int? idSottoConto = null;
                            if (dettaglioSottoConto)
                            {
                                if (rendicontoAnnualeConto.SottoContoRiferimento != null)
                                    idSottoConto = rendicontoAnnualeConto.SottoContoRiferimento.ID;
                                else
                                    idSottoConto = rendicontoAnnualeConto.GetConto().ID *-1;
                            }

                            int? idStabileConto = null;
                            if (rendicontoAnnualeConto.Stabile != null)
                                idStabileConto = rendicontoAnnualeConto.Stabile.ID;

                            int? idScalaConto = null;
                            if (rendicontoAnnualeConto.GruppoStabile != null)
                                idScalaConto = rendicontoAnnualeConto.GruppoStabile.ID;

                            var importoConto = new ImportiContoSottocontoDTO
                            {
                                Conto = rendicontoAnnualeConto.GetConto().ID,
                                SottoConto = idSottoConto,
                                Stabile = idStabileConto,
                                Scala = idScalaConto,
                                ImportoProprieta =
                                    _ripartizioneService.GetImportoCompetenza(
                                        rendicontoAnnualeConto.Importo.GetValueOrDefault(),
                                        rendicontoAnnualeConto.GetConto(),
                                        rendicontoAnnualeConto.SottoContoRiferimento,
                                        TipoSoggetto.Proprietario),
                                ImportoConduzione =
                                    _ripartizioneService.GetImportoCompetenza(
                                        rendicontoAnnualeConto.Importo.GetValueOrDefault(),
                                        rendicontoAnnualeConto.GetConto(),
                                        rendicontoAnnualeConto.SottoContoRiferimento,
                                        TipoSoggetto.Conduttore)
                            };

                            addImporto(importoConto, importiConto);
                        }

                    }
                }

                //====================================================================================
                //  Eseguo il riparto
                //====================================================================================
                var millesimi = _daoFactory.GetMillesimoDao().GetByCondominio(condominio.ID);
                var millesimiGroupByConto = millesimi.GroupBy(item => item.ContoRiferimento.ID).ToList();
                var unitaImmobiliari = _daoFactory.GetUnitaImmobiliareDao().GetByCondominio(condominio.ID).ToDictionary(item => item.ID);
                var conti = _daoFactory.GetContoDao().GetByCondominio(condominio.ID).ToDictionary(item => item.ID);
                var soggetti = soggettiAttivi.ToDictionary(item => item.ID);
                var riparto = new List<SpeseUnitaRipartoDTO>();
                foreach (var importiContoSottocontoDTO in importiConto)
                    riparto.AddRange(getRiparto(importiContoSottocontoDTO, millesimiGroupByConto, consuntivo, esercizio, dettaglioSottoConto));

                // ------------------------------------------------------------------
                // Proprietari attivi
                // ------------------------------------------------------------------
                var listaProprietariAttivi = new Dictionary<int, IList<SoggettoCondominio>>();
                var proprietariSoggettiAttivi = new Dictionary<int, SoggettoCondominio>();
                foreach (var soggettoCondominio in soggettiAttivi.Where(item => item.Tipo == TipoSoggetto.Proprietario))
                {
                    if (soggettoCondominio.Principale.GetValueOrDefault())
                    {
                        if (proprietariSoggettiAttivi.ContainsKey(soggettoCondominio.UnitaImmobiliare.ID))
                        {
                            if (soggettoCondominio.DataInizio.GetValueOrDefault() > proprietariSoggettiAttivi[soggettoCondominio.UnitaImmobiliare.ID].DataInizio.GetValueOrDefault() || proprietariSoggettiAttivi[soggettoCondominio.UnitaImmobiliare.ID].DataFine != null)
                                proprietariSoggettiAttivi[soggettoCondominio.UnitaImmobiliare.ID] = soggettoCondominio;
                        }
                        else
                            proprietariSoggettiAttivi.Add(soggettoCondominio.UnitaImmobiliare.ID, soggettoCondominio);
                    }

                    if (listaProprietariAttivi.ContainsKey(soggettoCondominio.UnitaImmobiliare.ID))
                        listaProprietariAttivi[soggettoCondominio.UnitaImmobiliare.ID].Add(soggettoCondominio);
                    else
                        listaProprietariAttivi.Add(soggettoCondominio.UnitaImmobiliare.ID, new List<SoggettoCondominio> { soggettoCondominio });
                }

                // ------------------------------------------------------------------
                // Conduttori attivi
                // ------------------------------------------------------------------
                var conduttoriSoggettiAttivi = new Dictionary<int, IList<SoggettoCondominio>>();
                foreach (var soggettoCondominioUnita in soggettiAttivi.Where(item => item.Tipo == TipoSoggetto.Conduttore).GroupBy(item => item.UnitaImmobiliare))
                    conduttoriSoggettiAttivi.Add(soggettoCondominioUnita.Key.ID, soggettoCondominioUnita.ToList());

                var soggettiAttiviByUnitaImmobiliare = new Dictionary<int, IList<SoggettoCondominio>>();
                foreach (var soggettoCondominioUnita in soggettiAttivi.GroupBy(item => item.UnitaImmobiliare))
                    soggettiAttiviByUnitaImmobiliare.Add(soggettoCondominioUnita.Key.ID, soggettoCondominioUnita.ToList());

                // ------------------------------------------------------------------
                // Aggiungo le spese personali (NON sono soggette a riparto)
                // ------------------------------------------------------------------
                foreach (var rendicontoAnnualeConto in rendicontoDaUsare.Conti.Where(item => item.GetConto().IsSpesePersonali))
                {
                    riparto.AddRange(rendicontoAnnualeConto.DettagliUnita.Select(spesa => new SpeseUnitaRipartoDTO
                    {
                        ID = spesa.ID,
                        IdConto = rendicontoAnnualeConto.GetConto().ID,
                        IdUnita = spesa.Unita.ID,
                        UnitaMisuraMillesimo = "PC",
                        ImportoConduttore = _ripartizioneService.GetImportoCompetenza(spesa.Importo.GetValueOrDefault(), rendicontoAnnualeConto.GetConto(), rendicontoAnnualeConto.SottoContoRiferimento, TipoSoggetto.Conduttore),
                        ImportoProprietario = _ripartizioneService.GetImportoCompetenza(spesa.Importo.GetValueOrDefault(), rendicontoAnnualeConto.GetConto(), rendicontoAnnualeConto.SottoContoRiferimento, TipoSoggetto.Proprietario)
                    }));
                }

                //=====================================================================================================
                //  Elaborazione delle ripartizioni
                //=====================================================================================================
                var index = 0;
                foreach (var spesa in riparto)
                {
                    try
                    {
                        index++;
                        var conto = conti.ContainsKey(spesa.IdConto) ? conti[spesa.IdConto] : _daoFactory.GetContoDao().GetById(spesa.IdConto, false);
                        var unita = unitaImmobiliari.ContainsKey(spesa.IdUnita.GetValueOrDefault()) ? unitaImmobiliari[spesa.IdUnita.GetValueOrDefault()] : _daoFactory.GetUnitaImmobiliareDao().GetById(spesa.IdUnita.GetValueOrDefault(), false);

                        SottoConto sottoconto = null;
                        if (spesa.IdSottoConto > 0)
                            sottoconto = conto.SottoConti.FirstOrDefault(item => item.ID == spesa.IdSottoConto.Value);

                        // -------------------------------------------------------
                        // Verifica se appartiene a scala e/o stabile selezionato
                        // -------------------------------------------------------
                        if (idStabile != null)
                        {
                            if (unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID != idStabile.Value)
                                continue;
                        }

                        if (idScala != null)
                        {
                            if (unita.GruppoStabileRiferimento.ID != idScala.Value)
                                continue;
                        }

                        // -------------------------
                        // Proprietario
                        // -------------------------
                        SoggettoCondominio proprietarioPrincipale = null;
                        if(proprietariSoggettiAttivi.ContainsKey(spesa.IdUnita.GetValueOrDefault()))
                            proprietarioPrincipale = proprietariSoggettiAttivi[spesa.IdUnita.GetValueOrDefault()];

                        // Se il proprietario non è presente lo cerco tra tutti i proprietari
                        if (proprietarioPrincipale == null)
                        {
                            proprietarioPrincipale = (from item in unita.Proprietari
                                                      where
                                                          item.DataInizio == null ||
                                                          item.DataInizio.Value < esercizio.DataChiusura
                                                      orderby item.DataInizio.GetValueOrDefault() descending
                                                      select item).FirstOrDefault();

                            _log.DebugFormat("Non trovato proprietario principale - {0} - unità:{1} - esercizio:{2}", Utility.GetMethodDescription(), spesa.IdUnita, idEsercizio.ToString());
                        }

                        var importoProprieta = spesa.ImportoProprietario;
                        if (importoProprieta != 0)
                        {
                            var soggProp = new List<ImportiDTO>();
                            if (!accorpamentoUnita)
                            {
                                var soggPropRip = (conto.SoggettiRipartizione.Where(itemSogg =>
                                                itemSogg.PercentualeRipartizione > 0 &&
                                                itemSogg.Soggetto.Tipo == TipoSoggetto.Proprietario &&
                                                itemSogg.Soggetto.UnitaImmobiliare.ID == spesa.IdUnita)).ToList();

                                // In presenza di ripartizioni personalizzate occorre dividere l'importo addebito alla proprietà tra i diversi proprietari
                                if (soggPropRip.Count > 0)
                                {
                                    var totaleSoggPropRip = soggPropRip.Sum(item => item.PercentualeRipartizione);
                                    soggProp.AddRange(from sogg in soggPropRip
                                                      let soggettoRipartizione = sogg.Soggetto
                                                      select new ImportiDTO
                                                      {
                                                          Id = soggettoRipartizione.ID,
                                                          Importo = (importoProprieta.GetValueOrDefault() * sogg.PercentualeRipartizione) / totaleSoggPropRip
                                                      });
                                }
                                else if (soggPropRip.Count == 0)
                                {
                                    IList<SoggettoCondominio> proprietariAttivi = new List<SoggettoCondominio>();
                                    if(listaProprietariAttivi.ContainsKey(spesa.IdUnita.GetValueOrDefault()))
                                        proprietariAttivi = listaProprietariAttivi[spesa.IdUnita.GetValueOrDefault()];

                                    if (proprietariAttivi.Count == 0 && proprietarioPrincipale != null)
                                        proprietariAttivi.Add(proprietarioPrincipale);

                                    soggProp.AddRange(proprietariAttivi.Select(soggAttivo => new ImportiDTO { Id = soggAttivo.ID, Importo = (importoProprieta.GetValueOrDefault() * soggAttivo.PercentualeRiferimento.GetValueOrDefault()) / 100 }));
                                }
                            }
                            else
                                soggProp.Add(new ImportiDTO(proprietarioPrincipale.ID, importoProprieta.GetValueOrDefault()));

                            foreach (var idSogg in soggProp)
                            {
                                try
                                {
                                    if (idSogg.Importo != 0)
                                    {
                                        var key = spesa.IdConto + "_" + spesa.IdUnita;
                                        if (!accorpamentoUnita)
                                            key += "_" + idSogg.Id;
                                        key += "_PROP";

                                        ReportRipartizioneBilancioDTO item;
                                        if (lista.ContainsKey(key))
                                            item = lista[key];
                                        else
                                        {
                                            item = new ReportRipartizioneBilancioDTO();
                                            lista.Add(key, item);
                                            item.IdPartecipante = idSogg.Id;
                                            item.Importo = 0;
                                            item.IdConto = spesa.IdConto;
                                            item.IdUnitaImmobiliare = spesa.IdUnita.GetValueOrDefault();
                                            item.IdStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID;
                                            item.IdGruppoStabile = unita.GruppoStabileRiferimento.ID;

                                            item.DisabilitaStampaMillesimi = conto.IsSpesePersonali || conto.DisabilitaMillesimiRiparto;

                                            var codice = string.Empty;
                                            if (conto.Codice != null)
                                                codice = conto.Codice;
                                            item.CodiceConto = codice;

                                            item.DescrizioneConto = !string.IsNullOrEmpty(conto.DescrizioneBilancio) && !dettaglioSottoConto
                                                                        ? conto.DescrizioneBilancio
                                                                        : conto.Descrizione;

                                            if (dettaglioSottoConto)
                                            {
                                                var codiceSottoConto = string.Empty;
                                                var descrizioneSottoConto = string.Empty;
                                                if (sottoconto != null)
                                                {
                                                    if (!string.IsNullOrEmpty(sottoconto.Codice))
                                                        codiceSottoConto = sottoconto.Codice;
                                                    descrizioneSottoConto = sottoconto.Descrizione;
                                                }
                                                else if (spesa.IdSottoConto < 0)
                                                {
                                                    descrizioneSottoConto = item.DescrizioneConto;
                                                    codiceSottoConto = item.CodiceConto;
                                                }

                                                item.CodiceSottoConto = codiceSottoConto;
                                                item.DescrizioneSottoConto = descrizioneSottoConto;
                                                item.IdSottoConto = spesa.IdSottoConto;
                                            }

                                            item.OrdineConto = conto.Ordine;
                                            item.TipoUnitaImmobiliare = unita.TipoUnitaImmobiliare.Descrizione;

                                            item.DescrizioneGruppoStabile = unita.GruppoStabileRiferimento.Descrizione;
                                            item.OrdineGruppoStabile = unita.GruppoStabileRiferimento.Ordine;
                                            item.DescrizioneStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Descrizione;
                                            item.OrdineStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Ordine;
                                            item.OrdineUnitaImmobiliare = unita.Ordine.GetValueOrDefault();
                                            item.SubalternoUnitaImmobiliare = unita.Subalterno;
                                            item.PianoUnitaImmobiliare = unita.Piano;
                                            item.InternoUnitaImmobiliare = getInternoUnitaImmobiliare(unita);

                                            item.Millesimi = spesa.ValoreMillesimo;
                                            item.UnitaMisuraMillesimi = spesa.UnitaMisuraMillesimo;

                                            if (!accorpamentoUnita)
                                            {
                                                var sogg = findSoggettoCondominio(idSogg.Id, soggetti);
                                                item.DataUscitaPartecipante = getDataUscita(sogg);
                                                item.Nominativo = sogg.DisplayName;
                                                item.IdPersona = sogg.Persona.ID;
                                            }
                                            else
                                            {
                                                item.DataUscitaPartecipante = getDataUscita(proprietarioPrincipale);
                                                item.Nominativo = proprietarioPrincipale.UnitaImmobiliare.Descrizione;
                                                item.IdPartecipante = proprietarioPrincipale.ID;
                                                item.IdPersona = proprietarioPrincipale.Persona.ID;
                                            }

                                            item.OrdinePartecipante = 10;
                                            item.TipoNominativo = "PROP";

                                            item.TipoNominativoEffettivo = findSoggettoCondominio(item.IdPartecipante, soggetti).Tipo.ToString().Substring(0, 1);
                                            item.NumeroColonne = 1;

                                            item.IdGruppoStabileAddebito = spesa.IdGruppoStabileAddebito;
                                            item.IdStabileAddebito = spesa.IdStabileAddebito;
                                        }
                                        item.Importo += idSogg.Importo;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - SPESE PROPRIETARI - {0} - soggetto:{1} - spesa:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), idSogg.Id, spesa.ID, idEsercizio);
                                    throw;
                                }
                            }
                        }

                        // -------------------------
                        // Conduttore
                        // -------------------------
                        if (spesa.ImportoConduttore != 0)
                        {
                            var soggCond = new List<ImportiDTO>();
                            if (!accorpamentoUnita)
                            {
                                var soggCondRip = (conto.SoggettiRipartizione.Where(
                                    itemSogg => itemSogg.PercentualeRipartizione > 0 &&
                                                itemSogg.Soggetto.Tipo == TipoSoggetto.Conduttore &&
                                                itemSogg.Soggetto.UnitaImmobiliare.ID == spesa.IdUnita)).ToList();

                                if (soggCondRip.Count > 0)
                                {
                                    var totaleSoggCondRip = soggCondRip.Sum(item => item.PercentualeRipartizione);
                                    soggCond.AddRange(soggCondRip.Select(sogg => new ImportiDTO
                                    {
                                        Id = sogg.Soggetto.ID,
                                        Importo = (spesa.ImportoConduttore.GetValueOrDefault() * sogg.PercentualeRipartizione) / totaleSoggCondRip
                                    }));
                                }
                                else if (soggCondRip.Count == 0)
                                {
                                    var conduttoriAttivi = new List<SoggettoCondominio>();
                                    if(conduttoriSoggettiAttivi.ContainsKey(spesa.IdUnita.GetValueOrDefault()))
                                        conduttoriAttivi = conduttoriSoggettiAttivi[spesa.IdUnita.GetValueOrDefault()].Where(item => item.PercentualeRiferimento > 0).ToList();
                                    if (!conduttoriAttivi.Any())
                                    {
                                        if(listaProprietariAttivi.ContainsKey(spesa.IdUnita.GetValueOrDefault()))
                                            conduttoriAttivi.AddRange(listaProprietariAttivi[spesa.IdUnita.GetValueOrDefault()]);
                                    }

                                    soggCond.AddRange(conduttoriAttivi.Select(soggAttivo => new ImportiDTO
                                    {
                                        Id = soggAttivo.ID,
                                        Importo = (spesa.ImportoConduttore.GetValueOrDefault() * soggAttivo.PercentualeRiferimento.GetValueOrDefault()) / 100
                                    }));
                                }
                            }
                            else if (proprietarioPrincipale != null)
                                soggCond.Add(new ImportiDTO(proprietarioPrincipale.ID, spesa.ImportoConduttore.GetValueOrDefault()));
                            else
                            {
                                _log.ErrorFormat("Unità immobiliare senza proprietario principale - {0} - idUnita:{1}", Utility.GetMethodDescription(), unita.ID);
                                throw new InvalidDataException($"L'unità immobiliare {unita.Descrizione} non ha un proprietario principale");
                            }

                            foreach (var idSogg in soggCond)
                            {
                                try
                                {
                                    if (idSogg.Importo != 0)
                                    {
                                        var key = spesa.IdConto + "_" + spesa.IdUnita;
                                        if (!accorpamentoUnita)
                                            key += "_" + idSogg.Id;
                                        key += "_COND";

                                        ReportRipartizioneBilancioDTO item;
                                        if (lista.ContainsKey(key))
                                            item = lista[key];
                                        else
                                        {
                                            item = new ReportRipartizioneBilancioDTO();
                                            lista.Add(key, item);
                                            item.IdPartecipante = idSogg.Id;
                                            item.Importo = 0;
                                            item.IdConto = spesa.IdConto;
                                            item.IdStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.ID;
                                            item.IdGruppoStabile = unita.GruppoStabileRiferimento.ID;
                                            item.IdUnitaImmobiliare = spesa.IdUnita.GetValueOrDefault();

                                            item.DisabilitaStampaMillesimi = conto.IsSpesePersonali || conto.DisabilitaMillesimiRiparto;

                                            var codice = string.Empty;
                                            if (conto.Codice != null)
                                                codice = conto.Codice;
                                            item.CodiceConto = codice;

                                            item.DescrizioneConto = !string.IsNullOrEmpty(conto.DescrizioneBilancio) && !dettaglioSottoConto
                                                                        ? conto.DescrizioneBilancio
                                                                        : conto.Descrizione;
                                            item.OrdineConto = conto.Ordine;

                                            if (dettaglioSottoConto)
                                            {
                                                var codiceSottoConto = string.Empty;
                                                var descrizioneSottoConto = string.Empty;
                                                if (sottoconto != null)
                                                {
                                                    if (!string.IsNullOrEmpty(sottoconto.Codice))
                                                        codiceSottoConto = sottoconto.Codice;
                                                    descrizioneSottoConto = sottoconto.Descrizione;
                                                }
                                                else if (spesa.IdSottoConto < 0)
                                                {
                                                    descrizioneSottoConto = item.DescrizioneConto;
                                                    codiceSottoConto = item.CodiceConto;
                                                }

                                                item.CodiceSottoConto = codiceSottoConto;
                                                item.DescrizioneSottoConto = descrizioneSottoConto;
                                                item.IdSottoConto = spesa.IdSottoConto;
                                            }

                                            item.TipoUnitaImmobiliare = unita.TipoUnitaImmobiliare.Descrizione;

                                            item.DescrizioneGruppoStabile = unita.GruppoStabileRiferimento.Descrizione;
                                            item.DescrizioneStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Descrizione;
                                            item.OrdineGruppoStabile = unita.GruppoStabileRiferimento.Ordine;
                                            item.OrdineStabile = unita.GruppoStabileRiferimento.PalazzinaRiferimento.Ordine;
                                            item.OrdineUnitaImmobiliare = unita.Ordine.GetValueOrDefault();
                                            item.SubalternoUnitaImmobiliare = unita.Subalterno;
                                            item.PianoUnitaImmobiliare = unita.Piano;
                                            item.InternoUnitaImmobiliare = getInternoUnitaImmobiliare(unita);
                                            item.Millesimi = spesa.ValoreMillesimo;
                                            item.UnitaMisuraMillesimi = spesa.UnitaMisuraMillesimo;

                                            if (!accorpamentoUnita)
                                            {
                                                var sogg = findSoggettoCondominio(idSogg.Id, soggetti);
                                                item.DataUscitaPartecipante = getDataUscita(sogg);
                                                item.Nominativo = sogg.DisplayName;
                                                item.IdPersona = sogg.Persona.ID;
                                            }
                                            else
                                            {
                                                item.DataUscitaPartecipante = getDataUscita(proprietarioPrincipale);
                                                item.Nominativo = proprietarioPrincipale.UnitaImmobiliare.Descrizione;
                                                item.IdPartecipante = proprietarioPrincipale.ID;
                                                item.IdPersona = proprietarioPrincipale.Persona.ID;
                                            }

                                            item.OrdinePartecipante = 20;
                                            item.TipoNominativo = "COND";
                                            item.TipoNominativoEffettivo = ripartizioneProprietarioConduttore ? "C" : findSoggettoCondominio(item.IdPartecipante, soggetti).Tipo.ToString().Substring(0, 1);

                                            item.NumeroColonne = 1;
                                        }

                                        item.Importo += idSogg.Importo;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - SPESE CONDUTTORI - {0} - soggetto:{1} - spesa:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), idSogg.Id, spesa.ID, idEsercizio);
                                    throw;
                                }
                            }
                        }

                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore inaspettato durante la lettura del datasource per il riparto del consuntivo - SPESE - {0} - spesa:{1} - esercizio:{2}", ex, Utility.GetMethodDescription(), spesa.ID, idEsercizio);
                        throw;
                    }
                }

                //==============================================================================================================
                //  Elaborazione SUBENTRI per avere una riga per ogni soggetto
                //==============================================================================================================
                elaboraSubentri(esercizio, accorpamentoUnita, lista, soggettiAttiviByUnitaImmobiliare, conti, dettaglioSottoConto);

                // ======================================================
                //  Rielaborazione nominativi
                // ======================================================
                elaborazioneNominativi(lista.Values);

                return lista.Values.ToList();
            }
        }