Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][14.0] Refactor Import EDOC #3546

Draft
wants to merge 29 commits into
base: 14.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d8de691
[IMP] l10n_br_account: imported doc=>no tax engine
rvalyi Oct 20, 2024
d3bbd96
[IMP] l10n_br_fiscal: imported doc=>no tax engine
rvalyi Oct 20, 2024
84007ed
[DEL] spec_driven_model: simplified importation
rvalyi Oct 20, 2024
826c192
[IMP] l10n_br_account: import account.move
rvalyi Nov 9, 2023
6317073
[IMP] l10n_br_account: use upload button
rvalyi Nov 9, 2023
2bea997
[IMP] l10n_br_account_nfe: sync' dups w. pay terms
rvalyi Nov 9, 2023
bcadea8
[FIX] l10n_br_nfe: uom workaround for XML import
rvalyi Nov 12, 2023
b1dc98d
[FIX] l10n_br_nfe: import NFE with autXML tag
Nov 15, 2023
d5493af
[FIX] l10n_br_account: tax incl/excl for import
rvalyi Oct 20, 2024
5824ae7
[FIX] l10n_br_account: proper UOM on imported move
rvalyi Nov 14, 2023
b4db4be
[FIX] l10n_br_account: no tax recompute on import
rvalyi Nov 14, 2023
de477c2
[REF] l10n_br_fiscal(_edi): mv doc import wiz
rvalyi Oct 20, 2024
7e0213a
[REF] l10n_br_nfe: mv import wizard
rvalyi Oct 20, 2024
cec6e1f
[MOV] document import wizard to fiscal_edi
mileo Dec 12, 2024
085f6e1
[REF][l10n_br_nfe] Simplifying the NF-e import wizard
mileo Dec 12, 2024
98dd9c5
[WIP] Geração de fatura através de um edoc
mileo Dec 12, 2024
8615ff6
[NEW] CT-e import wizard
mileo Dec 13, 2024
d977ecc
[NEW] MDFe import wizard
mileo Dec 13, 2024
77aff89
[IMP] Fiscal model to import products without create
mileo Dec 17, 2024
442fa5a
[NEW][l10n_br_nfe] Don't create products
mileo Dec 17, 2024
0e67292
[REF][l10n_br_account] import edoc
mileo Dec 18, 2024
cb4896d
[NEW][l10n_br_account] Create a.m. from after import edoc
mileo Dec 18, 2024
fe3694a
[NEW][l10n_br_fiscal] Import Docs Edit
mileo Dec 18, 2024
c3fbea1
[NEW][l10n_br_nfe] edoc import create product
mileo Dec 18, 2024
dc1cd22
fixup! [NEW][l10n_br_account] Create a.m. from after import edoc
mileo Dec 18, 2024
da84651
fixup! [NEW][l10n_br_fiscal] Import Docs Edit
mileo Dec 18, 2024
5456799
[REF] imported_document field to fiscal mixin
mileo Dec 18, 2024
9b9419f
[MIG] remove l10n_br_nfe.import_xml
mileo Jan 17, 2025
4b0042d
[MIG] l10n_br_fiscal.document.import.wizard.mixin
mileo Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion l10n_br_account/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"license": "AGPL-3",
"author": "Akretion, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/l10n-brazil",
"version": "14.0.11.15.0",
"version": "14.0.12.0.0",
"development_status": "Beta",
"maintainers": ["renatonlima", "rvalyi"],
"depends": [
Expand Down
24 changes: 24 additions & 0 deletions l10n_br_account/migrations/14.0.12.0.0/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2025 KMEE
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from openupgradelib import openupgrade


def delete_model(cr, model_name):
openupgrade.logged_query(
cr,
"""
DELETE FROM ir_model_access
WHERE model_id = (SELECT id FROM ir_model where model = '%s')
"""
% model_name,
)
openupgrade.logged_query(
cr, "DELETE FROM ir_model_fields WHERE model = '%s'" % model_name
)
openupgrade.logged_query(cr, "DELETE FROM ir_model WHERE model = '%s'" % model_name)


@openupgrade.migrate()
def migrate(env, version):
delete_model(env.cr, "l10n_br_fiscal.document.import.wizard.mixin")
1 change: 1 addition & 0 deletions l10n_br_account/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
from . import document_line
from . import account_incoterms
from . import ir_model_data
from . import account_journal
14 changes: 9 additions & 5 deletions l10n_br_account/models/account_journal.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# Copyright (C) 2009 - TODAY Renato Lima - Akretion
# Copyright 2023 Akretion (Raphaẽl Valyi <[email protected]>)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from odoo import fields, models
from odoo import models


class AccountJournal(models.Model):
_inherit = "account.journal"

revenue_expense = fields.Boolean(
string="Gera Financeiro",
)
def create_invoice_from_attachment(self, attachment_ids=None):
if self.env.company.country_id.code != "BR" or len(attachment_ids) < 1:
return super().create_invoice_from_attachment(attachment_ids=attachment_ids)
attachments = self.env["ir.attachment"].browse(attachment_ids)
return self.env["l10n_br_fiscal.document.import.wizard"]._get_importer_action(

Check warning on line 14 in l10n_br_account/models/account_journal.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_journal.py#L12-L14

Added lines #L12 - L14 were not covered by tests
attachments
)
22 changes: 22 additions & 0 deletions l10n_br_account/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,20 @@
icms_origin=base_line.icms_origin,
ind_final=base_line.ind_final,
)
if self.imported_document:
# then force the manual base and amount taxes:
for tax_item in balance_taxes_res["taxes"]:
if not tax_item.get("fiscal_tax_id") and not isinstance(
tax_item["fiscal_tax_id"], models.NewId
):
continue
tax_domain = (

Check warning on line 464 in l10n_br_account/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move.py#L463-L464

Added lines #L463 - L464 were not covered by tests
self.env["l10n_br_fiscal.tax"]
.browse(tax_item["fiscal_tax_id"].origin)
.tax_domain
)
tax_item["base"] = getattr(base_line, "%s_base" % (tax_domain,))
tax_item["amount"] = getattr(base_line, "%s_value" % (tax_domain,))

