Representación impresa de factura electrónica del SAT en versión 2.2

En el artículo anterior titulado Convirtiendo facturas electrónicas del XML a PDF describo el proceso para crear una representación impresa de una factura electrónica en la versión 2.0, basado en el famoso anexo 20 del SAT.

Ahora les dejo el código fuente del programa para la versión 2.2 (requiere aplicar el archivo de transformación cadenaoriginal_2_2.xslt), que debe usarse a partir del 1o de julio de este año…

#!/usr/bin/perl
#===================================================================#
# Program => CFD_to_PDF_2_2.pl (In Perl 5.0)          version 0.0.1 #
#===================================================================#
# Autor         => Fernando "El Pop" Romo        (pop@cofradia.org) #
# Creation date => 01/jul/2012                                      #
#-------------------------------------------------------------------#
# Info => This program take a CFD file in xml format and convert to #
#         PDF using a template                                      #
#-------------------------------------------------------------------#
#                    (c) 2012 - Fernando Romo                       #
#-------------------------------------------------------------------#
#              Release under the GNU/GPL License v3.0               #
#===================================================================#
 
# Load Modules
use strict;
use PDF::Reuse;
use Lingua::ES::Numeros ":constants";
use XML::Simple;
use Text::Wrap::Smart qw(wrap_smart);
 
my $file = $ARGV[0];
 
my $Fac = XMLin($file);
 
$file =~ s/.xml$//g;
 
prFile ( { Name         => "$file.pdf",
           HideToolbar  => 1,          # 1 or 0
           HideMenubar  => 1,          # 1 or 0
           HideWindowUI => 1,          # 1 or 0
           FitWindow    => 1,          # 1 or 0
           CenterWindow => 1   } );    # 1 or 0
 
prForm ( { file     => '/Users/pop/SAT/util/factura_clean_incuvox_2_2.pdf', # template file
           page     => 1,             # page number (of imported template)
           adjust   => 0,             # try to fill the media box
           effect   => 0,             # action to be taken
           tolerant => 1,             # continue even with an invalid form
           x        => -13,           # $x points from the left
           y        => 49,            # $y points from the bottom
           rotate   => 0,             # rotate 
           size     => 1,             # multiply everything by $size
           xsize    => 1,             # multiply horizontally by $xsize
           ysize    => 1, } );        # multiply vertically by $ysize
 
prFont('Helvetica');
 
# Moneda
 
my $Sufijo = 'PESOS';
my $Moneda = 'M.N.';
if (exists($Fac->{Moneda})) {
    if ($Fac->{Moneda} eq 'MXN') {
        $Sufijo = 'PESOS';
        $Moneda = 'M.N.';
    }
    else {
        $Moneda = "$Fac->{Moneda}";
        $Sufijo = '';
    }
}
 
sub Escape_UTF8 {
    my @out = @_;
    for (@out) {
        s/á/\x{e1}/g;
        s/é/\x{e9}/g;
        s/í/\x{ed}/g;
        s/ó/\x{f3}/g;
        s/ú/\x{fa}/g;
        s/Á/\x{c1}/g;
        s/É/\x{c9}/g;
        s/Í/\x{cd}/g;
        s/Ó/\x{d3}/g;
        s/Ú/\x{da}/g;
        s/ñ/\x{f1}/g;
        s/Ñ/\x{d1}/g;
    }
    return wantarray ? @out : $out[0];
}
 
sub Wrap_Text {
    my ($ref_string, $col, $row, $width, $font_size, $space, $split) = @_;
    my @text = wrap_smart($$ref_string, { no_split => $split, max_msg_size => $width,} );
    prFontSize ($font_size);
    foreach my $linea (@text) {
        prText( $col, $row, $linea, 'left');
        $row = $row - $space;
    }
    return $row + $space;
}
 
sub Dinero {
    my ($number) = @_;
    my $dec_pos = 2;
    if ($number =~  /\./) {
        my $len = length($number);
        $dec_pos = rindex($number,"\.");
        $dec_pos = $len - $dec_pos - 1 ;
    }
    my $number = sprintf("%.$dec_pos".'f', $number);
    1 while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
    $number =~ s/^(-?)/$1\$/;
    return $number;
}
 
sub Cantidad {
    my $number = sprintf "%.2f", shift @_;
    1 while $number =~ s/^(-?\d+)(\d\d\d)/$1,$2/;
    return $number;
}
 
