Generacion Addenda XML de factura de Comercial Mexicana

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

Introduccion
Afortunadamente Comercial Mexicana decidio usar el estandar de la AMECE para la factura electronica, en lugar de hacer uno propio de remision como en el caso de soriana.
De aqui http://www.amece.org.mx/amece/descargas/est_com/GIM-INVOIC-AMECE-XML-CFD.zip se puede obtener la guia de implementacion XML para la factura electronica.
Sigo sin estar muy convencido del esquema que proporciono Amece o el que me dio Soriana, lo parte que no me gusta es que estan metiendo nuevos elemntos hijos a la addenda en el mismo namespace. El SAT en algun lugar muy econido dice que lo que se agregue a la addenda debe de tener su propio namespace.
Como lo estan soluciando los socios comerciales es aciendo su propio esqueme que incluye la parte del SAT y ademas su ampliacion, cosa que veo incorrecta.
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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
<?php
//
// +-------------------------------------------------------------------------------+
// | satxcome.php : Genera Factura electronica Comercial Mexicana XML                        |
// +-------------------------------------------------------------------------------+
// | Copyright (c) 2006  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>                                |
// +-------------------------------------------------------------------------------+
// |  4/Julio/2006   Version original en base a guia 1.3.1 de la AMECE             |
// +-------------------------------------------------------------------------------+
//
function satxcome($nufa,$data) {
// {{{ 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");      // Contiene un regisro por linea/partida de la factura
require_once("dbi/clproduc.class.php");      // Datos Generales del Producto
require_once("dbi/clclient.class.php");      // Datos Generales del Producto
require_once "lib/getfolio.php";             // Le suma uno al foliador y regresa el siguiente folio
require_once "lib/numealet.php";             // genera el texto de un importe con letras
global $conn;                                // Conexion adodb a la base de datos
// }}}
// {{{ Inicialice varibles / contadores globales
error_reporting(E_ALL);
$remi = "";
$fact = new Clfactur($conn,$nufa);
$clie = new Clclient($conn,(int)$fact->row["factnucl"],'renglon');
// }}}
// {{{ Encabesados generales 
// +--------------------------------------------------------------------+
// | Genera el nodo raiz de la remision                                 |
// +--------------------------------------------------------------------+
$serie = substr($nufa,0,4);
$folio = substr($nufa,4);
$auto = $data['noAprobacion']; // Numero de autorizacion del SAT de los folios
//$gln = get_gln((int)$clie->row["cliesucu"]); // GLN del cliente en base a la sucursal
//$gln2 = get_gln((int)$clie->row["cliesucu"]); // GLN del cliente en base a la sucursal
$gln2 = $conn->getOne("select eancode from ediean where eansucu = ".$clie->row["cliesucu"]);
$fdoc = substr(fix_fdoc($fact->row["factfdoc"]),0,10);
$g_folio = $conn->getOne("select cfdcomercia from clfacedi where fedinufa = '$nufa'"); // Lee el folio anterior si existe
if (!$g_folio) $g_folio = getfolio("cte",6,"SATXINVO",20); // Toma folio consecutivo para cada mensaje EDI
 
 
 
global $xml, $root;
$xml = new DOMdocument("1.0","UTF-8");
$root = $xml->createElement("requestForPayment");
$root = $xml->appendChild($root);
 
$att = array("type"=>"SimpleInvoiceType",
             "contentVersion"=>"1.3.1",
             "documentStructureVersion"=>"AMC7.1",
             "documentStatus"=>"ORIGINAL",
             "DeliveryDate"=>$fdoc);
carga_att($root,$att);
$requestForPaymentIdentification = $xml->createElement("requestForPaymentIdentification");
$ele = array( "entityType"=>"INVOICE",
              "uniqueCreatorIdentification"=>$nufa);
carga_eles($requestForPaymentIdentification,$ele);
 
$specialInstruction = $xml->createElement("specialInstruction");
$specialInstruction->setAttribute("code","ZZZ");
$text = $xml->createElement("text", numealet($fact->row["factimto"]));
$tmp = $specialInstruction->appendChild($text);
$tmp = $root->appendChild($specialInstruction);
 
$orderIdentification = $xml->createElement("orderIdentification");
$referenceIdentification = $xml->createElement("referenceIdentification", utf8_encode(trim($fact->row["factnpec"])));
$referenceIdentification->setAttribute("type","ON");
$ReferenceDate = $xml->createElement("ReferenceDate", $fdoc);
$tmp = $orderIdentification->appendChild($referenceIdentification);
$tmp = $orderIdentification->appendChild($ReferenceDate);
$tmp = $root->appendChild($orderIdentification);
 
$AdditionalInformation = $xml->createElement("AdditionalInformation");
$referenceIdentification = $xml->createElement("referenceIdentification", $auto);
$referenceIdentification->setAttribute("type","ATZ");
$tmp = $AdditionalInformation->appendChild($referenceIdentification);
$tmp = $root->appendChild($AdditionalInformation);
 
$buyer = $xml->createElement("buyer");
$gln = $xml->createElement("gln", "7505000099632");    // Numero GLN de la sucursal
$tmp = $buyer->appendChild($gln);
$contactInformation = $xml->createElement("contactInformation");
$personOrDepartmentName = $xml->createElement("personOrDepartmentName");
$text = $xml->createElement("text","COMPRADOR");
$tmp = $personOrDepartmentName->appendChild($text);
$tmp = $contactInformation->appendChild($personOrDepartmentName);
$tmp = $buyer->appendChild($contactInformation);
$tmp = $root->appendChild($buyer);
 
$seller = $xml->createElement("seller");
$gln = $xml->createElement("gln", "7505000065005"); // GLN de la Corona
$alternatePartyIdentification = $xml->createElement("alternatePartyIdentification", "315057");
$alternatePartyIdentification->setAttribute("type","SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY");
$tmp = $seller->appendChild($gln);
$tmp = $seller->appendChild($alternatePartyIdentification);
$tmp = $root->appendChild($seller);
 
 
$shipto = $xml->createElement("shipTo");
$gln = $xml->createElement("gln", $gln2);
$tmp = $shipto->appendChild($gln);
$nameandaddress = $xml->createElement("nameAndAddress");
$name = $xml->createElement("name", satxcome_fix($clie->row["clienone"]));
$tmp = $nameandaddress->appendChild($name);
$calle = substr(trim($fact->row["factcdir"])." ".trim($fact->row["factccol"]),0,34);
$streetaddressone = $xml->createElement("streetAddressOne", satxcome_fix($calle));
$tmp = $nameandaddress->appendChild($streetaddressone);
$city = $xml->createElement("city", satxcome_fix($fact->row["factnpue"]));
$tmp = $nameandaddress->appendChild($city);
$postalcode = $xml->createElement("postalCode", satxcome_fix($fact->row["factcodp"]));
$tmp = $nameandaddress->appendChild($postalcode);
$tmp = $shipto->appendChild($nameandaddress);
$tmp = $root->appendChild($shipto);
 
// }}}
// {{{   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++) {
    $nupr = (int)$fali->faliprod[$i];
    $prod = new Clproduc($conn, $nupr,'renglon');
 
    $lineItem = $xml->createElement("lineItem");
    $lineItem->setAttribute("type","SimpleInvoiceLineItemType");
    $lineItem->setAttribute("number",$i+1);
 
      $tradeItemIdentification = $xml->createElement("tradeItemIdentification");
        $gtin = $xml->createElement("gtin",ltrim($prod->row["prodea13"],"0"));
        $tmp = $tradeItemIdentification->appendChild($gtin);
      $tmp = $lineItem->appendChild($tradeItemIdentification);
 
      $alternateTradeItemIdentification = $xml->createElement("alternateTradeItemIdentification",ltrim($prod->row["prodea13"],"0"));
      $alternateTradeItemIdentification->setAttribute("type","BUYER_ASSIGNED");
      $tmp = $lineItem->appendChild($alternateTradeItemIdentification);
 
      $tradeItemDescriptionInformation = $xml->createElement("tradeItemDescriptionInformation");
        $longText = $xml->createElement("longText",trim($prod->row["proddeco"]));
        $tmp = $tradeItemDescriptionInformation->appendChild($longText);
      $tmp = $lineItem->appendChild($tradeItemDescriptionInformation);
 
      $invoicedQuantity = $xml->createElement("invoicedQuantity",$fali->faliunif[$i]);
      $invoicedQuantity->setAttribute("unitOfMeasure","EA");
      $tmp = $lineItem->appendChild($invoicedQuantity);
 
      $prec = $fali->falineto[$i] / $fali->faliunif[$i];
 
      $grossPrice = $xml->createElement("grossPrice");
        $Amount = $xml->createElement("Amount",$prec);
        $tmp = $grossPrice->appendChild($Amount);
      $tmp = $lineItem->appendChild($grossPrice);
 
 
      $netPrice = $xml->createElement("netPrice");
        $Amount = $xml->createElement("Amount",$prec);
        $tmp = $netPrice->appendChild($Amount);
      $tmp = $lineItem->appendChild($netPrice);
 
      $AdditionalInformation = $xml->createElement("AdditionalInformation");
        $referenceIdentification = $xml->createElement("referenceIdentification", utf8_encode(trim($fact->row["factnpec"])));
        $referenceIdentification->setAttribute("type","ON");
        $tmp = $AdditionalInformation->appendChild($referenceIdentification);
      $tmp = $lineItem->appendChild($AdditionalInformation);
 
      $totalLineAmount = $xml->createElement("totalLineAmount");
        $grossAmount = $xml->createElement("grossAmount");
        $Amount = $xml->createElement("Amount",$fali->falineto[$i]);
          $tmp = $grossAmount->appendChild($Amount);
        $tmp = $totalLineAmount->appendChild($grossAmount);
        $netAmount = $xml->createElement("netAmount");
        $Amount = $xml->createElement("Amount",$fali->falineto[$i]);
          $tmp = $netAmount->appendChild($Amount);
        $tmp = $totalLineAmount->appendChild($netAmount);
      $tmp = $lineItem->appendChild($totalLineAmount);
 
    $tmp = $root->appendChild($lineItem);
    $lineItem=null;
 
}
// }}}
// {{{ Finaliza el documento XML
$ret=$conn->replace("cfdcomercia",array("fedinufa"=>$nufa,"fedifoli"=>$g_folio),"fedinufa",true);
 
