Exemple #1
0
        /// <summary>
        /// Crea un Riparto Bollette valido
        /// </summary>
        public RipartoBollette(TestataRipartoBollette testata, UnitaImmobiliare unita)
        {
            UnitaImmobiliare = unita;
            Testata = testata;

            if (Testata != null)
                Testata.Riparto.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;
            }
        }
        public AuthorizationMessages CalcoloRipartoAcqua(int idEsercizio, TipoUtenza tipoUtenza, int? idContoAcquaRiscaldata, int? idContoRiscaldamento, int? idContoMillesimiSpalo, string descrizioneMovimentoAcqua, string descrizioneMovimentoRiscaldamento, decimal? tariffaRiscaldamentoAcqua, decimal? tariffaAcquaFredda, IList<ParametriAddebitoMovimento> parametriAddebitoMovimenti, DateTime? dataRegistrazione)
        {
            try
            {
                if(!Library.Conversione.IsSqlSmallDateTime(dataRegistrazione.GetValueOrDefault()))
                    return new AuthorizationMessages("Non è possibile procedere al riparto delle bollette verificare la corettezza della data di registrazione: " + dataRegistrazione.GetValueOrDefault(), null);

                var fatalMessage = string.Empty;
                var warnMessage = string.Empty;
                var messaggioContatore = string.Empty;

                var esercizio = _daoFactory.GetEsercizioDao().GetById(idEsercizio, false);
                var utenze = _daoFactory.GetUtenzaDao().GetByCondominioTipo(esercizio.CondominioRiferimento, tipoUtenza).Where(item => item.IsAllowRipartoLetture()).ToList();
                var soggettiAttivi = _daoFactory.GetSoggettoCondominioDao().GetAttiviByEsercizio(esercizio, null);

                // ===========================================
                // Controllo presenza bollette
                // ===========================================
                var spesePresenti = false;
                var dictSpese = new Dictionary<int, IList<Spesa>>();
                foreach (var utenza in utenze)
                {
                    const string hql = "FROM Spesa SPE WHERE SPE.Utenza.RipartoLetture = 1 AND SPE.Utenza = :utenza AND SPE.EsercizioRiferimento = :esercizio";
                    var spese = _daoFactory.GetSpesaDao().GetByQuery(hql, new[] { new QueryParam("utenza", utenza), new QueryParam("esercizio", idEsercizio) });

                    // Controllo se tutte le bollette hanno la data di inizio e fine competenza
                    if (spese.Any(item => item.DataInizioCompetenza == null || item.DataFineCompetenza == null))
                    {
                        var speseSenzaCompetenza = spese.Where(item => item.DataInizioCompetenza == null || item.DataFineCompetenza == null);
                        fatalMessage = speseSenzaCompetenza.Aggregate(fatalMessage, (current, spesa) => current + ("Per La bolletta n." + spesa.NumeroDocumento + " del " + spesa.DataDocumento.GetValueOrDefault().ToShortDateString() + " non è stata definita la competenza." + Environment.NewLine));
                        _persistenceContext.RollbackAndCloseSession(Security.Login.Instance.CurrentLogin().LoginName);
                        _persistenceContext.BeginTransaction(Security.Login.Instance.CurrentLogin().LoginName, IsolationLevel.ReadUncommitted);

                        return new AuthorizationMessages(fatalMessage, warnMessage);
                    }

                    if (spese.Any(item => item.ImportoBolletta != 0))
                        spesePresenti = true;

                    dictSpese.Add(utenza.ID, spese);
                }
                if (!spesePresenti)
                {
                    fatalMessage += "Non sono presenti bollette da ripartire";
                    _persistenceContext.RollbackAndCloseSession(Security.Login.Instance.CurrentLogin().LoginName);
                    _persistenceContext.BeginTransaction(Security.Login.Instance.CurrentLogin().LoginName, IsolationLevel.ReadUncommitted);
                    return new AuthorizationMessages(fatalMessage, warnMessage);
                }

                // ===========================================
                // Se non ci sono errori elaboro tutte le utenze
                // ===========================================
                foreach (var utenza in utenze)
                {
                    DateTime? dataInizialeSpese = null;
                    DateTime? dataFinaleSpese = null;
                    DateTime? dataInizialeLetture = null;
                    DateTime? dataFinaleLetture = null;

                    var spese = dictSpese[utenza.ID];
                    spesePresenti = spese.Any(item => item.ImportoBolletta != 0);
                    if (spesePresenti)
                    {
                        dataInizialeSpese = spese.Min(item => item.DataInizioCompetenza).Value;
                        dataFinaleSpese = spese.Max(item => item.DataFineCompetenza).Value;
                    }

                    var lettureDate = new List<LetturaContatore>();

                    // Verifico le letture dei contatori escludendo quelli che prevedono un riparto lineare
                    foreach (var contatore in utenza.Contatori.Where(item => !item.IsContaCalorie))
                        lettureDate.AddRange(GetLettureByEsercizio(idEsercizio, contatore.ID));

                    var datiPresenti = false;
                    if (lettureDate.Count > 0)
                    {
                        datiPresenti = true;
                        dataInizialeLetture = lettureDate.Min(item => item.Data);
                        dataFinaleLetture = lettureDate.Max(item => item.Data);
                    }

                    if (datiPresenti && spesePresenti)
                    {
                        // =========================================================
                        //  Calcolo consumi e addebiti la competenza delle bollette
                        // =========================================================
                        var consumiAcquaCaldaLista = new List<List<ConsumoUnita>>();
                        var consumiTotali = new List<LetturaContatoreCalcoloDTO>();

                        // Calcolo consumo per ogni contatore
                        var letturePerContatore = new Dictionary<int, IList<LetturaContatoreCalcoloDTO>>();
                        var consumiPerContatore = new Dictionary<int, IList<LetturaContatoreCalcoloDTO>>();
                        foreach (var contatore in utenza.Contatori)
                        {
                            try
                            {
                                DateTime dataIniziale;
                                DateTime dataFinale;
                                if (contatore.Tipo.TipoCalcolo != TipoCalcoloContatoreEnum.AcquaCalda)
                                {
                                    dataIniziale = dataInizialeSpese.Value;
                                    dataFinale = dataFinaleSpese.Value;
                                }
                                else
                                {
                                    dataIniziale = dataInizialeLetture.Value;
                                    dataFinale = dataFinaleLetture.Value;
                                }

                                var letture = getLettureCalcoloByContatoreData(contatore, dataIniziale, dataFinale);
                                letturePerContatore.Add(contatore.ID, letture);
                                var consumi = getConsumoGiornaliero(contatore.ID, letture, dataIniziale, dataFinale);

                                // Se non sono stati calcolati consumi per il contatore considerato memorizzo il messaggio per eventualmente visualizzarlo all'utente
                                if (consumi.Count == 0)
                                {
                                    messaggioContatore += "Non sono stati trovate sufficienti letture per il Contatore: " +
                                                          contatore.Codice + " - " + contatore.Descrizione + " - Utenza: " +
                                                          utenza.Numero + " - " + utenza.Descrizione;
                                }

                                consumiPerContatore.Add(contatore.ID, consumi);

                                if (contatore.Tipo.TipoCalcolo == TipoCalcoloContatoreEnum.AcquaCalda)
                                {
                                    // ==================================================
                                    //  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());

                                    consumiAcquaCaldaLista.Add(consumiPerUnita.ToList());
                                }

                                foreach (var consumo in consumi)
                                {
                                    var consumoTotale = (from item in consumiTotali
                                                         where
                                                             item.IdUnitaImmobiliare == consumo.IdUnitaImmobiliare &&
                                                             item.Data == consumo.Data
                                                         select item).SingleOrDefault();
                                    if (consumoTotale != null)
                                        consumoTotale.Valore += consumo.Valore;
                                    else
                                        consumiTotali.Add(consumo);
                                }
                            }
                            catch (Exception ex)
                            {
                                _log.ErrorFormat("Errore durante il calcolo del consumo giornaliero (SINGOLO CONTATORE) - {0} - contatore:{1}", ex, Library.Utility.GetMethodDescription(), contatore.ID);
                                throw;
                            }
                        }

                        // Con la somma dei consumi giornalieri per contatore calcolo l'addebito
                        var addebitiCalcolati = _calcoliUtenzaService.CalcolaAddebito(esercizio, tipoUtenza, consumiTotali, descrizioneMovimentoAcqua, descrizioneMovimentoRiscaldamento, idContoAcquaRiscaldata, idContoRiscaldamento, idContoMillesimiSpalo, tariffaRiscaldamentoAcqua, tariffaAcquaFredda, true, dataRegistrazione.GetValueOrDefault());

                        // Se non sono riuscito a calcolare addebiti il riparto è fallito, visualizzo eventuali messaggi relativi ai singoli contatori come messaggi fatal
                        if (addebitiCalcolati.Count == 0)
                        {
                            fatalMessage += messaggioContatore;
                            messaggioContatore = null;
                        }
                        else
                        {
                            warnMessage += messaggioContatore;
                            messaggioContatore = null;
                        }

                        // Aggiorno letture utilizzate
                        foreach (var riparto in _calcoliUtenzaService.GetRipartoBollette())
                        {
                            foreach (var kvp in consumiPerContatore)
                            {
                                try
                                {
                                    // -----------------------------------------------------------------------------------
                                    // Se il contatore è condominiale non lo considero nei consumi dei contatori divisionali, viceversa per i conumi del contatore condominiale
                                    var contatore = _daoFactory.GetContatoreDao().GetById(kvp.Key, false);
                                    if (contatore.IsCondominiale && riparto.UnitaImmobiliare != null)
                                        continue;
                                    if (!contatore.IsCondominiale && riparto.UnitaImmobiliare == null)
                                        continue;
                                    // -----------------------------------------------------------------------------------

                                    var lettureUtilizzate = letturePerContatore[kvp.Key];

                                    // =================================================================
                                    // Lettura iniziale
                                    // =================================================================
                                    var riparto1 = riparto;

                                    var listaLettureIniziali = new SortedList<int, LetturaContatoreCalcoloDTO>();
                                    foreach (
                                        var letturaContatoreCalcoloDTO in
                                            lettureUtilizzate.Where(
                                                item =>
                                                (item.IdUnitaImmobiliare < 0 && riparto1.UnitaImmobiliare == null) ||
                                                (item.IdUnitaImmobiliare == riparto1.UnitaImmobiliare.ID)))
                                        listaLettureIniziali.Add(
                                            Math.Abs(
                                                (esercizio.DataApertura.GetValueOrDefault() -
                                                 letturaContatoreCalcoloDTO.Data).Days), letturaContatoreCalcoloDTO);
                                    var letturaIniziale = listaLettureIniziali.Values.FirstOrDefault();

                                    if (letturaIniziale == null)
                                    {
                                        var idUnitaImmobiliare = "<NULL>";
                                        if (riparto.UnitaImmobiliare != null)
                                            idUnitaImmobiliare = riparto.UnitaImmobiliare.ID.ToString();
                                        
                                        _log.Error("Le letture non sono sufficienti per poter effettuare il riparto: " + Library.Utility.GetMethodDescription() + " - Lettura Iniziale - idUnitaImmobiliare: " + idUnitaImmobiliare + " - idEsercizio: " + idEsercizio + " - tipoUtenza: " + tipoUtenza);

                                        _persistenceContext.RollbackAndCloseSession(
                                            Security.Login.Instance.CurrentLogin().LoginName);
                                        _persistenceContext.BeginTransaction(
                                            Security.Login.Instance.CurrentLogin().LoginName,
                                            IsolationLevel.ReadUncommitted);

                                        return new AuthorizationMessages("Le letture non sono sufficienti per poter effettuare il riparto" + Environment.NewLine + fatalMessage, warnMessage);
                                    }

                                    var valoreLetturaIniziale = letturaIniziale.Valore.GetValueOrDefault();
                                    var tipoLetturaIniziale = TipoLetturaEnum.Effettiva;

                                    // =================================================================
                                    // Lettura finale
                                    // =================================================================

                                    var listaLettureFinali = new SortedList<int, LetturaContatoreCalcoloDTO>();
                                    foreach (
                                        var letturaContatoreCalcoloDTO in
                                            lettureUtilizzate.Where(
                                                item =>
                                                (item.IdUnitaImmobiliare < 0 && riparto1.UnitaImmobiliare == null) ||
                                                (item.IdUnitaImmobiliare == riparto1.UnitaImmobiliare.ID)))
                                        listaLettureFinali.Add(
                                            Math.Abs(
                                                (esercizio.DataChiusura.GetValueOrDefault() -
                                                 letturaContatoreCalcoloDTO.Data).Days), letturaContatoreCalcoloDTO);
                                    var letturaFinale = listaLettureFinali.Values.FirstOrDefault();

                                    if (letturaFinale == null)
                                    {
                                        var idUnitaImmobiliare = "<NULL>";
                                        if (riparto.UnitaImmobiliare != null)
                                            idUnitaImmobiliare = riparto.UnitaImmobiliare.ID.ToString();

                                        
                                        _log.Error("Le letture non sono sufficienti per poter effettuare il riparto: " +
                                                   Library.Utility.GetMethodDescription() +
                                                   " - Lettura Finale - idUnitaImmobiliare: " + idUnitaImmobiliare +
                                                   " - idEsercizio: " + idEsercizio + " - tipoUtenza: " + tipoUtenza);

                                        _persistenceContext.RollbackAndCloseSession(
                                            Security.Login.Instance.CurrentLogin().LoginName);
                                        _persistenceContext.BeginTransaction(
                                            Security.Login.Instance.CurrentLogin().LoginName,
                                            IsolationLevel.ReadUncommitted);

                                        return
                                            new AuthorizationMessages(
                                                "Le letture non sono sufficienti per poter effettuare il riparto" +
                                                Environment.NewLine + fatalMessage, warnMessage);
                                    }

                                    var valoreLetturaFinale = letturaFinale.Valore.GetValueOrDefault();
                                    var tipoLetturaFinale = TipoLetturaEnum.Effettiva;
                                    //if (letturaFinale.Data < dataFinaleTotale)
                                    //{
                                    //    var riparto2 = riparto;
                                    //    var consumoPresunto = (from item in kvp.Value
                                    //                           where item.IdUnitaImmobiliare == riparto2.UnitaImmobiliare.ID && item.Data >= letturaFinale.Data && item.Data < dataFinaleTotale
                                    //                           select item).Sum(item => item.Valore.GetValueOrDefault());
                                    //    valoreLetturaFinale += consumoPresunto;
                                    //    tipoLetturaFinale = TipoLetturaEnum.Presunta;
                                    //}

                                    // =================================================================
                                    // Lettura cambio contatore
                                    // =================================================================
                                    LetturaContatoreCalcoloDTO letturaCambioContatore = null;
                                    var letturaPrecedente = letturaIniziale;
                                    var lettureInizialeFinale =
                                        lettureUtilizzate.Where(
                                            item =>
                                            (item.IdUnitaImmobiliare < 0 && riparto1.UnitaImmobiliare == null) ||
                                            (item.IdUnitaImmobiliare == riparto1.UnitaImmobiliare.ID) &&
                                            item.Data >= letturaIniziale.Data && item.Data <= letturaFinale.Data)
                                                         .OrderBy(item => item.Data);
                                    foreach (var letturaContatoreCalcoloDTO in lettureInizialeFinale)
                                    {
                                        if (letturaContatoreCalcoloDTO.Valore < letturaPrecedente.Valore)
                                            letturaCambioContatore = letturaPrecedente;
                                        letturaPrecedente = letturaContatoreCalcoloDTO;
                                    }

                                    var lettura = new RipartoBolletteLetture(riparto, _daoFactory.GetContatoreDao().GetById(kvp.Key, false), valoreLetturaIniziale, tipoLetturaIniziale, valoreLetturaFinale, tipoLetturaFinale)
                                        {
                                            DataLetturaIniziale = letturaIniziale.Data,
                                            DataLetturaFinale = letturaFinale.Data
                                        };
                                    if (letturaCambioContatore != null)
                                    {
                                        lettura.LetturaCambioContatore =
                                            letturaCambioContatore.Valore.GetValueOrDefault();
                                        lettura.DataLetturaCambioContatore = letturaCambioContatore.Data;
                                    }
                                    _daoFactory.GetRipartoBolletteLettureDao().SaveOrUpdate(lettura);
                                }
                                catch (Exception ex)
                                {
                                    _log.Error(
                                        "Errore durante il calcolo del riparto acqua di una bolletta (Singolo Dettaglio) - " +
                                        Library.Utility.GetMethodDescription() + " - key:" + kvp.Key +
                                        " - idEsercizio: " + idEsercizio + " - tipoUtenza: " + tipoUtenza +
                                        " - idContoAcquaRiscaldata:" + idContoAcquaRiscaldata.GetValueOrDefault() +
                                        " - idContoRiscaldamento:" + idContoRiscaldamento.GetValueOrDefault() +
                                        " - idContoMillesimiSpalo:" + idContoMillesimiSpalo.GetValueOrDefault() +
                                        " - descrizioneMovimentoAcqua:" + descrizioneMovimentoAcqua +
                                        " - descrizioneMovimentoRiscaldamento:" + descrizioneMovimentoRiscaldamento +
                                        " - tariffaRiscaldamentoAcqua:" + tariffaRiscaldamentoAcqua +
                                        " - dataRegistrazione:" + dataRegistrazione , ex);
                                    throw;
                                }
                            }
                        }

                        // ===================================================================================
                        //  Riparto separatamente le singole Bollette in percentuale sull'importo complessivo
                        // ===================================================================================
                        //const string hql = "FROM RipartoBollette RIP WHERE RIP.Esercizio = :esercizio";

                        var addebitiContatoriDivisionali = addebitiCalcolati.Where(item => item.Id > 0).ToList();
                        Conto contoMillesimiSpalo = null;
                        if (idContoMillesimiSpalo != null)
                            contoMillesimiSpalo = _daoFactory.GetContoDao().GetById(
                                idContoMillesimiSpalo.Value, false);
                        fatalMessage = spese.Select(spesa => setRipartoBolletta(spesa, addebitiContatoriDivisionali, contoMillesimiSpalo, spese.Sum(item => item.ImportoBolletta.GetValueOrDefault()), _calcoliUtenzaService.GetRipartoBollette(), soggettiAttivi)).Where(messaggio => !string.IsNullOrEmpty(messaggio)).Aggregate(fatalMessage, (current, messaggio) => current + (messaggio + Environment.NewLine));

                        // =========================================================
                        //  Calcolo costi di riscaldamento dell'Acqua
                        // =========================================================
                        // Merge tra tutte le lista di consumo acqua calda
                        // ------------------------------------------------
                        var consumiAcquaCalda = new List<ConsumoUnita>();
                        if (consumiAcquaCaldaLista.Count > 0)
                        {
                            consumiAcquaCalda = consumiAcquaCaldaLista[0];
                            foreach (var t in consumiAcquaCaldaLista)
                            {
                                foreach (var consumo in t)
                                {
                                    var primoConsumo = (from item in consumiAcquaCalda
                                                        where item.IdUnitaImmobiliare == consumo.IdUnitaImmobiliare
                                                        select item).SingleOrDefault();
                                    if (primoConsumo.IdUnitaImmobiliare > 0)
                                        primoConsumo.ConsumoTotale += consumo.ConsumoTotale;
                                    else
                                        consumiAcquaCalda.Add(consumo);
                                }
                            }
                        }

                        // Calcolo importo del riscaldamento
                        // ------------------------------------------------
                        if (tipoUtenza.IsAcqua && idContoRiscaldamento != null && idContoAcquaRiscaldata != null && tariffaRiscaldamentoAcqua != null)
                        {
                            // Elimino testate di vecchi riparti
                            foreach (var testata in esercizio.TestateContabiliRipartoAcqua)
                            {
                                testata.EsercizioRiferimento.TestateContabili.Remove(testata);
                                testata.EsercizioRiferimento = null;
                                testata.EsercizioRipartoAcqua = null;
                            }
                            esercizio.TestateContabiliRipartoAcqua.Clear();

                            var testataRiparto = new TestataRipartoBollette(esercizio, tipoUtenza, dataRegistrazione)
                                {
                                    DescrizioneMovimentoAcqua = descrizioneMovimentoAcqua,
                                    DescrizioneMovimentoRiscaldamento = descrizioneMovimentoRiscaldamento
                                };
                            if (idContoAcquaRiscaldata != null)
                                testataRiparto.ContoAcquaRiscaldamento =_daoFactory.GetContoDao().GetById(idContoAcquaRiscaldata.GetValueOrDefault(), false);
                            if (idContoRiscaldamento != null)
                                testataRiparto.ContoRiscaldamento = _daoFactory.GetContoDao().GetById(idContoRiscaldamento.GetValueOrDefault(), false);
                            if (idContoMillesimiSpalo != null)
                                testataRiparto.ContoSpalo = _daoFactory.GetContoDao().GetById(idContoMillesimiSpalo.GetValueOrDefault(), false);
                            if (tariffaRiscaldamentoAcqua != null)
                                testataRiparto.TariffaRiscaldamentoAcqua = tariffaRiscaldamentoAcqua;

                            var importiRiscaldamento = new List<ImportiDTO>(consumiAcquaCalda.Count);
                            var ripartoBollette = _calcoliUtenzaService.GetRipartoBollette();
                            foreach (var consumo in consumiAcquaCalda)
                            {
                                var riparto = (from item in ripartoBollette
                                                where item.UnitaImmobiliare.ID == consumo.IdUnitaImmobiliare
                                                select item).SingleOrDefault();
                                if (riparto != null)
                                {
                                    riparto.ConsumoAcquaCalda += consumo.ConsumoTotale;
                                    riparto.ImportoAcquaCalda += consumo.ConsumoTotale*tariffaRiscaldamentoAcqua;
                                }
                                else
                                {
                                    new RipartoBollette(testataRiparto, _daoFactory.GetUnitaImmobiliareDao().GetById(consumo.IdUnitaImmobiliare, false))
                                    {
                                        ConsumoAcquaCalda = consumo.ConsumoTotale,
                                        ImportoAcquaCalda = consumo.ConsumoTotale*tariffaRiscaldamentoAcqua
                                    };
                                }

                                importiRiscaldamento.Add(new ImportiDTO(consumo.IdUnitaImmobiliare, consumo.ConsumoTotale*tariffaRiscaldamentoAcqua.Value));
                            }
                            var newTestata = _movimentoContabileService.SetMovimentiRiscaldamentoAcqua(esercizio, idContoAcquaRiscaldata.Value, idContoRiscaldamento.Value, descrizioneMovimentoAcqua, descrizioneMovimentoRiscaldamento, importiRiscaldamento, dataRegistrazione.Value);
                            newTestata.EsercizioRipartoAcqua = esercizio;
                            esercizio.TestateContabiliRipartoAcqua.Add(newTestata);
                        }

                        // =========================================================
                        //  Calcolo importi contatori condominiali
                        // =========================================================
                        // Elimino testate di vecchi riparti
                        foreach (var testata in esercizio.TestateContabiliRipartoContatoreCondominiale)
                        {
                            testata.EsercizioRiferimento = null;
                            testata.EsercizioRipartoContatoreCondominiale = null;
                        }
                        esercizio.TestateContabiliRipartoContatoreCondominiale.Clear();

                        // Elimino parametri contatore condominiale
                        var parametriCondominiale =
                            _daoFactory.GetTestataRipartoContatoreCondominialeDao().GetByEsercizio(idEsercizio);
                        foreach (var testataRipartoContatoreCondominiale in parametriCondominiale)
                            _daoFactory.GetTestataRipartoContatoreCondominialeDao()
                                        .Delete(testataRipartoContatoreCondominiale);

                        var addebitiContatoriCondominiali = addebitiCalcolati.Where(item => item.Id < 0).ToList();
                        foreach (var importiDTO in addebitiContatoriCondominiali)
                        {
                            var dto = importiDTO;
                            var parametriMovimento =
                                parametriAddebitoMovimenti.FirstOrDefault(item => item.Id == dto.Id*-1);
                            var contoAddebito = _daoFactory.GetContoDao().GetById(parametriMovimento.IdConto, false);
                            var sottoContoAddebito =
                                _daoFactory.GetSottoContoDao().GetById(parametriMovimento.IdSottoConto, false);

                            var importoTotaleBollette = spese.Sum(item => item.ImportoBolletta.GetValueOrDefault());
                            var contiAddebito = new Dictionary<string, decimal>();
                            foreach (var spesa in spese)
                            {
                                foreach (var movimento in spesa.MovimentiBollette)
                                {
                                    var key = getKeyContoSottoconto(movimento.ContoRiferimento, movimento.SottoContoRiferimento);
                                    if (contiAddebito.ContainsKey(key))
                                        contiAddebito[key] += movimento.GetImportoConSegno().GetValueOrDefault();
                                    else
                                        contiAddebito.Add(key, movimento.GetImportoConSegno().GetValueOrDefault());
                                }
                            }

                            var importiAccredito = new List<ImportoMovimento>();
                            foreach (var importoConto in contiAddebito)
                            {
                                var contoAry = importoConto.Key.Split('|');

                                var idConto = int.Parse(contoAry[0]);
                                int? idSottoConto = null;
                                if (int.Parse(contoAry[1]) > 0)
                                    idSottoConto = int.Parse(contoAry[1]);

                                var importo = (importiDTO.Importo*importoConto.Value)/importoTotaleBollette;
                                importiAccredito.Add(new ImportoMovimento(idConto, idSottoConto, importo));
                            }
                            var testataMovimentiCondominiali = _movimentoContabileService.SetMovimentiContatoreCondominiale(esercizio, importiAccredito, addebitiContatoriDivisionali, dataRegistrazione.GetValueOrDefault(), contoAddebito, sottoContoAddebito, parametriMovimento.Descrizione);
                            testataMovimentiCondominiali.EsercizioRipartoContatoreCondominiale = esercizio;
                            esercizio.TestateContabiliRipartoContatoreCondominiale.Add(testataMovimentiCondominiali);

                            // salvo i parametri di riparto del contatore condominiale 
                            var parametriRipartoContatore =
                                _daoFactory.GetTestataRipartoContatoreCondominialeDao()
                                            .GetByEsercizioContatore(esercizio.ID, importiDTO.Id);
                            foreach (var ripartoContatoreCondominiale in parametriRipartoContatore)
                                _daoFactory.GetTestataRipartoContatoreCondominialeDao()
                                            .Delete(ripartoContatoreCondominiale);

                            var testataRipartoContatoreCondominiale = new TestataRipartoContatoreCondominiale(esercizio, _daoFactory.GetContatoreDao().GetById(importiDTO.Id*-1, false), contoAddebito, sottoContoAddebito, parametriMovimento.Descrizione);
                            _daoFactory.GetTestataRipartoContatoreCondominialeDao().SaveOrUpdate(testataRipartoContatoreCondominiale);
                        }

                    }
                    else
                    {
                        if (spesePresenti)
                        {
                            var messageSpese = spese.Aggregate(string.Empty, (current, spesa) => current + (string.Format(" - n.{0} del {1} - utenza:{2}", spesa.NumeroDocumento, spesa.DataDocumento.GetValueOrDefault().ToShortDateString(), spesa.Utenza.Numero) + Environment.NewLine));
                            fatalMessage += "Non sono presenti letture sufficienti per ripartire le seguenti bollette:" + Environment.NewLine + messageSpese;
                        }
                        else
                        {
                            warnMessage += string.Format("Per l'utenza: '{0}' non sono presenti bollette da ripartire", utenza.Descrizione.Trim());
                        }
                    }
                }

                return new AuthorizationMessages(fatalMessage, warnMessage);
            }
            catch (Exception ex)
            {
                _log.Error("Errore inaspettato durante la ripartizione delle bollette - " + Library.Utility.GetMethodDescription() + " - idEsercizio: " + idEsercizio + " - tipoUtenza: " + tipoUtenza + " - idContoAcquaRiscaldata:" + idContoAcquaRiscaldata.GetValueOrDefault() + " - idContoRiscaldamento:" + idContoRiscaldamento.GetValueOrDefault() + " - idContoMillesimiSpalo:" + idContoMillesimiSpalo.GetValueOrDefault() + " - descrizioneMovimentoAcqua:" + descrizioneMovimentoAcqua + " - descrizioneMovimentoRiscaldamento:" + descrizioneMovimentoRiscaldamento + " - tariffaRiscaldamentoAcqua:" + tariffaRiscaldamentoAcqua + " - dataRegistrazione:" + dataRegistrazione, ex);
                throw;
            }
        }
 public virtual object Clone()
 {
     var testata = new TestataRipartoBollette(Esercizio, TipoUtenza, DataRegistrazione);
     return testata;
 }