diff --git a/l10n_mx_facturae/__openerp__.py b/l10n_mx_facturae/__openerp__.py index 648897c065809d7028805d9a197b43136d68aaad..b0bd6742e2dac36f43b17677b114041e38d23a83 100644 --- a/l10n_mx_facturae/__openerp__.py +++ b/l10n_mx_facturae/__openerp__.py @@ -1,34 +1,33 @@ # -*- coding: utf-8 -*- { - 'name': 'Factura Electronica CFDI', - 'version': '2.8.0', - 'author': 'OpenPyme', - 'category': 'Localization/Mexico', - 'website': 'http://www.openpyme.mx/', - 'license': 'AGPL-3', - 'depends': [ - 'account', + "name": "Factura Electronica CFDI", + "version": "2.8.0", + "author": "OpenPyme", + "category": "Localization/Mexico", + "website": "http://www.openpyme.mx/", + "license": "AGPL-3", + "depends": [ + "account", # TODO: Deprecate this module and include into account base - 'account_invoice_discount', - 'base_vat', - 'l10n_mx', - 'l10n_mx_account_tax_category', - 'l10n_mx_ir_attachment_facturae', - 'l10n_mx_res_partner_bank', + "account_invoice_discount", + "base_vat", + "l10n_mx", + "l10n_mx_account_tax_category", + "l10n_mx_ir_attachment_facturae", + "l10n_mx_res_partner_bank", ], - 'demo': [ + "demo": [], + "data": [ + "views/account_invoice.xml", + "views/account_voucher.xml", + "views/res_partner.xml", + "wizard/account_invoice_refund.xml", + "report/account_invoice.xml", + "report/account_voucher.xml", + "data/ir_cron.xml", + "data/email_template.xml", + "data/ir_attachment_facturae_config.xml", ], - 'data': [ - 'views/account_invoice.xml', - 'views/account_voucher.xml', - 'views/res_partner.xml', - 'wizard/account_invoice_refund.xml', - 'report/account_invoice.xml', - 'report/account_voucher.xml', - 'data/ir_cron.xml', - 'data/email_template.xml', - 'data/ir_attachment_facturae_config.xml', - ], - 'installable': True, + "installable": True, } diff --git a/l10n_mx_facturae/data/ir_cron.xml b/l10n_mx_facturae/data/ir_cron.xml index 95322d884e17c7c2eba5343c5c3b3e454e39bd2f..976b588bbdd2c35b877b443728b3b76f18123d19 100644 --- a/l10n_mx_facturae/data/ir_cron.xml +++ b/l10n_mx_facturae/data/ir_cron.xml @@ -8,8 +8,8 @@ <field name="numbercall">-1</field> <field name="model" eval="'account.invoice'"/> <field name="function" eval="'cron_invoices_pending_to_cancel'"/> - <field name="args" eval="'(None,)'"/> - <field name="active" eval="False" /> + <field name="args" eval="'()'"/> + <field name="active" eval="True" /> </record> </data> </openerp> diff --git a/l10n_mx_facturae/migrations/2.4.0/post-migration.py b/l10n_mx_facturae/migrations/2.4.0/post-migration.py index 1fffeb910c5b0017cc17dbf4f674424c225d3038..12f4a13f9dcbc88f2c7ca95562b95600f31cdbf5 100644 --- a/l10n_mx_facturae/migrations/2.4.0/post-migration.py +++ b/l10n_mx_facturae/migrations/2.4.0/post-migration.py @@ -12,21 +12,22 @@ def migrate(env, installed_version): 'invoice' and set them as is_company True """ tools.message( - env.cr, 'l10n_mx_facturae', 'res.partner', 'is_company', - message='Setting is_company on True for res.partners...', + env.cr, + "l10n_mx_facturae", + "res.partner", + "is_company", + message="Setting is_company on True for res.partners...", ) - partners = env['res.partner'].search([('type', '=', 'invoice')]) - partners.write({'is_company': True}) + partners = env["res.partner"].search([("type", "=", "invoice")]) + partners.write({"is_company": True}) # Delete removed view that reference to a field named rate try: - dummy, id = env['ir.model.data'].get_object_reference( - 'l10n_mx_facturae', - 'account_invoice_form_inh_l10n_mx_facturae_rate', + dummy, id = env["ir.model.data"].get_object_reference( + "l10n_mx_facturae", "account_invoice_form_inh_l10n_mx_facturae_rate" ) tools.logged_query( - env.cr, 'DELETE FROM ir_ui_view WHERE id=%(id)s', - args={'id': id}, + env.cr, "DELETE FROM ir_ui_view WHERE id=%(id)s", args={"id": id} ) except ValueError: # account_invoice_form_inh_l10n_mx_facturae_rate view not exist in DB @@ -35,7 +36,8 @@ def migrate(env, installed_version): # Delete views from obsolete modules and mark them as uninstalled tools.logged_query( - env.cr, """ + env.cr, + """ UPDATE ir_module_module SET state='uninstalled' WHERE name in ( 'l10n_mx_invoice_datetime', 'l10n_mx_notes_invoice', @@ -51,7 +53,8 @@ def migrate(env, installed_version): """, ) tools.logged_query( - env.cr, """ + env.cr, + """ DELETE from ir_ui_view v USING ir_model_data d WHERE v.id=d.res_id AND d.model='ir.ui.view' AND diff --git a/l10n_mx_facturae/migrations/2.4.1/post-migration.py b/l10n_mx_facturae/migrations/2.4.1/post-migration.py index 2568a69e845dfc4e78a76d56b0f176ae24cc432f..dfc128bdf6380660b2f84c5898eafb0c9149e817 100644 --- a/l10n_mx_facturae/migrations/2.4.1/post-migration.py +++ b/l10n_mx_facturae/migrations/2.4.1/post-migration.py @@ -9,14 +9,13 @@ from openerp import SUPERUSER_ID def migrate(env, installed_version): """Set a configuration for invoices emitted with CFDI 3.2 specification so that the user can be able to cancel any invoice as needed""" - dummy, config_id = env['ir.model.data'].get_object_reference( - 'l10n_mx_facturae', - 'ir_attachment_facturae_mx_config_account_invoice_32', + dummy, config_id = env["ir.model.data"].get_object_reference( + "l10n_mx_facturae", "ir_attachment_facturae_mx_config_account_invoice_32" ) tools.logged_query( env.cr, """UPDATE ir_attachment_facturae_mx SET config_id=%(config_id)s WHERE cfdi_type='incoming' AND state IN ('signed', 'done') AND config_id is null;""", - args={'config_id': config_id}, + args={"config_id": config_id}, ) diff --git a/l10n_mx_facturae/migrations/2.8.0/post-migration.py b/l10n_mx_facturae/migrations/2.8.0/post-migration.py index b475eae4a37e5c1d01417628f41bc9be5f4ae9e4..dcaa6b44acca88fae989ed66b9fc8aa0a503677e 100644 --- a/l10n_mx_facturae/migrations/2.8.0/post-migration.py +++ b/l10n_mx_facturae/migrations/2.8.0/post-migration.py @@ -12,16 +12,16 @@ _logger = logging.getLogger(__name__) def compute_cfdi_id(env): """Update reference to `ir.attachment.facturae.mx` for invoices""" - ir_attachment_mx_obj = env['ir.attachment.facturae.mx'] - invoices = env['account.invoice'].search([('state', 'in', ['open', 'paid'])]) - _logger.info('Updating reference for cfdi on ' + str(len(invoices)) + ' invoices') + ir_attachment_mx_obj = env["ir.attachment.facturae.mx"] + invoices = env["account.invoice"].search([("state", "in", ["open", "paid"])]) + _logger.info("Updating reference for cfdi on " + str(len(invoices)) + " invoices") for invoice in invoices: related_attachment = ir_attachment_mx_obj.search( [ - ('res_id', '=', invoice.id), - ('type_attachment', '=', 'account.invoice'), - ('company_id', '=', invoice.company_id.id), - ('state', 'in', ['signed', 'done']), + ("res_id", "=", invoice.id), + ("type_attachment", "=", "account.invoice"), + ("company_id", "=", invoice.company_id.id), + ("state", "in", ["signed", "done"]), ] ) if related_attachment: diff --git a/l10n_mx_facturae/models/account_invoice.py b/l10n_mx_facturae/models/account_invoice.py index 962282e008bc14051bb345ace3ca4b85a44288fb..56def116393decabfbf102530425012040f3925a 100644 --- a/l10n_mx_facturae/models/account_invoice.py +++ b/l10n_mx_facturae/models/account_invoice.py @@ -23,11 +23,8 @@ _logger = logging.getLogger(__name__) class AccountInvoice(models.Model): - _name = 'account.invoice' - _inherit = [ - 'account.invoice', - 'base.cfdi', - ] + _name = "account.invoice" + _inherit = ["account.invoice", "base.cfdi"] @api.model def _default_address_issued_id(self): @@ -35,20 +32,17 @@ class AccountInvoice(models.Model): for issued company. If there is a key in context named `force_company` that company will be considered as issued company, else the current user company will be the issued company""" - company_id = self._context.get( - 'force_company', self.env.user.company_id.id, - ) - company = self.env['res.company'].browse(company_id) + company_id = self._context.get("force_company", self.env.user.company_id.id) + company = self.env["res.company"].browse(company_id) return company.partner_id @property def fname_invoice(self): - if self.state == 'draft': - return '' - fname = '_'.join([ - self.company_id.partner_id.vat_split, - self.number or self.internal_number, - ]) + if self.state == "draft": + return "" + fname = "_".join( + [self.company_id.partner_id.vat_split, self.number or self.internal_number] + ) return fname @property @@ -58,12 +52,12 @@ class AccountInvoice(models.Model): self.ensure_one() # Get interpolated sequence if self.journal_id.sequence_id.prefix: - d = self.env['ir.sequence']._interpolation_dict_context() + d = self.env["ir.sequence"]._interpolation_dict_context() serie = self.journal_id.sequence_id._interpolate( - self.journal_id.sequence_id.prefix, d, + self.journal_id.sequence_id.prefix, d ) else: - serie = '' + serie = "" return self._sanitize(serie).strip() @property @@ -72,7 +66,7 @@ class AccountInvoice(models.Model): """ self.ensure_one() folio = self._sanitize(self.internal_number) - return folio.replace(self.serie, '').strip() + return folio.replace(self.serie, "").strip() @property def formapago(self): @@ -82,7 +76,7 @@ class AccountInvoice(models.Model): try: code = self.payment_type_ids[0].code except IndexError: - code = '99' + code = "99" return code @property @@ -105,9 +99,10 @@ class AccountInvoice(models.Model): def total(self): self.ensure_one() return ( - self.subtotal - self.descuento + - self.impuestos['total_traslados'] + - self.impuestos['total_retenciones'] + self.subtotal + - self.descuento + + self.impuestos["total_traslados"] + + self.impuestos["total_retenciones"] ) @property @@ -117,30 +112,26 @@ class AccountInvoice(models.Model): self.ensure_one() tax_grouped = {} taxes = { - 'traslados': [], - 'retenciones': [], - 'total_traslados': 0.0, - 'total_retenciones': 0.0, + "traslados": [], + "retenciones": [], + "total_traslados": 0.0, + "total_retenciones": 0.0, } for line in self.invoice_line: for tax in line.export_invoice_line_for_xml().taxes: # Taxes with none type must be excluded from total taxes - if tax.type == 'none': + if tax.type == "none": continue # Mimic logic from compute function in account.invoice.tax # object to group taxes from invoice lines and be able to get # the same result for display on CFDI - if self.type in ('out_invoice', 'in_invoice'): - tax.account_id = ( - tax.account_collected_id or line.account_id.id - ) + if self.type in ("out_invoice", "in_invoice"): + tax.account_id = tax.account_collected_id or line.account_id.id tax.analytic_id = tax.account_analytic_collected_id else: - tax.account_id = ( - tax.account_paid_id or line.account_id.id - ) + tax.account_id = tax.account_paid_id or line.account_id.id tax.analytic_id = tax.account_analytic_paid_id key = (tax.id, tax.account_id, tax.analytic_id) @@ -153,116 +144,128 @@ class AccountInvoice(models.Model): # Classify taxes for CFDI for dummy, tax in tax_grouped.iteritems(): if tax.amount >= 0: - taxes['traslados'].append(tax) - taxes['total_traslados'] += tax.amount + taxes["traslados"].append(tax) + taxes["total_traslados"] += tax.amount else: - taxes['retenciones'].append(tax) - taxes['total_retenciones'] += tax.amount + taxes["retenciones"].append(tax) + taxes["total_retenciones"] += tax.amount return taxes address_issued_id = fields.Many2one( - 'res.partner', 'Address Issued Invoice', - readonly=True, states={'draft': [('readonly', False)]}, + "res.partner", + "Address Issued Invoice", + readonly=True, + states={"draft": [("readonly", False)]}, default=lambda self: self._default_address_issued_id(), - help='This address will be used as address that issued ' - 'for electronic invoice', + help="This address will be used as address that issued " + "for electronic invoice", ) - datetime = fields.Datetime(compute='_compute_datetime', store=True) + datetime = fields.Datetime(compute="_compute_datetime", store=True) date_invoice_cancel = fields.Datetime( - 'Date Invoice Cancelled', readonly=True, copy=False, - help='If the invoice is cancelled, save the date' - ' when was cancel', + "Date Invoice Cancelled", + readonly=True, + copy=False, + help="If the invoice is cancelled, save the date" " when was cancel", ) payment_method_id = fields.Many2one( - 'cfdi.payment.method', string='Payment Method', - readonly=True, states={'draft': [('readonly', False)]}, - help='Payment method associated with this payment term according' - 'to CFDI 3.3 catalog.', + "cfdi.payment.method", + string="Payment Method", + readonly=True, + states={"draft": [("readonly", False)]}, + help="Payment method associated with this payment term according" + "to CFDI 3.3 catalog.", ) cfdi_use = fields.Many2one( - 'cfdi.use', 'CFDI use', - readonly=True, states={'draft': [('readonly', False)]}, + "cfdi.use", "CFDI use", readonly=True, states={"draft": [("readonly", False)]} ) cfdi_adenda_id = fields.Many2one( - 'cfdi.adenda', 'Addendum', - help='Select addendum node to use on invoice.', + "cfdi.adenda", "Addendum", help="Select addendum node to use on invoice." ) cfdi_adenda_code = fields.Char( - related='cfdi_adenda_id.code', - help='Helper field to improve view management', - ) - cfdi_relation_type = fields.Many2one( - 'cfdi.relation.type', 'CFDI Relation type', + related="cfdi_adenda_id.code", help="Helper field to improve view management" ) + cfdi_relation_type = fields.Many2one("cfdi.relation.type", "CFDI Relation type") - state = fields.Selection(selection_add=[('waiting', _('To cancel'))]) + state = fields.Selection(selection_add=[("waiting", _("To cancel"))]) @api.model def cron_invoices_pending_to_cancel(self): - invoices = self.env['account.invoice'].search( - [ - ('state', 'in', ['waiting']) - ] - ) + invoices = self.env["account.invoice"].search([("state", "in", ["waiting"])]) for invoice in invoices: invoice.action_consult_cancellation_status() @api.one - @api.depends('state') + @api.depends("state") def _compute_datetime(self): - if self.state == 'open': + if self.state == "open": if not self.env.user.partner_id.tz: - raise UserError(_('Set your time zone')) + raise UserError(_("Set your time zone")) tz = timezone(self.env.user.partner_id.tz) invoice_time = datetime.now(tz).time() invoice_datetime = datetime.combine( - datetime.strptime(self.date_invoice, '%Y-%m-%d'), - invoice_time, + datetime.strptime(self.date_invoice, "%Y-%m-%d"), invoice_time ) self.datetime = invoice_datetime def onchange_partner_id( - self, cr, uid, ids, type, partner_id, - date_invoice=False, payment_term=False, partner_bank_id=False, - company_id=False, context=None, + self, + cr, + uid, + ids, + type, + partner_id, + date_invoice=False, + payment_term=False, + partner_bank_id=False, + company_id=False, + context=None, ): # pylint: disable=too-many-arguments, redefined-builtin """Copy fields cfdi_use, payment_method_id and cfdi_adenda_id from selected partner """ res = super(AccountInvoice, self).onchange_partner_id( - cr, uid, ids, - type, partner_id, date_invoice, payment_term, partner_bank_id, - company_id, context=context, + cr, + uid, + ids, + type, + partner_id, + date_invoice, + payment_term, + partner_bank_id, + company_id, + context=context, ) - partner = self.pool.get('res.partner').browse( - cr, uid, partner_id, context=context, + partner = self.pool.get("res.partner").browse( + cr, uid, partner_id, context=context ) - if partner and type in ['out_invoice', 'out_refund']: + if partner and type in ["out_invoice", "out_refund"]: if partner.cfdi_use.id: - res['value']['cfdi_use'] = partner.cfdi_use.id - res['value']['payment_method_id'] = partner.payment_method_id.id - res['value']['cfdi_adenda_id'] = partner.cfdi_adenda.id + res["value"]["cfdi_use"] = partner.cfdi_use.id + res["value"]["payment_method_id"] = partner.payment_method_id.id + res["value"]["cfdi_adenda_id"] = partner.cfdi_adenda.id return res @api.model def _prepare_refund( - self, invoice, date=None, period_id=None, description=None, - journal_id=None, + self, invoice, date=None, period_id=None, description=None, journal_id=None ): """Overrides the preprare refund function to set field UsoCFDI""" values = super(AccountInvoice, self)._prepare_refund( - invoice, date=date, period_id=period_id, description=description, + invoice, + date=date, + period_id=period_id, + description=description, journal_id=journal_id, ) # We set field UsoCFDI to Descuentos y devoluciones for all refunds - usocfdi = self.env.ref('l10n_mx.cfdi_use_G02') - values['cfdi_use'] = usocfdi.id - values['cfdi_relation_type'] = self._context.get('cfdi_relation_type') - payment_type = self.env.ref('l10n_mx.pay_method_condonacion') - values['payment_type_ids'] = [(4, payment_type.id, None)] - payment_method = self.env.ref('l10n_mx.cfdi_payment_method_1') - values['payment_method_id'] = payment_method.id + usocfdi = self.env.ref("l10n_mx.cfdi_use_G02") + values["cfdi_use"] = usocfdi.id + values["cfdi_relation_type"] = self._context.get("cfdi_relation_type") + payment_type = self.env.ref("l10n_mx.pay_method_condonacion") + values["payment_type_ids"] = [(4, payment_type.id, None)] + payment_method = self.env.ref("l10n_mx.cfdi_payment_method_1") + values["payment_method_id"] = payment_method.id return values @@ -276,45 +279,42 @@ class AccountInvoice(models.Model): @api.multi def action_cancel(self): - ''' + """ Extend `AccountInvoice.action_cancel()`; Cancels the CFDI related to the invoice - ''' + """ for account_invoice in self: # Maybe a third test could review state, but since # button cancel only is displayed in open state, we decided to not # used third test - account_invoice.check_if_can_cancel() res = None - if account_invoice.cfdi_folio_fiscal is False: - res = super(AccountInvoice, self).action_cancel() - elif ( - account_invoice.journal_id.sign_sat and - account_invoice.cfdi_folio_fiscal + account_invoice.check_if_can_cancel() + if ( + account_invoice.journal_id.sign_sat + and account_invoice.cfdi_folio_fiscal ): cancelacion = account_invoice.cancel_cfdi()[0] if cancelacion is None: - account_invoice.write( - {'state': account_invoice.cfdi_state} - ) + account_invoice.write({"state": account_invoice.cfdi_state}) elif cancelacion is False: self.undo_waiting_state() else: res = super(AccountInvoice, self).action_cancel() account_invoice.unlink_cfdi() + else: + res = super(AccountInvoice, self).action_cancel() return res @api.multi def undo_waiting_state(self): """when cancel is negate, undo waiting state""" self.ensure_one() - if self.state == 'waiting': - self.write({ - 'state': 'open' - }) + if self.state in "waiting": + self.write({"state": "open"}) @api.multi def action_consult_cancellation_status(self): + """ Verify cancellation status""" for account_invoice in self: res = None status_cancelacion = account_invoice.consult_cfdi_cancellation_status() @@ -330,17 +330,17 @@ class AccountInvoice(models.Model): @staticmethod def _sanitize(text): # Chars not allowed on CFDI - chars = '\\`*_{}[]()>#+-.!$/' # noqa + chars = "\\`*_{}[]()>#+-.!$/" # noqa # Replace all characters based on best performance answer as found on: # https://stackoverflow.com/a/27086669/2817675 for c in chars: if c in text: - text = text.replace(c, ' ') + text = text.replace(c, " ") return text class AccountInvoiceLine(models.Model): - _inherit = 'account.invoice.line' + _inherit = "account.invoice.line" @property def cfdi_product_code(self): @@ -359,9 +359,9 @@ class AccountInvoiceLine(models.Model): category = category.parent_id # If not have return for this point raise an error raise ValidationError( - _('Missing SAT code for product: {product}').format( - product=self.product_id.name, - ), + _("Missing SAT code for product: {product}").format( + product=self.product_id.name + ) ) @property @@ -384,15 +384,12 @@ class AccountInvoiceLine(models.Model): """Return computed taxes for display on CFDI """ self.ensure_one() - taxes = { - 'traslados': [], - 'retenciones': [], - } + taxes = {"traslados": [], "retenciones": []} for tax in self.export_invoice_line_for_xml().taxes: if tax.amount >= 0: - taxes['traslados'].append(tax) + taxes["traslados"].append(tax) else: - taxes['retenciones'].append(tax) + taxes["retenciones"].append(tax) return taxes @property @@ -405,15 +402,17 @@ class AccountInvoiceLine(models.Model): def export_invoice_line_for_xml(self): """Computes all values needed for export account.invoice.line as CFDI """ + class Dict2obj(object): """Convert dictionary to object @source http://stackoverflow.com/a/1305561/383912 """ + def __init__(self, d): - self.__dict__['d'] = d + self.__dict__["d"] = d def __getattr__(self, key): - value = self.__dict__['d'][key] + value = self.__dict__["d"][key] return value def process_tax(tax): @@ -426,44 +425,43 @@ class AccountInvoiceLine(models.Model): excluding IEPS tax if partner is not IEPS subjected @rtype: dictionary or None """ - tax_record = self.env['account.tax'].browse(tax['id']) + tax_record = self.env["account.tax"].browse(tax["id"]) tax_group = tax_record.tax_category_id # IEPS tax only must be included when partner is IEPS subjected - if tax_group.name == 'IEPS' and not partner.ieps_subjected: + if tax_group.name == "IEPS" and not partner.ieps_subjected: return # TODO: Delete on version 3.0.0 - if 'base' not in tax: - tax['base'] = currency.cfdi_round( - tax['price_unit'] * self.quantity, - ) - tax['group'] = tax_group.name - tax['type'] = tax_record.type - tax['TasaOCuota'] = abs(tax_record.amount) + if "base" not in tax: + tax["base"] = currency.cfdi_round(tax["price_unit"] * self.quantity) + tax["group"] = tax_group.name + tax["type"] = tax_record.type + tax["TasaOCuota"] = abs(tax_record.amount) return tax currency = self.invoice_id.currency_id - precision = self.env['decimal.precision'].precision_get( - 'Product Price', - ) + precision = self.env["decimal.precision"].precision_get("Product Price") total_discount = 1 - self.discount / 100.0 # Include global discount - total_discount *= (1 - self.invoice_id.global_discount / 100) + total_discount *= 1 - self.invoice_id.global_discount / 100 price = float_round(self.price_unit * total_discount, precision) partner = self.invoice_id.partner_id # Compute taxes using original compute_all function from # account.invoice.tax to get same result for CFDI display res = self.invoice_line_tax_id.compute_all( - price, self.quantity, product=self.product_id, partner=partner, + price, + self.quantity, + product=self.product_id, + partner=partner, currency=self.invoice_id.currency_id, ) - if len(res['taxes']) == 0: + if len(res["taxes"]) == 0: raise ValidationError( - _('Product {p} must have at least one tax selected.').format( - p=self.product_id.name, - ), + _("Product {p} must have at least one tax selected.").format( + p=self.product_id.name + ) ) taxes = [] - taxes_list = iter(res['taxes']) + taxes_list = iter(res["taxes"]) tax = next(taxes_list) # Iterate taxes and append to the new tax list as needed while True: @@ -475,29 +473,27 @@ class AccountInvoiceLine(models.Model): except StopIteration: if tax is None: raise ValidationError( - _('Incorrect tax sequence configuration, check ' - 'this data in Account >> Tax >> Sequence'), + _( + "Incorrect tax sequence configuration, check " + "this data in Account >> Tax >> Sequence" + ) ) break - res['price_unit'] = self.price_unit + res["price_unit"] = self.price_unit if not partner.ieps_subjected: # Recompute price_unit to include IEPS if needed try: - res['price_unit'] = self.invoice_line_tax_id.compute_all( - res['price_unit'], 1.0, product=self.product_id, - partner=partner, - )['base'] + res["price_unit"] = self.invoice_line_tax_id.compute_all( + res["price_unit"], 1.0, product=self.product_id, partner=partner + )["base"] except KeyError: # TODO: Delete on version 3.0.0 - res['price_unit'] = self.invoice_line_tax_id.compute_all( - res['price_unit'], 1.0, product=self.product_id, - partner=partner, - )['total'] - - res['importe'] = currency.round(res['price_unit'] * self.quantity) - res['descuento'] = currency.round( - res['importe'] * (1 - total_discount), - ) + res["price_unit"] = self.invoice_line_tax_id.compute_all( + res["price_unit"], 1.0, product=self.product_id, partner=partner + )["total"] + + res["importe"] = currency.round(res["price_unit"] * self.quantity) + res["descuento"] = currency.round(res["importe"] * (1 - total_discount)) # Overrides original taxes with the list computed by us - res['taxes'] = [Dict2obj(t) for t in taxes] + res["taxes"] = [Dict2obj(t) for t in taxes] return Dict2obj(res) diff --git a/l10n_mx_facturae/models/account_voucher.py b/l10n_mx_facturae/models/account_voucher.py index 7e54dff529ff010708000a235e64998fef30e050..777c69fce1522d1ab11b4a96f8df782a4b0e8fa4 100644 --- a/l10n_mx_facturae/models/account_voucher.py +++ b/l10n_mx_facturae/models/account_voucher.py @@ -5,31 +5,28 @@ from openerp.tools import float_round class AccountVoucher(models.Model): - _name = 'account.voucher' - _inherit = [ - 'account.voucher', - 'base.cfdi', - ] + _name = "account.voucher" + _inherit = ["account.voucher", "base.cfdi"] state = fields.Selection( [ - ('draft', 'Draft'), - ('cancel', 'Cancelled'), - ('proforma', 'Pro-forma'), - ('posted', 'Posted'), - ('signed', 'Signed'), - ], + ("draft", "Draft"), + ("cancel", "Cancelled"), + ("proforma", "Pro-forma"), + ("posted", "Posted"), + ("signed", "Signed"), + ] ) @api.multi def sign_voucher(self): """Create CFDI for selected vouchers""" # Only vouchers to sign are the receipts - receipts = self.filtered(lambda r: r.type == 'receipt') + receipts = self.filtered(lambda r: r.type == "receipt") # Get only receipts that doesn't have a CFDI yet and create it for receipt in receipts.filtered(lambda r: not r.cfdi_id.exists()): receipt.create_cfdi() - receipt.state = 'signed' + receipt.state = "signed" @api.multi def cancel_voucher(self): @@ -44,10 +41,12 @@ class AccountVoucher(models.Model): """General steps needed for cancel a voucher""" self.ensure_one() # Before cancel original voucher set relation to current related CFDI - self.write({ - 'cfdi_relation_type': self.env.ref('l10n_mx.cfdi_relation_type_04').id, - 'related_cfdi_ids': [(6, None, [self.cfdi_id.id])], - }) + self.write( + { + "cfdi_relation_type": self.env.ref("l10n_mx.cfdi_relation_type_04").id, + "related_cfdi_ids": [(6, None, [self.cfdi_id.id])], + } + ) # We also remove relation for attachments to avoid confusing situations self.cfdi_id.file_xml_sign.res_id = None self.cfdi_id.file_pdf.res_id = None @@ -77,12 +76,11 @@ class AccountVoucher(models.Model): # We need to give the date in the context to get proper rate voucher_currency = self.currency_id.with_context(date=self.date) voucher_currency = voucher_currency.with_context( - voucher_special_currency_rate=( - voucher_currency.rate * self.payment_rate - ), + voucher_special_currency_rate=(voucher_currency.rate * self.payment_rate), voucher_special_currency=( - self.payment_rate_currency_id and - self.payment_rate_currency_id.id or False + self.payment_rate_currency_id + and self.payment_rate_currency_id.id + or False ), ) return voucher_currency.compute(1.0, self.company_id.currency_id) @@ -94,27 +92,24 @@ class AccountVoucher(models.Model): # Get all records from account.move.line related to this voucher but # affecting an account different than the selected for this voucher - move_lines = self.move_ids.filtered( - lambda x: x.account_id != self.account_id, - ) + move_lines = self.move_ids.filtered(lambda x: x.account_id != self.account_id) # Get all lines form partial and full reconciliations - temp_lines = move_lines.mapped('reconcile_partial_id.line_partial_ids') - temp_lines |= move_lines.mapped('reconcile_id.line_id') + temp_lines = move_lines.mapped("reconcile_partial_id.line_partial_ids") + temp_lines |= move_lines.mapped("reconcile_id.line_id") # Get only invoices related to this voucher - invoices = (temp_lines - move_lines).mapped('invoice') - invoices = invoices.filtered(lambda i: i.type == 'out_invoice') + invoices = (temp_lines - move_lines).mapped("invoice") + invoices = invoices.filtered(lambda i: i.type == "out_invoice") return invoices @api.multi def numparcialidad(self, invoice): """Computes payment number based on all payments done to invoice""" # Get all payments done to given invoice - payments = invoice.mapped('payment_ids') - self.move_ids + payments = invoice.mapped("payment_ids") - self.move_ids # Leave only payments done in cash or bank older than current payments = payments.filtered( - lambda r: - r.date < self.date and r.journal_id.type in ('cash', 'bank') + lambda r: r.date < self.date and r.journal_id.type in ("cash", "bank") ) return len(payments) + 1 @@ -126,7 +121,7 @@ class AccountVoucher(models.Model): amount_residual = invoice.amount_total # Get all payments done to given invoice - payments = invoice.mapped('payment_ids') - self.move_ids + payments = invoice.mapped("payment_ids") - self.move_ids # Leave only payments done before (older than) the current one payments = payments.filtered(lambda r: r.date < self.date) @@ -148,7 +143,7 @@ class AccountVoucher(models.Model): amount_paid = 0.0 # Get payments done in this voucher for given invoice - payments = invoice.mapped('payment_ids') & self.move_ids + payments = invoice.mapped("payment_ids") & self.move_ids for payment in payments: # If currency_id exists it means we are dealing with a multi @@ -176,12 +171,11 @@ class AccountVoucher(models.Model): self.ensure_one() voucher_currency = self.currency_id.with_context(date=self.date) voucher_currency = voucher_currency.with_context( - voucher_special_currency_rate=( - voucher_currency.rate * self.payment_rate - ), + voucher_special_currency_rate=(voucher_currency.rate * self.payment_rate), voucher_special_currency=( - self.payment_rate_currency_id and - self.payment_rate_currency_id.id or False + self.payment_rate_currency_id + and self.payment_rate_currency_id.id + or False ), ) value = voucher_currency.compute(1.0, invoice.currency_id, round=False) diff --git a/l10n_mx_facturae/models/email_template.py b/l10n_mx_facturae/models/email_template.py index f3b83ab4c08c7e346d416dc32019cef31ccee1c6..4429b341b0e295d581c6ba34853b5d030cebc3ec 100644 --- a/l10n_mx_facturae/models/email_template.py +++ b/l10n_mx_facturae/models/email_template.py @@ -7,11 +7,12 @@ class EmailTemplate(models.Model): """ Extend generic message composition wizard to auto attach invoice related files when sending opening the Send Mail invoice button. """ - _inherit = 'email.template' + + _inherit = "email.template" @api.cr_uid_id_context def generate_email_batch( - self, cr, uid, template_id, res_ids, context=None, fields=None, + self, cr, uid, template_id, res_ids, context=None, fields=None ): """ Generates an email from the template for given (model, res_id) pair. @@ -24,27 +25,25 @@ class EmailTemplate(models.Model): format expected by :py:meth:`mail_thread.message_post`. """ values = super(EmailTemplate, self).generate_email_batch( - cr, uid, template_id, res_ids, context=context, fields=fields, + cr, uid, template_id, res_ids, context=context, fields=fields ) - att_obj = self.pool.get('ir.attachment.facturae.mx') - ir_model_data = self.pool.get('ir.model.data') + att_obj = self.pool.get("ir.attachment.facturae.mx") + ir_model_data = self.pool.get("ir.model.data") reference_ids = [] - states = ['done'] + states = ["done"] data = { - 'account': 'email_template_edi_invoice', - 'portal_sale': 'email_template_edi_invoice', - 'l10n_mx_ir_attachment_facturae': 'email_template_template_facturae_mx', - 'l10n_mx_facturae': 'account_voucher_cfdi_email_template', + "account": "email_template_edi_invoice", + "portal_sale": "email_template_edi_invoice", + "l10n_mx_ir_attachment_facturae": "email_template_template_facturae_mx", + "l10n_mx_facturae": "account_voucher_cfdi_email_template", } # Look for possible templates for invoice and override for module, name in data.iteritems(): try: reference_ids.append( - ir_model_data.get_object_reference( - cr, uid, module, name, - )[1], + ir_model_data.get_object_reference(cr, uid, module, name)[1] ) except ValueError: # Template not installed so we catch the error @@ -53,13 +52,11 @@ class EmailTemplate(models.Model): if template_id in reference_ids: for res_id in res_ids: - model = values[res_id]['model'] + model = values[res_id]["model"] iatt_ids = att_obj.search( - cr, uid, - [ - ('res_id', '=', res_id), - ('type_attachment', '=', model), - ], + cr, + uid, + [("res_id", "=", res_id), ("type_attachment", "=", model)], context=context, ) for iattach in att_obj.browse(cr, uid, iatt_ids, context=context): @@ -69,8 +66,6 @@ class EmailTemplate(models.Model): attachments.append(iattach.file_xml_sign.id) # Attach PDF file to mesage attachments.append(iattach.file_pdf.id) - values[res_id]['attachments'] = [] - values[res_id]['attachment_ids'] = [ - (6, 0, attachments), - ] + values[res_id]["attachments"] = [] + values[res_id]["attachment_ids"] = [(6, 0, attachments)] return values diff --git a/l10n_mx_facturae/models/res_partner.py b/l10n_mx_facturae/models/res_partner.py index a9aa1168c6afdd2c7e1613adbf220d736c985c8d..195f806a566c28d91a314c3eb83cc708bcbc2fb8 100644 --- a/l10n_mx_facturae/models/res_partner.py +++ b/l10n_mx_facturae/models/res_partner.py @@ -4,26 +4,28 @@ from openerp import fields, models class ResPartner(models.Model): - _inherit = 'res.partner' + _inherit = "res.partner" cfdi_use = fields.Many2one( - 'cfdi.use', 'CFDI use', - help='Cfdi usage that will be used by default on this customer ' - 'invoices and credit notes', + "cfdi.use", + "CFDI use", + help="Cfdi usage that will be used by default on this customer " + "invoices and credit notes", ) cfdi_adenda = fields.Many2one( - 'cfdi.adenda', 'CFDI Adendas', - help='This field allows adding a node or addendum to the invoice', + "cfdi.adenda", + "CFDI Adendas", + help="This field allows adding a node or addendum to the invoice", ) cfdi_adenda_code = fields.Char( - related='cfdi_adenda.code', - help='Helper field to improve view management', + related="cfdi_adenda.code", help="Helper field to improve view management" ) payment_method_id = fields.Many2one( - 'cfdi.payment.method', string='Payment Method', - help='Payment method associated with this partner according' - 'to CFDI 3.3 catalog.', + "cfdi.payment.method", + string="Payment Method", + help="Payment method associated with this partner according" + "to CFDI 3.3 catalog.", ) supplier_number = fields.Char( - help='Number or reference that the Client assigned to our company.', + help="Number or reference that the Client assigned to our company." ) diff --git a/l10n_mx_facturae/report/account_invoice.py b/l10n_mx_facturae/report/account_invoice.py index d8cb952809a40de108308062e5b1e77a2435f6ea..4eb976432557d925f43b8fbde275573194923247 100644 --- a/l10n_mx_facturae/report/account_invoice.py +++ b/l10n_mx_facturae/report/account_invoice.py @@ -6,25 +6,25 @@ from openerp.report import report_sxw class Parser(report_sxw.rml_parse): def __init__(self, cr, uid, name, context): super(Parser, self).__init__(cr, uid, name, context) - self.localcontext.update({ - 'qrcode_string': self._qrcode_string, - }) + self.localcontext.update({"qrcode_string": self._qrcode_string}) def _qrcode_string(self, invoice): if invoice.cfdi_id.sello: sello = invoice.cfdi_id.sello[-8: len(invoice.cfdi_id.sello)] else: - sello = '' - return ''.join([ - 'https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx' - '?id=', - invoice.cfdi_id.uuid and invoice.cfdi_id.uuid or 'N/A', - '&re=', - invoice.company_id.partner_id.vat_split, - '&rr=', - invoice.partner_id.vat_split, - '&tt=', - str(invoice.total), - '&fe=', - sello, - ]) + sello = "" + return "".join( + [ + "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx" + "?id=", + invoice.cfdi_id.uuid and invoice.cfdi_id.uuid or "N/A", + "&re=", + invoice.company_id.partner_id.vat_split, + "&rr=", + invoice.partner_id.vat_split, + "&tt=", + str(invoice.total), + "&fe=", + sello, + ] + ) diff --git a/l10n_mx_facturae/report/account_voucher.py b/l10n_mx_facturae/report/account_voucher.py index 649c678f89d598ca98da270d2dfa5c6393470472..0c16b89b335eabbdf0eb3b685d8125d3e9ca0821 100644 --- a/l10n_mx_facturae/report/account_voucher.py +++ b/l10n_mx_facturae/report/account_voucher.py @@ -8,7 +8,7 @@ class Parser(report_sxw.rml_parse): def __init__(self, cr, uid, name, context): super(self.__class__, self).__init__(cr, uid, name, context) - self.localcontext.update({'datosqr': self._datosqr}) + self.localcontext.update({"datosqr": self._datosqr}) def _datosqr(self, o): """Genera el string con info para la elaboración del codigo qr""" @@ -16,14 +16,14 @@ class Parser(report_sxw.rml_parse): def xstr(s): if s: return str(s) - return str('N/A') + return str("N/A") - msg = 'https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx' + msg = "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx" if o.cfdi_id.sello: - msg = msg + '?id=' + xstr(o.cfdi_id.uuid) - msg = msg + '&re=' + xstr(o.company_id.partner_id.vat_split) - msg = msg + '&rr=' + xstr(o.partner_id.vat_split) - msg = msg + '&tt=' + xstr(str(o.amount)) - msg = msg + '&fe=' + xstr(o.cfdi_id.sello[-8: len(o.cfdi_id.sello)]) + msg = msg + "?id=" + xstr(o.cfdi_id.uuid) + msg = msg + "&re=" + xstr(o.company_id.partner_id.vat_split) + msg = msg + "&rr=" + xstr(o.partner_id.vat_split) + msg = msg + "&tt=" + xstr(str(o.amount)) + msg = msg + "&fe=" + xstr(o.cfdi_id.sello[-8: len(o.cfdi_id.sello)]) return msg diff --git a/l10n_mx_facturae/tests/radish/sign_invoice_test.py b/l10n_mx_facturae/tests/radish/sign_invoice_test.py index dc253d94c8f6ce7dd46aa737e24e115f303883af..bf38bf1f4b35a46f0e1f72a5407b178f7111acaf 100644 --- a/l10n_mx_facturae/tests/radish/sign_invoice_test.py +++ b/l10n_mx_facturae/tests/radish/sign_invoice_test.py @@ -22,72 +22,67 @@ def setup(scenario): scenario.context.user = add_user(scenario) -@given('I have a customer') +@given("I have a customer") def have_customer(step): - partner_obj = step.context.env['res.partner'] - state_obj = step.context.env['res.country.state'] - country_obj = step.context.env['res.country'] + partner_obj = step.context.env["res.partner"] + state_obj = step.context.env["res.country.state"] + country_obj = step.context.env["res.country"] partner = step.table[0] user_id = step.context.user.id # It would be great to find a way to replace the list for # a dictionary so that avoid list access from index values = { - 'name': partner[0], - 'street': partner[1], - '10n_mx_street3': partner[2], - 'l10n_mx_city2': partner[3], - 'city': partner[4], - 'zip': partner[6], - 'type': partner[8], + "name": partner[0], + "street": partner[1], + "10n_mx_street3": partner[2], + "l10n_mx_city2": partner[3], + "city": partner[4], + "zip": partner[6], + "type": partner[8], } state_name = partner[5] country_name = partner[7] # Review if there is a country with the given name # if not create it - country = country_obj.sudo(user_id).search( - [('name', '=', country_name)], limit=1, - ) + country = country_obj.sudo(user_id).search([("name", "=", country_name)], limit=1) if country: country_id = country[0].id - values.update({'country_id': country_id}) + values.update({"country_id": country_id}) else: - country_values = {'name': country_name} + country_values = {"name": country_name} country_id = country_obj.sudo(user_id).create(country_values).id - values.update({'country_id': country_id}) + values.update({"country_id": country_id}) # Review if there is a state with the given name and the given country # if not create it state = state_obj.sudo(user_id).search( - [ - ('name', '=', state_name), - ('country_id', '=', country_id), - ], limit=1, + [("name", "=", state_name), ("country_id", "=", country_id)], limit=1 ) if state: - values.update({'state_id': state[0].id}) + values.update({"state_id": state[0].id}) else: state_values = { - 'name': state_name, - 'code': state_name, - 'country_id': country_id, + "name": state_name, + "code": state_name, + "country_id": country_id, } state_id = state_obj.sudo(user_id).create(state_values).id - values.update({'state_id': state_id}) + values.update({"state_id": state_id}) # Create customer partner = partner_obj.sudo(user_id).create(values) # Add partner id in step context step.context.partner = partner -@given('customer VAT number is MXAAA010101AAA') +@given("customer VAT number is MXAAA010101AAA") def have_customer_vat(step): partner = step.context.partner # Set vat number according to our step - partner.vat = 'MXBBB010101AAA' + partner.vat = "MXBBB010101AAA" -@when('I create a sales invoice for customer') +@when("I create a sales invoice for customer") def create_invoice(step): - account_invoice_obj = step.context.env['account.invoice'] + account_invoice_obj = step.context.env["account.invoice"] partner_id = step.context.partner.id company_id = step.context.company.id account_id = step.context.account.id @@ -95,49 +90,50 @@ def create_invoice(step): user_id = step.context.user.id # Create invoice with given values values = { - 'partner_id': partner_id, - 'account_id': account_id, - 'journal_id': journal_id, - 'company_id': company_id, - 'state': 'draft', + "partner_id": partner_id, + "account_id": account_id, + "journal_id": journal_id, + "company_id": company_id, + "state": "draft", } invoice = account_invoice_obj.sudo(user_id).create(values) step.context.invoice = invoice -@when('invoice line is') +@when("invoice line is") def have_lines(step): - invoice_line_obj = step.context.env['account.invoice.line'] + invoice_line_obj = step.context.env["account.invoice.line"] invoice_lines = step.table[0] invoice_id = step.context.invoice.id user_id = step.context.user.id values = { - 'name': invoice_lines[0], - 'quantity': invoice_lines[1], - 'price_unit': invoice_lines[2], - 'price_subtotal': invoice_lines[3], - 'invoice_id': invoice_id, + "name": invoice_lines[0], + "quantity": invoice_lines[1], + "price_unit": invoice_lines[2], + "price_subtotal": invoice_lines[3], + "invoice_id": invoice_id, } # Create lines invoice_line_obj.sudo(user_id).create(values) -@when('validate invoice') +@when("validate invoice") def validate_invoice(step): invoice = step.context.invoice invoice.invoice_open() -@then('I expect to have a XML and a PDF with same name, and a UUID') +@then("I expect to have a XML and a PDF with same name, and a UUID") def result(step): - attachment_obj = step.context.env['ir.attachment'] + attachment_obj = step.context.env["ir.attachment"] invoice = step.context.invoice # Looking for attachments related with the invoice attachments = attachment_obj.search( - [('res_model', '=', 'account.invoice'), ('res_id', '=', invoice.id)]) + [("res_model", "=", "account.invoice"), ("res_id", "=", invoice.id)] + ) # We want to have at least two files being pdf and xml their extension # Using regular expresions - file_types = ['.*\.pdf', '.*\.xml'] + file_types = [".*\.pdf", ".*\.xml"] for file_type in file_types: pattern = re.compile(file_type) for index, attachment in enumerate(attachments): @@ -145,26 +141,25 @@ def result(step): break assert ( (index + 1) != len(attachments), - '{type} file does not exist'.format( - type=re.sub('.*\.', '', file_type).upper(), + "{type} file does not exist".format( + type=re.sub(".*\.", "", file_type).upper() ), ) # Test attachments have the same name names = set([os.path.splitext(x.name)[0] for x in attachments]) - assert len(names) == 1, ''.join( - ['Name files must be the same ', str(names)]) - assert invoice.cfdi_folio_fiscal, 'Invoice without UUID' + assert len(names) == 1, "".join(["Name files must be the same ", str(names)]) + assert invoice.cfdi_folio_fiscal, "Invoice without UUID" def add_company(scenario): - company_obj = scenario.context.env['res.company'] - state_obj = scenario.context.env['res.country.state'] - country_obj = scenario.context.env['res.country'] + company_obj = scenario.context.env["res.company"] + state_obj = scenario.context.env["res.country.state"] + country_obj = scenario.context.env["res.country"] # First of all looking for an existing company company = company_obj.search([], limit=1) if company: # If there is a company only change vat an return - company.vat = 'MXLAN7008173R5' + company.vat = "MXLAN7008173R5" return company # If there is not already a company create one company_values = """ @@ -172,64 +167,62 @@ def add_company(scenario): l10n_mx_city2=Hacienda Del Rosario, city=Puebla, state=Puebla, zip=72000, country=Mexico, vat=MXAAA010101AAA """ - dict_company_values = dict(x.split('=') for x in company_values.split(', ')) # noqa + dict_company_values = dict(x.split("=") for x in company_values.split(", ")) # noqa # Review if there is a country with the given name # if not create it country = country_obj.search( - [('name', '=', dict_company_values['country'])], limit=1, + [("name", "=", dict_company_values["country"])], limit=1 ) if country: country_id = country[0].id - dict_company_values.update({'country_id': country_id}) + dict_company_values.update({"country_id": country_id}) else: - country_values = {'name': dict_company_values['country']} + country_values = {"name": dict_company_values["country"]} country_id = country_obj.create(country_values).id - dict_company_values.update({'country_id': country_id}) + dict_company_values.update({"country_id": country_id}) # Review if there is a state with the given name and the given country # if not create it state = state_obj.search( - [ - ('name', '=', dict_company_values['state']), - ('country_id', '=', country_id), - ], limit=1, + [("name", "=", dict_company_values["state"]), ("country_id", "=", country_id)], + limit=1, ) if state: - dict_company_values.update({'state_id': state[0].id}) + dict_company_values.update({"state_id": state[0].id}) else: state_values = { - 'name': dict_company_values['state'], - 'code': dict_company_values['state'], - 'country_id': country_id, + "name": dict_company_values["state"], + "code": dict_company_values["state"], + "country_id": country_id, } state_id = state_obj.create(state_values).id - dict_company_values.update({'state_id': state_id}) + dict_company_values.update({"state_id": state_id}) # Create company company = company_obj.create(dict_company_values) return company def set_test_certificates(scenario): - certificate_obj = scenario.context.env['res.company.facturae.certificate'] + certificate_obj = scenario.context.env["res.company.facturae.certificate"] # I hope cer and key files are placed in the same basedir - name_cer = 'CSD_Pruebas_CFDI_LAN7008173R5.cer' - name_key = 'CSD_Pruebas_CFDI_LAN7008173R5.key' + name_cer = "CSD_Pruebas_CFDI_LAN7008173R5.cer" + name_key = "CSD_Pruebas_CFDI_LAN7008173R5.key" path_cer = os.path.join(os.path.dirname(__file__), name_cer) path_key = os.path.join(os.path.dirname(__file__), name_key) - certificate_password = '12345678a' - with open(path_cer, 'rb') as file_cer: + certificate_password = "12345678a" + with open(path_cer, "rb") as file_cer: cetificate_file = base64.b64encode(file_cer.read()) - with open(path_key, 'rb') as file_key: + with open(path_key, "rb") as file_key: certificate_key_file = base64.b64encode(file_key.read()) # Search for an existing compampany certicate # or create one company_id = scenario.context.company.id - certificate = certificate_obj.search([('company_id', '=', company_id)]) + certificate = certificate_obj.search([("company_id", "=", company_id)]) if not certificate: values = { - 'company_id': company_id, - 'cetificate_file': cetificate_file, - 'certificate_key_file': certificate_key_file, - 'certificate_password': certificate_password, + "company_id": company_id, + "cetificate_file": cetificate_file, + "certificate_key_file": certificate_key_file, + "certificate_password": certificate_password, } certificate = certificate_obj.create(values) else: @@ -241,32 +234,26 @@ def set_test_certificates(scenario): def add_journal(scenario): - account_journal_obj = scenario.context.env['account.journal'] - journal = account_journal_obj.search([('type', '=', 'sale')], limit=1) + account_journal_obj = scenario.context.env["account.journal"] + journal = account_journal_obj.search([("type", "=", "sale")], limit=1) return journal def add_account(scenario): - account_account_obj = scenario.context.env['account.account'] + account_account_obj = scenario.context.env["account.account"] company_id = scenario.context.company.id account = account_account_obj.search( - [('company_id', '=', company_id), ('type', '=', 'receivable')], - limit=1, + [("company_id", "=", company_id), ("type", "=", "receivable")], limit=1 )[0] return account def add_user(scenario): - res_users_obj = scenario.context.env['res.users'] - group_obj = scenario.context.env['res.groups'] - group = group_obj.search( - [('name', '=', 'Invoicing & Payments')], limit=1, - ) + res_users_obj = scenario.context.env["res.users"] + group_obj = scenario.context.env["res.groups"] + group = group_obj.search([("name", "=", "Invoicing & Payments")], limit=1) user = res_users_obj.search( - [ - ('groups_id', 'in', (group.id)), - ('name', '!=', 'admin'), - ], limit=1, + [("groups_id", "in", (group.id)), ("name", "!=", "admin")], limit=1 ) - assert user is not False, 'No user in Invoicing & Payments group' + assert user is not False, "No user in Invoicing & Payments group" return user diff --git a/l10n_mx_facturae/tests/radish/terrain.py b/l10n_mx_facturae/tests/radish/terrain.py index 23e5b2b331571dadc5abb48ddea9c3633c31ee03..5c3755d46214007494643718107a9868dfb18425 100644 --- a/l10n_mx_facturae/tests/radish/terrain.py +++ b/l10n_mx_facturae/tests/radish/terrain.py @@ -16,7 +16,7 @@ def connect_database(scenario): scenario.context.uid = openerp.SUPERUSER_ID #: :class:`~openerp.api.Environment` for the current test case scenario.context.env = api.Environment( - scenario.context.cr, scenario.context.uid, {}, + scenario.context.cr, scenario.context.uid, {} ) diff --git a/l10n_mx_facturae/wizard/account_invoice_refund.py b/l10n_mx_facturae/wizard/account_invoice_refund.py index 7d611568b3e4078630aa807772dc70461d2232a3..e292b5146ccd344ce209932a1d64f748a2dcd011 100644 --- a/l10n_mx_facturae/wizard/account_invoice_refund.py +++ b/l10n_mx_facturae/wizard/account_invoice_refund.py @@ -4,13 +4,13 @@ from openerp import fields, models class AccountInvoiceRefund(models.TransientModel): - _inherit = 'account.invoice.refund' + _inherit = "account.invoice.refund" cfdi_relation_type = fields.Many2one( - 'cfdi.relation.type', 'CFDI Relation type', required=True, + "cfdi.relation.type", "CFDI Relation type", required=True ) - def compute_refund(self, mode='refund'): + def compute_refund(self, mode="refund"): """Call super function added cfdi_relation_type value in context to be able to use later when creating refund""" self = self.with_context(cfdi_relation_type=self.cfdi_relation_type.id) diff --git a/setup.cfg b/setup.cfg index 43532b18247001acd4d07bf0a0269c42c7cb37f4..cc72c0db0b180af432fea9de3fd11cd31486b18f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,7 @@ +[flake8] +# We also support "double" and "single" +inline-quotes = " + [isort] # If set to true - isort will combine as imports on the same line within for diff --git a/setup.py b/setup.py index 881a00f785a65fb36de395c7dd807b1ca2a6f99e..384301a8dd90e1098a7554d417e25b6fd4fb1c05 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ import os from setuptools import find_packages, setup -MANIFEST_NAMES = ('__openerp__.py', '__manifest__.py', '__terp__.py') +MANIFEST_NAMES = ("__openerp__.py", "__manifest__.py", "__terp__.py") class NoManifestFound(Exception): @@ -27,39 +27,36 @@ def parse_manifest(s): def read_manifest(addon_dir): manifest_path = get_manifest_path(addon_dir) if not manifest_path: - raise NoManifestFound('No manifest found in %s' % addon_dir) + raise NoManifestFound("No manifest found in %s" % addon_dir) return parse_manifest(open(manifest_path).read()) -addon_dir = 'l10n_mx_facturae' +addon_dir = "l10n_mx_facturae" manifest = read_manifest(addon_dir) long_description = ( - open(os.path.join(addon_dir, 'README.rst')).read() + - '\n' + - 'Contributors\n' - '============\n' + - '\n' + - open(os.path.join(addon_dir, 'CONTRIBUTORS.rst')).read() + - '\n' + - open(os.path.join(addon_dir, 'CHANGES.md')).read() + - '\n') + open(os.path.join(addon_dir, "README.rst")).read() + "\n" + "Contributors\n" + "============\n" + + "\n" + + open(os.path.join(addon_dir, "CONTRIBUTORS.rst")).read() + + "\n" + + open(os.path.join(addon_dir, "CHANGES.md")).read() + + "\n" +) setup( name=addon_dir, - version=manifest.get('version'), + version=manifest.get("version"), long_description=long_description, # Get more from http://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ - 'Programming Language :: Python', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.7', + "Programming Language :: Python", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", ], - keywords='Python PyERP', - license=manifest.get('license', 'GPL-3'), + keywords="Python PyERP", + license=manifest.get("license", "GPL-3"), packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=[ - 'setuptools', - ], + install_requires=["setuptools"], )