$neto = $fact->row["factneto"]+ $fact->row["factnet2"];
$totalAmount = $xml->createElement("totalAmount");
  $Amount = $xml->createElement("Amount", $neto); 
  $tmp = $totalAmount->appendChild($Amount);
$tmp = $root->appendChild($totalAmount);
 
$neto = $fact->row["factneto"]+ $fact->row["factnet2"];
$baseAmount = $xml->createElement("baseAmount");
  $Amount = $xml->createElement("Amount", $neto);
  $tmp = $baseAmount->appendChild($Amount);
$tmp = $root->appendChild($baseAmount);
 
$tax = $xml->createElement("tax");
$tax->setAttribute("type","VAT");
  $taxPercentage = $xml->createElement("taxPercentage", $fact->row["factpoim"]);
  $tmp = $tax->appendChild($taxPercentage);
  $taxAmount = $xml->createElement("taxAmount", $fact->row["factimpu"]);
  $tmp = $tax->appendChild($taxAmount);
  $taxCategory = $xml->createElement("taxCategory", "TRANSFERIDO");
  $tmp = $tax->appendChild($taxCategory);
$tmp = $root->appendChild($tax);
 
$payableAmount = $xml->createElement("payableAmount");
  $Amount = $xml->createElement("Amount", $fact->row["factimto"]); 
  $tmp = $payableAmount->appendChild($Amount);