sub Parte {
    my ($ref_parte, $row) = @_;
    my %Pedimentos = ();
    my @SinPedimento = ();
    my $parte_aux = 'N.S.: ';
    if (ref($$ref_parte) eq 'ARRAY') {
        for (my $i=0; $i <= (@{ $$ref_parte } - 1) ; $i++) {
            if (exists($$ref_parte->[$i]->{'cfd:InformacionAduanera'})) {
                $Pedimentos{ $$ref_parte->[$i]->{'cfd:InformacionAduanera'}{numero} }{aduana} = 
                    $$ref_parte->[$i]->{'cfd:InformacionAduanera'}{aduana};
                $Pedimentos{ $$ref_parte->[$i]->{'cfd:InformacionAduanera'}{numero} }{fecha} =
                    $$ref_parte->[$i]->{'cfd:InformacionAduanera'}{fecha};
                push @{ $Pedimentos{ $$ref_parte->[$i]->{'cfd:InformacionAduanera'}{numero} }{serie} },
                    $$ref_parte->[$i]->{noIdentificacion};
            } 
            else {
                push @SinPedimento, $$ref_parte->[$i]->{noIdentificacion};
            }
        }
        foreach my $numero (sort keys %Pedimentos) {
            $parte_aux = 'N.S.: ';
            $row = $row - 8;
            $row = Wrap_Text(\"Pedimento: $numero, Aduana: $Pedimentos{$numero}{aduana}, Fecha: $Pedimentos{$numero}{fecha}",85,$row,70,6,8,1);
            for (my $x=0; $x <= (@{ $Pedimentos{$numero}{serie} } - 1) ; $x++) {
                $parte_aux .= "$Pedimentos{$numero}{serie}[$x], ";
            }
            $parte_aux =~ s/, $//;
            $row = $row - 8;
            $row = Wrap_Text(\$parte_aux,85,$row,70,6,8,1);
        }
        if ($#SinPedimento >= 0) {
            $parte_aux = 'N.S.: ';
            foreach my $serie (sort @SinPedimento) {
                $parte_aux .= $serie . ', ';
            }
            $parte_aux =~ s/, $//;
            $row = $row - 8;
            $row = Wrap_Text(\$parte_aux,85,$row,70,6,8,1);
        }
    }
    else {
        if (exists($$ref_parte->{'cfd:InformacionAduanera'})) {
            $row = $row - 8;
            my $aduana_aux = 'Pedimento: ' . $$ref_parte->{'cfd:InformacionAduanera'}{numero} .
                             ', Aduana: ' . $$ref_parte->{'cfd:InformacionAduanera'}{aduana} .
                             ', fecha: ' . $$ref_parte->{'cfd:InformacionAduanera'}{fecha};
            $row = Wrap_Text(\$aduana_aux,85,$row,70,6,8,1);
        }
 
        if (exists($$ref_parte->{noIdentificacion})) {
            $row = $row - 8;
            $parte_aux .= $$ref_parte->{noIdentificacion};
            $row = Wrap_Text(\$parte_aux,85,$row,70,6,8,1);
        }
    }
 
    return $row;
}
 
sub Concepto {
    my ($ref_concepto, $row) = @_;
    if (ref($$ref_concepto) eq 'ARRAY') {
        for (my $i=0; $i <= (@{ $$ref_concepto } - 1) ; $i++) {
            prFontSize (8);
            prText( 18,  $row, $$ref_concepto->[$i]->{noIdentificacion}, 'left');
            prText( 375, $row, Cantidad($$ref_concepto->[$i]->{cantidad}), 'right');
            prText( 477, $row, Dinero($$ref_concepto->[$i]->{valorUnitario}) . " $Moneda", 'right');
            prText( 580, $row, Dinero($$ref_concepto->[$i]->{importe}) . " $Moneda", 'right');
            $row = Wrap_Text(\$$ref_concepto->[$i]->{descripcion},85,$row,60,8,10,1);
            if (exists($$ref_concepto->[$i]->{'cfd:Parte'})) {
                $row = Parte(\$$ref_concepto->[$i]->{'cfd:Parte'},$row);
            }
            $row = $row - 10;
        }
    }
    else {
        prFontSize (8);
        prText( 18,  $row, $$ref_concepto->{noIdentificacion}, 'left');
        prText( 375, $row, Cantidad($$ref_concepto->{cantidad}), 'right');
        prText( 477, $row, Dinero($$ref_concepto->{valorUnitario}) . " $Moneda", 'right');
        prText( 580, $row, Dinero($$ref_concepto->{importe}) . " $Moneda", 'right');
        $row = Wrap_Text(\$$ref_concepto->{descripcion},85,$row,55,8,10,1);
        if (exists($$ref_concepto->{'cfd:Parte'})) {
            $row = Parte(\$$ref_concepto->{'cfd:Parte'},$row);
        }
        $row = $row - 10;
    }
    return $row; 
}
 
