Lee la factura del ERP y genera un formato Intermedio
Arreglo Asociativo

Contenido/contents:
Introducion
Codigo Fuente
Uso de la funcion
Pagina anterior/Previous page

Introduccion
Si revisan la estructura del arreglo que se genera podran ver que es muy parecido al formato XML que pide el SAT, entonces surge la pregunta, porque generar este arreglo y no generar directamente el XML?
Este paso intermedio es porque ademas de generar facturas, se generan comprobantes de abonos en parcialdiades, notas de credito y algunas mas hasta recibos de honorarios.
Normalmente en la base de datos son tablas diferentes las Notas de Credito y las Facturas (al menos en mi caso asi es) asi que tengo este programa satxarre.php para las facturas y el satxarre_nocr.php para las notras de credito y el satxarre_cabo.php para los comprobantes de pago en parcialidades, pero los 3 usan el satxmlsv2.php para generar el CFD.
Codigo Fuente
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
<?php
//
// +---------------------------------------------------------------------------+
// | satxarre.php : Genera arreglo asociativo en base a la factura del ERP     |
// +---------------------------------------------------------------------------+
// | Copyright (c) 2005  Fabrica de Jabon la Corona, SA de CV                  |
// +---------------------------------------------------------------------------+
// | This program is free software; you can redistribute it and/or             |
// | modify it under the terms of the GNU General Public License               |
// | as published by the Free Software Foundation; either version 2            |
// | of the License, or (at your option) any later version.                    |
// |                                                                           |
// | This program is distributed in the hope that it will be useful,           |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
// | GNU General Public License for more details.                              |
// |                                                                           |
// | You should have received a copy of the GNU General Public License         |
// | along with this program; if not, write to the Free Software               |
// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA|
// +---------------------------------------------------------------------------+
// | Autor: Fernando Ortiz <fortiz@lacorona.com.mx>                            |
// +---------------------------------------------------------------------------+
// |                                                                           |
// +---------------------------------------------------------------------------+
//
function satxarre($nufa,$addenda="") {
// {{{ carga librerias requeridas para obtener los datos
require_once("dbi/clfactur.class.php");  // Es el registro maestro de la factura
require_once("dbi/clflinea.class.php");  // Regisro por partida de la factura
require_once("dbi/clcadena.class.php");  // Cadenas
require_once("dbi/clclient.class.php");  // Clientes
require_once("lib/cn_envio_bodega.php");  // Lista de clientes 'nuestros'
require_once("lib/cn_envio_export.php");  // Bodegas nuestras extranjero
require_once("lib/getrefe.php");  
global $conn;                            // Conexion adodb a la base de datos
// }}}
// {{{ Inicialice varibles / contadores globales
error_reporting(E_ALL);
$fact = new Clfactur($conn,$nufa,'renglon');
$clie = new Clclient($conn,(int)$fact->row['factnucl'],'renglon');
$cade = new Clcadena($conn,(int)$clie->row['clienuca'],'renglon');
$arr = array();
// }}}
// {{{ Encabezados generales 
$arr['folio'] = substr($nufa,4);
$arr['fecha'] = str_replace(array('-',' ',':'),'',fix_fdoc_arre($fact->row["factfdoc"]));
$arr['serie'] = substr($nufa,0,4);
//  
// +---------------------------------------------------------------------------+
// | $arr['noAprobacion'] 
// | $arr['anoAprobacion'] 
// | $arr['noCertificado'] 
require "satxfoli.inc.php"; 
// +---------------------------------------------------------------------------+
//  
$arr['subTotal'] = $fact->row["factneto"]+$fact->row['factnet2'];  // Antes de impuestos
//$arr['subTotal'] = $fact->row["factimpa"]+$fact->row['factimp2'];  // Antes de impuestos
//$arr['descuento'] = $fact->row["factdecl"]+$fact->row['factdec2'];  // prueba
$arr['total'] = $fact->row["factimto"];  // Despues de impuestos
$arr['metodoDePago'] = "";
$nuca = $fact->row["factnuca"]; 
if ( cn_envio_bodega($fact->row["factnucl"]) && 
     !cn_envio_export($fact->row["factnucl"])) {
         #
         # Trasalado entre nuestras bodegas
         #
    $arr['tipoDeComprobante'] = "traslado";
    $orig = trim($conn->GetOne("Select bodenomb from clbodega WHERE bodenubo = ".$fact->row["factnubo"]));
    $dest = trim($conn->GetOne("Select bodenomb from clbodega WHERE bodenucl = ".$fact->row["factnucl"]));
    $arr['formaDePago'] = "ESTE COMPROBANTE SE EXPIDE PARA TRANSPORTAR MERCANCIAS DE NUESTRA PROPIEDAD DE BODEGA $orig A BODEGA $dest";
} else {
         #
         # Todas las demas facturas
         #
    $arr['tipoDeComprobante'] = "ingreso";
    $arr['formaDePago'] = "EL PAGO DE ESTA FACTURA (CONTRAPRESTACION) SE EFECTUARA EN UNA SOLA EXHIBICION, SI POR ALGUNA RAZON NO FUERA ASI, EMITIREMOS LOS COMPROBANTES DE LAS PARCIALIDADES RESPECTIVAS";
}
if ($nuca == 29 || $nuca == 16 || $nuca == 19 || $nuca == 30 ||
    $nuca == 34 || $nuca == 63 || $nuca == 92 || $nuca == 146)  $arr['formaDePago'] = "PAGO EN UNA SOLA EXHIBICION";
 
 
$arr['Emisor']['nombre'] = "FABRICA DE JABON LA CORONA, S.A. DE C.V.";
$arr['Emisor']['rfc'] = "FJC780315E91";
$arr['Emisor']['ExpedidoEn']['calle'] = $fact->row["factedir"];
$arr['Emisor']['ExpedidoEn']['noExterior'] = $fact->row["facteext"];
$arr['Emisor']['ExpedidoEn']['noInterior'] = $fact->row["facteint"];
$arr['Emisor']['ExpedidoEn']['localidad'] = substr($fact->row["factepob"],6);
$arr['Emisor']['ExpedidoEn']['municipio'] = substr($fact->row["factepob"],6);
$arr['Emisor']['ExpedidoEn']['estado'] = get_estado($fact->row["factepob"]);
$arr['Emisor']['ExpedidoEn']['pais'] = "MEXICO";
$arr['Emisor']['ExpedidoEn']['codigoPostal'] = substr($fact->row["factepob"],0,5);
 
$arr['Receptor']['nombre'] = $fact->row["factnopr"];
// Usa tabla ISO8859-2
if ($nuca == 29)
    $arr['Receptor']['nombre'] = "ORGANIZACI".chr(211)."N SAHUAYO, S.A. DE C.V.";
$arr['Receptor']['rfc'] = $fact->row["factrfca"];
 
if (strlen(trim($cade->row['cadecall']))) {
    $a_edo = $cade->row["cadecoes"];
    $a_calle = $cade->row["cadecall"];
    $a_noExterior = $cade->row["cadenext"];
    $a_noInterior = $cade->row["cadenint"];
    $a_colonia = $cade->row["cadecolo"];
    $a_localidad = $cade->getPueb("cadecoes","cademuni","cadepobl");
    $a_municipio = $cade->getMuni("cadecoes","cademuni");
    $a_codigoPostal = $cade->row["cadecodp"];
} else {
    $a_edo = $fact->row["factedoe"];
    $a_calle = $fact->row["factcdir"];
    $a_noExterior = $fact->row["factnext"];
    $a_noInterior = $fact->row["factnint"];
    $a_colonia = $fact->row["factccol"];
    $a_localidad = $fact->row["factnpue"];
    $a_municipio = $fact->row["factnpue"];
    $a_codigoPostal = $fact->row["factcodp"];
}
 
if ($nuca == 29) $a_edo = $clie->row["cliecoes"];
if ($nuca == 29) $a_municipio = $clie->getPueb("cliecoes","cliemuni","cliepueb");
if ($nuca == 29) $a_colonia = satxarre_fix($fact->row["factccol"],35);
$edo = trim(getrefe("cte",6,"CLIECOES",$a_edo));
$pais = ($a_edo>40) ? $edo : "MEXICO";
$arr['Receptor']['Domicilio']['calle'] = $a_calle;
$arr['Receptor']['Domicilio']['noExterior'] = $a_noExterior;
$arr['Receptor']['Domicilio']['noInterior'] = $a_noInterior;
$arr['Receptor']['Domicilio']['colonia'] = $a_colonia;
$arr['Receptor']['Domicilio']['localidad'] = $a_localidad;
$arr['Receptor']['Domicilio']['municipio'] = $a_municipio;
$arr['Receptor']['Domicilio']['estado'] = $edo;
$arr['Receptor']['Domicilio']['pais'] = $pais;
$arr['Receptor']['Domicilio']['codigoPostal'] = $a_codigoPostal;
// }}}
// {{{  Datos para el esquema de detalllista solo si hace falta
// +--------------------------------------------------------------------+
// | Lee los datos de npec, fpec, gln solo si quieren complemento       |
// +--------------------------------------------------------------------+
//
if ($addenda=="detallista") {
    $arr['Complemento']['npec'] = $fact->row['factnpec'];
    $arr['Complemento']['fpec'] = $fact->row['factfpec'];
    $arr['Complemento']['gln'] = str_pad($fact->row['factnucl'],13,'0',STR_PAD_LEFT);
}
// }}}
// {{{  Diconsa
// +--------------------------------------------------------------------+
// | Lee los datos de almacen solo si es diconsa                        |
// +--------------------------------------------------------------------+
//
if ($addenda=="diconsa") {
    $arr['diconsa']['proveedor'] = 217;
    $arr['diconsa']['almacen'] = trim($clie->row['cliesucu']);
    $arr['diconsa']['pedido'] = trim($fact->row['factnpec']);
}
// }}}
// {{{   Para cada linea/partida de la factura (para cada producto
// +--------------------------------------------------------------------+
// | AHora si procesa la ocurrencia de productos de la factura          |
// +--------------------------------------------------------------------+
//
$fali = new Clflinea($conn, $nufa);
for ($i=0; $i<sizeof($fali->faliprod); $i++) {
    $unid = $fali->faliunif[$i];
    $impo = $fali->falineto[$i];
    if ($arr['serie']=='FIVA' && $fact->row["factrfca"]!="XAXX010101000")
        $arr['Conceptos'][$i+1]['descripcion'] = $fact->row['factobs1'].' '.
                                                 $fact->row['factobs2'].' '.
                                                 $fact->row['factobs3'];
    else
        $arr['Conceptos'][$i+1]['descripcion'] = $fali->falideco[$i];
    $arr['Conceptos'][$i+1]['cantidad'] = $unid;
    $arr['Conceptos'][$i+1]['valorUnitario'] = round((double)$impo / (double)$unid,2);
    $arr['Conceptos'][$i+1]['importe'] = $impo;
    if ($addenda=="detallista") {
        $arr['Conceptos'][$i+1]['poim'] = $fali->falipoim[$i];
        $arr['Conceptos'][$i+1]['impu'] = $fali->faliimpu[$i];
        $arr['Conceptos'][$i+1]['gtin'] = $fali->falicbar[$i];
        $arr['Conceptos'][$i+1]['prun'] = $fali->faliprun[$i];
        $arr['Conceptos'][$i+1]['neto'] = $fali->falineto[$i];
    }
}
// }}}
// {{{ Finaliza el arreglo
$arr['Traslados']['impuesto'] = "IVA";
$arr['Traslados']['tasa'] = $fact->row["factpoim"];
$arr['Traslados']['importe'] = $fact->row["factimpu"];
return($arr);
}
// }}}
// {{{ fix_fdoc_arre : Cuando el timestamp viene dd/mm/yyyy lo convierte a yyyy-mm-dd
function fix_fdoc_arre($fdoc) {
    if (strpos($fdoc,"/")!==FALSE) { // tiene diagonales viene dd/mm/yyyy hh:mm
        list($f,$h)=explode(" ",$fdoc);
        list($d,$m,$y)=explode("/",$f);
        $fdoc = "$y-$m-$d $h";
    }
    return ($fdoc);
}
// }}}
// {{{ 'Busca' el estado dentro del campo
function get_estado($esta) {
    $coes="XX";
    if (stristr($esta,"AGUAS")) $coes="AGUASCALIENTES";
    if (stristr($esta,"MEXICALI")) $coes="BAJA CALIFORNIA";
    if (stristr($esta,"B.C.S.")) $coes="BAJA CALIFORNIA SUR";
    if (stristr($esta,"CAMPE")) $coes="CAMPECHE";
    if (stristr($esta,"TUXTLA")) $coes="CHIAPAS";
    if (stristr($esta,"TAPACHULA")) $coes="CHIAPAS";
    if (stristr($esta,"CHIH")) $coes="CHIHUAHUA";
    if (stristr($esta,"COAH")) $coes="COAHUILA";
    if (stristr($esta,"COLIMA")) $coes="COLIMA";
    if (stristr($esta,"D.F.")) $coes="DISTRITO FEDERAL";
    if (stristr($esta,"DURANGO")) $coes="DURANGO";
    if (stristr($esta,"IRAPUATO")) $coes="GUANAJUATO";
    if (stristr($esta,"ACAPULCO")) $coes="GUERRERO";
    if (stristr($esta,"HIDALGO")) $coes="HIDALGO";
    if (stristr($esta,"GUADALAJARA")) $coes="JALISCO";
    if (stristr($esta,"XALOSTOC")) $coes="EDO. DE MEXICO";
    if (stristr($esta,"MORELIA")) $coes="MICHOACAN";
    if (stristr($esta,"UNDAMEO MICH")) $coes="MICHOACAN";
    if (stristr($esta,"MORELOS")) $coes="MORELOS";
    if (stristr($esta,"NAYARIT")) $coes="NAYARIT";
    if (stristr($esta,"GARZA")) $coes="NUEVO LEON";
    if (stristr($esta,"OAX")) $coes="OAXACA";
    if (stristr($esta,"PUEBLA")) $coes="PUEBLA";
    if (stristr($esta,"QUERETARO")) $coes="QUERETARO";
    if (stristr($esta,"QUINTANA")) $coes="QUINTANA ROO";
    if (stristr($esta,"SAN LUIS")) $coes="SAN LUIS POTOSI";
    if (stristr($esta,"CULIACAN")) $coes="SINALOA";
    if (stristr($esta,"HERMOSILLO")) $coes="SONORA";
    if (stristr($esta,"VILLAHERMOSA")) $coes="TABASCO";
    if (stristr($esta,"ALTAMIRA")) $coes="TAMAULIPAS";
    if (stristr($esta,"TLAXCALA")) $coes="TLAXCALA";
    if (stristr($esta,"PARAJE NUEVO")) $coes="VERACRUZ";
    if (stristr($esta,"UMAN")) $coes="YUCATAN";
    if (stristr($esta,"ZACATECAS")) $coes="ZACATECAS";
    return ($coes);
}
// }}}
// {{{ Convierte el caracter especial a char(209)
function satxarre_fix($str,$largo=-1) {
    $tmp = trim($str);
    $tmp = str_replace(array("}","{"),chr(209),$tmp);
    if ($largo>0) $tmp = substr($tmp,0,$largo-1);
    return ($tmp);
                }