$tmp = $root->appendChild($payableAmount);
 
$xml->preserveWhiteSpace = false;
// $xml->formatOutput = true;
$remi = $xml->saveXML();
return($remi);
}
// }}}
// {{{ carga_eles : genera nuevos elemntos al documento root
function carga_eles($obj, $ele) {
global $root, $xml;
foreach ($ele as $key => $val) {
    $tmp = $xml->createElement($key, utf8_encode(trim($val)));
    $tmp = $obj->appendChild($tmp);
}
$tmp = $root->appendChild($obj);
}
// }}}
// {{{ carga_att : genera atributos al elemento indicado
function carga_att($obj, $ele) {
global $root, $xml;
foreach ($ele as $key => $val) $obj->setAttribute($key, utf8_encode(trim($val)));
}
// }}}
// {{{ satxcome_fix :  le aplica el trim, el utf_encode, y el reg_replace para quitar los espacios de mas
function satxcome_fix($val) {
    $ret = preg_replace('/\s\s+/', ' ', $val);
    $ret = utf8_encode(trim($ret));
    return $ret;
    }
    // }}}
// {{{ fix_fdoc : Cuando el timestamp viene dd/mm/yyyy lo convierte a yyyy-mm-dd
function fix_fdoc($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);
}
// }}}
Ejemplo de uso de la funcion
Este programa genera los datos de la factura electronica que se van a agregar como Addenda a la factura electronica del SAT.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
########
#    Generacion de las facturas electronicas para Comercial Mexicana
########
DEFINE(BDD,cte);
require_once("lib/conecta.php");
require_once("satxcome.php");
require_once("satxarre.php");
require_once("satxmls.php");
$nufa = "XAFA887238";
$addenda = satxcome($nufa);
$data = satxarre($nufa);
$xml = satxmls($data,$addenda,"./");
?>
Al ejecutarse este programa genera el mensaje XML que se puede consultar aqui.