# Datos del CFD
 
prFontSize (10);
prText( 140, 793, "$Fac->{noCertificado}", 'left');
prText( 140, 780, "$Fac->{noAprobacion}", 'left');
prText( 300, 780, "$Fac->{anoAprobacion}", 'left');
prText( 140, 769, "$Fac->{tipoDeComprobante}",, 'left');
prText( 275, 768, "$Fac->{fecha}",, 'left');
prText( 140, 757, "$Fac->{formaDePago}", 'left');
prText( 140, 745, "$Fac->{metodoDePago}", 'left');
prFontSize (16);
prText( 140, 728, "$Fac->{serie}-$Fac->{folio}", 'left');
 
# Emisor
 
prFontSize (10);
prFont('Helvetica-Bold');
prText( 402, 758, "$Fac->{'cfd:Emisor'}{nombre}", 'left');
prFont('Helvetica');
prFontSize (8);
prText( 402, 746, "$Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{calle} $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{noExterior} $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{noInterior}", 'left');
prText( 402, 736, "Col. $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{colonia} C.P. $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{codigoPostal}", 'left');
prText( 402, 726, "$Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{municipio}, $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{estado}", 'left');
prText( 402, 716, "$Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{localidad}, $Fac->{'cfd:Emisor'}{'cfd:DomicilioFiscal'}{pais}", 'left');
prText( 402, 706, 'info@incuvox.com', 'left');
prText( 480, 706, 'http://incuvox.com', 'left');
prText( 402, 696, 'Tel. +52(55)4162-5800', 'left');
prFontSize (10);
prText( 402, 684, "R.F.C.:", 'left');
prFont('Helvetica-Bold');
prText( 437, 684, "$Fac->{'cfd:Emisor'}{rfc}", 'left');
prFont('Helvetica');
 
# Lugar de emision
 
prFontSize (8);
prText( 402, 650, "$Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{calle} $Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{noExterior} $Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{noInterior}", 'left');
prText( 402, 640, "$Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{colonia}, C.P. $Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{codigoPostal}", 'left');
prText( 402, 630, "$Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{municipio}, $Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{estado}", 'left');
prText( 402, 620, "$Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{localidad}, $Fac->{'cfd:Emisor'}{'cfd:ExpedidoEn'}{pais}", 'left');
 
# Facturado A
 
prFontSize (10);
prFont('Helvetica-Bold');
prText( 20, 690, "$Fac->{'cfd:Receptor'}{nombre}", 'left');
prFont('Helvetica');
prText( 20, 678, "$Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{calle} $Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{noExterior} $Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{noInterior}" , 'left');
prText( 20, 666, "$Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{colonia}, C.P. $Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{codigoPostal}", 'left');
prText( 20, 654, "$Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{municipio}, $Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{localidad}", 'left');
prText( 20, 642, "$Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{estado}, $Fac->{'cfd:Receptor'}{'cfd:Domicilio'}{pais}", 'left');
prText( 20, 620, "R.F.C.:", 'left');
prFont('Helvetica-Bold');
prText( 56, 620, "$Fac->{'cfd:Receptor'}{rfc}", 'left');
prFont('Helvetica');
 
# partidas
 
my $row = Concepto(\$Fac->{'cfd:Conceptos'}{'cfd:Concepto'},579);
 
# Addenda
 
if (exists($Fac->{'cfd:Addenda'}{Incuvox}{Note})) {
    prFont('Helvetica-Oblique');
    my $nota = 'Nota: ' .  $Fac->{'cfd:Addenda'}{Incuvox}{Note};
    Wrap_Text(\$nota,85,($row - 3),80,8,10,1);
    prFont('Helvetica');
}
 
# Numero en letras
 
my ( $pesos, $centavos ) = split( /\./, $Fac->{total} );
$pesos = 0 unless( $pesos );
$centavos = 0 unless( $centavos );
my $obj = new Lingua::ES::Numeros ('MAYUSCULAS' => 1, ACENTOS => 0);
my $letrero = $obj->cardinal($pesos) . " $Sufijo " . "$centavos/100 $Moneda\n";
 
Wrap_Text(\$letrero,65,314,70,8,10,1);
 
# Totales
 
