Merge lp:~vauxoo/openerp-mexico-localization/7.0-l10n_mx_facturae-Jinja2-template-CFD-CFDI-dev_jc into lp:openerp-mexico-localization/7.0

Proposed by Juan Carlos Hernandez
Status: Merged
Merge reported by: Moisés López - http://www.vauxoo.com
Merged at revision: not available
Proposed branch: lp:~vauxoo/openerp-mexico-localization/7.0-l10n_mx_facturae-Jinja2-template-CFD-CFDI-dev_jc
Merge into: lp:openerp-mexico-localization/7.0
Diff against target: 815 lines (+290/-247)
6 files modified
l10n_mx_facturae/__openerp__.py (+1/-0)
l10n_mx_facturae/invoice.py (+254/-204)
l10n_mx_facturae/template/cfd.xml (+1/-0)
l10n_mx_facturae_pac/invoice.py (+30/-39)
l10n_mx_facturae_pac_sf/ir_attachment_facturae.py (+3/-4)
l10n_mx_facturae_pac_sf/template/cfdi.xml (+1/-0)
To merge this branch: bzr merge lp:~vauxoo/openerp-mexico-localization/7.0-l10n_mx_facturae-Jinja2-template-CFD-CFDI-dev_jc
Reviewer Review Type Date Requested Status
Jorge Angel Naranjo Rogel - http://www.vauxoo.com Pending
Juan Carlos Hernandez Pending
Julio Serna-http://www.vauxoo.com Pending
Moisés López - http://www.vauxoo.com Pending
Review via email: mp+203193@code.launchpad.net

Description of the change

se agregó Jinja para crear los XML CFD y CFDI version 3.2.Es decir una plantilla para CFD y CFDI
se agregó una función para quitar los acentos.

To post a comment you must log in.
Revision history for this message
Moisés López - http://www.vauxoo.com (moylop260) wrote :

