diff --git a/l10n_mx_facturae/demo/demo_res_partner.xml b/l10n_mx_facturae/demo/demo_res_partner.xml index 941161b955a589aea6dd09eaa3500d875b498485..2ec790f9f7fdcd69663ba2ebead84d34b870f0ab 100644 --- a/l10n_mx_facturae/demo/demo_res_partner.xml +++ b/l10n_mx_facturae/demo/demo_res_partner.xml @@ -25,4 +25,31 @@ <field name="payment_method_id" ref="l10n_mx_base.cfdi_payment_method_1"/> </record> + <record id="l10n_mx_ir_attachment_facturae.demo_partner_company_mx_frontier" model="res.partner"> + <field name="cfdi_fiscal_regime_id" ref="l10n_mx_base.regime_fiscal_601"/> + <field name="cfdi_use_id" ref="l10n_mx_base.cfdi_use_S01"/> + </record> + + <record id="l10n_mx_ir_attachment_facturae.res_company_mx_frontier" model="res.company"> + <field name="cfdi_fiscal_regime_id" ref="l10n_mx_base.regime_fiscal_601"/> + <field name="cfdi_use_id" ref="l10n_mx_base.cfdi_use_S01"/> + </record> + + <record id="res_partner_2024" model="res.partner"> + <field name="name">Maria Olivia Martinez Sagaz</field> + <field name="is_company">1</field> + <field name="street">45 10 oriente</field> + <field name="city">Culiacán</field> + <field name="state_id" ref="base.state_mx_sin"/> + <field name="zip">80290</field> + <field name="vat">MXMASO451221PM4</field> + <field name="phone">(870)-931-0505</field> + <field name="country_id" ref="base.mx"/> + <field name="email">maria.martinez@example.com</field> + <field name="company_id" ref="l10n_mx_ir_attachment_facturae.res_company_mx_frontier"/> + <field name="cfdi_fiscal_regime_id" ref="l10n_mx_base.regime_fiscal_616"/> + <field name="cfdi_use_id" ref="l10n_mx_base.cfdi_use_S01"/> + <field name="payment_method_id" ref="l10n_mx_base.cfdi_payment_method_1"/> + </record> + </odoo> diff --git a/l10n_mx_facturae/models/account_move.py b/l10n_mx_facturae/models/account_move.py index 063bb5549bf2a6e95cd9a6b20900c749ade05c24..3bdc1422f9a7cfa8fde90a8892abf32638ac5324 100644 --- a/l10n_mx_facturae/models/account_move.py +++ b/l10n_mx_facturae/models/account_move.py @@ -124,10 +124,6 @@ class AccountMove(models.Model): "cfdi.use", "CFDI use", readonly=True, states={"draft": [("readonly", False)]} ) cfdi_relation_type = fields.Many2one("cfdi.relation.type", "CFDI Relation type") - state = fields.Selection( - selection_add=[("waiting", _("To cancel"))], - ondelete={'waiting': 'cascade'} - ) l10n_mx_edi_to_cancel = fields.Char( #compute="_compute_l10n_mx_edi_to_cancel", #search="_search_l10n_mx_edi_to_cancel", @@ -316,10 +312,9 @@ class AccountMove(models.Model): # Create new CFDI object for this invoice account_invoice.create_cfdi() - def action_cancel(self): - """Extend `AccountMove.action_cancel()`; Cancels the CFDI related to the - invoice - """ + def l10n_mx_action_cancel(self): + """Cancels the CFDI related to the invoice""" + # Get only invoices with related cfdi to cancel cfdi before cancel invoice cfdis = self.filtered( lambda i: @@ -327,38 +322,46 @@ class AccountMove(models.Model): and i.cfdi_id and i.cfdi_id.state not in ["draft", "cancel"] ) + for invoice in cfdis: - # Ensure we can cancel this invoice - invoice.check_if_can_cancel() - # If l10n_mx_edi_original_invoice is set save uuid to send info to PAC - # while cancel invoice - invoice.cfdi_id.substitute_cfdi_uuid = ( - invoice.l10n_mx_edi_original_invoice.cfdi_id.uuid + invoice.message_post( + body=_("Cancellation request sent") ) - cancelacion = invoice.cancel_cfdi()[0] + cancelacion = invoice.cancel_cfdi() if cancelacion: # CFDI cancelled (cancelacion == True) must cancel invoice too - super(AccountMove, invoice).action_cancel() + invoice.button_draft() + invoice.button_cancel() elif cancelacion is None: # CFDI set to approval (cancelacion == None) must set invoice # to waiting too - invoice.write({"state": "waiting"}) + invoice.write({"state": "posted"}) + invoice.message_post( + body=_("Awaiting cancellation") + ) elif cancelacion is False: # CFDI cancel denied (cancelacion == False) must get back invoice # to open state self.undo_waiting_state() - - # Call super only with invoices without CFDI - invoices = self - cfdis - return super(AccountMove, invoices).action_cancel() + invoice.message_post( + body=_("Denied cancellation") + ) def undo_waiting_state(self): """When cancel is negate revert invoice to open and post account_move""" for record in self: - to_update = record.filtered(lambda i: i.state == "waiting") - to_update.write({"state": "open"}) + to_update = record.filtered(lambda i: i.cfdi_state == "waiting") + to_update.write({"state": "posted"}) to_update.mapped("move_id").post() + @api.depends("state", "cfdi_state") + def _compute_show_reset_to_draft_button(self): + super()._compute_show_reset_to_draft_button() + + for move in self: + if move.state in ("posted", "cancel") and move.cfdi_state in ("signed", "done", "waiting", "cancel"): + move.show_reset_to_draft_button = False + def action_consult_cancellation_status(self): """Verify cancellation status""" # TODO: Is this really needed? Maybe we can reuse the action_cancel @@ -520,7 +523,6 @@ class AccountMove(models.Model): return res - class AccountMoveLine(models.Model): _inherit = "account.move.line" diff --git a/l10n_mx_facturae/models/account_payment.py b/l10n_mx_facturae/models/account_payment.py index d43314d24f540a963d1f8751804b6ef639ade3f6..5acacfaa4131fab54be3610859362f683416dcde 100644 --- a/l10n_mx_facturae/models/account_payment.py +++ b/l10n_mx_facturae/models/account_payment.py @@ -345,20 +345,8 @@ class AccountPayment(models.Model): tax_group = tax_rep_lines.mapped("tag_ids") key = tax_group.name + str(line["tax_id"].amount) - if company_currency != voucher_currency: - company_currency = company_currency.with_context( - special_currency_rate=self.currency_rate(), - special_currency=voucher_currency.id, - ) - tax_totals["importe" + key] = company_currency.compute( - line["importe"], voucher_currency, - ) - tax_totals["base" + key] = company_currency.compute( - line["tax_base"], voucher_currency, - ) - else: - tax_totals["importe" + key] = line["importe"] - tax_totals["base" + key] = line["tax_base"] + tax_totals["importe" + key] = line["importe"] + tax_totals["base" + key] = line["tax_base"] return tax_totals @@ -378,35 +366,11 @@ class AccountPayment(models.Model): importe=0.0, ) - if tax_move.currency_id != voucher_currency: - invoice_currency = ( - tax_move.currency_id - if tax_move.currency_id else company_currency - ) - invoice_currency = invoice_currency.with_context(date=self.date) - if invoice_currency != company_currency: - invoice_currency = invoice_currency.with_context( - special_currency_rate=self.tipocambiodr(invoice), - special_currency=invoice_currency.id, - ) - else: - invoice_currency = invoice_currency.with_context( - special_currency_rate=(1 / self.tipocambiodr(invoice)), - special_currency=voucher_currency.id, - ) - tax_base = invoice_currency.compute( - tax_move.tax_base_amount, voucher_currency, round=False, - ) - # Force rounding 6 decimals to use as many decimal as possible and - # avoid rounding errors when validating XML - tax_base = float_round( - tax_base, precision_digits=2, rounding_method="DOWN", - ) - else: - tax_base = tax_move.tax_base_amount + tax_base = self._l10n_mx_tax_base_dr(invoice, tax_move) + importe = self._l10n_mx_tax_importe_dr(invoice, tax_move) tax_totals[tax_move.tax_line_id.id]["tax_base"] += tax_base - tax_totals[tax_move.tax_line_id.id]["importe"] += abs(tax_move.balance) + tax_totals[tax_move.tax_line_id.id]["importe"] += importe return [line for line in tax_totals.values()] @@ -429,3 +393,27 @@ class AccountPayment(models.Model): domain.append(("tax_line_id.amount_type", "=", "percent")) return domain + + def _l10n_mx_tax_base_dr(self, invoice, tax_move): + amount = tax_move.tax_base_amount + + if invoice.currency_id != self.company_id.currency_id: + account = ( + tax_move.company_id.account_cash_basis_base_account_id or + tax_move.account_id + ) + base_line = tax_move.move_id.line_ids.filtered( + lambda l: + l.id != tax_move.id and l.account_id == account and l.tax_ids + ) + amount = -1 * base_line.amount_currency + + return amount + + def _l10n_mx_tax_importe_dr(self, invoice, tax_move): + amount = tax_move.balance + + if invoice.currency_id != self.company_id.currency_id: + amount = tax_move.amount_currency + + return -1 * amount diff --git a/l10n_mx_facturae/templates/account_payment.xml b/l10n_mx_facturae/templates/account_payment.xml index 3b9dfe6de3e3d28d6aaefef05b97d63788938dd1..eeec6bff4712c47cf2fa61b702326edda8cf65ce 100644 --- a/l10n_mx_facturae/templates/account_payment.xml +++ b/l10n_mx_facturae/templates/account_payment.xml @@ -54,12 +54,12 @@ <pago20:Totales t-attf-MontoTotalPagos="{{ o.l10n_mx_facturae_payment_montototalpagos() }}" t-att-TotalTrasladosBaseIVAExento="traslados.get('baseIVAExento', False)" - t-att-TotalTrasladosBaseIVA16="format_float(traslados.get('baseIVA16.0', False), o.currency_id.decimal_places)" - t-att-TotalTrasladosImpuestoIVA16="traslados.get('importeIVA16.0', False)" - t-att-TotalTrasladosBaseIVA8="traslados.get('baseIVA8.0', False)" - t-att-TotalTrasladosImpuestoIVA8="traslados.get('importeIVA8.0', False)" - t-att-TotalTrasladosBaseIVA0="traslados.get('baseIVA0.0', False)" - t-att-TotalTrasladosImpuestoIVA0="traslados.get('importeIVA0.0', False)" + t-att-TotalTrasladosBaseIVA16="format_float(traslados.get('baseIVA16.0'), o.currency_id.decimal_places) if traslados.get('baseIVA16.0', False) else False" + t-att-TotalTrasladosImpuestoIVA16="format_float(traslados.get('importeIVA16.0'), o.currency_id.decimal_places) if traslados.get('importeIVA16.0', False) else False" + t-att-TotalTrasladosBaseIVA8="format_float(traslados.get('baseIVA8.0'), o.currency_id.decimal_places) if traslados.get('baseIVA8.0', False) else False" + t-att-TotalTrasladosImpuestoIVA8="format_float(traslados.get('importeIVA8.0'), o.currency_id.decimal_places) if traslados.get('importeIVA8.0', False) else False" + t-att-TotalTrasladosBaseIVA0="format_float(traslados.get('baseIVA0.0'), o.currency_id.decimal_places) if traslados.get('baseIVA0.0', False) else False" + t-att-TotalTrasladosImpuestoIVA0="format_float(traslados.get('importeIVA0.0'), o.currency_id.decimal_places) if traslados.get('importeIVA0.0', False) else False" t-att-TotalRetencionesIVA="retenciones.get('importeIVA', False)" t-att-TotalRetencionesISR="retenciones.get('importeISR', False)" t-att-TotalRetencionesIEPS="retenciones.get('importeIEPS', False)" /> @@ -92,9 +92,9 @@ </pago20:RetencionesDR> <pago20:TrasladosDR> <pago20:TrasladoDR t-foreach="o.impuestos_dr(invoice)" t-as="tax_move" - t-att-BaseDR="format_float(tax_move.tax_base_amount, invoice.currency_id.decimal_places)" + t-att-BaseDR="format_float(o._l10n_mx_tax_base_dr(invoice, tax_move), invoice.currency_id.decimal_places)" t-att-ImpuestoDR="format_impuesto(tax_move.tax_line_id)" - t-att-ImporteDR="format_float(abs(tax_move.balance), invoice.currency_id.decimal_places)" + t-att-ImporteDR="format_float(abs(o._l10n_mx_tax_importe_dr(invoice, tax_move)), invoice.currency_id.decimal_places)" t-att-TasaOCuotaDR="format_tasaocuota(tax_move.tax_line_id)" t-att-TipoFactorDR="tax_move.tax_line_id.l10n_mx_tax_type" /> </pago20:TrasladosDR> diff --git a/l10n_mx_facturae/views/account_move.xml b/l10n_mx_facturae/views/account_move.xml index f7d429a9fef886ac2a9b461559f94711a6428e31..fd284480637fc124b089289351b9e171176c8648 100644 --- a/l10n_mx_facturae/views/account_move.xml +++ b/l10n_mx_facturae/views/account_move.xml @@ -31,6 +31,15 @@ <field name="inherit_id" ref="account.view_move_form"/> <field name="arch" type="xml"> <button name="button_cancel" position="before"> + <button name="l10n_mx_action_cancel" + string="Cancel CFDI" + type="object" + class="btn-primary" + attrs="{'invisible': [ + '&', + ('state', '!=', 'posted'), + ('cfdi_state', '!=', 'done') + ]}"/> <field name="is_cfdi_candidate" invisible="1" /> </button> <xpath expr="//header" position="after">