private string getKey(SpeseUnitaRipartoDTO spesa, bool dettaglioSottoConto)
 {
     if(dettaglioSottoConto)
         return $"{spesa.IdConto}&{spesa.IdSottoConto.GetValueOrDefault()}&{spesa.IdGruppoStabileAddebito}&{spesa.IdStabileAddebito}&{spesa.IdSoggettoCondominio}&{spesa.IdUnita}";
     else
         return $"{spesa.IdConto}&{spesa.IdGruppoStabileAddebito}&{spesa.IdStabileAddebito}&{spesa.IdSoggettoCondominio}&{spesa.IdUnita}";
 }
        private IEnumerable<SpeseUnitaRipartoDTO> getRiparto(IRipartizioneSpesa movimento, List<IGrouping<int, Millesimo>> millesimiGroupByConto, int? anno, int? detrazione, Esercizio esercizio, bool dettaglioSottoConto)
        {
            try
            {
                var importoProprieta = _ripartizioneService.GetImportoCompetenza(movimento.GetImportoConSegno(detrazione != null).GetValueOrDefault(), movimento, TipoSoggetto.Proprietario, anno, detrazione);
                var importoConduzione = _ripartizioneService.GetImportoCompetenza(movimento.GetImportoConSegno(detrazione != null).GetValueOrDefault(), movimento, TipoSoggetto.Conduttore, anno, detrazione);

                var millesimiConto = millesimiGroupByConto.Where(item => item.Key == movimento.ContoRiferimento.ID).ToList();
                var millesimiAttivi = new List<Millesimo>(millesimiConto.Count);
                foreach (var millesimoConto in millesimiConto)
                {
                    try
                    {
                        var millesimiGroupByUnita = millesimoConto.GroupBy(item => item.UnitaRiferimento.ID).ToList();
                        foreach (var spesa in movimento.DettaglioRipartizione)
                        {
                            try
                            {
                                IGrouping<int, Millesimo> millesimi = null;
                                if (spesa.UnitaRiferimento != null)
                                    millesimi = millesimiGroupByUnita.FirstOrDefault(item => item.Key == spesa.UnitaRiferimento.ID);
                                else if (spesa.SoggettoCondominio != null)
                                    millesimi = millesimiGroupByUnita.FirstOrDefault(item => item.Key == spesa.SoggettoCondominio.UnitaImmobiliare.ID);

                                if (millesimi != null)
                                    millesimiAttivi.AddRange(millesimi.ToList());
                            }
                            catch (Exception ex)
                            {
                                _log.ErrorFormat("Errore nel calcolo del riparto - SINGOLA SPESA - {0} - movimento:{1} - anno:{2} - esercizio:{3} - spesa:{4}", ex, Utility.GetMethodDescription(), movimento?.ID.ToString() ?? "<NULL>", anno.GetValueOrDefault(), esercizio?.ID.ToString() ?? "<NULL>", spesa?.ID.ToString() ?? "<NULL>");
                                throw;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.ErrorFormat("Errore nel calcolo del riparto - SINGOLO CONTO - {0} - movimento:{1} - anno:{2} - esercizio:{3} - conto:{4}", ex, Utility.GetMethodDescription(), movimento?.ID.ToString() ?? "<NULL>", anno.GetValueOrDefault(), esercizio?.ID.ToString() ?? "<NULL>", millesimoConto.Key);
                        throw;
                    }
                }

                IList<SpeseUnitaRipartoDTO> lista = new List<SpeseUnitaRipartoDTO>();
                if (millesimiAttivi.Count > 0)
                {
                    var totaleMillesimi = millesimiAttivi.Sum(item => item.Valore);
                    if (totaleMillesimi > 0)
                    {
                        foreach (var millesimo in millesimiAttivi)
                        {
                            // Se è definita devo usare la ripartizione specifica per conto
                            // ---------------------------------------------------------------------------------
                            var importoProprietario = (importoProprieta * millesimo.Valore) / totaleMillesimi;
                            var importoConduttore = (importoConduzione * millesimo.Valore) / totaleMillesimi;
                            var importi = getImportoProprietaConduzioneByUnita(movimento.ContoRiferimento, importoProprietario, importoConduttore, millesimo.UnitaRiferimento.ID);

                            var riparto = new SpeseUnitaRipartoDTO
                            {
                                IdConto = movimento.ContoRiferimento.ID,
                                IdUnita = millesimo.UnitaRiferimento.ID,
                                ValoreMillesimo = millesimo.Valore,
                                UnitaMisuraMillesimo = "PC",
                                ImportoProprietario = importi[0],
                                ImportoConduttore = importi[1]
                            };

                            if (dettaglioSottoConto)
                            {
                                if (movimento.SottoContoRiferimento != null)
                                    riparto.IdSottoConto = movimento.SottoContoRiferimento.ID;
                                else
                                    riparto.IdSottoConto = movimento.ID*-1;
                            }

                            lista.Add(riparto);
                        }
                    }
                    else
                    {
                        _log.WarnFormat("Totale millesimi a 0 - {0} - movimento:{1} - esercizio:{2} - anno:{3} - azienda:{4}", Utility.GetMethodDescription(), movimento.ID.ToString(), esercizio?.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>", anno, esercizio?.CondominioRiferimento.Azienda.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>");
                    }
                }
                else
                {
                    var millesimiAttiviDto = _millesimiService.GetByConto(movimento.ContoRiferimento, null, null, esercizio);
                    var totaleMillesimi = millesimiAttiviDto.Sum(item => item.Valore.GetValueOrDefault());
                    if (totaleMillesimi > 0)
                    {
                        foreach (var millesimo in millesimiAttiviDto)
                        {
                            // Se è definita devo usare la ripartizione specifica per conto
                            // ---------------------------------------------------------------------------------
                            var importoProprietario = (importoProprieta * millesimo.Valore) / totaleMillesimi;
                            var importoConduttore = (importoConduzione * millesimo.Valore) / totaleMillesimi;
                            var importi = getImportoProprietaConduzioneByUnita(movimento.ContoRiferimento, importoProprietario, importoConduttore, millesimo.IdUnitaRiferimento);

                            var riparto = new SpeseUnitaRipartoDTO
                            {
                                IdConto = movimento.ContoRiferimento.ID,
                                IdUnita = millesimo.IdUnitaRiferimento,
                                ValoreMillesimo = millesimo.Valore,
                                UnitaMisuraMillesimo = "PC",
                                ImportoProprietario = importi[0],
                                ImportoConduttore = importi[1]
                            };

                            if (dettaglioSottoConto)
                            {
                                if (movimento.SottoContoRiferimento != null)
                                    riparto.IdSottoConto = movimento.SottoContoRiferimento.ID;
                                else
                                    riparto.IdSottoConto = movimento.ID * -1;
                            }

                            lista.Add(riparto);
                        }
                    }
                    else
                    {
                        _log.WarnFormat("Totale millesimi a 0 - {0} - movimento:{1} - esercizio:{2} - anno:{3} - azienda:{4}", Utility.GetMethodDescription(), movimento.ID.ToString(), esercizio?.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>", anno, esercizio?.CondominioRiferimento.Azienda.ID.ToString(CultureInfo.InvariantCulture) ?? "<NULL>");
                    }
                }

                return lista;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore nel calcolo del riparto - {0} - movimento:{1} - anno:{2} - esercizio:{3}", ex, Utility.GetMethodDescription(), movimento?.ID.ToString() ?? "<NULL>", anno.GetValueOrDefault(), esercizio?.ID.ToString() ?? "<NULL>");
                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 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;
        }