/// <summary>
        /// Crea un dettaglio di ripartizione consumo acqua valido
        /// </summary>
        public RipartoBolletteDettaglio(RipartoBollette riparto, FasciaConsumoDettaglio dettaglioFascia, decimal consumo, decimal importoAddebitato)
        {
            Riparto = riparto;
            DettaglioFascia = dettaglioFascia;
            Consumo = consumo;
            ImportoAddebitato = importoAddebitato;

            if (Riparto != null)
                Riparto.DettaglioRipartoConsumo.Add(this);
        }
        /// <summary>
        /// Crea un dettaglio di ripartizione consumo acqua valido
        /// </summary>
        public RipartoBolletteLetture(RipartoBollette riparto, Contatore contatore, decimal letturaIniziale, TipoLetturaEnum tipoLetturaIniziale, decimal letturaFinale, TipoLetturaEnum tipoLetturaFinale)
        {
            Riparto = riparto;
            Contatore = contatore;
            LetturaIniziale = letturaIniziale;
            TipoLetturaIniziale = tipoLetturaIniziale;
            LetturaFinale = letturaFinale;
            TipoLetturaFinale = tipoLetturaFinale;

            if (Riparto != null)
                Riparto.DettaglioLetture.Add(this);
        }
        public IList<ImportiDTO> CalcolaAddebito(Esercizio esercizio, TipoUtenza tipoUtenza, IList<LetturaContatoreCalcoloDTO> consumi, string descrizioneMovimentoAcqua, string descrizioneMovimentoRiscaldamento, int? idContoAcquaRiscaldata, int? idContoRiscaldamento, int? idContoMillesimiSpalo, decimal? tariffaRiscaldamentoAcqua, decimal? tariffaAcquaFredda, bool salvaRiparto, DateTime dataRegistrazione, bool clearRiparto)
        {
            try
            {
                _ripartoBollette.Clear();
                var importiAddebito = new List<ImportiDTO>();

                if (consumi.Count > 0 && esercizio != null)
                {
                    TestataRipartoBollette testata = null;

                    // ==================================================
                    //  Elimino eventuali vecchi riparti
                    // ==================================================
                    if (clearRiparto && salvaRiparto)
                        ClearCalcoloAddebito(esercizio, tipoUtenza);
                    else
                        testata = _daoFactory.GetTestataRipartoBolletteDao().GetByEsercizioTipoUtenza(esercizio.ID, tipoUtenza.ID).FirstOrDefault();


                    // ==================================================
                    //  Raggruppo per unità per calcolare i consumi totali
                    // ==================================================
                    // Raggruppo le letture per unità immobiliare
                    var letturePerUnita = (from item in consumi
                                           group item by item.IdUnitaImmobiliare into g
                                           select new ConsumoUnita(g.Key, g.Sum(item => item.Valore.GetValueOrDefault()), g.Count())).ToList();

                    // ==================================================
                    //  Calcolo addebiti per unità
                    // ==================================================
                    importiAddebito = new List<ImportiDTO>(letturePerUnita.Count());
                    if (testata == null)
                    {
                        testata = new TestataRipartoBollette(esercizio, tipoUtenza, dataRegistrazione)
                        {
                            DescrizioneMovimentoAcqua = descrizioneMovimentoAcqua,
                            DescrizioneMovimentoRiscaldamento = descrizioneMovimentoRiscaldamento
                        };
                    }
                    if (idContoAcquaRiscaldata != null)
                        testata.ContoAcquaRiscaldamento = _daoFactory.GetContoDao().GetById(idContoAcquaRiscaldata.GetValueOrDefault(), false);
                    if (idContoRiscaldamento != null)
                        testata.ContoRiscaldamento = _daoFactory.GetContoDao().GetById(idContoRiscaldamento.GetValueOrDefault(), false);
                    if (idContoMillesimiSpalo != null)
                        testata.ContoSpalo = _daoFactory.GetContoDao().GetById(idContoMillesimiSpalo.GetValueOrDefault(), false);
                    if (tariffaRiscaldamentoAcqua != null)
                        testata.TariffaRiscaldamentoAcqua = tariffaRiscaldamentoAcqua;
                    if (tariffaAcquaFredda != null)
                        testata.TariffaAcquaFredda = tariffaAcquaFredda;
                    _daoFactory.GetTestataRipartoBolletteDao().SaveOrUpdate(testata);

                    foreach (var consumoUnita in letturePerUnita)
                    {
                        try
                        {
                            var unita = _daoFactory.GetUnitaImmobiliareDao().GetById(consumoUnita.IdUnitaImmobiliare, false);
                            if (salvaRiparto)
                            {
                                var riparto = new RipartoBollette(testata, unita);
                                _ripartoBollette.Add(riparto);
                                _daoFactory.GetRipartoBolletteDao().SaveOrUpdate(riparto);
                            }

                            //===============================
                            // CONSUMO
                            //===============================
                            var importoConsumo = consumoUnita.ConsumoTotale*tariffaAcquaFredda;

                            //===============================
                            // TOTALI
                            //===============================
                            importiAddebito.Add(new ImportiDTO(unita.ID, importoConsumo.GetValueOrDefault()));

                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - UNITA' IMMOBILIARE {0} - unità immobiliare:{1}", ex, Library.Utility.GetMethodDescription(), consumoUnita.IdUnitaImmobiliare);
                            throw;
                        }
                    }
                }

                return importiAddebito;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - {0} - esercizio:{1} - tipo utenza:{2}", ex, Library.Utility.GetMethodDescription(), esercizio != null ? esercizio.ID.ToString() : "<NULL>", tipoUtenza);
                throw;
            }
        }
        public IList<ImportiDTO> CalcolaAddebito(Esercizio esercizio, TipoUtenza tipoUtenza, IList<LetturaContatoreCalcoloDTO> consumi, string descrizioneMovimentoAcqua, string descrizioneMovimentoRiscaldamento, int? idContoAcquaRiscaldata, int? idContoRiscaldamento, int? idContoMillesimiSpalo, decimal? tariffaRiscaldamentoAcqua, decimal? tariffaAcquaFredda, bool salvaRiparto, DateTime dataRegistrazione, bool clearRiparto)
        {
            try
            {
                var importiAddebito = new List<ImportiDTO>();
                _ripartoBollette = new List<RipartoBollette>();

                if (consumi.Count > 0 && esercizio != null)
                {
                    // ==================================================
                    //  Elimino eventuali vecchi riparti
                    // ==================================================
                    if (clearRiparto && salvaRiparto && _testataRipartoBollette == null)
                        ClearCalcoloAddebito(esercizio, tipoUtenza);
                    else
                        _testataRipartoBollette = _daoFactory.GetTestataRipartoBolletteDao().GetByEsercizioTipoUtenza(esercizio.ID, tipoUtenza.ID).FirstOrDefault();

                    // ==================================================
                    //  Individuo il tariffario da applicare
                    // ==================================================
                    var condominio = esercizio.CondominioRiferimento;
                    var tariffa = condominio.Indirizzo.Comune.TariffaAcqua;

                    if (tariffa == null)
                    {
                        var ex = new Exception($"Non è stata trovata nessuna tariffa per il comune: {condominio.Indirizzo.Comune.Descrizione}");
                        _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - {0}", ex, Library.Utility.GetMethodDescription());
                        throw (ex);
                    }

                    // ==================================================
                    //  Raggruppo per unità per calcolare i consumi totali
                    // ==================================================
                    // Raggruppo i consumi per unità immobiliare
                    var consumiPerUnita = (from item in consumi
                                           group item by item.IdUnitaImmobiliare into g
                                           select new ConsumoUnita(g.Key, g.Sum(item => item.Valore.GetValueOrDefault()), g.Count())).ToList();

                    var fasceConsumo = _daoFactory.GetFasciaConsumoDettaglioDao().GetByTariffaTipo(tariffa, Sfera.Enums.TipoDettaglioBollettaEnum.Consumo);
                    var fasceConsumoQuotaFissa = _daoFactory.GetFasciaConsumoDettaglioDao().GetByTariffaTipo(tariffa, Sfera.Enums.TipoDettaglioBollettaEnum.QuotaFissa);

                    // ==================================================
                    //  Calcolo addebiti per unità
                    // ==================================================
                    importiAddebito = new List<ImportiDTO>(consumiPerUnita.Count);
                    if (_testataRipartoBollette == null)
                    {
                        _testataRipartoBollette = new TestataRipartoBollette(esercizio, tipoUtenza, dataRegistrazione)
                        {
                            DescrizioneMovimentoAcqua = descrizioneMovimentoAcqua,
                            DescrizioneMovimentoRiscaldamento = descrizioneMovimentoRiscaldamento
                        };
                    }

                    if(idContoAcquaRiscaldata != null)
                        _testataRipartoBollette.ContoAcquaRiscaldamento = _daoFactory.GetContoDao().GetById(idContoAcquaRiscaldata.GetValueOrDefault(), false);
                    if (idContoRiscaldamento != null)
                        _testataRipartoBollette.ContoRiscaldamento = _daoFactory.GetContoDao().GetById(idContoRiscaldamento.GetValueOrDefault(), false);
                    if (idContoMillesimiSpalo != null)
                        _testataRipartoBollette.ContoSpalo = _daoFactory.GetContoDao().GetById(idContoMillesimiSpalo.GetValueOrDefault(), false);
                    if (tariffaRiscaldamentoAcqua != null)
                        _testataRipartoBollette.TariffaRiscaldamentoAcqua = tariffaRiscaldamentoAcqua;
                    _daoFactory.GetTestataRipartoBolletteDao().SaveOrUpdate(_testataRipartoBollette);

                    foreach (var consumoUnita in consumiPerUnita)
                    {
                        try
                        {
                            var numeroResidenti = 2;
                            UnitaImmobiliare unita = null;
                            if (consumoUnita.IdUnitaImmobiliare > 0)
                            {
                                unita = _daoFactory.GetUnitaImmobiliareDao().GetById(consumoUnita.IdUnitaImmobiliare, false);
                                if (unita.NumeroResidenti > 0)
                                    numeroResidenti = unita.NumeroResidenti;
                            }

                            RipartoBollette riparto = null;
                            if (salvaRiparto)
                            {
                                riparto = new RipartoBollette(_testataRipartoBollette, unita) { ConsumoAcquaCalda = 0, ImportoAcquaCalda = 0 };
                                _ripartoBollette.Add(riparto);
                                _daoFactory.GetRipartoBolletteDao().SaveOrUpdate(riparto);
                            }

                            var fasceConsumoUnita = from item in fasceConsumo
                                                    where item.NumeroComponenti == numeroResidenti
                                                    orderby item.ValoreMinimo
                                                    select item;

                            //===============================
                            // CONSUMO
                            //===============================
                            // ----------------------------------------------------------------------------
                            // Loop per tutte le fasce per trovare i consumi da addebitare per ogni fascia
                            // ----------------------------------------------------------------------------
                            var consumoResiduo = (consumoUnita.ConsumoTotale * 1000) / consumoUnita.Giorni;
                            decimal importoConsumo = 0;
                            decimal consumoMassimoFasciaPrecedente = 0;
                            foreach (var dettaglioFascia in fasceConsumoUnita)
                            {
                                try
                                {
                                    if (consumoResiduo == 0)
                                        break;

                                    // tariffa per fascia attuale
                                    decimal importoTariffa = 0;
                                    var singolaTariffa = (from item in tariffa.Tariffe
                                                          where item.Tipo == Sfera.Enums.TipoDettaglioBollettaEnum.Consumo &&
                                                          item.FasciaConsumo.ID == dettaglioFascia.Fascia.ID
                                                          select item).SingleOrDefault();
                                    if (singolaTariffa != null)
                                        importoTariffa = singolaTariffa.Valore;

                                    // consumo (litri/gg) di competenza di questa fascia
                                    var consumoPerFascia = consumoResiduo;
                                    var consumoMassimoPerFascia = dettaglioFascia.ValoreMassimo - consumoMassimoFasciaPrecedente;
                                    if (consumoMassimoPerFascia < consumoPerFascia)
                                        consumoPerFascia = consumoMassimoPerFascia;

                                    // calcolo addebito (la tariffa è indicata per mc)
                                    var importoPerFascia = (consumoPerFascia * consumoUnita.Giorni) / 1000 * importoTariffa;
                                    importoConsumo += importoPerFascia;

                                    if (salvaRiparto)
                                        new RipartoBolletteDettaglio(riparto, dettaglioFascia, (consumoPerFascia * consumoUnita.Giorni) / 1000, importoPerFascia);

                                    consumoResiduo -= consumoPerFascia;
                                    consumoMassimoFasciaPrecedente = dettaglioFascia.ValoreMassimo;
                                }
                                catch (Exception ex)
                                {
                                    _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - DETTAGLIO FASCIA - {0} - unità immobiliare:{1} - dettaglio fascia:{2}", ex, Library.Utility.GetMethodDescription(), consumoUnita.IdUnitaImmobiliare, dettaglioFascia.ID);
                                    throw;
                                }
                            }

                            //===============================
                            // Quota Fissa
                            //===============================
                            var quotaFissa = 0m;
                            if(unita != null && !unita.EsclusaAddebitoQuotaFissa)
                                quotaFissa = calcoloQuotaFissa(unita, consumoUnita.ConsumoTotale, fasceConsumoQuotaFissa);
                            if (riparto != null)
                                riparto.QuotaFissa = quotaFissa;

                            //===============================
                            // Fognatura
                            //===============================
                            decimal importoTariffaFognatura = 0;
                            var singolaTariffaFognatura = (from item in tariffa.Tariffe
                                                            where item.Tipo == Sfera.Enums.TipoDettaglioBollettaEnum.Fognatura
                                                            select item).SingleOrDefault();
                            if (singolaTariffaFognatura != null)
                                importoTariffaFognatura = singolaTariffaFognatura.Valore;
                            var importoFognatura = consumoUnita.ConsumoTotale*importoTariffaFognatura;
                            if (riparto != null)
                                riparto.Fognatura = importoFognatura;

                            //===============================
                            // Depurazione
                            //===============================
                            decimal importoTariffaDepurazione = 0;
                            var singolaTariffaDepurazione = (from item in tariffa.Tariffe
                                                                where item.Tipo == Sfera.Enums.TipoDettaglioBollettaEnum.Depurazione
                                                                select item).SingleOrDefault();
                            if (singolaTariffaDepurazione != null)
                                importoTariffaDepurazione = singolaTariffaDepurazione.Valore;
                            var importoDepurazione = consumoUnita.ConsumoTotale*importoTariffaDepurazione;
                            if (riparto != null)
                                riparto.Depurazione = importoDepurazione;

                            //===============================
                            // TOTALI
                            //===============================
                            var importoImponibile = importoConsumo + quotaFissa + importoFognatura + importoDepurazione;
                            var importoIva = importoImponibile * 0.10m;
                            if (riparto != null)
                                riparto.ImportoIva = importoIva;

                            importiAddebito.Add(new ImportiDTO(consumoUnita.IdUnitaImmobiliare, importoImponibile + importoIva));

                        }
                        catch (Exception ex)
                        {
                            _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - UNITA' IMMOBILIARE {0} - unità immobiliare:{1}", ex, Library.Utility.GetMethodDescription(), consumoUnita.IdUnitaImmobiliare);
                            throw;
                        }
                    }
                }

                return importiAddebito;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("Errore inaspettato nel calcolo dell'addebito bolletta - {0} - esercizio:{1} - tipo utenza:{2}", ex, Library.Utility.GetMethodDescription(), esercizio?.ID.ToString() ?? "<NULL>", tipoUtenza);
                throw;
            }
        }