Curso complemento para recepción de pagos en C# .Net, Crear xml, timbrar | SAT cfdi 3.3, #3

En este video del curso para crear el complemento para recepción de pagos del cfdi 3.3, te enseñare como incorporar la clase que generamos en el video anterior en la clase Comprobante, y de esta manera crear el xml, para sellarlo y posteriormente timbrarlo.
También te explicare como debes armar el comprobante, ya que en este tipo de documento tiene validaciones en específico.

Video anterior: https://hdeleon.net/curso-complemento-para-recepcion-de-pagos-en-c-net-convertir-xsd-a-clases-de-c-sat-cfdi-3-3-2/

Código fuente: clic aquí.

Curso para crear la factura electrónica 3.3 cfdi del SAT GRATIS en C# .Net




Gratuitamente te enseñare como puedes crear tu factura electrónica con los siguientes videos, te aseguro que después de ver los videos podrás entender a la perfección como realizar el cfdi 3.3 que tanto martirio tiene a todos los contribuyentes en México.

Te invito a que te suscribas a mi canal de youtube para mas videos interesantes sobre programación.

1.- ¿Cómo convertir archivos XSD a clases de C# .Net? cfdi 3.3 

En este primer video te muestro como generar automáticamente las clase a partir de los archivos xsd del SAT.

2.- ¿Cómo crear el XML para cfdi 3.3 facturación electrónica C# .Net? – Limpiando código 

Una vez que creaste las clases de manera automatica, es momento de optimizarlas, y a continuación te muestro como hacerlo.

3.- ¿Cómo crear el XML para cfdi 3.3 facturación electrónica C# .Net? – implementando anexo 20

Ya por fin que tenemos nuestras clases adecuadas para crear el archivo XML, es momento de ir llenandolo conforme el anexo 20 del SAT, para ello te explico los campos del SAT para que son y como llenarlos de la forma correcta.

4.- ¿Cómo sellar el XML para cfdi 3.3 facturación electrónica C# .Net? – utf8, obtener número de Certificado

Ya que tenemos el xml listo, es momento comenzar el sellado, y te diré como obtener el numero del certificado; tambien te enseñare como cambiar la codificación de tu xml a utf8.

5.- ¿Cómo sellar el XML para cfdi 3.3 facturación electrónica C# .Net? – Sellar con key

Ya por fin vamos a sellar nuestro xml con nuestro archivo key, al igual te mostrare como arreglar el problema con los campos FieldSpecified que se generaron al crear nuestras clases en el primer video, agregar los namespace adecuados del SAT, y a obtener la cadena original por medio del archivo xslt necesaria para el sellado.

6.- ¿Cómo timbrar el XML para cfdi 3.3 facturación electrónica C# .Net? – conectandonos al PAC

Ya por fin en este vide veras como realizar el mitico timbrado de la factura, con lo cual tu factura ya sera valida para el SAT.

Para contratar el servicio de timbrado comunícate al siguiente teléfono (33) 36581329 o al correo electrónico [email protected]. Y si deseas un DESCUENTO diles que viste los videos de Héctor de León.

Si eres un perezoso o te urge hacer la facturación electrónica, te dejo el enlace al código del proyecto, espero te sirva: Código del proyecto

Dudas y comentarios pueden hacérmelos llegar en los comentarios abajo.

¿Cómo sellar el XML para cfdi 3.3 facturación electrónica C# .Net? – Sellar con key – SAT #5

En este video te mostrare como contrarrestar los campos FieldSpecified creados en el primer video, poner el formato correcto de fecha, obtener la cadena original, obtener el campo certificado, poner los namespaces al xml, y por ultimo como sellar el xml con tu key.

Descargar proyecto hecho en el video: clic aquí.

Video 1: https://www.youtube.com/watch?v=XlTz0NRQLm4

Video 2: https://www.youtube.com/watch?v=HjfqdTspnio

Video 3: https://www.youtube.com/watch?v=qIr-LdCzfF0

Video 4: https://www.youtube.com/watch?v=suRypKtb7VU

Catálogos sat mysql: https://hdeleon.net/catalogos-para-facturar-3-3-sat-en-mysql/

Puedes preguntarme sobre programación aquí: https://www.youtube.com/watch?v=M84D75OcuUU


