diff --git a/l10n_mx_facturae/__init__.py b/l10n_mx_facturae/__init__.py index 50c3dadd5328e0497fd9716373455df102be3209..6a530785b1b0c8396b86346839977fb02a1e9e9e 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 5ab72f8949c92d0d6a1e38fd0c4f4a5d76ebc6e5..617b9fe0e4ab41f125134a30a4bf786d8492f670 100644 --- a/l10n_mx_facturae/__openerp__.py +++ b/l10n_mx_facturae/__openerp__.py @@ -8,18 +8,15 @@ 'website': 'http://www.openpyme.mx/', 'license': 'AGPL-3', 'depends': [ - 'l10n_mx_facturae_groups', 'account', 'base_vat', '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', '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 @@ -29,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 0000000000000000000000000000000000000000..fa3f394ac88ea34dc6a477c4174fd714779978bc --- /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 eb8b01697497561a19f964922212e3e933112d53..a43e035ee2a32fdaf2dd2fa8ebd39d13d974e57a 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 1773b2728680169f705b3d37f9ec89505ff17bc0..375c1a6c29b07db3ea89592ae87f40fc53d87398 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.date_invoice_tz, - } - 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 8c5ab392b0a3612c94d46b97a0b4bc4f2d5fbe08..0000000000000000000000000000000000000000 --- 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 Binary files a/l10n_mx_facturae/report/account_print_invoice.odt and b/l10n_mx_facturae/report/account_print_invoice.odt differ diff --git a/l10n_mx_facturae/report/account_print_invoice.py b/l10n_mx_facturae/report/account_print_invoice.py index ad79e10e2b14519827f4e78f602995cbfc306ef1..4e6e8c8945572f0f5205e3a17395d01a4085a3ee 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 @@ -88,31 +86,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): @@ -130,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 4ef94a9c22e7b47a510dd816157ca374ecdef3a5..6df6ba527400317b6555f7ebfdb957aa0e17ed23 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 = ( @@ -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}" diff --git a/l10n_mx_facturae/views/account_invoice.xml b/l10n_mx_facturae/views/account_invoice.xml index 63e89d94d51de8e124ffda8fcdaaa98d9694124a..1698722f2a200d6553f2c00ba0442cc14af4d535 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> @@ -63,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 0197dd8163cc39637036a0726d9d4efd58dfeee9..0000000000000000000000000000000000000000 --- 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 80192eaa30c3fc1b70f6522fe6c592d966bab35d..0000000000000000000000000000000000000000 --- 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 bec15988de3668d8829953bce2afb866e5c3e7b3..0000000000000000000000000000000000000000 --- 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> -