prFontSize (8);
prText( 580, 314, Dinero($Fac->{subTotal}) . " $Moneda", 'right');
prText( 580, 303, Dinero($Fac->{descuento}) . " $Moneda", 'right');
prText( 458, 292, '16', 'right');
prText( 580, 292, Dinero($Fac->{'cfd:Impuestos'}{totalImpuestosTrasladados}) . " $Moneda", 'right');
prFont('Helvetica-Bold');
prText( 580, 281, Dinero($Fac->{total}) . " $Moneda", 'right');
prFont('Helvetica');
 
# Cadena Original
 
prFont('Courier');
my $cadena = Escape_UTF8(qx(xsltproc ~/SAT/xslt/cadenaoriginal_2_2.xslt $file.xml));
Wrap_Text(\$cadena,20,252,155,6,8,0);
 
# Sello
 
Wrap_Text(\$Fac->{sello},75,100,130,8,10,0);
 
# Verifica si esta cancelada y pone sello
if (exists($Fac->{'cfd:Addenda'}{Incuvox}{Factura}{Status})) {
    if (lc($Fac->{'cfd:Addenda'}{Incuvox}{Factura}{Status}) eq 'cancelada') {
        prAdd("q\nBT\n/" . prFont('Courier') . " 2 Tf\n40 45 -45 40 100 160 Tm\n1 0 0 rg\n(CANCELADO) Tj\nET\nQ\n");
        prAdd("q\nBT\n/" . prFont('Courier') . " .3 Tf\n40 45 -45 40 190 220 Tm\n1 0 0 rg\n(No puede ser usado como comprobante fiscal) Tj\nET\nQ\n");
    }
}
 
prEnd();

Esto procesa un XML como este:

<?xml version="1.0"
      encoding="UTF-8"?>
 