//CÓDIGO UTILIZADO EN EL VIDEO
 class Program
    {
        //modifiquen por su path
        static private string path = @"C:\Users\Bioxor\source\repos\Facturacion3.3-tutorial-hdeleon\";
        static string pathXML = path + @"miPrimerXML.xml";

        static void Main(string[] args)
        {
            //Obtener numero certificado------------------------------------------------------------

            string pathCer = path+@"XSDToXML\CSD01_AAA010101AAA.cer";
            string pathKey = path+@"XSDToXML\CSD01_AAA010101AAA.key";
            string clavePrivada = "12345678a";

            //Obtenemos el numero
            string numeroCertificado, aa, b, c;
            SelloDigital.leerCER(pathCer, out aa, out b, out c, out numeroCertificado);

            //Llenamos la clase COMPROBANTE--------------------------------------------------------
            Comprobante oComprobante = new Comprobante();
            oComprobante.Version = "3.3";
            oComprobante.Serie = "H";
            oComprobante.Folio = "1";
            oComprobante.Fecha = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
           // oComprobante.Sello = "faltante"; //sig video
            oComprobante.FormaPago = "99";
            oComprobante.NoCertificado = numeroCertificado;
           // oComprobante.Certificado = ""; //sig video
            oComprobante.SubTotal = 10m;
            oComprobante.Descuento = 1;
            oComprobante.Moneda = "MXN";
            oComprobante.Total = 9;
            oComprobante.TipoDeComprobante = "I";
            oComprobante.MetodoPago = "PUE";
            oComprobante.LugarExpedicion = "20131";

            ComprobanteEmisor oEmisor = new ComprobanteEmisor();

            oEmisor.Rfc = "POWE870601DM7";
            oEmisor.Nombre = "Una razón rh de cv";
            oEmisor.RegimenFiscal = "605";

            ComprobanteReceptor oReceptor = new ComprobanteReceptor();
            oReceptor.Nombre = "Pepe SA DE CV";
            oReceptor.Rfc = "PEPE080801JH1";
            oReceptor.UsoCFDI = "P01";

            //asigno emisor y receptor
            oComprobante.Emisor = oEmisor;
            oComprobante.Receptor = oReceptor;

            List<ComprobanteConcepto> lstConceptos = new List<ComprobanteConcepto>();
            ComprobanteConcepto oConcepto = new ComprobanteConcepto();
            oConcepto.Importe = 10m;
            oConcepto.ClaveProdServ = "92111704";
            oConcepto.Cantidad = 1;
            oConcepto.ClaveUnidad = "C81";
            oConcepto.Descripcion = "Un misil para la guerra";
            oConcepto.ValorUnitario = 10m;
            oConcepto.Descuento = 1;

            lstConceptos.Add(oConcepto);

            oComprobante.Conceptos = lstConceptos.ToArray();

            //Creamos el xml
            CreateXML(oComprobante);

            string cadenaOriginal = "";
            string pathxsl = path+ @"XSDToXML\cadenaoriginal_3_3.xslt";
            System.Xml.Xsl.XslCompiledTransform transformador = new System.Xml.Xsl.XslCompiledTransform(true);
            transformador.Load(pathxsl);

            using (StringWriter sw= new StringWriter())
            using (XmlWriter xwo= XmlWriter.Create(sw,transformador.OutputSettings)) {

                transformador.Transform(pathXML, xwo);
                cadenaOriginal = sw.ToString();
            }

            SelloDigital oSelloDigital = new SelloDigital();
            oComprobante.Certificado = oSelloDigital.Certificado(pathCer);
            oComprobante.Sello = oSelloDigital.Sellar(cadenaOriginal, pathKey, clavePrivada);

            CreateXML(oComprobante);

        }

        private static void CreateXML(Comprobante oComprobante)
        {
            //SERIALIZAMOS.-------------------------------------------------

            XmlSerializerNamespaces xmlNameSpace = new XmlSerializerNamespaces();
            xmlNameSpace.Add("cfdi", "http://www.sat.gob.mx/cfd/3");
            xmlNameSpace.Add("tfd", "http://www.sat.gob.mx/TimbreFiscalDigital");
            xmlNameSpace.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

            XmlSerializer oXmlSerializar = new XmlSerializer(typeof(Comprobante));

            string sXml = "";

            using (var sww = new Utils.StringWriterWithEncoding(Encoding.UTF8))
            {

                using (XmlWriter writter = XmlWriter.Create(sww))
                {

                    oXmlSerializar.Serialize(writter, oComprobante,xmlNameSpace);
                    sXml = sww.ToString();
                }

            }

            //guardamos el string en un archivo
            System.IO.File.WriteAllText(pathXML, sXml);
        }
    }

¿Cómo sellar el XML para cfdi 3.3 facturación electrónica C# .Net? – utf8, obtener No Cer – SAT #4

En este video te mostrare como crear tu xml en utf8, también a obtener el número del certificado a partir del archivo Cer e incluirlo en el xml.

Descargar código del tutorial

Certificados de prueba: http://www.sat.gob.mx/informacion_fiscal/factura_electronica/Paginas/certificado_sello_digital.aspx

Video 1: https://www.youtube.com/watch?v=XlTz0NRQLm4

Video 2: https://www.youtube.com/watch?v=HjfqdTspnio

Video 3: https://www.youtube.com/watch?v=qIr-LdCzfF0

Catálogos sat mysql: https://hdeleon.net/catalogos-para-facturar-3-3-sat-en-mysql/

¿Cómo crear un archivo pfx en c#? cancelación de factura electrónica SAT cfdi 3.3