Merged to Trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'l10n_mx_facturae/__openerp__.py'
2--- l10n_mx_facturae/__openerp__.py 2013-10-04 23:02:23 +0000
3+++ l10n_mx_facturae/__openerp__.py 2014-01-25 00:46:46 +0000
4@@ -68,6 +68,7 @@
5 "l10n_mx_facturae_report",
6 "l10n_mx_facturae_group_show_wizards",
7 "l10n_mx_settings_facturae",
8+ "l10n_mx_params_pac",
9 ],
10 "demo" : [
11 "demo/l10n_mx_facturae_seq_demo.xml",
12
13=== modified file 'l10n_mx_facturae/invoice.py'
14--- l10n_mx_facturae/invoice.py 2013-12-10 01:11:31 +0000
15+++ l10n_mx_facturae/invoice.py 2014-01-25 00:46:46 +0000
16@@ -45,6 +45,9 @@
17 import os
18 import codecs
19 from datetime import datetime, timedelta
20+import jinja2
21+import xml
22+import unicodedata
23
24
25 def exec_command_pipe(name, *args):
26@@ -80,37 +83,6 @@
27 return val
28 return None
29
30-# TODO: Agregar una libreria para esto
31-
32-
33-def conv_ascii(text):
34- """
35- @param text : text that need convert vowels accented & characters to ASCII
36- Converts accented vowels, ñ and ç to their ASCII equivalent characters
37- """
38- old_chars = [
39- 'á', 'é', 'í', 'ó', 'ú', 'à', 'è', 'ì', 'ò', 'ù', 'ä', 'ë', 'ï', 'ö',
40- 'ü', 'â', 'ê', 'î', 'ô', 'û', 'Á', 'É', 'Í', 'Ó', 'Ú', 'À', 'È', 'Ì',
41- 'Ò', 'Ù', 'Ä', 'Ë', 'Ï', 'Ö', 'Ü', 'Â', 'Ê', 'Î', 'Ô', 'Û', 'ñ', 'Ñ',
42- 'ç', 'Ç', 'ª', 'º', '°', ' ', 'Ã', 'Ø'
43- ]
44- new_chars = [
45- 'a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o',
46- 'u', 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U', 'A', 'E', 'I',
47- 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'n', 'N',
48- 'c', 'C', 'a', 'o', 'o', ' ', 'A', '0'
49- ]
50- for old, new in zip(old_chars, new_chars):
51- try:
52- text = text.replace(unicode(old, 'UTF-8'), new)
53- except:
54- try:
55- text = text.replace(old, new)
56- except:
57- raise osv.except_osv(_('Warning !'), _(
58- "Can't recode the string [%s] in the letter [%s]") % (text, old))
59- return text
60-
61 # Cambiar el error
62 msg2 = "Contact you administrator &/or to info@vauxoo.com"
63
64@@ -118,6 +90,39 @@
65 class account_invoice(osv.Model):
66 _inherit = 'account.invoice'
67
68+ def remove_accents(self, cr, uid, ids, input_str):
69+ nkfd_form = unicodedata.normalize('NFKD', unicode(input_str))
70+ only_ascii = nkfd_form.encode('ASCII', 'ignore')
71+ return self.conv_ascii(cr, uid, ids, only_ascii)
72+
73+ def conv_ascii(self, cr, uid, ids, text):
74+ """
75+ @param text : text that need convert vowels accented & characters to ASCII
76+ Converts accented vowels, ñ and ç to their ASCII equivalent characters
77+ """
78+ old_chars = [
79+ 'á', 'é', 'í', 'ó', 'ú', 'à', 'è', 'ì', 'ò', 'ù', 'ä', 'ë', 'ï', 'ö',
80+ 'ü', 'â', 'ê', 'î', 'ô', 'û', 'Á', 'É', 'Í', 'Ó', 'Ú', 'À', 'È', 'Ì',
81+ 'Ò', 'Ù', 'Ä', 'Ë', 'Ï', 'Ö', 'Ü', 'Â', 'Ê', 'Î', 'Ô', 'Û', 'ñ', 'Ñ',
82+ 'ç', 'Ç', 'ª', 'º', '°', ' ', 'Ã', 'Ø', '&', '´'
83+ ]
84+ new_chars = [
85+ 'a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o', 'u', 'a', 'e', 'i', 'o',
86+ 'u', 'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U', 'A', 'E', 'I',
87+ 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'A', 'E', 'I', 'O', 'U', 'n', 'N',
88+ 'c', 'C', 'a', 'o', 'o', ' ', 'A', '0' ,'y', ''
89+ ]
90+ for old, new in zip(old_chars, new_chars):
91+ try:
92+ text = text.replace(unicode(old, 'UTF-8'), new)
93+ except:
94+ try:
95+ text = text.replace(old, new)
96+ except:
97+ raise osv.except_osv(_('Warning !'), _(
98+ "Can't recode the string [%s] in the letter [%s]") % (text, old))
99+ return text
100+
101 def create_report(self, cr, uid, res_ids, report_name=False, file_name=False, context=None):
102 """
103 @param report_name : Name of report with the name of object more type
104@@ -700,7 +705,7 @@
105 key_item_sort.append([key_too, data_dict[key_too]])
106 return key_item_sort
107
108- def dict2xml(self, data_dict, node=False, doc=False):
109+ def dict2xml(self, cr, uid, ids, data_dict, node=False, doc=False):
110 """
111 @param data_dict : Dictionary of attributes for add in the XML
112 that will be generated
113@@ -717,20 +722,20 @@
114 if isinstance(attribute, dict):
115 if not parent:
116 node = doc.createElement(element)
117- self.dict2xml(attribute, node, doc)
118+ self.dict2xml(cr, uid, ids, attribute, node, doc)
119 else:
120 child = doc.createElement(element)
121- self.dict2xml(attribute, child, doc)
122+ self.dict2xml(cr, uid, ids, attribute, child, doc)
123 node.appendChild(child)
124 elif isinstance(attribute, list):
125 child = doc.createElement(element)
126 for attr in attribute:
127 if isinstance(attr, dict):
128- self.dict2xml(attr, child, doc)
129+ self.dict2xml(cr, uid, ids, attr, child, doc)
130 node.appendChild(child)
131 else:
132 if isinstance(attribute, str) or isinstance(attribute, unicode):
133- attribute = conv_ascii(attribute)
134+ attribute = self.remove_accents(cr, uid, ids, attribute)
135 else:
136 attribute = str(attribute)
137 node.setAttribute(element, attribute)
138@@ -742,88 +747,104 @@
139 def _get_facturae_invoice_xml_data(self, cr, uid, ids, context=None):
140 if context is None:
141 context = {}
142- data_dict = self._get_facturae_invoice_dict_data(
143- cr, uid, ids, context=context)[0]
144- doc_xml = self.dict2xml({
145- 'Comprobante': data_dict.get('Comprobante')})
146- invoice_number = "sn"
147- (fileno_xml, fname_xml) = tempfile.mkstemp(
148+ data_dict = self._get_facturae_invoice_dict_data(cr, uid, ids, context=context)[0]
149+ data_xml=False
150+ fname_xml=False
151+ ir_seq_app_obj = self.pool.get('ir.sequence.approval')
152+ invoice = self.browse(cr, uid, ids[0], context=context)
153+ sequence_app_id = ir_seq_app_obj.search(cr, uid, [(
154+ 'sequence_id', '=', invoice.invoice_sequence_id.id)], context=context)
155+ if sequence_app_id:
156+ type_inv = ir_seq_app_obj.browse(cr, uid, sequence_app_id[0], context=context).type
157+ if not 'cfdi' in type_inv:
158+ #doc_xml = self.dict2xml(cr, uid, ids, {'Comprobante': data_dict.get('Comprobante')})
159+ all_paths = tools.config["addons_path"].split(",")
160+ for my_path in all_paths:
161+ if os.path.isdir(os.path.join(my_path, 'l10n_mx_facturae', 'template')):
162+ fname_jinja_tmpl = my_path and os.path.join(my_path, 'l10n_mx_facturae', 'template', 'cfd' + '.xml') or ''
163+ dictargs = {
164+ 'o': data_dict
165+ }
166+ invoice_number = "sn"
167+ (fileno_xml, fname_xml) = tempfile.mkstemp('.xml', 'openerp_' + (invoice_number or '') + '__facturae__')
168+ with open(fname_jinja_tmpl, 'r') as f_jinja_tmpl:
169+ jinja_tmpl_str = f_jinja_tmpl.read().encode('utf-8')
170+ tmpl = jinja2.Template( jinja_tmpl_str )
171+ with open(fname_xml, 'w') as new_xml:
172+ new_xml.write( tmpl.render(**dictargs) )
173+ with open(fname_xml,'rb') as b:
174+ jinja2_xml = b.read().encode('utf-8')
175+ doc_xml = xml.dom.minidom.parseString(jinja2_xml)
176+ (fileno_xml, fname_xml) = tempfile.mkstemp(
177 '.xml', 'openerp_' + (invoice_number or '') + '__facturae__')
178- fname_txt = fname_xml + '.txt'
179- f = open(fname_xml, 'w')
180- doc_xml.writexml(
181- f, indent=' ', addindent=' ', newl='\r\n', encoding='UTF-8')
182- f.close()
183- os.close(fileno_xml)
184-
185- (fileno_sign, fname_sign) = tempfile.mkstemp('.txt', 'openerp_' + (
186- invoice_number or '') + '__facturae_txt_md5__')
187- os.close(fileno_sign)
188-
189- context.update({
190- 'fname_xml': fname_xml,
191- 'fname_txt': fname_txt,
192- 'fname_sign': fname_sign,
193- })
194- context.update(self._get_file_globals(cr, uid, ids, context=context))
195- fname_txt, txt_str = self._xml2cad_orig(
196- cr=False, uid=False, ids=False, context=context)
197- data_dict['cadena_original'] = txt_str
198-
199- if not txt_str:
200- raise osv.except_osv(_('Error en Cadena original!'), _(
201- "Can't get the string original of the voucher.\nCkeck your configuration.\n%s" % (msg2)))
202-
203- if not data_dict['Comprobante'].get('folio', ''):
204- raise osv.except_osv(_('Error in Folio!'), _(
205- "Can't get the folio of the voucher.\nBefore generating the XML, click on the button, generate invoice.\nCkeck your configuration.\n%s" % (msg2)))
206-
207- # time.strftime('%Y-%m-%dT%H:%M:%S',
208- # time.strptime(invoice.date_invoice, '%Y-%m-%d %H:%M:%S'))
209- context.update({'fecha': data_dict['Comprobante']['fecha']})
210- sign_str = self._get_sello(
211- cr=False, uid=False, ids=False, context=context)
212- if not sign_str:
213- raise osv.except_osv(_('Error in Stamp !'), _(
214- "Can't generate the stamp of the voucher.\nCkeck your configuration.\ns%s") % (msg2))
215-
216- nodeComprobante = doc_xml.getElementsByTagName("Comprobante")[0]
217- nodeComprobante.setAttribute("sello", sign_str)
218- data_dict['Comprobante']['sello'] = sign_str
219-
220- noCertificado = self._get_noCertificado(cr, uid, ids, context['fname_cer'])
221- if not noCertificado:
222- raise osv.except_osv(_('Error in No. Certificate !'), _(
223- "Can't get the Certificate Number of the voucher.\nCkeck your configuration.\n%s") % (msg2))
224- nodeComprobante.setAttribute("noCertificado", noCertificado)
225- data_dict['Comprobante']['noCertificado'] = noCertificado
226-
227- cert_str = self._get_certificate_str(context['fname_cer'])
228- if not cert_str:
229- raise osv.except_osv(_('Error in Certificate!'), _(
230- "Can't generate the Certificate of the voucher.\nCkeck your configuration.\n%s") % (msg2))
231- cert_str = cert_str.replace(' ', '').replace('\n', '')
232- nodeComprobante.setAttribute("certificado", cert_str)
233- data_dict['Comprobante']['certificado'] = cert_str
234-
235- self.write_cfd_data(cr, uid, ids, data_dict, context=context)
236-
237- if context.get('type_data') == 'dict':
238- return data_dict
239- if context.get('type_data') == 'xml_obj':
240- return doc_xml
241- data_xml = doc_xml.toxml('UTF-8')
242- data_xml = codecs.BOM_UTF8 + data_xml
243- fname_xml = (data_dict['Comprobante']['Emisor']['rfc'] or '') + '_' + (
244- data_dict['Comprobante'].get('serie', '') or '') + '_' + (
245- data_dict['Comprobante'].get('folio', '') or '') + '.xml'
246- data_xml = data_xml.replace('<?xml version="1.0" encoding="UTF-8"?>', '<?xml version="1.0" encoding="UTF-8"?>\n')
247- date_invoice = data_dict.get('Comprobante',{}) and datetime.strptime( data_dict.get('Comprobante',{}).get('fecha',{}), '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d') or False
248- facturae_version = '2.2'
249- if date_invoice and date_invoice < '2012-07-01':
250- facturae_version = '2.0'
251- self.validate_scheme_facturae_xml(cr, uid, ids, [data_xml], facturae_version)
252- data_dict.get('Comprobante',{})
253+ fname_txt = fname_xml + '.txt'
254+ f = open(fname_xml, 'w')
255+ doc_xml.writexml(f, indent=' ', addindent=' ', newl='\r\n', encoding='UTF-8')
256+ f.close()
257+ os.close(fileno_xml)
258+ (fileno_sign, fname_sign) = tempfile.mkstemp('.txt', 'openerp_' + (
259+ invoice_number or '') + '__facturae_txt_md5__')
260+ os.close(fileno_sign)
261+ context.update({
262+ 'fname_xml': fname_xml,
263+ 'fname_txt': fname_txt,
264+ 'fname_sign': fname_sign,
265+ })
266+ context.update(self._get_file_globals(cr, uid, ids, context=context))
267+ fname_txt, txt_str = self._xml2cad_orig(cr=False, uid=False, ids=False, context=context)
268+ data_dict['cadena_original'] = txt_str
269+
270+ if not txt_str:
271+ raise osv.except_osv(_('Error en Cadena original!'), _(
272+ "Can't get the string original of the voucher.\nCkeck your configuration.\n%s" % (msg2)))
273+
274+ if not data_dict['Comprobante'].get('folio', ''):
275+ raise osv.except_osv(_('Error in Folio!'), _(
276+ "Can't get the folio of the voucher.\nBefore generating the XML, click on the button, generate invoice.\nCkeck your configuration.\n%s" % (msg2)))
277+
278+ # time.strftime('%Y-%m-%dT%H:%M:%S',
279+ # time.strptime(invoice.date_invoice, '%Y-%m-%d %H:%M:%S'))
280+ context.update({'fecha': data_dict['Comprobante']['fecha']})
281+ sign_str = self._get_sello(cr=False, uid=False, ids=False, context=context)
282+ if not sign_str:
283+ raise osv.except_osv(_('Error in Stamp !'), _(
284+ "Can't generate the stamp of the voucher.\nCkeck your configuration.\ns%s") % (msg2))
285+
286+ nodeComprobante = doc_xml.getElementsByTagName("Comprobante")[0]
287+ nodeComprobante.setAttribute("sello", sign_str)
288+ data_dict['Comprobante']['sello'] = sign_str
289+
290+ noCertificado = self._get_noCertificado(cr, uid, ids, context['fname_cer'])
291+ if not noCertificado:
292+ raise osv.except_osv(_('Error in No. Certificate !'), _(
293+ "Can't get the Certificate Number of the voucher.\nCkeck your configuration.\n%s") % (msg2))
294+ nodeComprobante.setAttribute("noCertificado", noCertificado)
295+ data_dict['Comprobante']['noCertificado'] = noCertificado
296+
297+ cert_str = self._get_certificate_str(context['fname_cer'])
298+ if not cert_str:
299+ raise osv.except_osv(_('Error in Certificate!'), _(
300+ "Can't generate the Certificate of the voucher.\nCkeck your configuration.\n%s") % (msg2))
301+ cert_str = cert_str.replace(' ', '').replace('\n', '')
302+ nodeComprobante.setAttribute("certificado", cert_str)
303+ data_dict['Comprobante']['certificado'] = cert_str
304+
305+ self.write_cfd_data(cr, uid, ids, data_dict, context=context)
306+ if context.get('type_data') == 'dict':
307+ return data_dict
308+ if context.get('type_data') == 'xml_obj':
309+ return doc_xml
310+ data_xml = doc_xml.toxml('UTF-8')
311+ data_xml = codecs.BOM_UTF8 + data_xml
312+ fname_xml = (data_dict['Comprobante']['Emisor']['rfc'] or '') + '_' + (
313+ data_dict['Comprobante'].get('serie', '') or '') + '_' + (
314+ data_dict['Comprobante'].get('folio', '') or '') + '.xml'
315+ data_xml = data_xml.replace('<?xml version="1.0" encoding="UTF-8"?>', '<?xml version="1.0" encoding="UTF-8"?>\n')
316+ date_invoice = data_dict.get('Comprobante',{}) and datetime.strptime( data_dict.get('Comprobante',{}).get('fecha',{}), '%Y-%m-%dT%H:%M:%S').strftime('%Y-%m-%d') or False
317+ facturae_version = '2.2'
318+ if date_invoice and date_invoice < '2012-07-01':
319+ facturae_version = '2.0'
320+ self.validate_scheme_facturae_xml(cr, uid, ids, [data_xml], facturae_version)
321 return fname_xml, data_xml
322
323 def validate_scheme_facturae_xml(self, cr, uid, ids, datas_xmls=[], facturae_version = None, facturae_type="cfdv", scheme_type='xsd'):
324@@ -842,7 +863,6 @@
325 if os.path.isdir(os.path.join(my_path, 'l10n_mx_facturae', 'SAT')):
326 # If dir is in path, save it on real_path
327 fname_scheme = my_path and os.path.join(my_path, 'l10n_mx_facturae', 'SAT', facturae_type + facturae_version + '.' + scheme_type) or ''
328- #fname_scheme = os.path.join(tools.config["addons_path"], u'l10n_mx_facturae', u'SAT', facturae_type + facturae_version + '.' + scheme_type )
329 fname_out = certificate_lib.b64str_to_tempfile(cr, uid, ids, base64.encodestring(''), file_suffix='.txt', file_prefix='openerp__' + (False or '') + '__schema_validation_result__' )
330 result = certificate_lib.check_xml_scheme(cr, uid, ids, fname_data_xml, fname_scheme, fname_out)
331 if result: #Valida el xml mediante el archivo xsd
332@@ -865,8 +885,7 @@
333 cfd_data = cfd_datas
334 noCertificado = cfd_data.get(
335 'Comprobante', {}).get('noCertificado', '')
336- certificado = cfd_data.get(
337- 'Comprobante', {}).get('certificado', '')
338+ certificado = cfd_data.get('Comprobante', {}).get('certificado', '')
339 sello = cfd_data.get('Comprobante', {}).get('sello', '')
340 cadena_original = cfd_data.get('cadena_original', '')
341 data = {
342@@ -996,7 +1015,7 @@
343 invoice.date_invoice_tz, '%Y-%m-%d %H:%M:%S'))
344 or '',
345 'tipoDeComprobante': tipoComprobante,
346- 'formaDePago': u'Pago en una sola exhibición',
347+ 'formaDePago': "Pago en una sola exhibicion",
348 'noCertificado': '@',
349 'sello': '@',
350 'certificado': '@',
351@@ -1036,22 +1055,70 @@
352
353 invoice_data = invoice_data_parent['Comprobante']
354 invoice_data['Emisor'] = {}
355+ name = self.remove_accents(cr, uid, ids, address_invoice_parent.name)
356+ calle = address_invoice_parent.street and \
357+ address_invoice_parent.street.replace('\n\r', ' ').\
358+ replace('\r\n', ' ').replace('\n', ' ').replace(
359+ '\r', ' ') or ''
360+ calle = self.remove_accents(cr, uid, ids, calle)
361+ colonia = address_invoice_parent.street2 and \
362+ address_invoice_parent.street2.replace('\n\r', ' ').\
363+ replace('\r\n', ' ').replace('\n', ' ').replace(
364+ '\r', ' ') or False
365+ colonia = self.remove_accents(cr, uid, ids, colonia)
366+ localidad = address_invoice_parent.l10n_mx_city2 and \
367+ address_invoice_parent.l10n_mx_city2.replace(
368+ '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
369+ replace('\r', ' ') or False
370+ localidad = self.remove_accents(cr, uid, ids, localidad)
371+ municipio = address_invoice_parent.city and \
372+ address_invoice_parent.city.replace('\n\r', ' ').\
373+ replace('\r\n', ' ').replace('\n', ' ').replace(
374+ '\r', ' ') or ''
375+ municipio = self.remove_accents(cr, uid, ids, municipio)
376+ estado = address_invoice_parent.state_id and \
377+ address_invoice_parent.state_id.name and \
378+ address_invoice_parent.state_id.name.replace(
379+ '\n\r', ' ').replace('\r\n', ' ').replace(
380+ '\n', ' ').replace('\r', ' ') or ''
381+ estado = self.remove_accents(cr, uid, ids, estado)
382+ pais = address_invoice_parent.country_id and address_invoice_parent.\
383+ country_id.name and address_invoice_parent.country_id.name.\
384+ replace('\n\r', ' ').replace('\r\n', ' ').replace(
385+ '\n', ' ').replace('\r', ' ') or ''
386+ pais = self.remove_accents(cr, uid, ids, pais)
387+
388+ ExpedidoEncalle = address_invoice.street and address_invoice.\
389+ street.replace('\n\r', ' ').replace('\r\n', ' ').\
390+ replace('\n', ' ').replace('\r', ' ') or ''
391+ ExpedidoEncalle = self.remove_accents(cr, uid, ids, ExpedidoEncalle)
392+ ExpedidoEncolonia = address_invoice.street2 and address_invoice.\
393+ street2.replace('\n\r', ' ').replace('\r\n', ' ').\
394+ replace('\n', ' ').replace('\r', ' ') or False
395+ ExpedidoEncolonia = self.remove_accents(cr, uid, ids, ExpedidoEncolonia)
396+ ExpedidoEnlocalidad = address_invoice.l10n_mx_city2 and \
397+ address_invoice.l10n_mx_city2.replace('\n\r', ' ').\
398+ replace('\r\n', ' ').replace('\n', ' ').replace(
399+ '\r', ' ') or False
400+ ExpedidoEnlocalidad = self.remove_accents(cr, uid, ids, ExpedidoEnlocalidad)
401+ ExpedidoEnmunicipio = address_invoice.city and address_invoice.\
402+ city.replace('\n\r', ' ').replace('\r\n', ' ').replace(
403+ '\n', ' ').replace('\r', ' ') or ''
404+ ExpedidoEnmunicipio = self.remove_accents(cr, uid, ids, ExpedidoEnmunicipio)
405+ ExpedidoEnestado = address_invoice.state_id and address_invoice.\
406+ state_id.name and address_invoice.state_id.name.replace(
407+ '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
408+ replace('\r', ' ') or ''
409+ ExpedidoEnestado = self.remove_accents(cr, uid, ids, ExpedidoEnestado)
410+
411+
412 invoice_data['Emisor'].update({
413-
414 'rfc': (('vat_split' in address_invoice_parent._columns and \
415 address_invoice_parent.vat_split or address_invoice_parent.vat) \
416 or '').replace('-', ' ').replace(' ', ''),
417- 'nombre': address_invoice_parent.name or '',
418- # Obtener domicilio dinamicamente
419- # virtual_invoice.append( (invoice.company_id and
420- # invoice.company_id.partner_id and
421- # invoice.company_id.partner_id.vat or '').replac
422-
423+ 'nombre': name or '',
424 'DomicilioFiscal': {
425- 'calle': address_invoice_parent.street and \
426- address_invoice_parent.street.replace('\n\r', ' ').\
427- replace('\r\n', ' ').replace('\n', ' ').replace(
428- '\r', ' ') or '',
429+ 'calle': calle or '',
430 'noExterior': address_invoice_parent.l10n_mx_street3 and \
431 address_invoice_parent.l10n_mx_street3.replace(
432 '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
433@@ -1060,37 +1127,18 @@
434 address_invoice_parent.l10n_mx_street4.replace(
435 '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
436 replace('\r', ' ') or 'N/A', # "Numero Interior"
437- 'colonia': address_invoice_parent.street2 and \
438- address_invoice_parent.street2.replace('\n\r', ' ').\
439- replace('\r\n', ' ').replace('\n', ' ').replace(
440- '\r', ' ') or False,
441- 'localidad': address_invoice_parent.l10n_mx_city2 and \
442- address_invoice_parent.l10n_mx_city2.replace(
443- '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
444- replace('\r', ' ') or False,
445- 'municipio': address_invoice_parent.city and \
446- address_invoice_parent.city.replace('\n\r', ' ').\
447- replace('\r\n', ' ').replace('\n', ' ').replace(
448- '\r', ' ') or '',
449- 'estado': address_invoice_parent.state_id and \
450- address_invoice_parent.state_id.name and \
451- address_invoice_parent.state_id.name.replace(
452- '\n\r', ' ').replace('\r\n', ' ').replace(
453- '\n', ' ').replace('\r', ' ') or '',
454- 'pais': address_invoice_parent.country_id and \
455- address_invoice_parent.country_id.name and \
456- address_invoice_parent.country_id.name.replace(
457- '\n\r', ' ').replace('\r\n', ' ').replace(
458- '\n', ' ').replace('\r', ' ')or '',
459+ 'colonia': colonia or False,
460+ 'localidad': localidad or False,
461+ 'municipio': municipio or '',
462+ 'estado': estado or '',
463+ 'pais': pais or '',
464 'codigoPostal': address_invoice_parent.zip and \
465 address_invoice_parent.zip.replace('\n\r', ' ').\
466 replace('\r\n', ' ').replace('\n', ' ').replace(
467 '\r', ' ').replace(' ', '') or '',
468 },
469 'ExpedidoEn': {
470- 'calle': address_invoice.street and address_invoice.\
471- street.replace('\n\r', ' ').replace('\r\n', ' ').\
472- replace('\n', ' ').replace('\r', ' ') or '',
473+ 'calle': ExpedidoEncalle or '',
474 'noExterior': address_invoice.l10n_mx_street3 and \
475 address_invoice.l10n_mx_street3.replace(
476 '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
477@@ -1099,24 +1147,11 @@
478 address_invoice.l10n_mx_street4.replace('\n\r', ' ').\
479 replace('\r\n', ' ').replace('\n', ' ').replace(
480 '\r', ' ') or 'N/A', # "Numero Interior"
481- 'colonia': address_invoice.street2 and address_invoice.\
482- street2.replace('\n\r', ' ').replace('\r\n', ' ').\
483- replace('\n', ' ').replace('\r', ' ') or False,
484- 'localidad': address_invoice.l10n_mx_city2 and \
485- address_invoice.l10n_mx_city2.replace('\n\r', ' ').\
486- replace('\r\n', ' ').replace('\n', ' ').replace(
487- '\r', ' ') or False,
488- 'municipio': address_invoice.city and address_invoice.\
489- city.replace('\n\r', ' ').replace('\r\n', ' ').replace(
490- '\n', ' ').replace('\r', ' ') or '',
491- 'estado': address_invoice.state_id and address_invoice.\
492- state_id.name and address_invoice.state_id.name.replace(
493- '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
494- replace('\r', ' ') or '',
495- 'pais': address_invoice.country_id and address_invoice.\
496- country_id.name and address_invoice.country_id.name.\
497- replace('\n\r', ' ').replace('\r\n', ' ').replace(
498- '\n', ' ').replace('\r', ' ')or '',
499+ 'colonia': ExpedidoEncolonia or False,
500+ 'localidad': ExpedidoEnlocalidad or False,
501+ 'municipio': ExpedidoEnmunicipio or '',
502+ 'estado': ExpedidoEnestado or '',
503+ 'pais': pais or '',
504 'codigoPostal': address_invoice.zip and address_invoice.\
505 zip.replace('\n\r', ' ').replace('\r\n', ' ').replace(
506 '\n', ' ').replace('\r', ' ').replace(' ', '') or '',
507@@ -1148,13 +1183,40 @@
508 address_invoice = partner_obj.browse(cr, uid, \
509 invoice.partner_id.id, context=context)
510 invoice_data['Receptor'] = {}
511+ parent_name = self.remove_accents(cr, uid, ids, parent_obj.name)
512+ Receptorcalle = address_invoice.street and address_invoice.\
513+ street.replace('\n\r', ' ').replace('\r\n', ' ').replace(
514+ '\n', ' ').replace('\r', ' ') or ''
515+ Receptorcalle = self.remove_accents(cr, uid, ids, Receptorcalle)
516+ Receptorpais = address_invoice.country_id and address_invoice.\
517+ country_id.name and address_invoice.country_id.name.\
518+ replace('\n\r', ' ').replace('\r\n', ' ').replace(
519+ '\n', ' ').replace('\r', ' ')or ''
520+ Receptorpais = self.remove_accents(cr, uid, ids, Receptorpais)
521+ Receptorcolonia = address_invoice.street2 and address_invoice.\
522+ street2.replace('\n\r', ' ').replace('\r\n', ' ').\
523+ replace('\n', ' ').replace('\r', ' ') or False
524+ Receptorcolonia = self.remove_accents(cr, uid, ids, Receptorcolonia)
525+ Receptorlocalidad = address_invoice.l10n_mx_city2 and \
526+ address_invoice.l10n_mx_city2.replace('\n\r', ' ').\
527+ replace('\r\n', ' ').replace('\n', ' ').replace(
528+ '\r', ' ') or False
529+ Receptorlocalidad = self.remove_accents(cr, uid, ids, Receptorlocalidad)
530+ Receptormunicipio = address_invoice.city and address_invoice.\
531+ city.replace('\n\r', ' ').replace('\r\n', ' ').replace(
532+ '\n', ' ').replace('\r', ' ') or ''
533+ Receptormunicipio = self.remove_accents(cr, uid, ids, Receptormunicipio)
534+ Receptorestado = address_invoice.state_id and address_invoice.\
535+ state_id.name and address_invoice.state_id.name.replace(
536+ '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
537+ replace('\r', ' ') or ''
538+ Receptorestado = self.remove_accents(cr, uid, ids, Receptorestado)
539+
540 invoice_data['Receptor'].update({
541 'rfc': rfc,
542- 'nombre': (parent_obj.name or ''),
543+ 'nombre': parent_name or '',
544 'Domicilio': {
545- 'calle': address_invoice.street and address_invoice.\
546- street.replace('\n\r', ' ').replace('\r\n', ' ').replace(
547- '\n', ' ').replace('\r', ' ') or '',
548+ 'calle': Receptorcalle or '',
549 'noExterior': address_invoice.l10n_mx_street3 and \
550 address_invoice.l10n_mx_street3.replace('\n\r', ' ').\
551 replace('\r\n', ' ').replace('\n', ' ').replace(
552@@ -1163,24 +1225,11 @@
553 address_invoice.l10n_mx_street4.replace('\n\r', ' ').\
554 replace('\r\n', ' ').replace('\n', ' ').replace(
555 '\r', ' ') or 'N/A', # "Numero Interior"
556- 'colonia': address_invoice.street2 and address_invoice.\
557- street2.replace('\n\r', ' ').replace('\r\n', ' ').\
558- replace('\n', ' ').replace('\r', ' ') or False,
559- 'localidad': address_invoice.l10n_mx_city2 and \
560- address_invoice.l10n_mx_city2.replace('\n\r', ' ').\
561- replace('\r\n', ' ').replace('\n', ' ').replace(
562- '\r', ' ') or False,
563- 'municipio': address_invoice.city and address_invoice.\
564- city.replace('\n\r', ' ').replace('\r\n', ' ').replace(
565- '\n', ' ').replace('\r', ' ') or '',
566- 'estado': address_invoice.state_id and address_invoice.\
567- state_id.name and address_invoice.state_id.name.replace(
568- '\n\r', ' ').replace('\r\n', ' ').replace('\n', ' ').\
569- replace('\r', ' ') or '',
570- 'pais': address_invoice.country_id and address_invoice.\
571- country_id.name and address_invoice.country_id.name.\
572- replace('\n\r', ' ').replace('\r\n', ' ').replace(
573- '\n', ' ').replace('\r', ' ')or '',
574+ 'colonia': Receptorcolonia or False,
575+ 'localidad': Receptorlocalidad or False,
576+ 'municipio': Receptormunicipio or '',
577+ 'estado': Receptorestado or '',
578+ 'pais': Receptorpais or '',
579 'codigoPostal': address_invoice.zip and address_invoice.\
580 zip.replace('\n\r', ' ').replace('\r\n', ' ').replace(
581 '\n', ' ').replace('\r', ' ') or '',
582@@ -1202,7 +1251,7 @@
583 line.quantity or 0.0
584 concepto = {
585 'cantidad': "%.2f" % (line.quantity or 0.0),
586- 'descripcion': line.name or '',
587+ 'descripcion': self.remove_accents(cr, uid, ids, line.name) or '',
588 'valorUnitario': "%.2f" % (price_unit or 0.0),
589 'importe': "%.2f" % (line.price_subtotal or 0.0), # round(line.price_unit *(1-(line.discount/100)),2) or 0.00),#Calc: iva, disc, qty
590 # Falta agregar discount
591@@ -1259,7 +1308,7 @@
592 totalImpuestosRetenidos += line_tax_id_amount
593 impuesto_dict = {impuesto_str:
594 {
595- 'impuesto': tax_name,
596+ 'impuesto': self.remove_accents(cr, uid, ids, tax_name),
597 'importe': "%.2f" % (line_tax_id_amount),
598 }
599 }
600@@ -1281,7 +1330,7 @@
601 if tax_required in tax_names:
602 continue
603 invoice_data_impuestos['Traslados'].append({'Traslado': {
604- 'impuesto': tax_required,
605+ 'impuesto': self.remove_accents(cr, uid, ids, tax_required),
606 'tasa': "%.2f" % (0.0),
607 'importe': "%.2f" % (0.0),
608 }})
609@@ -1349,11 +1398,12 @@
610 invoice_data_parents[0]['Comprobante'][
611 'NumCtaPago'] = invoice.acc_payment.last_acc_number\
612 or 'No identificado'
613+ metodoDePago = invoice.pay_method_id.name or 'No identificado'
614 invoice_data_parents[0]['Comprobante'][
615- 'metodoDePago'] = invoice.pay_method_id.name or 'No identificado'
616- invoice_data_parents[0]['Comprobante']['Emisor']['RegimenFiscal'] = {
617- 'Regimen': invoice.company_emitter_id.partner_id.\
618- regimen_fiscal_id.name or ''}
619+ 'metodoDePago'] = self.remove_accents(cr, uid, ids, metodoDePago)
620+ regimen = invoice.company_emitter_id.partner_id.regimen_fiscal_id.name or ''
621+ regimen = self.remove_accents(cr, uid, ids, regimen)
622+ invoice_data_parents[0]['Comprobante']['Emisor']['RegimenFiscal'] ={'Regimen': regimen}
623 invoice_data_parents[0]['Comprobante']['LugarExpedicion'] = address
624 return invoice_data_parents
625
626
627=== added directory 'l10n_mx_facturae/template'
628=== added file 'l10n_mx_facturae/template/cfd.xml'
629--- l10n_mx_facturae/template/cfd.xml 1970-01-01 00:00:00 +0000
630+++ l10n_mx_facturae/template/cfd.xml 2014-01-25 00:46:46 +0000
631@@ -0,0 +1,1 @@
632+<?xml version="1.0" encoding="UTF-8"?><Comprobante LugarExpedicion="{{ o['Comprobante']['LugarExpedicion'] }}" Moneda="{{ o['Comprobante']['Moneda'] }}" NumCtaPago="{{ o['Comprobante']['NumCtaPago'] }}" TipoCambio="{{ o['Comprobante']['TipoCambio'] }}" anoAprobacion="{{ o['Comprobante']['anoAprobacion'] }}" certificado="{{ o['Comprobante']['certificado'] }}" descuento="{{ o['Comprobante']['descuento'] }}" fecha="{{ o['Comprobante']['fecha'] }}" folio="{{ o['Comprobante']['folio'] }}" formaDePago="{{ o['Comprobante']['formaDePago'] }}" metodoDePago="{{ o['Comprobante']['metodoDePago'] }}" noAprobacion="{{ o['Comprobante']['noAprobacion'] }}" noCertificado="{{ o['Comprobante']['noCertificado'] }}" sello="{{ o['Comprobante']['sello'] }}" serie="{{ o['Comprobante']['serie'] }}" subTotal="{{ o['Comprobante']['subTotal'] }}" tipoDeComprobante="{{ o['Comprobante']['tipoDeComprobante'] }}" total="{{ o['Comprobante']['total'] }}" version="{{ o['Comprobante']['version'] }}" xmlns="{{ o['Comprobante']['xmlns'] }}" xmlns:xsi="{{ o['Comprobante']['xmlns:xsi'] }}" xsi:schemaLocation="{{ o['Comprobante']['xsi:schemaLocation'] }}"><Emisor nombre="{{ o['Comprobante']['Emisor']['nombre'] }}" rfc="{{ o['Comprobante']['Emisor']['rfc'] }}"><DomicilioFiscal calle="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['calle'] }}" codigoPostal="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['codigoPostal'] }}" colonia="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['colonia'] }}" estado="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['estado'] }}" localidad="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['localidad'] }}" municipio="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['municipio'] }}" noExterior="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['noExterior'] }}" noInterior="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['noInterior'] }}" pais="{{ o['Comprobante']['Emisor']['DomicilioFiscal']['pais'] }}"/><ExpedidoEn calle="{{ o['Comprobante']['Emisor']['ExpedidoEn']['calle'] }}" codigoPostal="{{ o['Comprobante']['Emisor']['ExpedidoEn']['codigoPostal'] }}" colonia="{{ o['Comprobante']['Emisor']['ExpedidoEn']['colonia'] }}" estado="{{ o['Comprobante']['Emisor']['ExpedidoEn']['estado'] }}" localidad="{{ o['Comprobante']['Emisor']['ExpedidoEn']['localidad'] }}" municipio="{{ o['Comprobante']['Emisor']['ExpedidoEn']['municipio'] }}" noExterior="{{ o['Comprobante']['Emisor']['ExpedidoEn']['noExterior'] }}" noInterior="{{ o['Comprobante']['Emisor']['ExpedidoEn']['noInterior'] }}" pais="{{ o['Comprobante']['Emisor']['ExpedidoEn']['pais'] }}"/><RegimenFiscal Regimen="{{ o['Comprobante']['Emisor']['RegimenFiscal']['Regimen'] }}"/></Emisor><Receptor nombre="{{ o['Comprobante']['Receptor']['nombre'] }}" rfc="{{ o['Comprobante']['Receptor']['rfc'] }}"><Domicilio calle="{{ o['Comprobante']['Receptor']['Domicilio']['calle'] }}" codigoPostal="{{ o['Comprobante']['Receptor']['Domicilio']['codigoPostal'] }}" colonia="{{ o['Comprobante']['Receptor']['Domicilio']['colonia'] }}" estado="{{ o['Comprobante']['Receptor']['Domicilio']['estado'] }}" localidad="{{ o['Comprobante']['Receptor']['Domicilio']['localidad'] }}" municipio="{{ o['Comprobante']['Receptor']['Domicilio']['municipio'] }}" noExterior="{{ o['Comprobante']['Receptor']['Domicilio']['noExterior'] }}" noInterior="{{ o['Comprobante']['Receptor']['Domicilio']['noInterior'] }}" pais="{{ o['Comprobante']['Receptor']['Domicilio']['pais'] }}"/></Receptor>{% if o['Comprobante']['Conceptos']%}<Conceptos>{% for i in o['Comprobante']['Conceptos'] %}<Concepto cantidad="{{ i['Concepto']['cantidad'] }}" descripcion="{{ i['Concepto']['descripcion'] }}" importe="{{ i['Concepto']['importe'] }}" noIdentificacion="{{ i['Concepto']['noIdentificacion'] }}" unidad="{{ i['Concepto']['unidad'] }}" valorUnitario="{{ i['Concepto']['valorUnitario'] }}"/>{% endfor %}{% endif %}</Conceptos>{% if o['Comprobante']['Impuestos']['totalImpuestosTrasladados'] %}<Impuestos totalImpuestosTrasladados="{{ o['Comprobante']['Impuestos']['totalImpuestosTrasladados'] }}"><Traslados>{% for i in o['Comprobante']['Impuestos']['Traslados'] %}<Traslado importe="{{ i['Traslado']['importe'] }}" impuesto="{{ i['Traslado']['impuesto'] }}" tasa="{{ i['Traslado']['tasa'] }}"/>{% endfor %}</Traslados></Impuestos>{% endif %}</Comprobante>
633\ No newline at end of file
634
635=== modified file 'l10n_mx_facturae_pac/invoice.py'
636--- l10n_mx_facturae_pac/invoice.py 2013-11-20 23:20:47 +0000
637+++ l10n_mx_facturae_pac/invoice.py 2014-01-25 00:46:46 +0000
638@@ -29,7 +29,6 @@
639 import os
640 import codecs
641 import base64
642-import xml.dom.minidom
643 from datetime import datetime, timedelta
644 from openerp.tools.translate import _
645 try:
646@@ -39,6 +38,8 @@
647 pass
648 import time
649 from openerp import tools
650+import jinja2
651+import xml
652
653
654 class account_invoice(osv.Model):
655@@ -54,7 +55,6 @@
656 invoice = self.browse(cr, uid, ids[0], context=context)
657 sequence_app_id = ir_seq_app_obj.search(cr, uid, [(
658 'sequence_id', '=', invoice.invoice_sequence_id.id)], context=context)
659- type_inv = 'cfd22'
660 if sequence_app_id:
661 type_inv = ir_seq_app_obj.browse(
662 cr, uid, sequence_app_id[0], context=context).type
663@@ -114,6 +114,7 @@
664 invoice = self.browse(cr, uid, ids[0], context=context)
665 sequence_app_id = ir_seq_app_obj.search(cr, uid, [(
666 'sequence_id', '=', invoice.invoice_sequence_id.id)], context=context)
667+ all_paths = tools.config["addons_path"].split(",")
668 type_inv = 'cfd22'
669 if sequence_app_id:
670 type_inv = ir_seq_app_obj.browse(
671@@ -124,6 +125,10 @@
672 receptor = 'cfdi:Receptor'
673 concepto = 'cfdi:Conceptos'
674 facturae_version = '3.2'
675+ for my_path in all_paths:
676+ if os.path.isdir(os.path.join(my_path, 'l10n_mx_facturae_pac_sf', 'template')):
677+ fname_jinja_tmpl = my_path and os.path.join(my_path, 'l10n_mx_facturae_pac_sf',
678+ 'template', 'cfdi' + '.xml') or ''
679 else:
680 comprobante = 'Comprobante'
681 emisor = 'Emisor'
682@@ -131,16 +136,30 @@
683 receptor = 'Receptor'
684 concepto = 'Conceptos'
685 facturae_version = '2.2'
686- data_dict = self._get_facturae_invoice_dict_data(
687- cr, uid, ids, context=context)[0]
688- doc_xml = self.dict2xml({comprobante: data_dict.get(comprobante)})
689+ for my_path in all_paths:
690+ if os.path.isdir(os.path.join(my_path, 'l10n_mx_facturae', 'template')):
691+ fname_jinja_tmpl = my_path and os.path.join(my_path, 'l10n_mx_facturae',
692+ 'template', 'cfd' + '.xml') or ''
693+
694+ data_dict = self._get_facturae_invoice_dict_data(cr, uid, ids, context=context)[0]
695+ dictargs = {
696+ 'o': data_dict
697+ }
698 invoice_number = "sn"
699+ (fileno_xml, fname_xml) = tempfile.mkstemp('.xml', 'openerp_' + (invoice_number or '') + '__facturae__')
700+ with open(fname_jinja_tmpl, 'r') as f_jinja_tmpl:
701+ jinja_tmpl_str = f_jinja_tmpl.read().encode('utf-8')
702+ tmpl = jinja2.Template( jinja_tmpl_str )
703+ with open(fname_xml, 'w') as new_xml:
704+ new_xml.write( tmpl.render(**dictargs) )
705+ with open(fname_xml,'rb') as b:
706+ jinja2_xml = b.read().encode('utf-8')
707+ doc_xml = xml.dom.minidom.parseString(jinja2_xml)
708 (fileno_xml, fname_xml) = tempfile.mkstemp(
709 '.xml', 'openerp_' + (invoice_number or '') + '__facturae__')
710 fname_txt = fname_xml + '.txt'
711 f = open(fname_xml, 'w')
712- doc_xml.writexml(
713- f, indent=' ', addindent=' ', newl='\r\n', encoding='UTF-8')
714+ doc_xml.writexml(f, indent=' ', addindent=' ', newl='\r\n', encoding='UTF-8')
715 f.close()
716 os.close(fileno_xml)
717 (fileno_sign, fname_sign) = tempfile.mkstemp('.txt', 'openerp_' + (
718@@ -152,8 +171,7 @@
719 'fname_sign': fname_sign,
720 })
721 context.update(self._get_file_globals(cr, uid, ids, context=context))
722- fname_txt, txt_str = self._xml2cad_orig(
723- cr=False, uid=False, ids=False, context=context)
724+ fname_txt, txt_str = self._xml2cad_orig(cr=False, uid=False, ids=False, context=context)
725 data_dict['cadena_original'] = txt_str
726 msg2=''
727
728@@ -166,8 +184,7 @@
729 "Can't get the folio of the voucher.\nBefore generating the XML, click on the button, generate invoice.\nCkeck your configuration.\n%s" % (msg2)))
730
731 context.update({'fecha': data_dict[comprobante]['fecha']})
732- sign_str = self._get_sello(
733- cr=False, uid=False, ids=False, context=context)
734+ sign_str = self._get_sello(cr=False, uid=False, ids=False, context=context)
735 if not sign_str:
736 raise osv.except_osv(_('Error in Stamp !'), _(
737 "Can't generate the stamp of the voucher.\nCkeck your configuration.\ns%s") % (msg2))
738@@ -190,13 +207,11 @@
739 cert_str = cert_str.replace(' ', '').replace('\n', '')
740 nodeComprobante.setAttribute("certificado", cert_str)
741 data_dict[comprobante]['certificado'] = cert_str
742+
743+
744 if 'cfdi' in type_inv:
745 nodeComprobante.removeAttribute('anoAprobacion')
746 nodeComprobante.removeAttribute('noAprobacion')
747- x = doc_xml.documentElement
748- nodeReceptor = doc_xml.getElementsByTagName(receptor)[0]
749- nodeConcepto = doc_xml.getElementsByTagName(concepto)[0]
750- x.insertBefore(nodeReceptor, nodeConcepto)
751
752 self.write_cfd_data(cr, uid, ids, data_dict, context=context)
753
754@@ -215,28 +230,4 @@
755 if date_invoice and date_invoice < '2012-07-01':
756 facturae_version = '2.0'
757 self.validate_scheme_facturae_xml(cr, uid, ids, [data_xml], facturae_version)
758- data_dict.get('Comprobante',{})
759 return fname_xml, data_xml
760-
761- def validate_scheme_facturae_xml(self, cr, uid, ids, datas_xmls=[], facturae_version = None, facturae_type="cfdv", scheme_type='xsd'):
762- #TODO: bzr add to file fname_schema
763- if not datas_xmls:
764- datas_xmls = []
765- certificate_lib = self.pool.get('facturae.certificate.library')
766- for data_xml in datas_xmls:
767- (fileno_data_xml, fname_data_xml) = tempfile.mkstemp('.xml', 'openerp_' + (False or '') + '__facturae__' )
768- f = open(fname_data_xml, 'wb')
769- f.write( data_xml )
770- f.close()
771- os.close(fileno_data_xml)
772- all_paths = tools.config["addons_path"].split(",")
773- for my_path in all_paths:
774- if os.path.isdir(os.path.join(my_path, 'l10n_mx_facturae', 'SAT')):
775- # If dir is in path, save it on real_path
776- fname_scheme = my_path and os.path.join(my_path, 'l10n_mx_facturae', 'SAT', facturae_type + facturae_version + '.' + scheme_type) or ''
777- #fname_scheme = os.path.join(tools.config["addons_path"], u'l10n_mx_facturae', u'SAT', facturae_type + facturae_version + '.' + scheme_type )
778- fname_out = certificate_lib.b64str_to_tempfile(cr, uid, ids, base64.encodestring(''), file_suffix='.txt', file_prefix='openerp__' + (False or '') + '__schema_validation_result__' )
779- result = certificate_lib.check_xml_scheme(cr, uid, ids, fname_data_xml, fname_scheme, fname_out)
780- if result: #Valida el xml mediante el archivo xsd
781- raise osv.except_osv('Error al validar la estructura del xml!', 'Validación de XML versión %s:\n%s'%(facturae_version, result))
782- return True
783
784=== modified file 'l10n_mx_facturae_pac_sf/ir_attachment_facturae.py'
785--- l10n_mx_facturae_pac_sf/ir_attachment_facturae.py 2013-12-10 01:11:31 +0000
786+++ l10n_mx_facturae_pac_sf/ir_attachment_facturae.py 2014-01-25 00:46:46 +0000
787@@ -148,8 +148,8 @@
788 has completed correctly.\n- The uuid cancelled is:\
789 ') + folio_cancel
790 invoice_obj.write(cr, uid, [invoice.id], {
791- 'cfdi_fecha_cancelacion': time.strftime(
792- '%Y-%m-%d %H:%M:%S')
793+ 'cfdi_fecha_cancelacion': time.strftime('%Y-%m-%d %H:%M:%S'),
794+ 'pac_id' : pac_params_id or False
795 })
796 status = True
797 else:
798@@ -169,8 +169,7 @@
799 pac_params_obj = invoice_obj.pool.get('params.pac')
800 for ir_attachment_facturae_mx_id in self.browse(cr, uid, ids, context=context):
801 invoice = ir_attachment_facturae_mx_id.invoice_id
802- comprobante = invoice_obj._get_type_sequence(
803- cr, uid, [invoice.id], context=context)
804+ comprobante = invoice_obj._get_type_sequence(cr, uid, [invoice.id], context=context)
805 cfd_data = base64.decodestring(fdata or invoice_obj.fdata)
806 xml_res_str = xml.dom.minidom.parseString(cfd_data)
807 xml_res_addenda = invoice_obj.add_addenta_xml(
808
809=== added directory 'l10n_mx_facturae_pac_sf/template'
810=== added file 'l10n_mx_facturae_pac_sf/template/cfdi.xml'
811--- l10n_mx_facturae_pac_sf/template/cfdi.xml 1970-01-01 00:00:00 +0000
812+++ l10n_mx_facturae_pac_sf/template/cfdi.xml 2014-01-25 00:46:46 +0000
813@@ -0,0 +1,1 @@
814+<?xml version="1.0" encoding="UTF-8"?><cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" LugarExpedicion="{{ o['cfdi:Comprobante']['LugarExpedicion'] }}" Moneda="{{ o['cfdi:Comprobante']['Moneda'] }}" NumCtaPago="{{ o['cfdi:Comprobante']['NumCtaPago'] }}" TipoCambio="{{ o['cfdi:Comprobante']['TipoCambio'] }}" anoAprobacion="{{ o['cfdi:Comprobante']['anoAprobacion'] }}" certificado="{{ o['cfdi:Comprobante']['certificado'] }}" descuento="{{ o['cfdi:Comprobante']['descuento'] }}" fecha="{{ o['cfdi:Comprobante']['fecha'] }}" folio="{{ o['cfdi:Comprobante']['folio'] }}" formaDePago="{{ o['cfdi:Comprobante']['formaDePago'] }}" metodoDePago="{{ o['cfdi:Comprobante']['metodoDePago'] }}" noAprobacion="{{ o['cfdi:Comprobante']['noAprobacion'] }}" noCertificado="{{ o['cfdi:Comprobante']['noCertificado'] }}" sello="{{ o['cfdi:Comprobante']['sello'] }}" serie="{{ o['cfdi:Comprobante']['serie'] }}" subTotal="{{ o['cfdi:Comprobante']['subTotal'] }}" tipoDeComprobante="{{ o['cfdi:Comprobante']['tipoDeComprobante'] }}" total="{{ o['cfdi:Comprobante']['total'] }}" version="{{ o['cfdi:Comprobante']['version'] }}" xmlns="{{ o['cfdi:Comprobante']['xmlns'] }}" xmlns:xsi="{{ o['cfdi:Comprobante']['xmlns:xsi'] }}" xsi:schemaLocation="{{ o['cfdi:Comprobante']['xsi:schemaLocation'] }}"><cfdi:Emisor nombre="{{ o['cfdi:Comprobante']['cfdi:Emisor']['nombre'] }}" rfc="{{ o['cfdi:Comprobante']['cfdi:Emisor']['rfc'] }}"><cfdi:DomicilioFiscal calle="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['calle'] }}" codigoPostal="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['codigoPostal'] }}" colonia="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['colonia'] }}" estado="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['estado'] }}" localidad="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['localidad'] }}" municipio="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['municipio'] }}" noExterior="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['noExterior'] }}" noInterior="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['noInterior'] }}" pais="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:DomicilioFiscal']['pais'] }}"/><cfdi:ExpedidoEn calle="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['calle'] }}" codigoPostal="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['codigoPostal'] }}" colonia="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['colonia'] }}" estado="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['estado'] }}" localidad="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['localidad'] }}" municipio="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['municipio'] }}" noExterior="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['noExterior'] }}" noInterior="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['noInterior'] }}" pais="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:ExpedidoEn']['pais'] }}"/><cfdi:RegimenFiscal Regimen="{{ o['cfdi:Comprobante']['cfdi:Emisor']['cfdi:RegimenFiscal']['Regimen'] }}"/></cfdi:Emisor><cfdi:Receptor nombre="{{ o['cfdi:Comprobante']['cfdi:Receptor']['nombre'] }}" rfc="{{ o['cfdi:Comprobante']['cfdi:Receptor']['rfc'] }}"><cfdi:Domicilio calle="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['calle'] }}" codigoPostal="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['codigoPostal'] }}" colonia="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['colonia'] }}" estado="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['estado'] }}" localidad="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['localidad'] }}" municipio="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['municipio'] }}" noExterior="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['noExterior'] }}" noInterior="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['noInterior'] }}" pais="{{ o['cfdi:Comprobante']['cfdi:Receptor']['cfdi:Domicilio']['pais'] }}"/></cfdi:Receptor>{% if o['cfdi:Comprobante']['cfdi:Conceptos']%}<cfdi:Conceptos>{% for i in o['cfdi:Comprobante']['cfdi:Conceptos'] %}<cfdi:Concepto cantidad="{{ i['cfdi:Concepto']['cantidad'] }}" descripcion="{{ i['cfdi:Concepto']['descripcion'] }}" importe="{{ i['cfdi:Concepto']['importe'] }}" noIdentificacion="{{ i['cfdi:Concepto']['noIdentificacion'] }}" unidad="{{ i['cfdi:Concepto']['unidad'] }}" valorUnitario="{{ i['cfdi:Concepto']['valorUnitario'] }}"/>{% endfor %}{% endif %}</cfdi:Conceptos>{% if o['cfdi:Comprobante']['cfdi:Impuestos']['totalImpuestosTrasladados'] %}<cfdi:Impuestos totalImpuestosTrasladados="{{ o['cfdi:Comprobante']['cfdi:Impuestos']['totalImpuestosTrasladados'] }}"><cfdi:Traslados>{% for i in o['cfdi:Comprobante']['cfdi:Impuestos']['cfdi:Traslados'] %}<cfdi:Traslado importe="{{ i['cfdi:Traslado']['importe'] }}" impuesto="{{ i['cfdi:Traslado']['impuesto'] }}" tasa="{{ i['cfdi:Traslado']['tasa'] }}"/>{% endfor %}</cfdi:Traslados></cfdi:Impuestos>{% endif %}</cfdi:Comprobante>
815\ No newline at end of file