<cfd:Comprobante
    xmlns:cfd="http://www.sat.gob.mx/cfd/2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sat.gob.mx/cfd/2
                        http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv22.xsd"
    version="2.2"
    serie="Falsa"
    folio="666"
    fecha="2012-07-01T00:13:32"
    sello="1LBn6TRoUuDN5J9rgdrCg3hKYPMU8qT+USefiDQU3ig4vFF25c8KgfSiaLuMEE4bzeOuXj5C1OMJjHgRcVuC1//Tv3N9GMMQYstg+OIANhtx5fobxqobbDBgLXNlc+7AqM6OjOM2vk6J8iLyAF+esdPbmE/XUDRneWajl09Lmr0="
    noAprobacion="263844"
    anoAprobacion="2010"
    formaDePago="Contado en una sola exibición"
    tipoDeComprobante="ingreso"
    noCertificado="00001000000102302080"
    certificado="MIIECTCCAvGgAwIBAgIUMDAwMDEwMDAwMDAxMDIzMDIwODAwDQYJKoZIhvcNAQEFBQAwggE2MTgwNgYDVQQDDC9BLkMuIGRlbCBTZXJ2aWNpbyBkZSBBZG1pbmlzdHJhY2nDs24gVHJpYnV0YXJpYTEvMC0GA1UECgwmU2VydmljaW8gZGUgQWRtaW5pc3RyYWNpw7NuIFRyaWJ1dGFyaWExHzAdBgkqhkiG9w0BCQEWEGFjb2RzQHNhdC5nb2IubXgxJjAkBgNVBAkMHUF2LiBIaWRhbGdvIDc3LCBDb2wuIEd1ZXJyZXJvMQ4wDAYDVQQRDAUwNjMwMDELMAkGA1UEBhMCTVgxGTAXBgNVBAgMEERpc3RyaXRvIEZlZGVyYWwxEzARBgNVBAcMCkN1YXVodGVtb2MxMzAxBgkqhkiG9w0BCQIMJFJlc3BvbnNhYmxlOiBGZXJuYW5kbyBNYXJ0w61uZXogQ29zczAeFw0xMDEyMDMyMzA4MTNaFw0xMjEyMDIyMzA4MTNaMIGpMRkwFwYDVQQDExBJTkNVVk9YIFNBIERFIENWMRkwFwYDVQQpExBJTkNVVk9YIFNBIERFIENWMRkwFwYDVQQKExBJTkNVVk9YIFNBIERFIENWMSUwIwYDVQQtExxJTkMxMDExMDlRMzYgLyBST0FGNjQxMjE3Szk0MR4wHAYDVQQFExUgLyBST0FGNjQxMjE3SERGTUxSMDgxDzANBgNVBAsTBk1hdHJpejCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2UQW4gKh5RBbYXKvkYcr5gEtp5R0QVVeHsMNlfOdhByXZKMWH6rE+wSlTrCAmOigy8fUJpw7Tokx8FQvGHZOWqwHjrr0Nw274MHMwAX8d0++xvhrJbAonCFCUkGGHgMwxrSVm9Fib5t6sxaZkN4N3NLkV80SJxXn0a2p+ux3zIcCAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwDQYJKoZIhvcNAQEFBQADggEBACrnr14H3QbM4Gp52HNdkqvdvH8ByWqe9C532g2aT8g1Ft9HL8p25x5DSX+SjtzKwtwVo97/M1y+8Xpfw6tfG0iKc5XPoKv9UnRr4Yy3VnMiL0Wdjj874ywQ/o0X+zn7VlNMW4PBfkI3W82ms+EKavSgUIO1L7cwidwFiektkb37D3HOei66076QCwp5NZ53yLISpftdmzYGjvbSPwhILIwiDcN95vKOR9WqC4g/zN+CQnn4cF9CYyNRvamz46D1/iltU0QI9ho6BjrpRPH9KmM3oYiC4p+FhvvJBHy32Sxzmu1vMh/b4dPwP/4yL5vp50KqxdjdgFtcbW48nAYE4/8="
    metodoDePago="Depósito en cuenta o compensación de documentos"
    Moneda="USD"
    TipoCambio="13.45"
    subTotal="4797.1012"
    descuento="0"
    total="5564.64"
    LugarExpedicion="México, D.F.">
 
    <cfd:Emisor rfc="INC101109Q36"
            nombre="Incuvox, S.A. de C.V.">
            <cfd:DomicilioFiscal calle="José Enrique Pestalozzi"
                             noExterior="837-A"
                             colonia="Narvarte Poniente"
                             localidad="Distrito Federal"
                             referencia="Esquina con Concepción Beistegui"
                             municipio="Benito Juárez"
                             estado="Distrito Federal"
                             pais="México"
                             codigoPostal="03020"/>
            <cfd:ExpedidoEn calle="José Enrique Pestalozzi"
                        noExterior="837-A"
                        colonia="Narvarte Poniente"
                        localidad="Distrito Federal"
                        municipio="Benito Juárez"
                        estado="Distrito Federal"
                        pais="México"
                        codigoPostal="03020"/>
            <cfd:RegimenFiscal Regimen="Persona Moral, Régimen General"/>
    </cfd:Emisor>
 
    <cfd:Receptor rfc="JCC960111P76"
              nombre="Juan Camanei Company, S.A. de C.V.">
              <cfd:Domicilio calle="Av. Insurgentes Sur"
                         noExterior="1600"
                         noInterior="301"
                         colonia="Guadalupe Inn"
                         localidad="Distrito Federal"
                         municipio="Álvaro Obregón"
                         estado="Distrito Federal"
                         pais="México"
                         codigoPostal="01020"/>
    </cfd:Receptor>
 
    <cfd:Conceptos>
        <cfd:Concepto cantidad="1.00"
                  unidad="pz"
                  noIdentificacion="A104DE"
                  descripcion="Tarjeta Sangoma A104De AFT para 4 x T1/E1 con cancelador de eco"
                  valorUnitario="2429.10"
                  importe="2429.10">
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="104E4DM-10414"
                         descripcion="Tarjeta Sangoma A104De AFT para 4 x T1/E1 con cancelador de eco">
                         <cfd:InformacionAduanera numero="3817-2000166"
                                              fecha="2012-03-15"
                                              aduana="México"/>
                  </cfd:Parte>
        </cfd:Concepto>
        <cfd:Concepto cantidad="4.00"
                  unidad="pz"
                  noIdentificacion="BANEG703"
                  descripcion="Convertidor de Impedancia de 75 a 120 Ohms con conector RJ45 a CCITT G703"
                  valorUnitario="70.00"
                  importe="280.00">
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="NEO-B1267"
                         descripcion="Convertidor de Impedancia de 75 a 120 Ohms con conector RJ45 a CCITT G703">
                         <cfd:InformacionAduanera numero="3646-0001935"
                                              fecha="2010-07-05"
                                              aduana="México"/>
                  </cfd:Parte>
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="NEO-B1268"
                         descripcion="Convertidor de Impedancia de 75 a 120 Ohms con conector RJ45 a CCITT G703">
                         <cfd:InformacionAduanera numero="3646-0001935"
                                              fecha="2010-07-05"
                                              aduana="México"/>
                  </cfd:Parte>
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="NEO-B1271"
                         descripcion="Convertidor de Impedancia de 75 a 120 Ohms con conector RJ45 a CCITT G703">
                         <cfd:InformacionAduanera numero="3646-0001935"
                                              fecha="2010-07-05"
                                              aduana="México"/>
                  </cfd:Parte>
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="NEO-B1272"
                         descripcion="Convertidor de Impedancia de 75 a 120 Ohms con conector RJ45 a CCITT G703">
                         <cfd:InformacionAduanera numero="3646-0001935"
                                              fecha="2010-07-05"
                                              aduana="México"/>
                  </cfd:Parte>
        </cfd:Concepto>
        <cfd:Concepto cantidad="1.00"
                  unidad="pz"
                  noIdentificacion="D100-060E"
                  descripcion="Tarjeta Sangoma D100-060 para transcoding de 60 puertos"
                  valorUnitario="787.50"
                  importe="787.50">
                  <cfd:Parte cantidad="1.00"
                         noIdentificacion="D100-60E-00125"
                         descripcion="Tarjeta Sangoma D100-060 para transcoding de 60 puertos">
                         <cfd:InformacionAduanera numero="3646-1001788"
                                              fecha="2011-06-16"
                                              aduana="México"/>
                  </cfd:Parte>
        </cfd:Concepto>
        <cfd:Concepto cantidad="1.00"
                  unidad="pz"
                  noIdentificacion="D1X0-UPG-340"
                  descripcion="Upgrade de 60 a 400 puertos para Tarjeta Sangoma D100-060E"
                  valorUnitario="1300.5012"
                  importe="1300.5012">
        </cfd:Concepto>
    </cfd:Conceptos> 
 
    <cfd:Impuestos totalImpuestosTrasladados="767.54">
               <cfd:Traslados>
                   <cfd:Traslado impuesto="IVA"
                             tasa="16.00"
                             importe="767.54"/>
                   </cfd:Traslados>
    </cfd:Impuestos>
 
    <cfd:Addenda>
        <Incuvox xmlns="http://incuvox.com/cfd"
                 xsi:schemaLocation="http://incuvox.com/cfd
                                     http://incuvox.com/cfd/addenda.xsd">
                 <Factura Status="Emitida"/>
                 <Contacto Nombre="Juan Camanei"
                           eMail="juan@camanei.com.mx"
                           Telefono="(55)53506500"/>
                 <Note>Equipo solicitado por Juan Camanei</Note>
        </Incuvox>
    </cfd:Addenda>
 
