using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace Exferia_Aplicacion.Modelos_Factura_E
{
    public class INTERNO_Factura_e_Modelo
    {
        private string error;
        #region region Propiedades
        //datos de las partes implicadas
        public INTERNO_Vendedor_Factura_E_modelo Vendedor { get; set; }
        public INTERNO_Comprador_Factura_E_modelo Comprador { get; set; }

        //datos factura
        public string Identificador { get; set; }//BatchIdentifier

        public string Moneda { get; set;}
        public long NumeroFactura { get; set;}
        public String SerieDelegacion { get; set; }
        public bool FacturaOriginal { get; set; }
        INTERNO_Correcciones_Factura_E_Modelo Correcciones { get; set; }
        public DateTime Fecha{ get; set; }
        public DateTime PeriodoInicio { get; set; }
        public DateTime PeriodoFin { get; set; }
        //impuestos----------------------------------------

        INTERNO_Impuestos_Factura_E_modelo Impuesto { get; set; }
        //resumen-----------------------------------------
        public decimal TotalBruto { get; set; }
        public decimal? TotalDescuento { get; set; }
        public decimal TotalBase { get; set; }
        public decimal TotalImpuestos { get; set; }
        public decimal TotalFactura { get; set; }
        public decimal TotalPendiente { get; set; }
        public decimal TotalEjecutable { get; set; }
        public decimal? TotalAnticipo { get; set; }
        //elementos factura------------------------------
        INTERNO_Item_Factura_E_modelo[] Items { get; set; }

        #endregion
        #region Constantes
        const string FACTURA_E_NAME = "fe:Facturae";

        const string FACTURA_E_HEADER_NAME = "FileHeader";
        const string FACTURA_E_VERSION_NAME = "SchemaVersion";
        const string FACTURA_E_VERSION = "3.2.1";
        const string FACTURA_E_Modality_NAME = "Modality";
        const string FACTURA_E_Modality= "I";
        const string FACTURA_E_InvoiceIssuerType_NAME = "InvoiceIssuerType";
        const string FACTURA_E_InvoiceIssuerType = "EM";

        const string FACTURA_E_BATCH_NAME = "Batch";
        const string FACTURA_E_BATCH_ID_NAME = "BatchIdentifier";

        const string FACTURA_E_InvoicesCount_NAME = "InvoicesCount";
        const string FACTURA_E_InvoicesCount = "1";

        const string FACTURA_E_TotalInvoicesAmount_NAME = "TotalInvoicesAmount";
        const string FACTURA_E_TotalAmount_NAME = "TotalAmount";
        const string FACTURA_E_TotalOutstandingAmount_NAME = "TotalOutstandingAmount";

        const string FACTURA_E_InvoiceCurrencyCode_NAME = "InvoiceCurrencyCode";
        const string FACTURA_E_InvoiceCurrencyCode = "EUR";


        const string FACTURA_E_PARTES_NAME = "Parties";
        const string FACTURA_E_LIN_FACTURA_NAME = "Invoices";
        
        //direccion
        const string FACTURA_E_Address_NAME = "Address";
        const string FACTURA_E_PostCode_NAME = "PostCode";
        const string FACTURA_E_Town_NAME = "Town";
        const string FACTURA_E_Province_NAME = "Province";
        const string FACTURA_E_CountryCode_NAME = "CountryCode";

        //TaxIdentification
        const string FACTURA_E_PersonTypeCode_NAME = "PersonTypeCode";
        const string FACTURA_E_TaxIdentificationNumber_NAME = "TaxIdentificationNumber";
        const string FACTURA_E_ResidenceTypeCode_NAME = "ResidenceTypeCode";
        const string FACTURA_E_ResidenceTypeCode = "R";


        const string FACTURA_E_CorporateName_NAME = "CorporateName";
        const string FACTURA_E_TradeName_NAME = "TradeName";
        const string FACTURA_E_AddressInSpain_NAME = "AddressInSpain";

        //centro administrativo
        const string FACTURA_E_CentreCode_NAME = "CentreCode";
        const string FACTURA_E_RoleTypeCode_NAME = "RoleTypeCode";
        const string FACTURA_E_Name_NAME = "Name";
        const string FACTURA_E_CentreDescription_NAME = "CentreDescription";

        //SellerParty
        const string FACTURA_E_SellerParty_NAME = "SellerParty";
        //BuyerParty
        const string FACTURA_E_BuyerParty_NAME = "BuyerParty";
        const string FACTURA_E_AdministrativeCentres_NAME = "AdministrativeCentres";
        const string FACTURA_E_AdministrativeCentre_NAME = "AdministrativeCentre";



        //TaxIdentification
        const string FACTURA_E_TaxIdentification_NAME = "TaxIdentification";

        //LegalEntity
        const string FACTURA_E_LegalEntity_NAME = "LegalEntity";

        //datos contacto
        const string FACTURA_E_ContactDetails_NAME = "ContactDetails";
        const string FACTURA_E_Telephone_NAME = "Telephone";
        const string FACTURA_E_TeleFax_NAME = "TeleFax";
        const string FACTURA_E_WebAddress_NAME = "WebAddress";
        const string FACTURA_E_ElectronicMail_NAME = "ElectronicMail";

        //Invoice
        const string FACTURA_E_Invoice_NAME = "Invoice";

        const string FACTURA_E_InvoiceHeader_NAME = "InvoiceHeader";
        const string FACTURA_E_InvoiceNumber_NAME = "InvoiceNumber";
        const string FACTURA_E_InvoiceSeriesCode_NAME = "InvoiceDocumentType";
        const string FACTURA_E_ReasonCode_NAME = "ReasonCode";
        const string FACTURA_E_ReasonCode = "01";

        const string FACTURA_E_InvoiceDocumentType_NAME = "InvoiceDocumentType";
        const string FACTURA_E_InvoiceDocumentType = "FC";

        const string FACTURA_E_InvoiceClass_NAME = "InvoiceClass";

        const string FACTURA_E_Corrective_NAME = "Corrective";
        const string FACTURA_E_ReasonDescription_NAME = "ReasonDescription";
        const string FACTURA_E_CorrectionMethodDescription_NAME = "CorrectionMethodDescription";
        const string FACTURA_E_CorrectionMethod_NAME = "CorrectionMethod";
        const string FACTURA_E_CorrectionMethod = "01";

        const string FACTURA_E_AdditionalReasonDescription_NAME = "AdditionalReasonDescription";
        const string FACTURA_E_TaxPeriod_NAME = "TaxPeriod";
        const string FACTURA_E_StartDate_NAME = "StartDate";
        const string FACTURA_E_EndDate_NAME = "EndDate";

        const string FACTURA_E_InvoiceIssueData_NAME = "InvoiceIssueData";
        const string FACTURA_E_InvoicingPeriod_NAME = "InvoicingPeriod";
        const string FACTURA_E_IssueDate_NAME = "IssueDate";
        const string FACTURA_E_TaxesOutputs_NAME = "TaxesOutputs";

        //const string FACTURA_E_InvoiceCurrencyCode_NAME = "InvoiceCurrencyCode";
        const string FACTURA_E_TaxCurrencyCode_NAME = "TaxCurrencyCode";
        const string FACTURA_E_LanguageName_NAME = "LanguageName";
        const string FACTURA_E_LanguageName = "es";



        //impuestos
        const string FACTURA_E_Tax_NAME = "Tax";
        const string FACTURA_E_TaxTypeCode_NAME = "TaxTypeCode";
        const string FACTURA_E_TaxRate_NAME = "TaxRate";
        const string FACTURA_E_TaxableBase_NAME = "TaxableBase";
        //const string FACTURA_E_TotalAmount_NAME = "TotalAmount";
        const string FACTURA_E_TaxAmount_NAME = "TaxAmount";

        //total (InvoiceTotals)
        const string FACTURA_E_InvoiceTotals_NAME = "InvoiceTotals";
 
        const string FACTURA_E_TotalGrossAmount_NAME = "TotalGrossAmount";
        const string FACTURA_E_TotalGeneralDiscounts_NAME = "TotalGeneralDiscounts";
        const string FACTURA_E_TotalGrossAmountBeforeTaxes_NAME = "TotalGrossAmountBeforeTaxes";
        const string FACTURA_E_TotalTaxOutputs_NAME = "TotalTaxOutputs";
        const string FACTURA_E_TotalTaxesWithheld_NAME = "TotalTaxesWithheld";
        const string FACTURA_E_TotalTaxesWithheld = "0.0";



        //const string FACTURA_E_TotalTaxesWithheld_NAME = "TotalTaxesWithheld";
        //const string FACTURA_E_TotalOutstandingAmount_NAME = "TotalOutstandingAmount";
        const string FACTURA_E_TotalPaymentsOnAccount_NAME = "TotalPaymentsOnAccount";
        const string FACTURA_E_TotalExecutableAmount_NAME = "TotalExecutableAmount";
        //const string FACTURA_E_InvoiceTotals_NAME = "InvoiceTotals";

        //items
        const string FACTURA_E_Items_NAME = "Items";
        const string FACTURA_E_InvoiceLine_NAME = "InvoiceLine";
        const string FACTURA_E_DeliveryNote_NAME = "DeliveryNote";
        const string FACTURA_E_DeliveryNoteNumber = "DeliveryNoteNumber";
        const string FACTURA_E_DeliveryNoteDate_NAME = "DeliveryNoteDate";
        const string FACTURA_E_ItemDescription_NAME = "ItemDescription";
        const string FACTURA_E_Quantity_NAME = "Quantity";
        const string FACTURA_E_UnitOfMeasure_NAME = "UnitOfMeasure";
        const string FACTURA_E_UnitOfMeasure = "01";

        const string FACTURA_E_UnitPriceWithoutTax_NAME = "UnitPriceWithoutTax";
        const string FACTURA_E_TotalCost_NAME = "TotalCost";

        const string FACTURA_E_DiscountsAndRebates_NAME = "DiscountsAndRebates";
        const string FACTURA_E_Discount_NAME = "Discount";
        const string FACTURA_E_DiscontReason_NAME = "DiscontReason";
        const string FACTURA_E_DiscountRate_NAME = "DiscountRate";
        const string FACTURA_E_DiscountAmount_NAME = "DiscountAmount";

        const string FACTURA_E_GrossAmount_NAME = "GrossAmount";
        //const string FACTURA_E_TaxesOutputs_NAME = "TaxesOutputs";
        const string FACTURA_E_TransactionDate_NAME = "TransactionDate";
        const string FACTURA_E_AdditionalLineItemInformation_NAME = "AdditionalLineItemInformation";
        const string FACTURA_E_ArticleCode_NAME = "ArticleCode";








        #endregion
        #region Constructores
        public INTERNO_Factura_e_Modelo()
        {
            Moneda = "EUR";
            Vendedor = new INTERNO_Vendedor_Factura_E_modelo();
            Comprador = new INTERNO_Comprador_Factura_E_modelo();
        }
        #endregion
        #region Metodos
        public string importarXML(string path)
        {
            error = "";
            string res = null;
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(path);
                //busca incio factura e
                foreach (XmlNode node in doc.DocumentElement.ChildNodes)
                {
                    if(node.Name!=null && node.Name== FACTURA_E_NAME)
                    {
                        res= leeXML(node);
                        if(res!=null)
                        {
                            res = "Error al importar XML: " + path +" Error: " +res;
                        }
                        return res;
                    }
                }
                res = "Error al importar XML: " + path + " Error: Formato de archivo no valido.";
            }
            catch (Exception e)
            {
                res = "Error al importar XML: " + path + " Error: " + e.Message;
            }
                


            return res;
        }

        public string exportarXML(string path)
        {
            error = "";
            string res = null;
            XmlDocument doc = new XmlDocument();
            try
            {
                XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
                XmlElement root = doc.DocumentElement;
                doc.InsertBefore(xmlDeclaration, root);
                XmlElement factura = doc.CreateElement(string.Empty, FACTURA_E_NAME, string.Empty);
                res = grabaXML(doc, factura);
                if (res != null)
                {
                    res = "Error al grabar XML: " + path + " Error: " + res;
                }
                doc.AppendChild(factura);
                doc.Save(path);
            }
            catch (Exception e)
            {
                res = "Error al exportar XML: " + path + " Error: " + e.Message;
            }



            return res;
        }
        #endregion
        #region GrabaEscrituraXML
        private string grabaXML(XmlDocument doc, XmlElement factura)
        {
            string res = null;
            XmlElement header = doc.CreateElement(string.Empty, FACTURA_E_HEADER_NAME, string.Empty);
            XmlElement parties = doc.CreateElement(string.Empty, FACTURA_E_PARTES_NAME, string.Empty);
            XmlElement items = doc.CreateElement(string.Empty, FACTURA_E_LIN_FACTURA_NAME, string.Empty);

            res = grabaCabecera(doc, header);
            if (res != null)
                return res;
            factura.AppendChild(header);

            res = grabaPartesInvolucradas(doc, parties);
            if (res != null)
                return res;
            factura.AppendChild(parties);
            res = grabaLineasFactura(doc, items);
            if (res != null)
                return res;
            factura.AppendChild(items);
            return res;
        }

        private string grabaCabecera(XmlDocument doc, XmlElement cab)
        {
            string res = null;
            try
            {
                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_VERSION_NAME, string.Empty);
                nod.InnerText = FACTURA_E_VERSION;
                cab.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_Modality_NAME, string.Empty);
                nod.InnerText = FACTURA_E_Modality;
                cab.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceIssuerType_NAME, string.Empty);
                nod.InnerText = FACTURA_E_InvoiceIssuerType;
                cab.AppendChild(nod);

                //batch
                XmlElement batch = doc.CreateElement(string.Empty, FACTURA_E_BATCH_NAME, string.Empty);

                nod = doc.CreateElement(string.Empty, FACTURA_E_BATCH_ID_NAME, string.Empty);
                nod.InnerText = Identificador;
                batch.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoicesCount_NAME, string.Empty);
                nod.InnerText = FACTURA_E_InvoicesCount;
                batch.AppendChild(nod);

                XmlElement nod2 = doc.CreateElement(string.Empty, FACTURA_E_TotalInvoicesAmount_NAME, string.Empty);
                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalAmount_NAME, string.Empty);
                nod.InnerText = TotalFactura.ToString();
                nod2.AppendChild(nod);
                batch.AppendChild(nod2);

                nod2 = doc.CreateElement(string.Empty, FACTURA_E_TotalOutstandingAmount_NAME, string.Empty);
                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalAmount_NAME, string.Empty);
                nod.InnerText = TotalPendiente.ToString();
                nod2.AppendChild(nod);
                batch.AppendChild(nod2);

                nod2 = doc.CreateElement(string.Empty, FACTURA_E_TotalExecutableAmount_NAME, string.Empty);
                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalAmount_NAME, string.Empty);
                nod.InnerText = TotalFactura.ToString();
                nod2.AppendChild(nod);
                batch.AppendChild(nod2);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceCurrencyCode_NAME, string.Empty);
                nod.InnerText = FACTURA_E_InvoiceCurrencyCode;
                batch.AppendChild(nod);

                cab.AppendChild(batch);
            }
            catch(Exception e)
            {
                res = "Error en " + nameof(grabaCabecera) + ": " + e.Message;
            }
            return res;
           
            
        }
        private string grabaPartesInvolucradas(XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                //SellerParty
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_SellerParty_NAME, string.Empty);
                res = grabaTaxIdentification(Vendedor, doc, nbase);
                if (res != null)
                    return res;

                res = grabaLegalEntity(Vendedor, doc, nbase, true);
                if (res != null)
                    return res;
                nodo.AppendChild(nbase);
                //comprador
                nbase = doc.CreateElement(string.Empty, FACTURA_E_BuyerParty_NAME, string.Empty);
                res = grabaTaxIdentification(Comprador, doc, nbase);
                if (res != null)
                    return res;
                //centros administrativos
                if(Comprador.Centros!=null && Comprador.Centros.Length>0)
                {
                    XmlElement ncentros = doc.CreateElement(string.Empty, FACTURA_E_AdministrativeCentres_NAME, string.Empty);
                    foreach (var centro in Comprador.Centros)
                    {
                        if (centro == null)
                            continue;
                        res = grabaCentroAdministrativo(centro, doc, ncentros);
                        if (res != null)
                            return res;
                    }
                    nbase.AppendChild(ncentros);

                }
                
                res = grabaLegalEntity(Comprador, doc, nbase);
                if (res != null)
                    return res;
                nodo.AppendChild(nbase);

            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaPartesInvolucradas) + ": " + e.Message;
            }
            return res;
        }
        private string grabaLineasFactura(XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_Invoice_NAME, string.Empty);
                //head
                XmlElement nheader = doc.CreateElement(string.Empty, FACTURA_E_InvoiceHeader_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceNumber_NAME, string.Empty);
                nod.InnerText = NumeroFactura.ToString();
                nheader.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceSeriesCode_NAME, string.Empty);
                nod.InnerText = SerieDelegacion;
                nheader.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceDocumentType_NAME, string.Empty);
                nod.InnerText = FACTURA_E_InvoiceDocumentType;
                nheader.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceClass_NAME, string.Empty);
                nod.InnerText = FacturaOriginal?"OO":"OR";
                nheader.AppendChild(nod);
                
                if (!FacturaOriginal && Correcciones!=null)
                {
                    res = grabaCorreccion(Correcciones, doc, nheader);
                    if (res != null)
                        return res;
                }
                nbase.AppendChild(nheader);

                res = grabaInvoiceIssueData(doc, nbase);
                if (res != null)
                    return res;

                //TaxesOutputs
                XmlElement nTaxesOutputs = doc.CreateElement(string.Empty, FACTURA_E_TaxesOutputs_NAME, string.Empty);
                res = grabaImpuestos(Impuesto, doc, nTaxesOutputs);
                if(res != null)
                    return res;
                nbase.AppendChild(nTaxesOutputs);
                //InvoiceTotals
                res = grabaInvoiceTotals(doc, nbase);
                if (res != null)
                    return res;
                //Items
                if(Items!= null && Items.Length>0)
                {
                    XmlElement nItems = doc.CreateElement(string.Empty, FACTURA_E_Items_NAME, string.Empty);

                    foreach( var item in Items)
                    {
                        res = grabaItem(item, doc, nItems);
                        if (res != null)
                            return res;
                    }

                    nbase.AppendChild(nItems);
                }
                
                nodo.AppendChild(nbase);



            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaPartesInvolucradas) + ": " + e.Message;
            }
            return res;
        }

        private string grabaTaxIdentification(INTERNO_Entidad_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement taxn = doc.CreateElement(string.Empty, FACTURA_E_TaxIdentification_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_PersonTypeCode_NAME, string.Empty);
                nod.InnerText = dat.Tipo;
                taxn.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_ResidenceTypeCode_NAME, string.Empty);
                nod.InnerText = FACTURA_E_ResidenceTypeCode;
                taxn.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_TaxIdentificationNumber_NAME, string.Empty);
                nod.InnerText = dat.IdImpuestos;
                taxn.AppendChild(nod);

                nodo.AppendChild(taxn);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaTaxIdentification) + ": " + e.Message;
            }
            return res;
        }

        private string grabaDireccon(INTERNO_Direccion_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_AddressInSpain_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_Address_NAME, string.Empty);
                nod.InnerText = dat.Direccion;
                nbase.AppendChild(nod);
                
                nod = doc.CreateElement(string.Empty, FACTURA_E_PostCode_NAME, string.Empty);
                nod.InnerText = dat.CP;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_Town_NAME, string.Empty);
                nod.InnerText = dat.Poblacion;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_Province_NAME, string.Empty);
                nod.InnerText = dat.Provincia;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_CountryCode_NAME, string.Empty);
                nod.InnerText = dat.Pais;
                nbase.AppendChild(nod);

                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaDireccon) + ": " + e.Message;
            }
            return res;
        }
        private string grabaContacto(INTERNO_Direccion_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nod;
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_ContactDetails_NAME, string.Empty);
                if (dat.Tlf != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_Telephone_NAME, string.Empty);
                    nod.InnerText = dat.Tlf;
                    nbase.AppendChild(nod);
                }
                if (dat.Fax != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_TeleFax_NAME, string.Empty);
                    nod.InnerText = dat.Fax;
                    nbase.AppendChild(nod);
                }
                if (dat.Web != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_WebAddress_NAME, string.Empty);
                    nod.InnerText = dat.Web;
                    nbase.AppendChild(nod);
                }
                if (dat.Email != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_ElectronicMail_NAME, string.Empty);
                    nod.InnerText = dat.Email;
                    nbase.AppendChild(nod);
                }

                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaContacto) + ": " + e.Message;
            }
            return res;
        }
        private string grabaLegalEntity(INTERNO_Entidad_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo, bool contacto=false)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_LegalEntity_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_CorporateName_NAME, string.Empty);
                nod.InnerText = dat.RazonSocial;
                nbase.AppendChild(nod);
                if (dat.NombreComercial != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_TradeName_NAME, string.Empty);
                    nod.InnerText = dat.NombreComercial;
                    nbase.AppendChild(nod);
                }
                res=grabaDireccon(dat, doc, nbase);
                if (res != null)
                    return res;
                if(contacto)
                {
                    res = grabaContacto(dat, doc, nbase);
                    if (res != null)
                        return res;
                }

                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaLegalEntity) + ": " + e.Message;
            }
            return res;
        }
        private string grabaCentroAdministrativo(INTERNO_CentroAdministrativo_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_AdministrativeCentre_NAME, string.Empty);

                XmlElement nod;
                if (dat.Codigo != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_CentreCode_NAME, string.Empty);
                    nod.InnerText = dat.Codigo;
                    nbase.AppendChild(nod);
                }
                if (dat.Role != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_RoleTypeCode_NAME, string.Empty);
                    nod.InnerText = dat.Role;
                    nbase.AppendChild(nod);
                }
                if (dat.Encargado != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_Name_NAME, string.Empty);
                    nod.InnerText = dat.Encargado;
                    nbase.AppendChild(nod);
                }
                res = grabaDireccon(dat, doc, nbase);
                if (res != null)
                    return res;
                if (dat.Descripcion != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_CentreDescription_NAME, string.Empty);
                    nod.InnerText = dat.Descripcion;
                    nbase.AppendChild(nod);
                }
                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaCentroAdministrativo) + ": " + e.Message;
            }
            return res;
        }
        private string grabaCorreccion(INTERNO_Correcciones_Factura_E_Modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_Corrective_NAME, string.Empty);
                XmlElement nod;
                if (dat.NumeroFactura != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceNumber_NAME, string.Empty);
                    nod.InnerText = dat.NumeroFactura.ToString();
                    nbase.AppendChild(nod);
                }
                if (dat.SerieDelegacion != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceSeriesCode_NAME, string.Empty);
                    nod.InnerText = dat.SerieDelegacion.ToString();
                    nbase.AppendChild(nod);
                }
                nod = doc.CreateElement(string.Empty, FACTURA_E_ReasonCode_NAME, string.Empty);
                nod.InnerText = FACTURA_E_ReasonCode;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_ReasonDescription_NAME, string.Empty);
                nod.InnerText = dat.RazonCode;
                nbase.AppendChild(nod);

                XmlElement nTaxPeriod = doc.CreateElement(string.Empty, FACTURA_E_TaxPeriod_NAME, string.Empty);

                nod = doc.CreateElement(string.Empty, FACTURA_E_StartDate_NAME, string.Empty);
                nod.InnerText = toStr(dat.Inicio); 
                nTaxPeriod.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_EndDate_NAME, string.Empty);
                nod.InnerText = toStr(dat.Fin);
                nTaxPeriod.AppendChild(nod);

                nbase.AppendChild(nTaxPeriod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_CorrectionMethod_NAME, string.Empty);
                nod.InnerText = FACTURA_E_CorrectionMethod;
                nbase.AppendChild(nod);

                if (dat.RazonCorreccion != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_CorrectionMethodDescription_NAME, string.Empty);
                    nod.InnerText = dat.RazonCorreccion;
                    nbase.AppendChild(nod);
                }
                if (dat.Observaciones != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_AdditionalReasonDescription_NAME, string.Empty);
                    nod.InnerText = dat.Observaciones;
                    nbase.AppendChild(nod);
                }
                               

                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaCorreccion) + ": " + e.Message;
            }
            return res;
        }

        private string grabaInvoiceIssueData(XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_InvoiceIssueData_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_IssueDate_NAME, string.Empty);
                nod.InnerText = toStr(Fecha);
                nbase.AppendChild(nod);
                if (PeriodoInicio != null && PeriodoFin != null)
                {
                    XmlElement nbase2 = doc.CreateElement(string.Empty, FACTURA_E_InvoicingPeriod_NAME, string.Empty);

                    nod = doc.CreateElement(string.Empty, FACTURA_E_StartDate_NAME, string.Empty);
                    nod.InnerText = toStr(PeriodoInicio);
                    nbase2.AppendChild(nod);
                    nod = doc.CreateElement(string.Empty, FACTURA_E_EndDate_NAME, string.Empty);
                    nod.InnerText = toStr(PeriodoFin);
                    nbase2.AppendChild(nod);
                    nbase.AppendChild(nbase2);
                }

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceCurrencyCode_NAME, string.Empty);
                nod.InnerText = Moneda;
                nbase.AppendChild(nod);
                nod = doc.CreateElement(string.Empty, FACTURA_E_TaxCurrencyCode_NAME, string.Empty);
                nod.InnerText = Moneda;
                nbase.AppendChild(nod);
                nod = doc.CreateElement(string.Empty, FACTURA_E_LanguageName_NAME, string.Empty);
                nod.InnerText = FACTURA_E_LanguageName;
                nbase.AppendChild(nod);
                
                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaInvoiceIssueData) + ": " + e.Message;
            }
            return res;
        }
        private string grabaImpuestos(INTERNO_Impuestos_Factura_E_modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                if (dat.Porcentaje != null || dat.Tipo != null || dat.Base != null || dat.Importe != null)
                {
                    XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_Tax_NAME, string.Empty);

                    XmlElement nod;
                    if (dat.Tipo != null)
                    {
                        nod = doc.CreateElement(string.Empty, FACTURA_E_TaxTypeCode_NAME, string.Empty);
                        nod.InnerText = toStr(dat.Tipo.Value);
                        nbase.AppendChild(nod);
                    }
                    if (dat.Porcentaje != null)
                    {
                        nod = doc.CreateElement(string.Empty, FACTURA_E_TaxRate_NAME, string.Empty);
                        nod.InnerText = toStr(dat.Porcentaje.Value);
                        nbase.AppendChild(nod);
                    }
                    XmlElement nbase2;
                    if (dat.Base != null)
                    {
                        nbase2 = doc.CreateElement(string.Empty, FACTURA_E_TaxableBase_NAME, string.Empty);
                        nod = doc.CreateElement(string.Empty, FACTURA_E_TotalAmount_NAME, string.Empty);
                        nod.InnerText = toStr(dat.Base.Value);
                        nbase2.AppendChild(nod);
                        nbase.AppendChild(nbase2);
                    }
                    if (dat.Importe != null)
                    {
                        nbase2 = doc.CreateElement(string.Empty, FACTURA_E_TaxAmount_NAME, string.Empty);
                        nod = doc.CreateElement(string.Empty, FACTURA_E_TotalAmount_NAME, string.Empty);
                        nod.InnerText = toStr(dat.Importe.Value);
                        nbase2.AppendChild(nod);
                        nbase.AppendChild(nbase2);
                    }
                    nodo.AppendChild(nbase);
                }
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaImpuestos) + ": " + e.Message;
            }
            return res;
        }

        private string grabaInvoiceTotals(XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_InvoiceTotals_NAME, string.Empty);

                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_TotalGrossAmount_NAME, string.Empty);
                nod.InnerText = toStr(TotalBruto);
                nbase.AppendChild(nod);
                if(TotalDescuento!=null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_TotalGeneralDiscounts_NAME, string.Empty);
                    nod.InnerText = toStr(TotalDescuento.Value);
                    nbase.AppendChild(nod);
                }
              

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalGrossAmountBeforeTaxes_NAME, string.Empty);
                nod.InnerText = toStr(TotalBase);
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalTaxOutputs_NAME, string.Empty);
                nod.InnerText = toStr(TotalImpuestos);
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalTaxesWithheld_NAME, string.Empty);
                nod.InnerText = FACTURA_E_TotalTaxesWithheld;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_InvoiceTotals_NAME, string.Empty);
                nod.InnerText = toStr(TotalFactura);
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalOutstandingAmount_NAME, string.Empty);
                nod.InnerText = toStr(TotalPendiente);
                nbase.AppendChild(nod);

                if (TotalAnticipo != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_TotalPaymentsOnAccount_NAME, string.Empty);
                    nod.InnerText = toStr(TotalAnticipo.Value);
                    nbase.AppendChild(nod);
                }

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalExecutableAmount_NAME, string.Empty);
                nod.InnerText = toStr(TotalEjecutable);
                nbase.AppendChild(nod);
                
                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaInvoiceTotals) + ": " + e.Message;
            }
            return res;
        }
        private string grabaItem(INTERNO_Item_Factura_E_modelo dat, XmlDocument doc, XmlElement nodo)
        {
            string res = null;
            try
            {
                XmlElement nbase = doc.CreateElement(string.Empty, FACTURA_E_InvoiceLine_NAME, string.Empty);
                XmlElement nbase2 = doc.CreateElement(string.Empty, FACTURA_E_DeliveryNote_NAME, string.Empty);


                XmlElement nod = doc.CreateElement(string.Empty, FACTURA_E_DeliveryNoteNumber, string.Empty);
                nod.InnerText = dat.Codigo;
                nbase2.AppendChild(nod);

                if (dat.FechaAlbaran != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_DeliveryNoteDate_NAME, string.Empty);
                    nod.InnerText = toStr(dat.FechaAlbaran);
                    nbase2.AppendChild(nod);
                }
                nbase.AppendChild(nbase2);

                nod = doc.CreateElement(string.Empty, FACTURA_E_ItemDescription_NAME, string.Empty);
                nod.InnerText = dat.Descripcion;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_Quantity_NAME, string.Empty);
                nod.InnerText = toStr(dat.Cantidad);
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_UnitOfMeasure_NAME, string.Empty);
                nod.InnerText = FACTURA_E_UnitOfMeasure;
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_UnitPriceWithoutTax_NAME, string.Empty);
                nod.InnerText = toStr(dat.Precio);
                nbase.AppendChild(nod);

                nod = doc.CreateElement(string.Empty, FACTURA_E_TotalCost_NAME, string.Empty);
                nod.InnerText = toStr(dat.Total);
                nbase.AppendChild(nod);
                if (dat.DescuentoPorcentaje != null || dat.Descuentoimporte != null)
                {
                    nbase2 = doc.CreateElement(string.Empty, FACTURA_E_DiscountsAndRebates_NAME, string.Empty);
                    var nbase3 = doc.CreateElement(string.Empty, FACTURA_E_Discount_NAME, string.Empty);
                    if (dat.DescuentoRazon != null)
                    {
                        nod = doc.CreateElement(string.Empty, FACTURA_E_DiscontReason_NAME, string.Empty);
                        nod.InnerText = dat.DescuentoRazon;
                        nbase3.AppendChild(nod);
                    }
                    if (dat.DescuentoPorcentaje != null)
                    {
                        nod = doc.CreateElement(string.Empty, FACTURA_E_DiscountRate_NAME, string.Empty);
                        nod.InnerText = toStr(dat.DescuentoPorcentaje.Value);
                        nbase3.AppendChild(nod);
                    }
                    if (dat.Descuentoimporte != null)
                    {
                        nod = doc.CreateElement(string.Empty, FACTURA_E_DiscountAmount_NAME, string.Empty);
                        nod.InnerText = toStr(dat.Descuentoimporte.Value);
                    }
                    nbase3.AppendChild(nod);

                    nbase2.AppendChild(nbase3);
                    nbase.AppendChild(nbase2);
                }

                nod = doc.CreateElement(string.Empty, FACTURA_E_GrossAmount_NAME, string.Empty);
                nod.InnerText = toStr(dat.ImporteBruto);
                nbase.AppendChild(nod);

                res = grabaImpuestos(dat, doc, nbase);
                if (res != null)
                    return res;

                if (dat.FechaAlbaran != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_TransactionDate_NAME, string.Empty);
                    nod.InnerText = toStr(dat.FechaAlbaran);
                    nbase.AppendChild(nod);
                }
                if (dat.Adicional != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_AdditionalLineItemInformation_NAME, string.Empty);
                    nod.InnerText = dat.Adicional;
                    nbase.AppendChild(nod);
                }
                if (dat.CodigoArticulo != null)
                {
                    nod = doc.CreateElement(string.Empty, FACTURA_E_AdditionalLineItemInformation_NAME, string.Empty);
                    nod.InnerText = dat.CodigoArticulo;
                    nbase.AppendChild(nod);
                }
                
                nodo.AppendChild(nbase);
            }
            catch (Exception e)
            {
                res = "Error en " + nameof(grabaItem) + ": " + e.Message;
            }
            return res;
        }
        string toStr(DateTime t)
        {
           return t.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
        }
        string toStr(long t)
        {
            return t.ToString();
        }
        string toStr(decimal t)
        {
            return t.ToString();
        }
        
        #endregion
        #region LecturaXML
        private string leeXML(XmlNode factura)
        {
            string res = null;
            bool cab, part, lin;
            cab = part = lin = false;

            foreach (XmlNode node in factura.ChildNodes)
            {
                if (node.Name == null)
                    continue;
                string name = node.Name.ToUpper();
                if (node.Name == FACTURA_E_HEADER_NAME.ToUpper())
                {
                    if(cab)
                        return "Estructura de archivo no valida, tiene dos " + FACTURA_E_HEADER_NAME;

                    cab = true;
                    res = leeCabecera(node);
                    if (res != null)
                        return res;
                }
                else if (node.Name == FACTURA_E_PARTES_NAME.ToUpper())
                {
                    if (part)
                        return "Estructura de archivo no valida, tiene dos " + FACTURA_E_HEADER_NAME;

                    part = true;
                    res = leePartesInvolucradas(node);
                    if (res != null)
                        return res;
                }
                else if (node.Name == FACTURA_E_LIN_FACTURA_NAME.ToUpper())
                {
                    if (lin)
                        return "Estructura de archivo no valida, tiene dos " + FACTURA_E_HEADER_NAME;

                    lin = true;
                    res = leeLineasFactura(node);
                    if (res != null)
                        return res;
                }
                if (lin && part && cab)
                    break;
            }

            if (!cab)
                res = "No se ha encontrado " + FACTURA_E_HEADER_NAME;
            if (!part)
                res = " No se ha encontrado " + FACTURA_E_PARTES_NAME;
            if (!lin)
                res = " No se ha encontrado " + FACTURA_E_LIN_FACTURA_NAME;
            return res;
        }

        private string leeCabecera(XmlNode cab)
        {
            string res = null;
            //version
            var str = getText(cab,FACTURA_E_VERSION_NAME);
            if (str == null|| str != FACTURA_E_VERSION)
                return "Version no compatible" + error;
            //id BatchIdentifier
            str= getText(cab, FACTURA_E_BATCH_NAME+"/"+ FACTURA_E_BATCH_ID_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            Identificador = str;
            decimal? dat = getdecimal(cab, FACTURA_E_BATCH_NAME + "/" + FACTURA_E_TotalInvoicesAmount_NAME+ "/"+ FACTURA_E_TotalAmount_NAME);
            if (dat == null)
                return "Estructura invalida" + error;
            TotalFactura = dat.Value;

            dat = getdecimal(cab, FACTURA_E_BATCH_NAME + "/" + FACTURA_E_TotalOutstandingAmount_NAME + "/" + FACTURA_E_TotalAmount_NAME);
            if (dat == null)
                return "Estructura invalida" + error;
            TotalPendiente = dat.Value;
            //moneda
            str = getText(cab, FACTURA_E_BATCH_NAME + "/" + FACTURA_E_InvoiceCurrencyCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            Moneda = str;
            return res;
        }


        private string leePartesInvolucradas(XmlNode partes)
        {
            //vendedor---------------------------------------------------
            Vendedor = new INTERNO_Vendedor_Factura_E_modelo();
            string res = null;
            var n = getNode(partes, FACTURA_E_SellerParty_NAME);
            if (n == null)
                return "Estructura invalida" + error;

            res = getTaxIdentification(Vendedor, n, FACTURA_E_TaxIdentification_NAME);
            if (res!=null)
                return res;

            res = getLegalEntity(Vendedor, n, FACTURA_E_LegalEntity_NAME);
            if (res != null)
                return res;
            res = geteContacto(Vendedor, n, FACTURA_E_LegalEntity_NAME+"/"+ FACTURA_E_ContactDetails_NAME);
            if (res != null)
                return res;
            //comprador----------------------------------------------------
            Comprador = new INTERNO_Comprador_Factura_E_modelo();
            n = getNode(partes, FACTURA_E_BuyerParty_NAME);
            if (n == null)
                return "Estructura invalida" + error;
            res = getTaxIdentification(Vendedor, n, FACTURA_E_TaxIdentification_NAME);
            if (res != null)
                return res;

            res = getLegalEntity(Vendedor, n, FACTURA_E_LegalEntity_NAME);
            if (res != null)
                return res;

            //centros administrativos
            n = getNode(partes, FACTURA_E_AdministrativeCentres_NAME);
            if (n == null)
                error = null;
            var nodes = getNodes(n, FACTURA_E_AdministrativeCentre_NAME);
            if (nodes!=null)
            {
                var nn = nodes.Count;
                if(nn>0)
                {
                    Comprador.Centros = new INTERNO_CentroAdministrativo_Factura_E_Modelo[nn];
                    for(int i=0; i<nn; i++)
                    {
                        Comprador.Centros[i] = new INTERNO_CentroAdministrativo_Factura_E_Modelo();
                        res = getAdministrativeCentre(Comprador.Centros[i], nodes.Item(i));
                        if (res != null)
                            return res;
                    }

                }
            }
            return res;
        }

        
        private string leeLineasFactura(XmlNode fact)
        {
            string res = null;
            var n = getNode(fact, FACTURA_E_Invoice_NAME);
            if (n == null)
                return "Estructura invalida" + error;
            //cabecera-----------------------------------------------------------------------
            int? i = getInt(n, FACTURA_E_InvoiceHeader_NAME + "/" + FACTURA_E_InvoiceNumber_NAME);
            if (i == null)
                return "Estructura invalida" + error;
            NumeroFactura = i.Value;

            string str = getText(n, FACTURA_E_InvoiceHeader_NAME + "/" + FACTURA_E_InvoiceSeriesCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            SerieDelegacion = str;

            str = getText(n, FACTURA_E_InvoiceHeader_NAME + "/" + FACTURA_E_InvoiceClass_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            FacturaOriginal = str == "OO";
            if (!FacturaOriginal)
            {
                var correccion = getNode(n, FACTURA_E_InvoiceHeader_NAME + "/" + FACTURA_E_Corrective_NAME);
                if (correccion == null)
                    return "Estructura invalida " + FACTURA_E_Corrective_NAME + " " + error;
                Correcciones = new INTERNO_Correcciones_Factura_E_Modelo();
                res = getCorreccion(Correcciones, correccion);
                if (res != null)
                    return res;
            }
            else
                Correcciones = null;
            //InvoiceIssueData
            DateTime? time = getTime(n, FACTURA_E_InvoiceIssueData_NAME + "/" + FACTURA_E_IssueDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            Fecha = time.Value;

            time = getTime(n, FACTURA_E_InvoiceIssueData_NAME + "/" + FACTURA_E_InvoicingPeriod_NAME+"/"+ FACTURA_E_StartDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            PeriodoInicio = time.Value;
            time = getTime(n, FACTURA_E_InvoiceIssueData_NAME + "/" + FACTURA_E_InvoicingPeriod_NAME+ "/" + FACTURA_E_EndDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            PeriodoFin = time.Value;
            //TaxesOutputs

            Impuesto = new INTERNO_Impuestos_Factura_E_modelo();
            res = getImpuestos(Impuesto, n, FACTURA_E_TaxesOutputs_NAME + "/" + FACTURA_E_Tax_NAME);
            if (res != null)
                return res;
            //InvoiceTotals
            res = getTotal(n, FACTURA_E_InvoiceTotals_NAME);
            if (res != null)
                return res;

            //Items
            var items = getNodes(n, FACTURA_E_Items_NAME + "/" + FACTURA_E_InvoiceLine_NAME);
            if (items == null)
                return "Estructura invalida, sin items: " + error;
            var nn = items.Count;
            if (nn <= 0)
                return "Estructura invalida, sin items.";
            Items = new INTERNO_Item_Factura_E_modelo[nn];

            for (int ii=0; ii<nn; ii++)
            {
                Items[ii] = new INTERNO_Item_Factura_E_modelo();
                res = getItem(Items[ii], items[ii]);
                if (res != null)
                    return res;
            }
            return res;
        }

        private string getItem(INTERNO_Item_Factura_E_modelo dat, XmlNode node)
        {
            string str = getText(node, FACTURA_E_DeliveryNote_NAME+"/"+ FACTURA_E_DeliveryNoteNumber);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Codigo = str;
            DateTime? time = getTime(node, FACTURA_E_DeliveryNote_NAME + "/" + FACTURA_E_DeliveryNoteDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.FechaAlbaran = time.Value;

            str = getText(node, FACTURA_E_ItemDescription_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Descripcion = str;

            int? i = getInt(node, FACTURA_E_Quantity_NAME);
            if (i == null)
                return "Estructura invalida" + error;
            dat.Cantidad = i.Value;

            decimal? f = getdecimal(node, FACTURA_E_UnitPriceWithoutTax_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Precio = f.Value;

            f = getdecimal(node, FACTURA_E_TotalCost_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Total = f.Value;


            str = getText(node, FACTURA_E_DiscountsAndRebates_NAME+"/"+ FACTURA_E_Discount_NAME + "/"+ FACTURA_E_DiscontReason_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.DescuentoRazon = str;
            f = getdecimal(node, FACTURA_E_DiscountsAndRebates_NAME + "/" + FACTURA_E_Discount_NAME + "/" + FACTURA_E_DiscountRate_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.DescuentoPorcentaje = f.Value;
            f = getdecimal(node, FACTURA_E_DiscountsAndRebates_NAME + "/" + FACTURA_E_Discount_NAME + "/" + FACTURA_E_DiscountAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Descuentoimporte = f.Value;

            f = getdecimal(node, FACTURA_E_GrossAmount_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.ImporteBruto = f.Value;

            var res = getImpuestos(dat,node, FACTURA_E_TaxesOutputs_NAME + "/"+FACTURA_E_Tax_NAME);
            if (res != null)
                return res;
            time = getTime(node, FACTURA_E_TransactionDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.FechaAlbaran = time.Value;
            str = getText(node, FACTURA_E_AdditionalLineItemInformation_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.Adicional = str;

            str = getText(node, FACTURA_E_ArticleCode_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.CodigoArticulo = str;
            return null;
        }
        private string getTotal( XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return getTotal(n);
        }
        private string getTotal( XmlNode node)
        {
            decimal? f = getdecimal(node, FACTURA_E_TotalGrossAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalBruto = f.Value;

            f = getdecimal(node, FACTURA_E_TotalGeneralDiscounts_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalDescuento = f.Value;

            f = getdecimal(node, FACTURA_E_TotalGrossAmountBeforeTaxes_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalBase = f.Value;

            f = getdecimal(node, FACTURA_E_TotalTaxOutputs_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalImpuestos = f.Value;

            f = getdecimal(node, FACTURA_E_InvoiceTotals_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            if (TotalFactura == f.Value)
                return "Valores de total factura no coinciden: " + FACTURA_E_InvoiceTotals_NAME;

            f = getdecimal(node, FACTURA_E_TotalOutstandingAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalPendiente = f.Value;

            f = getdecimal(node, FACTURA_E_TotalPaymentsOnAccount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalAnticipo = f.Value;
            f = getdecimal(node, FACTURA_E_TotalExecutableAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            TotalEjecutable = f.Value;
            return null;
        }
        private string getImpuestos(INTERNO_Impuestos_Factura_E_modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return getImpuestos(dat, n);
        }
        private string getImpuestos(INTERNO_Impuestos_Factura_E_modelo dat, XmlNode node)
        {
            int? i  = getInt(node, FACTURA_E_TaxTypeCode_NAME);
            if (i == null)
                return "Estructura invalida" + error;
            dat.Tipo = i.Value;

            decimal? f = getdecimal(node, FACTURA_E_TaxRate_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Porcentaje = f.Value;

            f = getdecimal(node, FACTURA_E_TaxableBase_NAME+"/"+ FACTURA_E_TotalAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Base = f.Value;
            f = getdecimal(node, FACTURA_E_TaxAmount_NAME + "/" + FACTURA_E_TotalAmount_NAME);
            if (f == null)
                return "Estructura invalida" + error;
            dat.Importe = f.Value;

            return null;
        }

        private string getCorreccion(INTERNO_Correcciones_Factura_E_Modelo dat, XmlNode node)
        {
            int? i = getInt(node, FACTURA_E_InvoiceNumber_NAME);
            if (i == null)
                return "Estructura invalida" + error;
            dat.NumeroFactura = i.Value;

            string str = getText(node, FACTURA_E_InvoiceSeriesCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.SerieDelegacion = str;

            str = getText(node, FACTURA_E_ReasonDescription_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.RazonCode = str;

            str = getText(node, FACTURA_E_CorrectionMethodDescription_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.RazonCorreccion = str;

            str = getText(node, FACTURA_E_AdditionalReasonDescription_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Observaciones = str;

            DateTime? time = getTime(node, FACTURA_E_TaxPeriod_NAME+"/"+ FACTURA_E_StartDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.Inicio = time.Value;

            time = getTime(node, FACTURA_E_TaxPeriod_NAME + "/" + FACTURA_E_EndDate_NAME);
            if (time == null)
                return "Estructura invalida" + error;
            dat.Fin = time.Value;

            return null;
        }

        private string getTaxIdentification(INTERNO_Entidad_Factura_E_Modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return getTaxIdentification(dat, n);
        }

        private string getTaxIdentification(INTERNO_Entidad_Factura_E_Modelo dat, XmlNode node)
        {
            string res = null;
            string str = getText(node, FACTURA_E_PersonTypeCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Tipo = str;
            str = getText(node, FACTURA_E_TaxIdentificationNumber_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.IdImpuestos = str;
            return null;
        }

        private string getLegalEntity(INTERNO_Entidad_Factura_E_Modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return getLegalEntity(dat, n);
        }

        private string getLegalEntity(INTERNO_Entidad_Factura_E_Modelo dat, XmlNode node)
        {
            string str = getText(node, FACTURA_E_CorporateName_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.RazonSocial = str;
            str = getText(node, FACTURA_E_TradeName_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.NombreComercial = str;
            return geteDireccion(dat, node, FACTURA_E_AddressInSpain_NAME);
        }
        private string getAdministrativeCentre(INTERNO_CentroAdministrativo_Factura_E_Modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return getAdministrativeCentre(dat, n);
        }
        private string getAdministrativeCentre(INTERNO_CentroAdministrativo_Factura_E_Modelo dat, XmlNode node)
        {
            string str = getText(node, FACTURA_E_CentreCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Codigo = str;

            str = getText(node, FACTURA_E_RoleTypeCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Role = str;

            str = getText(node, FACTURA_E_Name_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Encargado = str;

            str = getText(node, FACTURA_E_CentreDescription_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Descripcion = str;
            return geteDireccion(dat, node, FACTURA_E_AddressInSpain_NAME);
        }
        private string geteDireccion(INTERNO_Direccion_Factura_E_Modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return geteDireccion(dat, n);
        }

        private string geteDireccion(INTERNO_Direccion_Factura_E_Modelo dat, XmlNode node)
        {
            string str = getText(node, FACTURA_E_Address_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Direccion = str;

            str = getText(node, FACTURA_E_PostCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.CP = str;

            str = getText(node, FACTURA_E_Town_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Poblacion = str;

            str = getText(node, FACTURA_E_Province_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Provincia = str;

            str = getText(node, FACTURA_E_CountryCode_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Pais = str;
            return null;
        }
        private string geteContacto(INTERNO_Direccion_Factura_E_Modelo dat, XmlNode node, string xpath)
        {
            var n = getNode(node, xpath);
            if (n == null)
                return error;
            return geteContacto(dat, n);
        }
        private string geteContacto(INTERNO_Direccion_Factura_E_Modelo dat, XmlNode node)
        {
            string str = getText(node, FACTURA_E_Telephone_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Tlf = str;

            str = getText(node, FACTURA_E_TeleFax_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Fax = str;

            str = getText(node, FACTURA_E_WebAddress_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Web = str;

            str = getText(node, FACTURA_E_ElectronicMail_NAME);
            if (str == null)
                return "Estructura invalida" + error;
            dat.Email = str;
            return null;
        }
        #endregion

        #region funciones comunes
        private XmlNodeList getNodes(XmlNode node, string xpath)
        {
            XmlNodeList res = null;
            try
            {
                res = node.SelectNodes(xpath);
            }
            catch (Exception e)
            {
                error = e.Message;
                res = null;
            }
            if (res == null)
                error = "No encontrado nodos: " + xpath + " " + error;
            return res;
        }
        private XmlNode getNode(XmlNode node, string xpath)
        {
            XmlNode res = null;
            try
            {
                res = node.SelectSingleNode(xpath);
            }
            catch (Exception e)
            {
                error = e.Message;
                res = null;
            }
            if (res == null)
                error = "No encontrado nodo: " + xpath + " " + error;
            return res;
        }

        private string getText(XmlNode node, string xpath)
        {
            string res = null;
            var n = getNode(node, xpath);
            if (n != null && n.InnerText != null)
                res = n.InnerText;
            if (res == null)
                error = "Texto no encontrado en: " + xpath + " " + error;
            return res;
        }

        private decimal? getdecimal(XmlNode node, string xpath)
        {
            decimal? res = null;
            var str = getText(node, xpath);
            if(str!=null)
            {
                try
                {
                    res = decimal.Parse(str);
                }
                catch
                {
                    error = "El valor de " + xpath + " no es numerico " + error;
                    res = null;
                }
            }

            return res;
        }
        private int? getInt(XmlNode node, string xpath)
        {
            int? res = null;
            var str = getText(node, xpath);
            if (str != null)
            {
                try
                {
                    res = int.Parse(str);
                }
                catch
                {
                    error = "El valor de " + xpath + " no es numerico " + error;
                    res = null;
                }
            }

            return res;
        }

        private DateTime? getTime(XmlNode node, string xpath)
        {
            DateTime? res = null;
            var str = getText(node, xpath);
            if (str != null)
            {
                try
                {
                  
                    res = DateTime.ParseExact(str, @"yyyy-MM-dd\THH:mm:ss.fff\Z",
                        CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
                }
                catch
                {
                    error = "El valor de " + xpath + " no es de tipo datetime " + error;
                    res = null;
                }
            }

            return res;
        }
        #endregion
    }


}
