From 4874d26c13108c181567492b656d321fb3d39a47 Mon Sep 17 00:00:00 2001 From: federico <federico.cruz@openpyme.mx> Date: Mon, 12 Jun 2017 18:53:47 -0500 Subject: [PATCH 1/5] refactor(l10n_mx_facturae_group_show_wizards l10n_mx_facturae_group): remove unused modules these modules have never been used then ... we remove them --- l10n_mx_facturae/__openerp__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/l10n_mx_facturae/__openerp__.py b/l10n_mx_facturae/__openerp__.py index 5ab72f8949..4e18374bef 100644 --- a/l10n_mx_facturae/__openerp__.py +++ b/l10n_mx_facturae/__openerp__.py @@ -8,7 +8,6 @@ 'website': 'http://www.openpyme.mx/', 'license': 'AGPL-3', 'depends': [ - 'l10n_mx_facturae_groups', 'account', 'base_vat', 'document', @@ -19,7 +18,6 @@ 'l10n_mx_ir_attachment_facturae', 'l10n_mx_notes_invoice', 'l10n_mx_res_partner_bank', - 'l10n_mx_facturae_group_show_wizards', 'account_payment_type', # TODO: sale.order workflow fails when there is an active sale order # and we update the l10n_mx_factuare module. This dependency is not -- GitLab From bfdb0f6fd1d48ade132af1f261515ee2f406ef41 Mon Sep 17 00:00:00 2001 From: federico <federico.cruz@openpyme.mx> Date: Tue, 13 Jun 2017 13:51:08 -0500 Subject: [PATCH 2/5] refactor(account.invoice): remove related fields with l10n_mx_invoice_datetime module l10n_mx_invoice_datetime is deprecated then remove things related with module --- l10n_mx_facturae/__openerp__.py | 1 - l10n_mx_facturae/models/account_invoice.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/l10n_mx_facturae/__openerp__.py b/l10n_mx_facturae/__openerp__.py index 4e18374bef..ee324cf6aa 100644 --- a/l10n_mx_facturae/__openerp__.py +++ b/l10n_mx_facturae/__openerp__.py @@ -13,7 +13,6 @@ 'document', 'report_aeroo', 'l10n_mx_facturae_cer', - 'l10n_mx_invoice_datetime', 'l10n_mx_account_tax_category', 'l10n_mx_ir_attachment_facturae', 'l10n_mx_notes_invoice', diff --git a/l10n_mx_facturae/models/account_invoice.py b/l10n_mx_facturae/models/account_invoice.py index 1773b27286..dfcdc3a0ae 100644 --- a/l10n_mx_facturae/models/account_invoice.py +++ b/l10n_mx_facturae/models/account_invoice.py @@ -390,6 +390,6 @@ class account_invoice(orm.Model): result = { 'company_id': self.company_id.id, 'xml_data': xml_data, 'fname': fname_xml, - 'sello': data.get('sello'), 'date_tz': self.date_invoice_tz, + 'sello': data.get('sello'), 'date_tz': self.datetime, } return result -- GitLab From eff8f89263e2b05d50afa637dc30e78c14017d4b Mon Sep 17 00:00:00 2001 From: federico <federico.cruz@openpyme.mx> Date: Tue, 13 Jun 2017 13:52:16 -0500 Subject: [PATCH 3/5] refactor(account.invoice): remove l10n_mx_facturae_groups module remove all things related with l10n_mx_facturae_groups module --- l10n_mx_facturae/views/account_invoice.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/l10n_mx_facturae/views/account_invoice.xml b/l10n_mx_facturae/views/account_invoice.xml index 63e89d94d5..6a06c995f8 100644 --- a/l10n_mx_facturae/views/account_invoice.xml +++ b/l10n_mx_facturae/views/account_invoice.xml @@ -20,8 +20,7 @@ <xpath expr="//sheet[@string='Invoice']/h1" position="after"> <h4 collspan="2"> <field string="Fiscal Number" name="cfdi_folio_fiscal" - placeholder="Fiscal Number" readonly="1" - groups="l10n_mx_facturae_groups.group_l10n_mx_facturae_user"/> + placeholder="Fiscal Number" readonly="1"/> </h4> </xpath> <xpath expr="//sheet[@string='Invoice']/notebook/page[@string='Invoice Lines']/group/field[@name='payment_term']" position="after"> @@ -45,8 +44,7 @@ <xpath expr="//sheet[@string='Supplier Invoice']/div/h1" position="after"> <h4 collspan="2"> <field string="Fiscal Number" name="cfdi_folio_fiscal" - placeholder="Fiscal Number" attrs="{'readonly': [('state', '!=', 'draft')]}" - groups="l10n_mx_facturae_groups.group_l10n_mx_facturae_user"/> + placeholder="Fiscal Number" attrs="{'readonly': [('state', '!=', 'draft')]}"/> </h4> </xpath> </field> -- GitLab From 35070d0fdd94c571b6ee2737cb61c1e4f35c3c09 Mon Sep 17 00:00:00 2001 From: federico <federico.cruz@openpyme.mx> Date: Tue, 13 Jun 2017 13:53:09 -0500 Subject: [PATCH 4/5] refactor(account.invoice): remove l10n_mx_partner_address since we start to use l10n_mx_toponyms this field is not loger alive --- .../report/account_print_invoice.py | 44 +++++++++---------- l10n_mx_facturae/report/invoice.xml | 2 +- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/l10n_mx_facturae/report/account_print_invoice.py b/l10n_mx_facturae/report/account_print_invoice.py index ad79e10e2b..286ca8fa6b 100644 --- a/l10n_mx_facturae/report/account_print_invoice.py +++ b/l10n_mx_facturae/report/account_print_invoice.py @@ -88,31 +88,27 @@ class Parser(report_sxw.rml_parse): else: add_invoice = partner - # Aseguramos que la dirección sea de facturación - if add_invoice.type in ['invoice', 'default']: - res = { - 'name': add_invoice.name or '', - 'vat': add_invoice.vat_split or add_invoice.vat or '', - 'street': add_invoice.street or False, - 'no_ext': add_invoice.l10n_mx_street3 or '', - 'no_int': add_invoice.l10n_mx_street4 or '', - 'suburb': add_invoice.street2 or '', - 'city': add_invoice.city or '', - 'state': add_invoice.state_id.name or '', - 'country': add_invoice.country_id.name or '', - 'county': add_invoice.l10n_mx_city2 or '', - 'zip': add_invoice.zip or '', - 'phone': add_invoice.phone or '', - 'fax': add_invoice.fax or '', - 'mobile': add_invoice.mobile or '', - } - if not res['vat']: - # Comprobamos que tengamos un RFC definido - raise openerp.exceptions.Warning( - _('Not Vat Number set on partner')) - else: + res = { + 'name': add_invoice.name or '', + 'vat': add_invoice.vat_split or add_invoice.vat or '', + 'street': add_invoice.street or False, + 'no_ext': add_invoice.l10n_mx_street3 or '', + 'no_int': add_invoice.l10n_mx_street4 or '', + 'suburb': add_invoice.street2 or '', + 'city': add_invoice.city or '', + 'state': add_invoice.state_id.name or '', + 'country': add_invoice.country_id.name or '', + 'county': add_invoice.l10n_mx_city2 or '', + 'zip': add_invoice.zip or '', + 'phone': add_invoice.phone or '', + 'fax': add_invoice.fax or '', + 'mobile': add_invoice.mobile or '', + } + + if not res['vat']: + # Comprobamos que tengamos un RFC definido raise openerp.exceptions.Warning( - _('Customer Address Not Invoice Type')) + _('Not Vat Number set on partner')) return res def _get_qrcode(self, invoice): diff --git a/l10n_mx_facturae/report/invoice.xml b/l10n_mx_facturae/report/invoice.xml index 4ef94a9c22..3d46e3474f 100644 --- a/l10n_mx_facturae/report/invoice.xml +++ b/l10n_mx_facturae/report/invoice.xml @@ -58,7 +58,7 @@ noExterior="${emitter.l10n_mx_street3 or 'N/A'}" noInterior="${emitter.l10n_mx_street4 or 'N/A'}" pais="${emitter.country_id.name or 'N/A'}"/> - <cfdi:RegimenFiscal Regimen="${emitter.regimen_fiscal_id.name}"/> + <cfdi:RegimenFiscal Regimen="${emitter.property_account_position.name}"/> </cfdi:Emisor> <cfdi:Receptor nombre="${reciver.name}" rfc="${reciver.vat_split}"> <cfdi:Domicilio calle="${reciver.street}" codigoPostal="${reciver.zip}" -- GitLab From 45bc540cf5a6cbb4e500e5a7f9dd232467e50e9f Mon Sep 17 00:00:00 2001 From: federico <federico.cruz@openpyme.mx> Date: Fri, 16 Jun 2017 11:46:38 -0500 Subject: [PATCH 5/5] refactor(CFDI): refactor module in order to allow CFDI module handle all sign SAT process in order to make easier to handle SAT sign this commit is intendet to allow CFDI to handle all workflow since creation new CFDI object until have a CFDI SAT giend XML and PDF files --- l10n_mx_facturae/__init__.py | 1 - l10n_mx_facturae/__openerp__.py | 2 +- .../data/ir_attachment_facturae_config.xml | 14 + l10n_mx_facturae/models/__init__.py | 1 - l10n_mx_facturae/models/account_invoice.py | 455 +++++------------- .../models/ir_attachment_facturae.py | 41 -- .../report/account_print_invoice.odt | Bin 17713 -> 17658 bytes .../report/account_print_invoice.py | 4 +- l10n_mx_facturae/report/invoice.xml | 4 +- l10n_mx_facturae/views/account_invoice.xml | 11 - l10n_mx_facturae/wizard/__init__.py | 29 -- l10n_mx_facturae/wizard/installer.py | 65 --- l10n_mx_facturae/wizard/installer_view.xml | 42 -- 13 files changed, 129 insertions(+), 540 deletions(-) create mode 100644 l10n_mx_facturae/data/ir_attachment_facturae_config.xml delete mode 100644 l10n_mx_facturae/models/ir_attachment_facturae.py delete mode 100644 l10n_mx_facturae/wizard/__init__.py delete mode 100644 l10n_mx_facturae/wizard/installer.py delete mode 100644 l10n_mx_facturae/wizard/installer_view.xml diff --git a/l10n_mx_facturae/__init__.py b/l10n_mx_facturae/__init__.py index 50c3dadd53..6a530785b1 100644 --- a/l10n_mx_facturae/__init__.py +++ b/l10n_mx_facturae/__init__.py @@ -2,4 +2,3 @@ from . import models from . import report -from . import wizard diff --git a/l10n_mx_facturae/__openerp__.py b/l10n_mx_facturae/__openerp__.py index ee324cf6aa..617b9fe0e4 100644 --- a/l10n_mx_facturae/__openerp__.py +++ b/l10n_mx_facturae/__openerp__.py @@ -26,8 +26,8 @@ 'demo': [ ], 'data': [ + 'data/ir_attachment_facturae_config.xml', 'report/account_print_invoice.xml', - 'wizard/installer_view.xml', 'views/account_invoice.xml', 'report/account_print_invoice.xml', ], diff --git a/l10n_mx_facturae/data/ir_attachment_facturae_config.xml b/l10n_mx_facturae/data/ir_attachment_facturae_config.xml new file mode 100644 index 0000000000..fa3f394ac8 --- /dev/null +++ b/l10n_mx_facturae/data/ir_attachment_facturae_config.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<openerp> + <data> + + <record model="ir.attachment.facturae.mx.config" id="ir_attachment_facturae_mx_config_invoice"> + <field name="model">account.invoice</field> + <field name="template_xml_sign">invoice.report.aaero.xml</field> + <field name="template_xml_cancel">Aun.no.hay.uno</field> + <field name="template_pdf_sign">invoice.report.aaero</field> + <field name="template_pdf_cancel">invoice.report.aaero</field> + </record> + + </data> +</openerp> diff --git a/l10n_mx_facturae/models/__init__.py b/l10n_mx_facturae/models/__init__.py index eb8b016974..a43e035ee2 100644 --- a/l10n_mx_facturae/models/__init__.py +++ b/l10n_mx_facturae/models/__init__.py @@ -3,4 +3,3 @@ from . import account_invoice from . import account_invoice_line from . import email_template -from . import ir_attachment_facturae diff --git a/l10n_mx_facturae/models/account_invoice.py b/l10n_mx_facturae/models/account_invoice.py index dfcdc3a0ae..375c1a6c29 100644 --- a/l10n_mx_facturae/models/account_invoice.py +++ b/l10n_mx_facturae/models/account_invoice.py @@ -2,160 +2,39 @@ from datetime import datetime -from openerp import fields, api -from openerp.osv import orm -from openerp.tools.translate import _ -from openerp.report import render_report -from xml.dom.minidom import parseString +from openerp import api, fields, models +from openerp.exceptions import Warning as UserError from pytz import timezone -import time -import base64 -import tempfile -import os +# Allow module to work with normal OpenERP/Odoo or with PyERP +# on PyERP workflows on invoices has been replaced with blinker signals +# that's why we need to import a fake signal to prevent python fail +try: + from openerp.addons.account import signals +except ImportError: + from . import signals +import logging -class account_invoice(orm.Model): - _inherit = 'account.invoice' +_logger = logging.getLogger(__name__) - @api.model - def _get_invoice_sequence(self): - sequence_id = False - company = self.company_id - while True: - if self.type == 'out_invoice': - if 'invoice_out_sequence_id' in company._columns: - sequence_id = company.invoice_out_sequence_id - elif self.type == 'out_refund': - if 'invoice_out_refund_sequence_id' in company._columns: - sequence_id = company.invoice_out_refund_sequence_id - company = company.parent_id - if sequence_id or not company: - break - if not sequence_id: - if ( - 'invoice_sequence_id' in self.journal_id._columns and - self.journal_id.invoice_sequence_id - ): - sequence_id = self.journal_id.invoice_sequence_id - elif ( - 'sequence_id' in self.journal_id._columns and - self.journal_id.sequence_id - ): - sequence_id = self.journal_id.sequence_id - sequence_id = sequence_id and sequence_id.id or False - if not sequence_id: - sequence_str = 'account.invoice.' + self.type - test = 'code=%s' - self._cr.execute( - 'SELECT id FROM ir_sequence WHERE ' + - test+' AND active=%s LIMIT 1', (sequence_str, True)) - res2 = self._cr.dictfetchone() - sequence_id = res2 and res2['id'] or False - return sequence_id - def create_report( - self, cr, uid, res_ids, report_name=False, - file_name=False, context=None - ): - """ - @param report_name : Name of report with the name of object more type - of report - @param file_name : Path where is save the report temporary more the - name of report that is 'openerp___facturae__' more six random - characters for no files duplicate - """ - if context is None: - context = {} - if not report_name or not res_ids: - return (False, Exception('Report name and Resources ids are required !!!')) - ret_file_name = file_name + '.pdf' - result, format = render_report( - cr, uid, res_ids, report_name, {'model': 'account.invoice'}, - context - ) - fp = open(ret_file_name, 'wb+') - fp.write(result) - fp.close() - return result + +class account_invoice(models.Model): + _inherit = 'account.invoice' @property def fname_invoice(self): if self.state == 'draft': return '' fname = "_".join( - [self.address_issued_id.vat_split or - self.address_issued_id.vat, self.number or + [self.company_id.partner_id.vat_split or + self.company_id.partner_id.vat, self.number or self.internal_number] ) return fname - def action_cancel_draft(self, cr, uid, ids, *args): - self.write(cr, uid, ids, { - 'no_certificado': False, - 'certificado': False, - 'sello': False, - 'cadena_original': False, - 'date_invoice_cancel': False, - 'cfdi_sello': False, - 'cfdi_no_certificado': False, - 'cfdi_cadena_original': False, - 'cfdi_fecha_timbrado': False, - 'cfdi_folio_fiscal': False, - 'cfdi_fecha_cancelacion': False - }) - return super(account_invoice, self).action_cancel_draft(cr, uid, ids, args) - - def action_cancel(self, cr, uid, ids, context=None): - if context is None: - context = {} - ids = isinstance(ids, (int, long)) and [ids] or ids - self.write( - cr, uid, ids, - {'date_invoice_cancel': time.strftime('%Y-%m-%d %H:%M:%S')} - ) - return super(account_invoice, self).action_cancel( - cr, uid, ids, context=context - ) - - def action_date_assign(self, cr, uid, ids, context=None): - if not context: - context = {} - currency_mxn_ids = self.pool.get('res.currency').search( - cr, uid, [('name', '=', 'MXN')], limit=1, context=context) - currency_mxn_id = currency_mxn_ids and currency_mxn_ids[0] or False - if not currency_mxn_id: - raise orm.except_orm(_('Error !'), _('No hay moneda MXN.')) - for id in ids: - invoice = self.browse(cr, uid, [id])[0] - invoice = self.browse(cr, uid, [id], context)[0] - rate = self.pool.get('res.currency').compute( - cr, uid, invoice.currency_id.id, currency_mxn_id, 1,) - self.write(cr, uid, [id], {'rate': rate}) - return super(account_invoice, self).action_date_assign( - cr, uid, ids, context=context - ) - datetime = fields.Datetime(compute='_compute_datetime', store=True) - no_certificado = fields.Text( - 'No. Certificate', size=64, copy=False, - help='Number of serie of certificate used for the invoice' - ) - # TODO: Is this field really needed? - certificado = fields.Text( - 'Certificate', size=64, copy=False, - help='Certificate used in the invoice' - ) - # TODO: Is this field really needed? - sello = fields.Text( - 'Stamp', size=512, copy=False, help='Digital Stamp' - ) - # TODO: Duplicated field - cadena_original = fields.Text( - 'String Original', size=512, copy=False, - help='Data stream with the information contained in the electronic' - ' invoice' - ) date_invoice_cancel = fields.Datetime( 'Date Invoice Cancelled', readonly=True, copy=False, help='If the invoice is cancelled, save the date' @@ -165,33 +44,22 @@ class account_invoice(orm.Model): 'Type of Change', readonly=True, copy=False, help='Rate used in the date of invoice' ) - # TODO: Is this field really needed? - cfdi_sello = fields.Text( - 'CFD-I Stamp', copy=False, help='Sign assigned by the SAT' - ) - # TODO: Is this field really needed? - cfdi_no_certificado = fields.Char( - 'CFD-I Certificado', size=32, copy=False, - help='Serial Number of the Certificate' - ) - # TODO: Is this field really needed? - cfdi_cadena_original = fields.Text( - 'CFD-I Original String', copy=False, - help='Original String used in the electronic invoice' - ) - cfdi_fecha_timbrado = fields.Datetime( - 'CFD-I Date Stamping', copy=False, - help='Date when is stamped the electronic invoice' - ) - # TODO: This field and date_canceled used by same pourpose - cfdi_fecha_cancelacion = fields.Datetime( - 'CFD-I Cancellation Date', copy=False, - help='If the invoice is cancel, this field saved the date when is cancel' - ) cfdi_folio_fiscal = fields.Char( 'CFD-I Folio Fiscal', size=64, copy=False, + compute='_compute_cfdi_folio_fiscal', help='Folio used in the electronic invoice' ) + cfdi_id = fields.Many2one( + 'ir.attachment.facturae.mx', 'CFDI', compute='_compute_cfdi_id') + + @api.one + def _compute_cfdi_id(self): + ir_attachment_mx_obj = self.env['ir.attachment.facturae.mx'] + related_attachment = ir_attachment_mx_obj.search( + [('res_id', '=', self.id), + ('type_attachment', '=', 'account.invoice')], limit=1) + if related_attachment: + self.cfdi_id = related_attachment @api.one @api.depends('state') @@ -205,191 +73,90 @@ class account_invoice(orm.Model): ) self.datetime = invoice_datetime + @api.one + @api.depends('state') + def _compute_cfdi_folio_fiscal(self): + self.cfdi_folio_fiscal = self.cfdi_id.uuid + + @signals.invoice_validate.connect + def sign_invoice_sat(self, cr, uid, ids, context=None): + context = dict(context or {}) + ir_attach_obj = self.pool.get('ir.attachment.facturae.mx') + for account_invoice in self.browse(cr, uid, ids, context): + if account_invoice.journal_id.sign_sat: + ir_attach_obj.sign_cfdi_sat( + cr, uid, ids, object_id=account_invoice.id, + object_model='account.invoice', + name=account_invoice.fname_invoice) + + @signals.invoice_cancel.connect + def action_cancel(self, cr, uid, ids, context=None): + context = dict(context or {}) + ir_attach_obj = self.pool.get('ir.attachment.facturae.mx') + for account_invoice in self.browse(cr, uid, ids, context): + # Maybe a third test could review state, but since + # button cancel only is displayed in open state, we decided to not + # used third test + if account_invoice.journal_id.sign_sat and account_invoice.cfdi_folio_fiscal: + ir_attach_obj.cancel_cfdi_sat( + cr, uid, ids, object_id=account_invoice.id, + object_model='account.invoice', + name=account_invoice.fname_invoice) + + def get_tmpl_email_id(self): + email_pool = self.env['email.template'] + email_ids = email_pool.search( + [('model_id.model', '=', 'account.invoice')]) + return email_ids and email_ids[0].id or False + + def action_send_customer(self): + attachment_obj = self.env['ir.attachment'] + obj_ir_mail_server = self.env['ir.mail_server'] + mail_obj = self.env['mail.mail'] + template_pool = self.env['email.template'] + + # Grab attachments + attachments = attachment_obj.search( + [('res_model', '=', 'account.invoice'), + ('res_id', '=', self.id)]) + attachments_id = [x.id for x in attachments] + + # TODO: Hard coding name + smtp_server = obj_ir_mail_server.search([('name', '=', 'FacturaE')]) + if smtp_server: + _logger.debug('Testing SMTP servers') + try: + obj_ir_mail_server.connect( + smtp_server.smtp_host, smtp_server.smtp_port, + user=smtp_server.smtp_user, + password=smtp_server.smtp_pass, + encryption=smtp_server.smtp_encryption, + smtp_debug=smtp_server.smtp_debug) + except Exception, e: + raise UserError( + _('Connection test failed!'), + _('Configure outgoing mail server named FacturaE: %s') + % e + ) - def _get_file(self, cr, uid, inv_ids, context={}): - if not context: - context = {} - id = inv_ids[0] - invoice = self.browse(cr, uid, [id], context=context)[0] - fname_invoice = invoice.fname_invoice and invoice.fname_invoice + \ - '.xml' or '' - aids = self.pool.get('ir.attachment').search(cr, uid, [( - 'datas_fname', '=', invoice.fname_invoice + '.xml'), ( - 'res_model', '=', 'account.invoice'), ('res_id', '=', id)]) - xml_data = "" - if aids: - brow_rec = self.pool.get('ir.attachment').browse(cr, uid, aids[0]) - if brow_rec.datas: - xml_data = base64.decodestring(brow_rec.datas) - else: - fname, xml_data = self._get_facturae_invoice_xml_data( - cr, uid, inv_ids, context=context) - self.pool.get('ir.attachment').create(cr, uid, { - 'name': fname_invoice, - 'datas': base64.encodestring(xml_data), - 'datas_fname': fname_invoice, - 'res_model': 'account.invoice', - 'res_id': invoice.id, - }, context=context) - self.fdata = base64.encodestring(xml_data) - msg = _("Press in the button 'Upload File'") - return {'file': self.fdata, 'fname': fname_invoice, - 'name': fname_invoice, 'msg': msg} - - def add_node(self, node_name=None, attrs=None, parent_node=None, - minidom_xml_obj=None, attrs_types=None, order=False): - """ - @params node_name : Name node to added - @params attrs : Attributes to add in node - @params parent_node : Node parent where was add new node children - @params minidom_xml_obj : File XML where add nodes - @params attrs_types : Type of attributes added in the node - @params order : If need add the params in order in the XML, add a - list with order to params - """ - if not order: - order = attrs - new_node = minidom_xml_obj.createElement(node_name) - for key in order: - if attrs_types[key] == 'attribute': - new_node.setAttribute(key, attrs[key]) - elif attrs_types[key] == 'textNode': - key_node = minidom_xml_obj.createElement(key) - text_node = minidom_xml_obj.createTextNode(attrs[key]) - - key_node.appendChild(text_node) - new_node.appendChild(key_node) - parent_node.appendChild(new_node) - return new_node - - def _get_type_sequence(self, cr, uid, ids, context=None): - if context is None: - context = {} - invoice = self.browse(cr, uid, ids[0], context=context) - type_inv = invoice.journal_id.type_cfdi or 'cfd22' - if 'cfdi32' in type_inv: # Revisa si en tipo es cfdi - comprobante = 'cfdi:Comprobante' - else: - comprobante = 'Comprobante' - return comprobante - - def _get_file_cancel(self, cr, uid, inv_ids, context=None): - inv_ids = inv_ids[0] - atta_obj = self.pool.get('ir.attachment') - atta_id = atta_obj.search(cr, uid, [('res_id', '=', inv_ids), ( - 'name', 'ilike', '%.xml')], context=context) - if atta_id: - atta_brw = atta_obj.browse(cr, uid, atta_id, context)[0] - inv_xml = atta_brw.datas or False + # Server tested, create mail content + _logger.debug('Start processing mail template') + template_id = self.get_tmpl_email_id() + values = template_pool.generate_email(template_id, self.id) + assert values.get('email_from'), 'email_from is missing or empty after template rendering, send_mail() cannot proceed' + # Get recipients + values['recipient_ids'] = [ + (4, pid) for pid in values.get('partner_ids', list()) + ] + mail = mail_obj.create(values) + # Process attachments + mail.write({'attachment_ids': [(6, 0, attachments_id)]}) + # Send mail + mail_obj.send([mail.id]) else: - inv_xml = False - raise orm.except_orm(('State of Cancellation!'), ( - "This invoice hasn't stamped, so that not possible cancel.")) - return {'file': inv_xml} - - def _get_time_zone(self, cr, uid, invoice_id, context=None): - """ - TODO: Why is this function needed? - """ - import pytz - res_users_obj = self.pool.get('res.users') - userstz = res_users_obj.browse(cr, uid, [uid])[0].partner_id.tz - a = 0 - if userstz: - hours = pytz.timezone(userstz) - fmt = '%Y-%m-%d %H:%M:%S %Z%z' - now = datetime.now() - loc_dt = hours.localize(datetime(now.year, now.month, now.day, - now.hour, now.minute, now.second)) - timezone_loc = (loc_dt.strftime(fmt)) - diff_timezone_original = timezone_loc[-5:-2] - timezone_original = int(diff_timezone_original) - s = str(datetime.now(pytz.timezone(userstz))) - s = s[-6:-3] - timezone_present = int(s) * -1 - a = timezone_original + (( - timezone_present + timezone_original) * -1) - return a - - def action_printable(self, cr, uid, ids, context=None): - if context is None: - context = {} - msj = '' - index_pdf = '' - attachment_obj = self.pool.get('ir.attachment') - ir_attachment_facturae_obj = self.pool.get('ir.attachment.facturae.mx') - invoice_id = ir_attachment_facturae_obj.browse( - cr, uid, ids[0], context=context - ).res_id - for invoice in self.browse(cr, uid, [invoice_id], context=context): - (fileno, fname) = tempfile.mkstemp( - '.pdf', 'openerp_' + - (invoice.fname_invoice or '') + - '__facturae__' - ) - os.close(fileno) - result = self.create_report( - cr, uid, [invoice.id], - "invoice.report.aaero", fname - ) - attachment_ids = attachment_obj.create( - cr, uid, { - 'name': invoice.fname_invoice + '.pdf', - 'datas_fname': invoice.fname_invoice + '.pdf', - 'datas': base64.encodestring(result), - 'res_model': 'account.invoice', - 'res_id': invoice.id, - }, - context=None + raise UserError( + _('Warning'), + _('Not Found outgoing mail server name of "FacturaE".' + '\nConfigure the outgoing mail server named "FacturaE"') ) - if attachment_ids: - # TODO: WHY???? - # aids.append( attachment.id ) but without error in last write - ir_attachment_facturae_obj.write( - cr, uid, ids, - {'file_pdf': attachment_ids or False, - 'state': 'printable', - 'msj': msj, - 'last_date': time.strftime('%Y-%m-%d %H:%M:%S'), - 'file_pdf_index': index_pdf}, - context=context - ) - else: - raise orm.except_orm( - _('Warning'), _('Not Attached PDF\n') - ) return True - - @api.model - def _get_facturae_invoice_xml_data(self): - """ - Function use to generate XML from template - using aeroo_report module - """ - ir_attachment_facturae_obj = self.env['ir.attachment.facturae.mx'] - # Call render report in order to - # generate XML report - result, format = render_report( - self.env.cr, self.env.uid, self._ids, - 'invoice.report.aaero.xml', {'model': 'account.invoice'}, - ) - # Convert string to XML - xml_data = parseString(result.strip()) - # Sign the created XML - # Create a new context to pass company_id - context = dict(self._context or {}) - context.update({'company_id': self.company_id.id}) - new_facturae_obj = ir_attachment_facturae_obj.with_context( - context) - xml_data, data = new_facturae_obj.sign_xml(xml_data) - # Get invoice name - fname_xml = '.'.join([self.fname_invoice, 'xml']) - # Write values into invoice - self.write(data) - # Return result - result = { - 'company_id': self.company_id.id, - 'xml_data': xml_data, 'fname': fname_xml, - 'sello': data.get('sello'), 'date_tz': self.datetime, - } - return result diff --git a/l10n_mx_facturae/models/ir_attachment_facturae.py b/l10n_mx_facturae/models/ir_attachment_facturae.py deleted file mode 100644 index 8c5ab392b0..0000000000 --- a/l10n_mx_facturae/models/ir_attachment_facturae.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- encoding: utf-8 -*- -########################################################################### -# Module Writen to OpenERP, Open Source Management Solution -# -# Authors: Openpyme (<http://openpyme.mx>) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -from openerp.osv import orm - - -class ir_attachment_facturae_mx(orm.Model): - _inherit = 'ir.attachment.facturae.mx' - - # Extend _get_signed_xml to be able to sign an invoice - def _get_signed_xml(self, cr, uid, ids, context): - context = dict(context or {}) - account_invoice_obj = self.pool.get('account.invoice') - result = super(ir_attachment_facturae_mx, self)._get_signed_xml( - cr, uid, ids, context=context - ) - for attachment in self.browse(cr, uid, ids, context=context): - if attachment.type_attachment == 'account.invoice': - for invoice in account_invoice_obj.browse( - cr, uid, [attachment.res_id], context=context - ): - result = invoice._get_facturae_invoice_xml_data() - return result diff --git a/l10n_mx_facturae/report/account_print_invoice.odt b/l10n_mx_facturae/report/account_print_invoice.odt index 4a9f650ecd9addafbab14d91763c6edfe2d3bf3b..fe0f2e49582641d0eb35657557fda00df4987eb9 100644 GIT binary patch delta 12993 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 delta 13129 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 H|C0VcmId=Y diff --git a/l10n_mx_facturae/report/account_print_invoice.py b/l10n_mx_facturae/report/account_print_invoice.py index 286ca8fa6b..4e6e8c8945 100644 --- a/l10n_mx_facturae/report/account_print_invoice.py +++ b/l10n_mx_facturae/report/account_print_invoice.py @@ -26,11 +26,9 @@ import string import logging import base64 import StringIO -import time from openerp.tools.translate import _ from openerp.report import report_sxw -from openerp.addons.report_webkit import webkit_report import openerp import qrcode @@ -126,7 +124,7 @@ class Parser(report_sxw.rml_parse): qr.add_data('?re=' + invoice.company_id.partner_id.vat_split or invoice.company_id.partner_id.vat) qr.add_data('&rr=' + invoice.partner_id.vat_split or invoice.company_id.vat) qr.add_data('&tt=' + tt) - qr.add_data('&id=' + invoice.cfdi_folio_fiscal) + qr.add_data('&id=' + invoice.cfdi_id.uuid) qr.make(fit=True) # Genera la imagen y la pone en memoria para poder diff --git a/l10n_mx_facturae/report/invoice.xml b/l10n_mx_facturae/report/invoice.xml index 3d46e3474f..6df6ba5274 100644 --- a/l10n_mx_facturae/report/invoice.xml +++ b/l10n_mx_facturae/report/invoice.xml @@ -5,8 +5,8 @@ """ invoice = o emitter = ( - o.company_emitter_id and - o.company_emitter_id.address_invoice_parent_company_id or + o.company_id and + o.company_id.partner_id or False) reciver = o.partner_id payment_code = ( diff --git a/l10n_mx_facturae/views/account_invoice.xml b/l10n_mx_facturae/views/account_invoice.xml index 6a06c995f8..1698722f2a 100644 --- a/l10n_mx_facturae/views/account_invoice.xml +++ b/l10n_mx_facturae/views/account_invoice.xml @@ -61,16 +61,5 @@ </field> </record> - <record id="view_account_invoice_filter_cfdi" model="ir.ui.view"> - <field name="name">view.account.invoice.filter.cfdi</field> - <field name="model">account.invoice</field> - <field name="inherit_id" ref="account.view_account_invoice_filter" /> - <field name="arch" type="xml"> - <field name="number" positon="after"> - <!-- <field name="cfdi_folio_fiscal" string="Fiscal Number" filter_domain="[('cfdi_folio_fiscal','ilike',self)]"/> --> - </field> - </field> - </record> - </data> </openerp> diff --git a/l10n_mx_facturae/wizard/__init__.py b/l10n_mx_facturae/wizard/__init__.py deleted file mode 100644 index 0197dd8163..0000000000 --- a/l10n_mx_facturae/wizard/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- encoding: utf-8 -*- -########################################################################### -# Module Writen to OpenERP, Open Source Management Solution -# -# Copyright (c) 2010 Vauxoo - http://www.vauxoo.com/ -# All Rights Reserved. -# info Vauxoo (info@vauxoo.com) -############################################################################ -# Coded by: moylop260 (moylop260@vauxoo.com) -# Launchpad Project Manager for Publication: Nhomar Hernandez - nhomar@vauxoo.com -############################################################################ -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -# import wizard_create_facturae_file -import installer diff --git a/l10n_mx_facturae/wizard/installer.py b/l10n_mx_facturae/wizard/installer.py deleted file mode 100644 index 80192eaa30..0000000000 --- a/l10n_mx_facturae/wizard/installer.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- encoding: utf-8 -*- -########################################################################### -# Module Writen to OpenERP, Open Source Management Solution -# -# Authors: Vaouxoo (<http://www.vauxoo.com/>) -# Openpyme (<http://openpyme.mx>) -# -# -# Coded by: Maria Gabriela Quilarque <gabriela@openerp.com.ve> -# AgustÃn Cruz Lozano (agustin.cruz@openpyme.mx) -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -from openerp.osv import fields, orm - - -class facturae_config(orm.TransientModel): - _name = 'facturae.config' - _inherit = 'res.config' - _description = __doc__ - - def _assign_vat(self, cr, uid, vat, company_id, context=None): - """ - @param vat : VAT that will be set in the company - @param company_id : Id from the company that the user works - """ - if context is None: - context = {} - partner_id = self.pool.get('res.company').browse( - cr, uid, company_id).partner_id.id - partner_obj = self.pool.get('res.partner') - if partner_obj.check_vat(cr, uid, [partner_id], context): - partner_obj.write(cr, uid, partner_id, { - 'vat': vat, - }, context=context) - - def execute(self, cr, uid, ids, context=None): - if context is None: - context = {} - ids = isinstance(ids, (int, long)) and [ids] or ids - company_id = self.pool.get('res.users').browse(cr, uid, [uid], context)[0].company_id.partner_id.id - wiz_data = self.read(cr, uid, ids) - if wiz_data[0]['vat']: - self._assign_vat(cr, uid, wiz_data[0]["vat"], company_id, context) - - _columns = { - 'vat': fields.char('VAT', 64, help='Federal Register of Causes'), - 'company_id': fields.many2one( - 'res.company', 'Company', - help="Select company to assing vat and/or cif" - ), - } diff --git a/l10n_mx_facturae/wizard/installer_view.xml b/l10n_mx_facturae/wizard/installer_view.xml deleted file mode 100644 index bec15988de..0000000000 --- a/l10n_mx_facturae/wizard/installer_view.xml +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0"?> -<openerp> - <data> -<!-- -Configurar Factura Electronica ---> - <record id="invoice_elec_config_view" model="ir.ui.view"> - <field name="name">configure.electronic.invoice.form</field> - <field name="model">facturae.config</field> - <field name="inherit_id" ref="base.res_config_view_base"/> - <field name="arch" type="xml"> - <xpath expr="/form/group" position="replace"> - <group string="Configure your data for Electronic Invoice"/> - </xpath> - <xpath expr="/form/footer" position="after"> - <group colspan="1" col="1"> - <field name="vat"/> - </group> - </xpath> - </field> - </record> -<!-- -Acción ---> - <record id="action_config_invoice_electronic" model="ir.actions.act_window"> - <field name="name">Configure Electronic Invoice</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">facturae.config</field> - <field name="view_id" ref="invoice_elec_config_view"/> - <field name="view_type">form</field> - <field name="view_mode">form</field> - <field name="target">new</field> - </record> - <!-- register configuration wizard --> - - <record model="ir.actions.todo" id="config_auto_invoice_electronic"> - <field name="action_id" ref="action_config_invoice_electronic"/> - <field name="type">automatic</field> - </record> - </data> -</openerp> - -- GitLab