</cfd:Comprobante>

Los cambios importantes son el uso del prefijo “cfd:” en los tags de XML que usa la factura electrónica, así como la inclusión de los campos “Moneda”, “TipoCambio”, “metodoDePago” y en el emisor el campo “Regimen”. En el artículo anterior describo las dependencias de este programa.

Autor: Fernando “El Pop” Romo (pop at cofradia.org), twitter @El_Pop


Si este artículo te es útil, ayúdanos con un donativo de 100.00 MXN para poder seguir operando:






0 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 50 votes, average: 0.00 out of 5 (0 votes, average: 0.00 out of 5)
You need to be a registered member to rate this post.
Loading ... Loading ...
Perl, Programacion | RSS 2.0 |     1,392 views

RSS feed

1 Comment »

Comment by Mauricio Baeza
2012-07-12 17:16:59

En CFDI, el prefijo CFDI esta claro tanto el XSD: http://www.sat.gob.mx/cfd/3/cfdv32.xsd
como en el XSLT: http://www.sat.gob.mx/sitio_internet/cfd/3/cadenaoriginal_3_0/cadenaoriginal_3_2.xslt

Pero para CFD, en el XLST, si viene el prefijo CFD: http://www.sat.gob.mx/sitio_internet/cfd/2/cadenaoriginal_2_2/cadenaoriginal_2_2.xslt
pero en el XSD no: http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv22.xsd

El validador del SAT: https://www.consulta.sat.gob.mx/SICOFI_WEB/ModuloECFD_Plus/ValidadorComprobantes/Validador.asp
pasa correctamente la validación con y sin prefijo CFD, pero muchos validadores que están pululando por ahí, incluyendo los de varios que se creen dueños de la verdad en cuestión de facturacíon electrónica.

Lo menciono para que tomen sus precauciones.

Saludos

 
Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.

Trackback responses to this post