Para cancelar una factura electrónica es necesario crear un tercer certificado llamado pfx, este certificado se debe crear por medio de Openssl en conjunto de nuestro archivo Cer y nuestro archivo Key los cuales debemos ya tener si es que estamos timbrando.

Para crear el archivo pfx utilizaremos la clase Process de .Net, esta clase sirve para mandar comandos como si estuviéramos en consola, de esta manera utilizaremos los comandos de Openssl.

Les recuerdo que antes deben instalar Openssl y como está en el siguiente ejemplo debe estar instalado en la unidad c:/openssl-win32.

En caso que se tenga Openssl instalado en otra ruta distinta, solo modifiquen esa parte del código. A continuación la clase mágica:

 public class PFX
    {
        string cer = "";
        string key = "";
        string clavePrivada = "";
        string ArchivoPFX = "";
        string ArchivoKPEM = "";
        string ArchivoCPEM = "";

        public string error = "";
        public string mensajeExito = "";

        ///
<summary>
        ///
        /// </summary>

        /// <param name="cer_">archivo cer a utilizar</param>
        /// <param name="key_">archivo key a utilizar</param>
        /// <param name="clavePrivada_">clave para el archivo pfx</param>
        /// <param name="archivoPfx_">ruta del archivo pfx</param>
        /// <param name="path">ruta para archivos temporales PEM</param>
        public PFX(string cer_, string key_, string clavePrivada_, string archivoPfx_, string pathTemp)
        {
            cer = cer_;
            key = key_;
            clavePrivada = clavePrivada_;

            ArchivoKPEM = pathTemp + "k.pem";
            ArchivoCPEM = pathTemp + "c.pem";
            ArchivoPFX = archivoPfx_;
        }

        public bool creaPFX()
        {
            bool exito = false;

            //validaciones
            if (!File.Exists(cer))
            {
                error = "No existe el archivo cer en el sistema";
                return false;
            }
            if (!File.Exists(key))
            {
                error = "No existe el archivo key en el sistema";
                return false;
            }
            if (clavePrivada.Trim().Equals(""))
            {
                error = "No existe una clave privada aun en el sistema";
                return false;
            }

            //creamos objetos Process
            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            System.Diagnostics.Process proc2 = new System.Diagnostics.Process();
            System.Diagnostics.Process proc3 = new System.Diagnostics.Process();
            proc.EnableRaisingEvents = false;
            proc2.EnableRaisingEvents = false;
            proc3.EnableRaisingEvents = false;

            //openssl x509 -inform DER -in certificado.cer -out certificado.pem
            proc.StartInfo.FileName = "openssl";
            proc.StartInfo.Arguments = "x509 -inform DER -in \"" + cer + "\" -out \"" + ArchivoCPEM + "\"";
            proc.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
            proc.Start();
            proc.WaitForExit();

            //openssl pkcs8 -inform DER -in llave.key -passin pass:a0123456789 -out llave.pem
            proc2.StartInfo.FileName = "openssl";
            proc2.StartInfo.Arguments = "pkcs8 -inform DER -in \"" + key + "\" -passin pass:" + clavePrivada + " -out \"" + ArchivoKPEM + "\"";
            proc2.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
            proc2.Start();
            proc2.WaitForExit();

            //openssl pkcs12 -export -out archivopfx.pfx -inkey llave.pem -in certificado.pem -passout pass:clavedesalida
            proc3.StartInfo.FileName = "openssl";
            proc3.StartInfo.Arguments = "pkcs12 -export -out \"" + ArchivoPFX + "\" -inkey \"" + ArchivoKPEM + "\" -in \"" + ArchivoCPEM + "\" -passout pass:" + clavePrivada;
            proc3.StartInfo.WorkingDirectory = @"C:\openssl-win32\bin\";
            proc3.Start();
            proc3.WaitForExit();

            proc.Dispose();
            proc2.Dispose();
            proc3.Dispose();

            //enviamos mensaje exitoso
            if (System.IO.File.Exists(ArchivoPFX))
                mensajeExito = "Se ha creado el archivo PFX ";
            else
            {
                error = "Error al crear el archivo PFX, puede ser que el cer o el key no sean archivos con formato correcto";
                return false;
            }

            //eliminamos los archivos pem
            if (System.IO.File.Exists(ArchivoCPEM)) System.IO.File.Delete(ArchivoCPEM);
            if (System.IO.File.Exists(ArchivoKPEM)) System.IO.File.Delete(ArchivoKPEM);

            exito = true;

            return exito;
        }
    }

Para utilizarla de la siguiente manera:


//yo siempre utilizo la misma clave privada de mi timbrado para encriptar el pfx
//la ruta para archivos temporales solo se utiliza para archivos que serán eliminados al final
oPFX = new PFX("algunaruta/archivocer.cer", "algunaruta/archivokey.key", "algunpassword", "algunacarpeta/miarchivo.pfx", "rutaparacreararchivostemporalesPem/");

if (oPFX.creaPFX())
                    Console.WriteLine("Archivo creado con éxito");
else
                    Console.WriteLine(oPFX.error);