// }}}
?>
Ejemplo de uso de la funcion
Este pequeño programa genera el arreglo de la factura seleccionada.
1
2
3
4
5
6
7
8
9
10
<?php
require_once("myconn/myconn.inc.php");
$conn = myconn();
require_once("satxarre.php");
require_once("satxmlsv2.php");
$data = satxarre("FAXA051661");
echo "<pre>";
print_r($data);
echo "</pre>";
?>
A continuacion esta un listado de lo que presenta el navegador al ejecutar el programa anterior:
Array
(
    [folio] => 051661
    [fecha] => 20061120085048
    [serie] => FAXA
    [noAprobacion] => 2951
    [anoAprobacion] => 2006
    [noCertificado] => 00001000000000823747
    [subTotal] => 43824.69
    [total] => 50398.39
    [metodoDePago] => 
    [tipoDeComprobante] => ingreso
    [formaDePago] => EL PAGO DE ESTA FACTURA (CONTRAPRESTACION) SE EFECTUARA EN UNA SOLA EXHIBICION, SI POR ALGUNA RAZON NO FUERA ASI, EMITIREMOS LOS COMPROBANTES DE LAS PARCIALIDADES RESPECTIVAS
    [Emisor] => Array
        (
            [nombre] => FABRICA DE JABON LA CORONA, S.A. DE C.V.
            [rfc] => FJC780315E91
            [ExpedidoEn] => Array
                (
                    [calle] => CARLOS B.ZETINA NO.80                 
                    [noExterior] => 
                    [noInterior] => 
                    [localidad] => XALOSTOC, EDO. DE MEXICO        
                    [municipio] => XALOSTOC, EDO. DE MEXICO        
                    [estado] => EDO. DE MEXICO
                    [pais] => MEXICO
                    [codigoPostal] => 55348
                )

        )

    [Receptor] => Array
        (
            [nombre] => NUEVA WAL-MART DE MEXICO SRL DE CV
            [rfc] =>  NWM9709244W4
            [Domicilio] => Array
                (
                    [calle] => NEXTENGO                          
                    [noExterior] => 78        
                    [noInterior] => 
                    [colonia] => STA. CRUZ ACAYUCAN                
                    [localidad] => AZCAPOTZALCO
                    [municipio] => AZCAPOTZALCO
                    [estado] => DISTRITO FEDERAL
                    [pais] => MEXICO
                    [codigoPostal] => 2770
                )

        )

    [Conceptos] => Array
        (
            [1] => Array
                (
                    [descripcion] => TEPEYAC 25P 400 G C/ENV           
                    [cantidad] => 22
                    [valorUnitario] => 110.97
                    [importe] => 2441.34
                )

            [2] => Array
                (
                    [descripcion] => ZOTE AZUL 25P 400 G.              
                    [cantidad] => 11
                    [valorUnitario] => 110.97
                    [importe] => 1220.67
                )

            [3] => Array
                (
                    [descripcion] => ZOTE BCO. 25P 400 G               
                    [cantidad] => 22
                    [valorUnitario] => 110.97
                    [importe] => 2441.34
                )

            [4] => Array
                (
                    [descripcion] => ZOTE BCO. 50P 200 G               
                    [cantidad] => 7
                    [valorUnitario] => 110.97
                    [importe] => 776.79
                )

            [5] => Array
                (
                    [descripcion] => ZOTE ROSA 25P 400 G               
                    [cantidad] => 44
                    [valorUnitario] => 110.97
                    [importe] => 4882.68
                )

            [6] => Array
                (
                    [descripcion] => ZOTE ROSA 50P 200 G               
                    [cantidad] => 6
                    [valorUnitario] => 110.97
                    [importe] => 665.82
                )

            [7] => Array
                (
                    [descripcion] => ROMA 4P 5 KGS                     
                    [cantidad] => 12
                    [valorUnitario] => 218.34
                    [importe] => 2620.08
                )

            [8] => Array
                (
                    [descripcion] => ROMA 10P 2 KGS                    
                    [cantidad] => 24
                    [valorUnitario] => 219.74
                    [importe] => 5273.64
                )

            [9] => Array
                (
                    [descripcion] => ROMA 10P 1 KG                     
                    [cantidad] => 120
                    [valorUnitario] => 111.29
                    [importe] => 13354.20
                )

            [10] => Array
                (
                    [descripcion] => FOCA 10P 2 KGS                    
                    [cantidad] => 12
                    [valorUnitario] => 233.87
                    [importe] => 2806.38
                )

            [11] => Array
                (
                    [descripcion] => BLANCA NIEVES 10P 2 KGS           
                    [cantidad] => 10
                    [valorUnitario] => 201.47
                    [importe] => 2014.65
                )

            [12] => Array
                (
                    [descripcion] => BLANCA NIEVES 10P 1 KG            
                    [cantidad] => 40
                    [valorUnitario] => 102.15
                    [importe] => 4086.00
                )

            [13] => Array
                (
                    [descripcion] => BRILOZA 10P 1 KG                  
                    [cantidad] => 5
                    [valorUnitario] => 102.15
                    [importe] => 510.75
                )

            [14] => Array
                (
                    [descripcion] => FOCA 12B 1LT                      
                    [cantidad] => 6
                    [valorUnitario] => 121.73
                    [importe] => 730.35
                )

        )

    [Traslados] => Array
        (
            [impuesto] => IVA
            [tasa] => 15.00
            [importe] => 6573.70
        )

) 
Este arreglo es el parametro de entrada para la funcion satxmls que ya genera el mensaje XML fiscalmente valido.