private DatiFornitori770 getDatiFornitore(Fornitore fornitore, Condominio condominio, int index)
        {
            var datiFornitore = new DatiFornitori770
            {
                Cognome = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Giuridica) ? fornitore.PersonaRiferimento.RagioneSociale : fornitore.PersonaRiferimento.Cognome,
                Nome = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Giuridica) ? string.Empty : fornitore.PersonaRiferimento.Nome,
                CodiceFiscale = fornitore.GetCodiceFiscale(),
                ComuneNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.ComuneNascita.Descrizione : string.Empty,
                ProvinciaNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.ComuneNascita.ProvinciaAppartenenza.Codice : string.Empty,
                DataNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.DataNascita.GetValueOrDefault().ToShortDateString() : string.Empty,
                Sesso = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.Sesso.ToString().Substring(0, 1).ToUpper() : string.Empty,
                IndirizzoCompleto = fornitore.PersonaRiferimento.IndirizzoResidenza.GetIndirizzoCompleto(),
                ComuneResidenza = fornitore.PersonaRiferimento.IndirizzoResidenza.Comune.Descrizione,
                Provincia = fornitore.PersonaRiferimento.IndirizzoResidenza.Comune.ProvinciaAppartenenza.Codice,
                CodiceFiscaleCondominio = condominio.CodiceFiscale,
                Causale = fornitore.GetTipologiaReddito(),
                ProgressivoComunicazione = index.ToString().PadLeft(8, '0')
            };

            return datiFornitore;
        }
        public ResultCreazioneFile GetModello770(int idCondominio, int idAzienda, int anno, int? idFornitoreModello770, DateTime dataDichiarazione)
        {
            byte[] bytes = null;
            var message = string.Empty;
            var numeroRecordE = 0;

            var annoModulo = string.Empty;
            if (anno > 2009)
                annoModulo = (anno + 1).ToString();

            var modulo = GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_frontespizio");
            if (modulo != null)
            {
                try
                {
                    var condominio = _daoFactory.GetCondominioDao().GetById(idCondominio, false);

                    // =============================================================================================
                    // Ritenute da inserire nel modello 770
                    // =============================================================================================
                    var ritenute = _ritenutaService.GetByCondominioAnno(idCondominio, idAzienda, anno).OrderBy(item => item.PagamentoRiferimento.Data.GetValueOrDefault());

                    // -----------------------------------------------------------------
                    // Raggruppamento per periodo riferimento, tributo, data versamento
                    // -----------------------------------------------------------------
                    var ritenutePerMese = (from item in ritenute
                                           group item by item.GetPeriodoRiferimento(false) + "¥" + item.PagamentoRiferimento.ScadenzaRiferimento.SpesaRiferimento.FornitoreRiferimento.CodiceTributo + "¥" + item.GetDataVersamento().GetValueOrDefault().ToShortDateString() into itemPerMese
                                           select itemPerMese).ToList();

                    // -----------------------------------------------------------------
                    // Raggruppamento per fornitore
                    // -----------------------------------------------------------------
                    var ritenutePerFornitore = (from item in ritenute
                                                group item by item.PagamentoRiferimento.ScadenzaRiferimento.SpesaRiferimento.FornitoreRiferimento.ID into itemPerFornitore
                                                select itemPerFornitore).ToList();

                    // =============================================================================================
                    // Creazione dei moduli
                    // =============================================================================================

                    // Importi versati in eccesso
                    var importiVersatiInEccesso = ritenute.Where(item => item.Tipo == TipoVersamentoRitenutaEnum.Eccesso).Sum(item => item.Importo.GetValueOrDefault());

                    // -----------------------------------------------------------------------------
                    // Frontespizio
                    // -----------------------------------------------------------------------------
                    var datiFrontespizio = new DatiFrontespizio770
                    {
                        CodiceFiscaleCondominio = condominio.CodiceFiscale,
                        CognomeStudio = condominio.Azienda.Descrizione,
                        CapCondominio = condominio.Indirizzo.Cap,
                        CodiceComuneCondominio = condominio.Indirizzo.Comune.CodiceCatastale,
                        DenominazioneCondominio = condominio.Descrizione,
                        IndirizzoCompletoCondominio = condominio.Indirizzo.GetIndirizzoCompleto(),
                        ProvinciaCondominio = condominio.Indirizzo.Comune.ProvinciaAppartenenza.Codice,
                        ComuneCondominio = condominio.Indirizzo.Comune.Descrizione,
                        CodiceAttivitaCondominio = "949990",
                        NaturaGiuridicaCondominio = "51",
                        SituazioneCondominio = "6",
                        StatoCondominio = "1",
                        ImpegnoPresentazione = "2",
                        CapStudio = condominio.Azienda.IndirizzoSede.Cap,
                        CivicoStudio = condominio.Azienda.IndirizzoSede.Civico,
                        ComuneStudio = condominio.Azienda.IndirizzoSede.Comune.Descrizione,
                        IndirizzoStudio = condominio.Azienda.IndirizzoSede.Indirizzo,
                        TipoIndirizzoStudio = "VIA",
                        LocalitaStudio = condominio.Azienda.IndirizzoSede.Localita,
                        NomeStudio = string.Empty,
                        CodiceFiscaleStudio = condominio.Azienda.CodiceFiscale,
                        CodiceComuneStudio = condominio.Indirizzo.Comune.CodiceCatastale,
                        CodiceFiscaleAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.CodiceFiscale,
                        CognomeAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.Cognome,
                        NomeAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.Nome,
                        ComuneNascitaAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.ComuneNascita.Descrizione,
                        DataNascitaAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.DataNascita.GetValueOrDefault().ToShortDateString(),
                        MaschioAmministratore = (condominio.Azienda.Amministratore.PersonaRiferimento.Sesso.GetValueOrDefault() == SessoEnum.Maschio) ? "1" : string.Empty,
                        FemminaAmministratore = (condominio.Azienda.Amministratore.PersonaRiferimento.Sesso.GetValueOrDefault() == SessoEnum.Femmina) ? "1" : string.Empty,
                        ProvinciaNascitaAmministratore = condominio.Azienda.Amministratore.PersonaRiferimento.ComuneNascita.ProvinciaAppartenenza.Codice,
                        CodiceCaricaAmministratore = "13",
                        ProvinciaStudio = condominio.Azienda.IndirizzoSede.Comune.ProvinciaAppartenenza.Codice,
                        DataPresentazione = dataDichiarazione.ToShortDateString(),
                        NumeroComunicazioniFornitori = idFornitoreModello770 == null ? ritenutePerFornitore.Count().ToString() : string.Empty,
                        PresenzaModelloSS = idFornitoreModello770 == null ? "1" : string.Empty,
                        PresenzaModelloST = idFornitoreModello770 == null ? "1" : string.Empty,
                        PresenzaModelloSV = string.Empty,
                        PresenzaModelloSX = idFornitoreModello770 == null && importiVersatiInEccesso > 0 ? "1" : string.Empty,
                        PresenzaModello770Ordinario = string.Empty,

                        PresenzaModelloSSLavoratoreAutonomo = idFornitoreModello770 != null ? "1" : string.Empty,
                        PresenzaModelloSTLavoratoreAutonomo = idFornitoreModello770 != null ? "1" : string.Empty,
                        PresenzaModelloSXLavoratoreAutonomo = idFornitoreModello770 != null && importiVersatiInEccesso > 0 ? "1" : string.Empty,
                        PresenzaModelloSYLavoratoreAutonomo = string.Empty,
                        NumeroComunicazioniFornitoriLavoratoreAutonomo = idFornitoreModello770 != null ? ritenutePerFornitore.Count().ToString() : string.Empty,
                        CodiceFiscaleFornitore770 = string.Empty
                    };

                    if(idFornitoreModello770 > 0)
                    {
                        var fornitoreModello770 = _daoFactory.GetFornitoreDao().Find(idFornitoreModello770.GetValueOrDefault(), false);
                        if (fornitoreModello770 != null)
                            datiFrontespizio.CodiceFiscaleFornitore770 = fornitoreModello770.GetCodiceFiscale();
                    }

                    var moduloFrontespizio = FillForm.FillStream(datiFrontespizio, (byte[])modulo, GestioneFiscaleResources.Modello770Frontespizio_FieldMapping, false, true);

                    // -----------------------------------------------------------------------------
                    // Dati Fornitori
                    // -----------------------------------------------------------------------------
                    var index = 0;
                    var moduloFornitori = new List<byte[]>(ritenutePerFornitore.Count());
                    foreach (var itemGroup in ritenutePerFornitore)
                    {
                        var fornitore = _daoFactory.GetFornitoreDao().GetById(itemGroup.Key, false);
                        index++;
                        var datiFornitore = new DatiFornitori770
                        {
                            Cognome = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Giuridica) ? fornitore.PersonaRiferimento.RagioneSociale : fornitore.PersonaRiferimento.Cognome,
                            Nome = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Giuridica) ? string.Empty : fornitore.PersonaRiferimento.Nome,
                            CodiceFiscale = fornitore.GetCodiceFiscale(),
                            ComuneNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.ComuneNascita.Descrizione : string.Empty,
                            ProvinciaNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.ComuneNascita.ProvinciaAppartenenza.Codice : string.Empty,
                            DataNascita = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.DataNascita.GetValueOrDefault().ToShortDateString() : string.Empty,
                            Sesso = (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica) ? fornitore.PersonaRiferimento.Sesso.ToString().Substring(0, 1).ToUpper() : string.Empty,
                            IndirizzoCompleto = fornitore.PersonaRiferimento.IndirizzoResidenza.GetIndirizzoCompleto(),
                            ComuneResidenza = fornitore.PersonaRiferimento.IndirizzoResidenza.Comune.Descrizione,
                            Provincia = fornitore.PersonaRiferimento.IndirizzoResidenza.Comune.ProvinciaAppartenenza.Codice,
                            CodiceFiscaleCondominio = condominio.CodiceFiscale,
                            Causale = (fornitore.CodiceTributo == "1040") ? "A" : "W",
                            ProgressivoComunicazione = index.ToString().PadLeft(8, '0')
                        };

                        if (fornitore.PersonaRiferimento.TipoPersona.GetValueOrDefault() == TipoPersonaEnum.Fisica && int.Parse(fornitore.PersonaRiferimento.ComuneNascita.Codice) > 999201)
                            datiFornitore.ProvinciaNascita = "EE";

                        // Importi
                        var speseSoggette = _spesaService.GetSoggetteRitenutaByFornitoreCondominioAnno(fornitore, condominio, anno);
                        var imponibileIva = speseSoggette.Sum(item => item.Imponibile);
                        var imponibileRitenuta = speseSoggette.Sum(item => item.GetImponibileRitenuta());
                        var altreSommeNonSoggette = Math.Truncate(imponibileIva - imponibileRitenuta);

                        datiFornitore.AltreSommeNonSoggetteARitenuta = (altreSommeNonSoggette > 0) ? altreSommeNonSoggette.ToString() : string.Empty;
                        datiFornitore.AmmontareLordoCorrisposto = Math.Truncate(imponibileIva).ToString();
                        datiFornitore.Imponibile = Math.Truncate(imponibileIva - altreSommeNonSoggette).ToString();
                        datiFornitore.Ritenute = Math.Truncate(itemGroup.Sum(item => item.Importo.GetValueOrDefault())).ToString();

                        moduloFornitori.Add(FillForm.FillStream(datiFornitore, (byte[])GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_fornitore"), GestioneFiscaleResources.Modello770Fornitore_FieldMapping, false, true));
                    }

                    // ---------------------------------------------------------------------
                    //  Quadro ST
                    // ---------------------------------------------------------------------
                    var moduloST = new List<byte[]>();
                    var datiST = new List<DatiProspettoSTBody770>();
                    var countRow = 0;
                    foreach (var itemGroup in ritenutePerMese)
                    {
                        countRow++;
                        var keys = itemGroup.Key.Split('¥');
                        var importoInteressi = itemGroup.Sum(item => item.ImportoInteressi.GetValueOrDefault());

                        // Nel calcolo dell'importo delle ritenute operate NON devono essere compresi gli importi versati in eccesso
                        var importo = itemGroup.Where(item => item.Tipo == TipoVersamentoRitenutaEnum.Normale).Sum(item => item.Importo.GetValueOrDefault());
                        var importoRitenute = importo < 1 ? 1 : Math.Truncate(importo);

                        // Nel calcolo dell'importo delle ritenute versate DEVONO essere compresi gli importi versati in eccesso
                        importo = itemGroup.Sum(item => item.ImportoConInteressi);
                        var importoVersato = importo < 1 ? 1 : Math.Truncate(importo);

                        var datiProspettoST = new DatiProspettoSTBody770
                        {
                            AnnoRiferimento = keys[0].Substring(2, 4),
                            MeseRiferimento = keys[0].Substring(0, 2),
                            CodiceTributo = keys[1],
                            RitenuteOperate = importoRitenute.ToString(),
                            Interessi = (importoInteressi > 0) ? Math.Truncate(importoInteressi).ToString() : string.Empty,
                            Ravvedimento = (importoInteressi > 0) ? "1" : string.Empty,
                            ImportoVersato = importoVersato.ToString(),
                            DataVersamento = keys[2]
                        };
                        datiST.Add(datiProspettoST);

                        if (countRow == 12)
                        {
                            numeroRecordE++;
                            var datiSTHeader = new DatiProspettoSTHeader770
                            {
                                CodiceFiscaleCondominio = condominio.CodiceFiscale,
                                NumeroModello = numeroRecordE.ToString().PadLeft(2, '0'),
                            };
                            var precompilato = FillForm.FillStream(datiSTHeader, (byte[])GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_ST"), GestioneFiscaleResources.Modello770STHeader_FieldMapping, true, true);
                            moduloST.Add(FillForm.FillStream(datiST.ToArray(), precompilato, GestioneFiscaleResources.Modello770STBody_FieldMapping, false, true));
                            countRow = 0;
                            datiST.Clear();
                        }
                    }
                    if (datiST.Count > 0)
                    {
                        numeroRecordE++;
                        var datiSTHeader = new DatiProspettoSTHeader770
                        {
                            CodiceFiscaleCondominio = condominio.CodiceFiscale,
                            NumeroModello = numeroRecordE.ToString().PadLeft(2, '0'),
                        };
                        var precompilato = FillForm.FillStream(datiSTHeader, (byte[])GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_ST"), GestioneFiscaleResources.Modello770STHeader_FieldMapping, true, true);
                        moduloST.Add(FillForm.FillStream(datiST.ToArray(), precompilato, GestioneFiscaleResources.Modello770STBody_FieldMapping, false, true));
                    }

                    // ---------------------------------------------------------------------
                    //  Quadro SX - Riepilogo dei crediti e delle compensazioni
                    // ---------------------------------------------------------------------
                    byte[] moduloSX = null;
                    if (importiVersatiInEccesso > 0)
                    {
                        var datiSX = new DatiProspettoSX770
                        {
                            CodiceFiscaleCondominio = condominio.CodiceFiscale,
                            NumeroModello = "0001",
                            ImportoRitenuteVersateEccesso = Math.Truncate(importiVersatiInEccesso).ToString()
                        };
                        moduloSX = FillForm.FillStream(datiSX, (byte[])GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_SX"), GestioneFiscaleResources.Modello770SX_FieldMapping, false, true);
                    }

                    // ---------------------------------------------------------------------
                    //  Quadro SS - Dati riassuntivi
                    // ---------------------------------------------------------------------
                    var datiSS = new DatiProspettoSS770
                    {
                        CodiceFiscaleCondominio = condominio.CodiceFiscale,
                        NumeroModello = "01",
                        ImportoRitenute = Math.Truncate(ritenute.Sum(item => item.Importo.GetValueOrDefault())).ToString()
                    };
                    var moduloSS = FillForm.FillStream(datiSS, (byte[])GestioneFiscaleResources.ResourceManager.GetObject("Modello770" + annoModulo + "_SS"), GestioneFiscaleResources.Modello770SS_FieldMapping, false, true);

                    // =============================================================================================
                    // Merge dei moduli
                    // =============================================================================================
                    var stream = new MemoryStream();
                    var doc = new PdfMerge();

                    // frontespizio
                    doc.AddDocument(moduloFrontespizio);

                    // fornitore
                    foreach (var item in moduloFornitori)
                        doc.AddDocument(item);

                    // quadro ST
                    foreach (var item in moduloST)
                        doc.AddDocument(item);

                    // quadro SX
                    if (moduloSX != null)
                        doc.AddDocument(moduloSX);

                    // quadro SS
                    doc.AddDocument(moduloSS);

                    doc.Merge(stream);

                    bytes = new byte[stream.Length];
                    stream.Seek(0, SeekOrigin.Begin);
                    stream.Read(bytes, 0, bytes.Length);
                    stream.Close();

                    return new ResultCreazioneFile(bytes, message);
                }
                catch (Exception ex)
                {
                    
                    _log.Fatal("Errore inaspettato durante la creazione del file per il modello 770 -" + Library.Utility.GetMethodDescription() + " - condominio:" + idCondominio + " - anno:" + anno, ex);
                    message = "Si sono verificati problemi inaspettati durante la generazione del modello 770." + Environment.NewLine + "Controllare il log per ulteriori dettagli.";
                    return new ResultCreazioneFile(bytes, message);
                }
            }
            return new ResultCreazioneFile(null, "Il modulo per l'anno " + annoModulo + " non è ancora disponibile");
        }