From a69e56908f656fb21f8f43900a11008f61317430 Mon Sep 17 00:00:00 2001 From: Renan Hiroki Bastos Date: Mon, 30 Oct 2023 20:01:32 -0300 Subject: [PATCH 1/5] [WIP] --- l10n_br_account_nfe/__init__.py | 1 + l10n_br_account_nfe/__manifest__.py | 1 + .../models/account_move_line.py | 8 +- l10n_br_account_nfe/wizards/__init__.py | 1 + .../wizards/import_document.py | 81 +++++++++++++++++++ .../wizards/import_document.xml | 17 ++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 l10n_br_account_nfe/wizards/__init__.py create mode 100644 l10n_br_account_nfe/wizards/import_document.py create mode 100644 l10n_br_account_nfe/wizards/import_document.xml diff --git a/l10n_br_account_nfe/__init__.py b/l10n_br_account_nfe/__init__.py index 2cc1876f12df..131bce8ddf5f 100644 --- a/l10n_br_account_nfe/__init__.py +++ b/l10n_br_account_nfe/__init__.py @@ -1,3 +1,4 @@ from .hooks import post_init_hook from . import models +from . import wizards diff --git a/l10n_br_account_nfe/__manifest__.py b/l10n_br_account_nfe/__manifest__.py index e207fb5d8d8f..aa6f5f5005a9 100644 --- a/l10n_br_account_nfe/__manifest__.py +++ b/l10n_br_account_nfe/__manifest__.py @@ -22,6 +22,7 @@ ], "data": [ "views/account_payment_mode.xml", + "wizards/import_document.xml", ], "post_init_hook": "post_init_hook", "installable": True, diff --git a/l10n_br_account_nfe/models/account_move_line.py b/l10n_br_account_nfe/models/account_move_line.py index e36606e2b5ac..6239ba192a05 100644 --- a/l10n_br_account_nfe/models/account_move_line.py +++ b/l10n_br_account_nfe/models/account_move_line.py @@ -2,7 +2,7 @@ # @author Renato Lima # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models +from odoo import api, models from odoo.addons.l10n_br_fiscal.constants.fiscal import ( DOCUMENT_ISSUER_COMPANY, @@ -31,3 +31,9 @@ def write(self, values): invoice.fiscal_document_id.action_document_confirm() invoice.fiscal_document_id._document_export() return result + + @api.onchange("fiscal_operation_line_id") + def _onchange_fiscal_operation_line_id(self): + if self.move_id.fiscal_document_id.imported_document: + return + return super(AccountMoveLine, self)._onchange_fiscal_operation_line_id() diff --git a/l10n_br_account_nfe/wizards/__init__.py b/l10n_br_account_nfe/wizards/__init__.py new file mode 100644 index 000000000000..285f70e22eee --- /dev/null +++ b/l10n_br_account_nfe/wizards/__init__.py @@ -0,0 +1 @@ +from . import import_document diff --git a/l10n_br_account_nfe/wizards/import_document.py b/l10n_br_account_nfe/wizards/import_document.py new file mode 100644 index 000000000000..49316136fa89 --- /dev/null +++ b/l10n_br_account_nfe/wizards/import_document.py @@ -0,0 +1,81 @@ +# Copyright (C) 2022 Renan Hiroki Bastos - Kmee +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + + +from odoo import fields, models + +# from datetime import datetime + + +class NfeImport(models.TransientModel): + """Importar XML Nota Fiscal Eletrônica""" + + _inherit = "l10n_br_nfe.import_xml" + + # TODO: Mover isso pro módulo l10n_br_nfe + fiscal_operation_id = fields.Many2one( + comodel_name="l10n_br_fiscal.operation", + string="Fiscal Operation", + ) + + def _create_edoc_from_xml(self): + edoc = super()._create_edoc_from_xml() + + edoc.fiscal_operation_id = self.fiscal_operation_id + + invoice_values = { + "partner_id": edoc.partner_id.id, + "invoice_date": edoc.document_date, # TODO: Arrumar datedue + "move_type": "in_invoice", + } + invoice = self.env["account.move"].create(invoice_values) + invoice.fiscal_document_id = edoc + # TODO: Colocar operação e linhas de operação + + invoice_lines = self.env["account.move.line"] + fiscal_position = self.env["account.fiscal.position"].browse( + invoice.partner_id.property_account_position_id.id + ) + for line in edoc.fiscal_line_ids: + values = line._convert_to_write(line.read()[0]) + values.update( + { + "move_id": invoice.id, + "exclude_from_invoice_tab": True, + # TODO: Adicionar lógica igual do stock_invoice_on_shipping para a conta + "account_id": fiscal_position.map_account( + line.product_id.categ_id.property_account_expense_categ_id + ).id, + } + ) + invoice_line = self.env["account.move.line"].create(values) + invoice_line.fiscal_document_line_id = line + invoice_line.exclude_from_invoice_tab = ( + False # TODO: Criar novo campo para essa checagem + ) + invoice_line.fiscal_operation_id = self.fiscal_operation_id + invoice_line._onchange_fiscal_operation_id() + invoice_lines += invoice_line + # for dup in edoc.nfe40_dup: + # invoice_line = self.env['account.move.line'].new({ + # 'name': invoice.payment_reference or '', + # 'debit': 0.0, + # 'credit': dup.nfe40_vDup, + # 'quantity': 1.0, + # 'date_maturity': dup.nfe40_dVenc, + # 'move_id': invoice.id, + # 'currency_id': invoice.currency_id.id, + # 'account_id': invoice.partner_id.property_account_payable_id.id, + # 'partner_id': invoice.partner_id.id, + # 'exclude_from_invoice_tab': True, + # }) + # invoice_lines += invoice_line + invoice.write({"line_ids": [(6, 0, invoice_lines.ids)]}) + + if not self.partner_id: + self.partner_id = edoc.partner_id + + self._attach_original_nfe_xml_to_document(edoc) + self.imported_products_ids._find_or_create_product_supplierinfo() + + return edoc diff --git a/l10n_br_account_nfe/wizards/import_document.xml b/l10n_br_account_nfe/wizards/import_document.xml new file mode 100644 index 000000000000..fb1aa5d9c95c --- /dev/null +++ b/l10n_br_account_nfe/wizards/import_document.xml @@ -0,0 +1,17 @@ + + + + + + l10n_br_nfe.import_xml.form.inherit + l10n_br_nfe.import_xml + + + + + + + + + From 293db87c2d602faf8fc454a872187b8702f76acf Mon Sep 17 00:00:00 2001 From: Renan Hiroki Bastos Date: Tue, 31 Oct 2023 12:40:15 -0300 Subject: [PATCH 2/5] [WIP] --- l10n_br_account_nfe/models/document.py | 36 +++++++++++ .../wizards/import_document.py | 60 +------------------ 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/l10n_br_account_nfe/models/document.py b/l10n_br_account_nfe/models/document.py index 37c166701d5f..f091f1efcc13 100644 --- a/l10n_br_account_nfe/models/document.py +++ b/l10n_br_account_nfe/models/document.py @@ -166,3 +166,39 @@ def _process_document_in_contingency(self): if self.move_ids: copy_invoice = self.move_ids[0].copy() copy_invoice.action_post() + + @api.model_create_multi + def create(self, vals_list): + if self._context.get("create_from_move"): + filtered_vals_list = [] + for values in vals_list: + if not values.get("imported_document", False): + filtered_vals_list.append(values) + documents = super().create(filtered_vals_list) + else: + documents = super().create(vals_list) + if documents and self._context.get("create_from_document"): + documents._create_account_moves() + return documents + + def _create_account_moves(self): + self.flush() + AccountMove = self.env["account.move"] + invoices_to_create = [] + for document in self: + invoices_to_create.append( + { + "partner_id": document.partner_id.id, + "user_id": self.env.user.id, + "company_id": self.env.company.id, + "currency_id": self.env.company.currency_id.id, + "invoice_date": document.document_date, # TODO: Arrumar datedue + "move_type": "in_invoice", + "imported_document": True, + } + ) + if invoices_to_create: + invoices = AccountMove.create(invoices_to_create) + for document, invoice in zip(self, invoices): + invoice.write({"fiscal_document_id": document.id}) + return True diff --git a/l10n_br_account_nfe/wizards/import_document.py b/l10n_br_account_nfe/wizards/import_document.py index 49316136fa89..741fcb7eed92 100644 --- a/l10n_br_account_nfe/wizards/import_document.py +++ b/l10n_br_account_nfe/wizards/import_document.py @@ -19,63 +19,9 @@ class NfeImport(models.TransientModel): ) def _create_edoc_from_xml(self): - edoc = super()._create_edoc_from_xml() - + edoc = super( + NfeImport, self.with_context(create_from_document=True) + )._create_edoc_from_xml() edoc.fiscal_operation_id = self.fiscal_operation_id - invoice_values = { - "partner_id": edoc.partner_id.id, - "invoice_date": edoc.document_date, # TODO: Arrumar datedue - "move_type": "in_invoice", - } - invoice = self.env["account.move"].create(invoice_values) - invoice.fiscal_document_id = edoc - # TODO: Colocar operação e linhas de operação - - invoice_lines = self.env["account.move.line"] - fiscal_position = self.env["account.fiscal.position"].browse( - invoice.partner_id.property_account_position_id.id - ) - for line in edoc.fiscal_line_ids: - values = line._convert_to_write(line.read()[0]) - values.update( - { - "move_id": invoice.id, - "exclude_from_invoice_tab": True, - # TODO: Adicionar lógica igual do stock_invoice_on_shipping para a conta - "account_id": fiscal_position.map_account( - line.product_id.categ_id.property_account_expense_categ_id - ).id, - } - ) - invoice_line = self.env["account.move.line"].create(values) - invoice_line.fiscal_document_line_id = line - invoice_line.exclude_from_invoice_tab = ( - False # TODO: Criar novo campo para essa checagem - ) - invoice_line.fiscal_operation_id = self.fiscal_operation_id - invoice_line._onchange_fiscal_operation_id() - invoice_lines += invoice_line - # for dup in edoc.nfe40_dup: - # invoice_line = self.env['account.move.line'].new({ - # 'name': invoice.payment_reference or '', - # 'debit': 0.0, - # 'credit': dup.nfe40_vDup, - # 'quantity': 1.0, - # 'date_maturity': dup.nfe40_dVenc, - # 'move_id': invoice.id, - # 'currency_id': invoice.currency_id.id, - # 'account_id': invoice.partner_id.property_account_payable_id.id, - # 'partner_id': invoice.partner_id.id, - # 'exclude_from_invoice_tab': True, - # }) - # invoice_lines += invoice_line - invoice.write({"line_ids": [(6, 0, invoice_lines.ids)]}) - - if not self.partner_id: - self.partner_id = edoc.partner_id - - self._attach_original_nfe_xml_to_document(edoc) - self.imported_products_ids._find_or_create_product_supplierinfo() - return edoc From fcd242fc2c80b05eb266269f588d49f74aaf2497 Mon Sep 17 00:00:00 2001 From: Renan Hiroki Bastos Date: Wed, 1 Nov 2023 17:56:02 -0300 Subject: [PATCH 3/5] [WIP] --- l10n_br_account_nfe/models/__init__.py | 2 + l10n_br_account_nfe/models/account_move.py | 36 ++++++++++++++ .../models/account_move_line.py | 15 ++++-- l10n_br_account_nfe/models/document.py | 47 +++++++++++++++++-- l10n_br_account_nfe/models/document_line.py | 18 +++++++ 5 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 l10n_br_account_nfe/models/account_move.py create mode 100644 l10n_br_account_nfe/models/document_line.py diff --git a/l10n_br_account_nfe/models/__init__.py b/l10n_br_account_nfe/models/__init__.py index b0e09929a8b1..5d4013cfc6fb 100644 --- a/l10n_br_account_nfe/models/__init__.py +++ b/l10n_br_account_nfe/models/__init__.py @@ -1,4 +1,6 @@ from . import account_payment_mode +from . import account_move from . import account_move_line from . import document +from . import document_line from . import leiauteNFe diff --git a/l10n_br_account_nfe/models/account_move.py b/l10n_br_account_nfe/models/account_move.py new file mode 100644 index 000000000000..9ab16c855608 --- /dev/null +++ b/l10n_br_account_nfe/models/account_move.py @@ -0,0 +1,36 @@ +# Copyright (C) 2023 - TODAY Renan Hiroki Bastos - KMEE +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import models + + +class AccountMove(models.Model): + _inherit = "account.move" + + def _create_financial_lines_from_dups(self): + for invoice in self: + if invoice.nfe40_dup: + invoice.financial_move_line_ids = [ + (2, financial_line, 0) + for financial_line in invoice.financial_move_line_ids.ids + ] + financial_lines = [] + for dup in invoice.nfe40_dup: + financial_lines.append( + { + "move_id": invoice.id, + "name": dup.nfe40_nDup, + "debit": 0.0, + "credit": dup.nfe40_vDup, + "quantity": 1.0, + "amount_currency": -dup.nfe40_vDup, + "date_maturity": dup.nfe40_dVenc, + "currency_id": invoice.currency_id.id, + "account_id": invoice.partner_id.property_account_payable_id.id, + "partner_id": invoice.partner_id.id, + "exclude_from_invoice_tab": True, + } + ) + invoice.financial_move_line_ids = [ + (0, 0, dup) for dup in financial_lines + ] diff --git a/l10n_br_account_nfe/models/account_move_line.py b/l10n_br_account_nfe/models/account_move_line.py index 6239ba192a05..e201c7cad8b6 100644 --- a/l10n_br_account_nfe/models/account_move_line.py +++ b/l10n_br_account_nfe/models/account_move_line.py @@ -32,8 +32,13 @@ def write(self, values): invoice.fiscal_document_id._document_export() return result - @api.onchange("fiscal_operation_line_id") - def _onchange_fiscal_operation_line_id(self): - if self.move_id.fiscal_document_id.imported_document: - return - return super(AccountMoveLine, self)._onchange_fiscal_operation_line_id() + @api.model_create_multi + def create(self, vals_list): + account_move_lines = super().create(vals_list) + # for account_move_line, vals in zip(account_move_lines, vals_list): + # if self._context.get("create_from_document") \ + # and vals.get("fiscal_document_line_id"): + # account_move_line.write({ + # "fiscal_document_line_id": vals.get("fiscal_document_line_id"), + # }) + return account_move_lines diff --git a/l10n_br_account_nfe/models/document.py b/l10n_br_account_nfe/models/document.py index f091f1efcc13..216f272e0f75 100644 --- a/l10n_br_account_nfe/models/document.py +++ b/l10n_br_account_nfe/models/document.py @@ -178,7 +178,8 @@ def create(self, vals_list): else: documents = super().create(vals_list) if documents and self._context.get("create_from_document"): - documents._create_account_moves() + invoices = documents._create_account_moves() + invoices._create_financial_lines_from_dups() return documents def _create_account_moves(self): @@ -193,12 +194,48 @@ def _create_account_moves(self): "company_id": self.env.company.id, "currency_id": self.env.company.currency_id.id, "invoice_date": document.document_date, # TODO: Arrumar datedue + "invoice_line_ids": [ + (0, None, self._prepare_invoice_line(line)) + for line in document.fiscal_line_ids + ], "move_type": "in_invoice", - "imported_document": True, + "imported_document": document.imported_document, } ) if invoices_to_create: invoices = AccountMove.create(invoices_to_create) - for document, invoice in zip(self, invoices): - invoice.write({"fiscal_document_id": document.id}) - return True + for document, invoice in zip(self, invoices): + invoice.write({"fiscal_document_id": document.id}) + for invoice_line in invoice.invoice_line_ids: + # TODO: Não vai funcionar para notas com o mesmo produto + # em mais de uma linha + invoice_line.fiscal_document_line_id = ( + document.fiscal_line_ids.filtered( + lambda fl: fl.product_id == invoice_line.product_id + ) + ) + return invoices + + def _prepare_invoice_line(self, fiscal_line): + fiscal_position = self.env["account.fiscal.position"].browse( + fiscal_line.partner_id.property_account_position_id.id + ) + values = fiscal_line._convert_to_write(fiscal_line.read()[0]) + # TODO: Utilizar lógica parecida com do stock.invoice.onshipping + # para mapear account_id + values.update( + { + "product_id": fiscal_line.product_id.id, + "quantity": fiscal_line.quantity, + "discount": fiscal_line.discount_value, + "price_unit": fiscal_line.price_unit, + "name": fiscal_line.name, + # "tax_ids": [(6, 0, order_line.tax_ids_after_fiscal_position.ids)], + "product_uom_id": fiscal_line.uom_id.id, + "fiscal_document_line_id": fiscal_line.id, + "account_id": fiscal_position.map_account( + fiscal_line.product_id.categ_id.property_account_expense_categ_id + ).id, + } + ) + return values diff --git a/l10n_br_account_nfe/models/document_line.py b/l10n_br_account_nfe/models/document_line.py new file mode 100644 index 000000000000..dc06ff208d5b --- /dev/null +++ b/l10n_br_account_nfe/models/document_line.py @@ -0,0 +1,18 @@ +# Copyright (C) 2023 - TODAY Renan Hiroki Bastos - Kmee +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import api, models + + +class FiscalDocumentLine(models.Model): + _inherit = "l10n_br_fiscal.document.line" + + @api.model_create_multi + def create(self, vals_list): + if self._context.get("create_from_move_line") and self._context.get( + "create_from_document" + ): + return [] + else: + documents = super().create(vals_list) + return documents From 47df87301cc18ee5a9966bafe3e7a5df0ca2b40b Mon Sep 17 00:00:00 2001 From: Renan Hiroki Bastos Date: Tue, 7 Nov 2023 14:30:53 -0300 Subject: [PATCH 4/5] [WIP] --- l10n_br_account_nfe/models/document.py | 22 +++++++++---- l10n_br_account_nfe/models/document_line.py | 34 +++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/l10n_br_account_nfe/models/document.py b/l10n_br_account_nfe/models/document.py index 216f272e0f75..9855eb49e215 100644 --- a/l10n_br_account_nfe/models/document.py +++ b/l10n_br_account_nfe/models/document.py @@ -214,9 +214,11 @@ def _create_account_moves(self): lambda fl: fl.product_id == invoice_line.product_id ) ) + invoice._move_autocomplete_invoice_lines_values() return invoices def _prepare_invoice_line(self, fiscal_line): + fiscal_line.reserve_map_taxes_ids() fiscal_position = self.env["account.fiscal.position"].browse( fiscal_line.partner_id.property_account_position_id.id ) @@ -225,17 +227,25 @@ def _prepare_invoice_line(self, fiscal_line): # para mapear account_id values.update( { + "name": fiscal_line.name, + "account_id": fiscal_position.map_account( + fiscal_line.product_id.categ_id.property_account_expense_categ_id + ).id, "product_id": fiscal_line.product_id.id, + "product_uom_id": fiscal_line.uom_id.id, "quantity": fiscal_line.quantity, "discount": fiscal_line.discount_value, "price_unit": fiscal_line.price_unit, - "name": fiscal_line.name, - # "tax_ids": [(6, 0, order_line.tax_ids_after_fiscal_position.ids)], - "product_uom_id": fiscal_line.uom_id.id, + "tax_ids": [ + ( + 6, + 0, + fiscal_line.fiscal_tax_ids.account_taxes( + user_type="purchase" + ).ids, + ) + ], "fiscal_document_line_id": fiscal_line.id, - "account_id": fiscal_position.map_account( - fiscal_line.product_id.categ_id.property_account_expense_categ_id - ).id, } ) return values diff --git a/l10n_br_account_nfe/models/document_line.py b/l10n_br_account_nfe/models/document_line.py index dc06ff208d5b..7ba6ce2dfc6f 100644 --- a/l10n_br_account_nfe/models/document_line.py +++ b/l10n_br_account_nfe/models/document_line.py @@ -7,6 +7,40 @@ class FiscalDocumentLine(models.Model): _inherit = "l10n_br_fiscal.document.line" + def reserve_map_taxes_ids(self): + for line in self: + line.icms_tax_id = self.env["l10n_br_fiscal.tax"].search( + [ + ("tax_group_id.name", "=", "ICMS"), + ("percent_amount", "=", line.icms_percent), + ("cst_in_id", "=", line.icms_cst_id.id), + ], + limit=1, + ) + line.ipi_tax_id = self.env["l10n_br_fiscal.tax"].search( + [ + ("tax_group_id.name", "=", "IPI"), + ("percent_amount", "=", line.ipi_percent), + ], + limit=1, + ) + line.pis_tax_id = self.env["l10n_br_fiscal.tax"].search( + [ + ("tax_group_id.name", "=", "PIS"), + ("percent_amount", "=", line.pis_percent), + ], + limit=1, + ) + line.cofins_tax_id = self.env["l10n_br_fiscal.tax"].search( + [ + ("tax_group_id.name", "=", "COFINS"), + ("percent_amount", "=", line.cofins_percent), + ], + limit=1, + ) + line._update_fiscal_tax_ids(line._get_all_tax_id_fields()) + line._update_taxes() + @api.model_create_multi def create(self, vals_list): if self._context.get("create_from_move_line") and self._context.get( From 4d12f6e1b321401d3a5ce34f78b117e78b585c55 Mon Sep 17 00:00:00 2001 From: Renan Hiroki Bastos Date: Tue, 14 Nov 2023 15:37:09 -0300 Subject: [PATCH 5/5] [FIX] Set product uom when creating record during import --- l10n_br_nfe/models/product_product.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/l10n_br_nfe/models/product_product.py b/l10n_br_nfe/models/product_product.py index fff8573fe260..129c8549badc 100644 --- a/l10n_br_nfe/models/product_product.py +++ b/l10n_br_nfe/models/product_product.py @@ -97,4 +97,14 @@ def default_get(self, default_fields): ) ) values["ncm_id"] = ncm.id + + # UOM + if parent_dict.get("nfe40_uCom"): + uom = self.env["uom.uom"].search( + [("code", "ilike", parent_dict.get("nfe40_uCom"))], limit=1 + ) + if uom: + values["uom_id"] = uom.id + values["uom_po_id"] = uom.id + return values