Check warning on line 470 in l10n_br_account/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move.py#L469-L470

Added lines #L469 - L470 were not covered by tests
return balance_taxes_res

def _preprocess_taxes_map(self, taxes_map):
Expand Down Expand Up @@ -598,6 +612,11 @@
move.button_cancel()
move.button_draft()

def action_import_confirm(self):
for move in self.filtered(lambda d: d.document_type_id):
move.ensure_one_doc()
return move.fiscal_document_id.action_import_confirm()

Check warning on line 618 in l10n_br_account/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move.py#L617-L618

Added lines #L617 - L618 were not covered by tests

def _post(self, soft=True):
for move in self.with_context(skip_post=True):
move.fiscal_document_ids.filtered(
Expand Down Expand Up @@ -791,4 +810,7 @@
line_form.fiscal_operation_id = self.fiscal_operation_id
line_form.fiscal_document_line_id = line
move_form.save()
move = self.env["account.move"].browse(move_form.id)
for line in move.invoice_line_ids:
line.product_uom_id = line.fiscal_document_line_id.uom_id.id
return move_form
41 changes: 36 additions & 5 deletions l10n_br_account/models/account_move_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@

@api.model_create_multi
def create(self, vals_list):
inv_line_index = -1
for values in vals_list:
inv_line_index_old = inv_line_index
if values.get("product_id"):
inv_line_index += 1
if values.get("fiscal_document_line_id"):
fiscal_line_data = (
self.env["l10n_br_fiscal.document.line"]
Expand Down Expand Up @@ -207,16 +211,28 @@
else False
)

if move_id.imported_document and inv_line_index != inv_line_index_old:
# this will fix the the Debit side for imported fiscal documents
amount_tax_included = move_id.fiscal_document_id.fiscal_line_ids[

Check warning on line 216 in l10n_br_account/models/account_move_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move_line.py#L216

Added line #L216 was not covered by tests
inv_line_index
].amount_tax_included_from_tax_values
amount_tax_not_included = (

Check warning on line 219 in l10n_br_account/models/account_move_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move_line.py#L219

Added line #L219 was not covered by tests
move_id.fiscal_document_id.fiscal_line_ids[
inv_line_index
].amount_tax_excluded_from_tax_values
)
else:
amount_tax_included = values.get("amount_tax_included")
amount_tax_not_included = values.get("amount_tax_not_included")

values.update(
self._get_amount_credit_debit_model(
move_id,
exclude_from_invoice_tab=values.get(
"exclude_from_invoice_tab", False
),
amount_tax_included=values.get("amount_tax_included", 0),
amount_tax_not_included=values.get(
"amount_tax_not_included", 0
),
amount_tax_included=amount_tax_included,
amount_tax_not_included=amount_tax_not_included,
amount_tax_withholding=values.get("amount_tax_withholding", 0),
amount_total=fiscal_line.amount_total,
currency_id=move_id.currency_id,
Expand Down Expand Up @@ -447,7 +463,7 @@

insurance_value = self.env.context.get("insurance_value", 0)
other_value = self.env.context.get("other_value", 0)
freight_value = self.env.context.get("other_value", 0)
freight_value = self.env.context.get("freight_value", 0)
ii_customhouse_charges = self.env.context.get("ii_customhouse_charges", 0)
icms_relief_value = self.env.context.get("icms_relief_value", 0)

Expand Down Expand Up @@ -509,6 +525,11 @@
# override the default product uom (set by the onchange):
self.product_uom_id = self.fiscal_document_line_id.uom_id.id

def _get_computed_taxes(self):
if self._is_imported() and self.fiscal_tax_ids and self.tax_ids:
return self.tax_ids

Check warning on line 530 in l10n_br_account/models/account_move_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move_line.py#L530

Added line #L530 was not covered by tests
return super()._get_computed_taxes()

@api.onchange("fiscal_tax_ids")
def _onchange_fiscal_tax_ids(self):
"""Ao alterar o campo fiscal_tax_ids que contém os impostos fiscais,
Expand Down Expand Up @@ -616,6 +637,11 @@
# The formatting was a little strange, but I tried to make it as close as
# possible to the logic adopted by native Odoo.
# Example: _get_fields_onchange_subtotal
if self._is_imported():
# this will get the Credit side correct for imported fiscal documents:
amount_tax_included = self.amount_tax_included_from_tax_values
amount_tax_not_included = self.amount_tax_excluded_from_tax_values

Check warning on line 643 in l10n_br_account/models/account_move_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/account_move_line.py#L642-L643

Added lines #L642 - L643 were not covered by tests

return self._get_amount_credit_debit_model(
move_id=self.move_id if move_id is None else move_id,
exclude_from_invoice_tab=self.exclude_from_invoice_tab
Expand Down Expand Up @@ -695,3 +721,8 @@
"debit": balance > 0.0 and balance or 0.0,
"credit": balance < 0.0 and -balance or 0.0,
}

@api.constrains("product_uom_id")
def _check_product_uom_category_id(self):
not_imported = self.filtered(lambda line: not line._is_imported())
return super(AccountMoveLine, not_imported)._check_product_uom_category_id()
21 changes: 21 additions & 0 deletions l10n_br_account/models/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,24 @@
):
self._document_deny()
return super().exec_after_SITUACAO_EDOC_DENEGADA(old_state, new_state)

def action_import_confirm(self):
"""
This is the import wizard confirmation action that will
trigger the account.move importation for the current file.
After the importation, it either redirect for processing
the next file if any, either it redirect to the imported
account.move(s) at the end of the attachments sequence.
"""
move_type = "%s_invoice" % (self.fiscal_operation_type,)
move_id = self.env["account.move"].import_fiscal_document(

Check warning on line 215 in l10n_br_account/models/document.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document.py#L214-L215

Added lines #L214 - L215 were not covered by tests
self, move_type=move_type
)
return {

Check warning on line 218 in l10n_br_account/models/document.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document.py#L218

Added line #L218 was not covered by tests
"name": _("Imported Invoices"),
"type": "ir.actions.act_window",
"target": "current",
"views": [[False, "tree"], [False, "form"]],
"res_ids": [move_id.id],
"res_model": "account.move",
}
30 changes: 30 additions & 0 deletions l10n_br_account/models/document_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
related="price_unit",
readonly=False,
)
amount_tax_included_from_tax_values = fields.Float(
compute="_compute_amount_tax_from_tax_values",
help="Used on imported or edited fiscal documents",
)
amount_tax_excluded_from_tax_values = fields.Float(
compute="_compute_amount_tax_excluded_from_tax_values",
help="Used on imported or edited fiscal documents",
)

@api.model_create_multi
def create(self, vals_list):
Expand Down Expand Up @@ -64,3 +72,25 @@
vals_list = filtered_vals_list

return super().create(vals_list)

def _compute_amount_tax_from_tax_values(self, included=True):
included_taxes = (

Check warning on line 77 in l10n_br_account/models/document_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document_line.py#L77

Added line #L77 was not covered by tests
self.env["l10n_br_fiscal.tax.group"]
.search([("tax_include", "=", included)])
.mapped("tax_domain")
)
for line in self:
for tax in included_taxes:
if not hasattr(line, "%s_value" % (tax,)):
continue

Check warning on line 85 in l10n_br_account/models/document_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document_line.py#L85

Added line #L85 was not covered by tests
if included:
line.amount_tax_included_from_tax_values += getattr(

Check warning on line 87 in l10n_br_account/models/document_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document_line.py#L87

Added line #L87 was not covered by tests
line, "%s_value" % (tax,)
)
else:
line.amount_tax_excluded_from_tax_values += getattr(

Check warning on line 91 in l10n_br_account/models/document_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document_line.py#L91

Added line #L91 was not covered by tests
line, "%s_value" % (tax,)
)

def _compute_amount_tax_excluded_from_tax_values(self):
self._compute_amount_tax_from_tax_values(included=False)

Check warning on line 96 in l10n_br_account/models/document_line.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/models/document_line.py#L96

Added line #L96 was not covered by tests
6 changes: 3 additions & 3 deletions l10n_br_account/views/document_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<field name="model">l10n_br_fiscal.document</field>
<field name="inherit_id" ref="l10n_br_fiscal.document_form" />
<field name="arch" type="xml">
<field name="state_fiscal" position="after">
<field name="move_ids" invisible="1" />
</field>
<field name="state_fiscal" position="after">
<field name="move_ids" invisible="1" />
</field>
</field>
</record>

Expand Down
1 change: 1 addition & 0 deletions l10n_br_account/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from . import account_move_reversal
from . import document_import_wizard_mixin
124 changes: 124 additions & 0 deletions l10n_br_account/wizards/document_import_wizard_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Copyright 2023 Akretion (Raphaẽl Valyi <[email protected]>)
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html


from odoo import _, fields, models


class DocumentImportWizardMixin(models.TransientModel):
"""
Extend the generic Document Importer so that importing
a fiscal document will also create an account move and so
it can be used sequencially with several attachments from
the vendor bills upload button.
"""

_inherit = "l10n_br_fiscal.document.import.wizard"

# a transient wizard cannot be linked to any persistent
# account.move record. So in case the user upload several
# attachments, the solution we implemented
# is to store the id of the 1st imported move and redirect
# to the next imported account.move from there.
first_imported_move_id = fields.Integer()

# def action_import_and_open_move(self):
# """
# This is the import wizard confirmation action that will
# trigger the account.move importation for the current file.
# After the importation, it either redirect for processing
# the next file if any, either it redirect to the imported
# account.move(s) at the end of the attachments sequence.
# """
# _binding, fiscal_document = self._import_edoc()
# move_type = "%s_invoice" % (self.fiscal_operation_type,)
# move_id = (
# self.env["account.move"]
# .import_fiscal_document(
# fiscal_document,
# move_type=move_type,
# )
# .id
# )

# attachments = (
# self.env["ir.attachment"]
# .sudo()
# .search(
# [
# ("res_model", "=", "l10n_br_fiscal.document.import.wizard.mixin"),
# ("res_id", "=", self.id),
# ("create_uid", "=", self._uid),
# ],
# order="id",
# )
# )
# if attachments:
# # then we should link the current attachment
# # to the imported account.move
# attachments[0].res_model = "account.move"
# attachments[0].res_id = move_id

# if len(attachments) > 1:
# # process the next files to import:
# return self._get_importer_action(attachments[1:], move_id=move_id)

# else:
# # no more file to import
# if not self.first_imported_move_id:
# # only one imported account move:
# return {
# "name": _("Imported Invoice"),
# "type": "ir.actions.act_window",
# "target": "current",
# "views": [[False, "form"]],
# "res_id": move_id,
# "res_model": "account.move",
# }
# else: # several imported account moves:
# moves = self.env["account.move"].search(
# [
# ("imported_document", "=", True),
# ("id", ">=", self.first_imported_move_id),
# ("create_uid", "=", self._uid),
# ]
# )
# return {
# "name": _("Imported Invoices"),
# "type": "ir.actions.act_window",
# "target": "current",
# "views": [[False, "tree"], [False, "form"]],
# "res_ids": moves.ids,
# "res_model": "account.move",
# }

def _get_importer_action(self, attachments, move_id=None):
"""
Try to parse the 1st file of the the attachments to
detect its type and return the specialized wizard import
action for it. Also mark the other attachments to be imported
next.
"""
binding = self._parse_file_data(attachments[0].datas)
kind, specialized_importer = self._detect_binding(binding)
wizard = self.env[specialized_importer].create(

Check warning on line 104 in l10n_br_account/wizards/document_import_wizard_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/wizards/document_import_wizard_mixin.py#L102-L104

Added lines #L102 - L104 were not covered by tests
{
"file": attachments[0].datas,
"first_imported_move_id": self.first_imported_move_id or move_id,
}
)

for attachment in attachments:
# this link will allow to retrive the next attachments to import:
attachment.res_model = "l10n_br_fiscal.document.import.wizard"
attachment.res_id = wizard.id

Check warning on line 114 in l10n_br_account/wizards/document_import_wizard_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/wizards/document_import_wizard_mixin.py#L113-L114

Added lines #L113 - L114 were not covered by tests

wizard._onchange_file()
return {

Check warning on line 117 in l10n_br_account/wizards/document_import_wizard_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_br_account/wizards/document_import_wizard_mixin.py#L116-L117

Added lines #L116 - L117 were not covered by tests
"name": _("Adjust Importation for document type %s") % (kind,),
"type": "ir.actions.act_window",
"target": "new",
"views": [[False, "form"]],
"res_id": wizard.id,
"res_model": specialized_importer,
}
Loading
Loading