From eb837c6d9e3827342d77e9e9417b7f683891e3d4 Mon Sep 17 00:00:00 2001 From: Kaynnan Lemes Date: Mon, 15 Jul 2024 11:02:32 -0300 Subject: [PATCH] [IMP] l10n_br_account_withholding: handling of partner_id assignment --- l10n_br_account_withholding/README.rst | 9 ++ l10n_br_account_withholding/__manifest__.py | 1 + .../models/__init__.py | 1 + .../models/account_move.py | 16 ++- .../models/res_partner.py | 20 +++ .../readme/CONFIGURE.md | 2 + l10n_br_account_withholding/readme/USAGE.md | 2 + .../static/description/index.html | 18 ++- .../tests/test_account_wh_invoice.py | 115 ++++++++++++++++++ .../views/res_partner.xml | 19 +++ 10 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 l10n_br_account_withholding/models/res_partner.py create mode 100644 l10n_br_account_withholding/views/res_partner.xml diff --git a/l10n_br_account_withholding/README.rst b/l10n_br_account_withholding/README.rst index e3d3a282eba5..47eb9897628f 100644 --- a/l10n_br_account_withholding/README.rst +++ b/l10n_br_account_withholding/README.rst @@ -103,6 +103,9 @@ estes passos: se necessário. Se um diário não for especificado, o módulo usará o diário da fatura de compra original. +3. **Definir uma Prefeitura para o ISSQN:** Crie ou edite um parceiro, + vá até a aba "Fiscal" e marque a opção "É Prefeitura". + Usage ===== @@ -115,6 +118,12 @@ impostos no Odoo: 2. **Confirmação da Fatura:** Ao confirmar a fatura de compra, o módulo gera automaticamente as faturas de retenção de impostos. +3. **Definir uma Prefeitura para o ISSQN:** Ao incluir um imposto de + retenção e informar a cidade correspondente para o ISSQN, o módulo + busca automaticamente o parceiro marcado como Prefeitura para essa + cidade. Caso não o encontre, ele retorna o parceiro padrão definido + no Grupo de Impostos. + Bug Tracker =========== diff --git a/l10n_br_account_withholding/__manifest__.py b/l10n_br_account_withholding/__manifest__.py index a84e12d3e499..27a858a077bd 100644 --- a/l10n_br_account_withholding/__manifest__.py +++ b/l10n_br_account_withholding/__manifest__.py @@ -14,6 +14,7 @@ "l10n_br_account", ], "data": [ + "views/res_partner.xml", "views/l10n_br_fiscal_tax_group.xml", "views/account_move.xml", ], diff --git a/l10n_br_account_withholding/models/__init__.py b/l10n_br_account_withholding/models/__init__.py index e958216983e8..d5d20ae7e74a 100644 --- a/l10n_br_account_withholding/models/__init__.py +++ b/l10n_br_account_withholding/models/__init__.py @@ -1,3 +1,4 @@ from . import account_move from . import l10n_br_fiscal_tax_group from . import account_move_line +from . import res_partner diff --git a/l10n_br_account_withholding/models/account_move.py b/l10n_br_account_withholding/models/account_move.py index 68918e32b4fa..918b164acfd0 100644 --- a/l10n_br_account_withholding/models/account_move.py +++ b/l10n_br_account_withholding/models/account_move.py @@ -78,8 +78,22 @@ def _prepare_wh_invoice(self, move_line, fiscal_group): """ wh_date_invoice = move_line.move_id.date wh_due_invoice = wh_date_invoice.replace(day=fiscal_group.wh_due_day) + + if fiscal_group.tax_scope == "city": + city_id = ( + self.invoice_line_ids[0].issqn_fg_city_id + if self.invoice_line_ids[0].issqn_fg_city_id + else self.partner_id.city_id + ) + partner_wh = self.env["res.partner"].search( + [("city_id", "=", city_id.id), ("wh_cityhall", "=", True)], limit=1 + ) + partner_id = partner_wh if partner_wh else fiscal_group.partner_id + else: + partner_id = fiscal_group.partner_id + values = { - "partner_id": fiscal_group.partner_id.id, + "partner_id": partner_id.id, "date": wh_date_invoice, "invoice_date": wh_date_invoice, "invoice_date_due": wh_due_invoice + relativedelta(months=1), diff --git a/l10n_br_account_withholding/models/res_partner.py b/l10n_br_account_withholding/models/res_partner.py new file mode 100644 index 000000000000..8b2fc34e5bf3 --- /dev/null +++ b/l10n_br_account_withholding/models/res_partner.py @@ -0,0 +1,20 @@ +# Copyright 2024 - TODAY, Kaynnan Lemes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + + _inherit = "res.partner" + + # TODO: Add WH fields for State and Country + wh_cityhall = fields.Boolean(string="Is City Hall?") + + _sql_constraints = [ + ( + "unique_wh_cityhall", + "UNIQUE(city_id, wh_cityhall)", + "Only one partner with the same City Hall can exist in the same city.", + ), + ] diff --git a/l10n_br_account_withholding/readme/CONFIGURE.md b/l10n_br_account_withholding/readme/CONFIGURE.md index e08f357b2aa7..c9af791e1e12 100644 --- a/l10n_br_account_withholding/readme/CONFIGURE.md +++ b/l10n_br_account_withholding/readme/CONFIGURE.md @@ -3,3 +3,5 @@ Configure a geração de faturas de retenção de impostos no Odoo seguindo este 1. **Acesse Configurações Fiscais:** Vá até `Fiscal -> Configurações -> Grupos de Impostos`. Procure por impostos retidos do tipo entrada. 2. **Configure os Impostos Retidos:** Para cada imposto que requer uma fatura de retenção, garanta que esteja corretamente configurado. Defina um fornecedor e o diário para a geração da fatura do imposto se necessário. Se um diário não for especificado, o módulo usará o diário da fatura de compra original. + +3. **Definir uma Prefeitura para o ISSQN:** Crie ou edite um parceiro, vá até a aba "Fiscal" e marque a opção "É Prefeitura". \ No newline at end of file diff --git a/l10n_br_account_withholding/readme/USAGE.md b/l10n_br_account_withholding/readme/USAGE.md index c072fec6019a..e2b1b9437134 100644 --- a/l10n_br_account_withholding/readme/USAGE.md +++ b/l10n_br_account_withholding/readme/USAGE.md @@ -3,3 +3,5 @@ Siga estes passos para utilizar a geração de faturas de retenção de impostos 1. **Criando uma Fatura de Compra:** Ao criar uma fatura de compra, aplique o imposto retido nas linhas necessárias. 2. **Confirmação da Fatura:** Ao confirmar a fatura de compra, o módulo gera automaticamente as faturas de retenção de impostos. + +3. **Definir uma Prefeitura para o ISSQN:** Ao incluir um imposto de retenção e informar a cidade correspondente para o ISSQN, o módulo busca automaticamente o parceiro marcado como Prefeitura para essa cidade. Caso não o encontre, ele retorna o parceiro padrão definido no Grupo de Impostos. \ No newline at end of file diff --git a/l10n_br_account_withholding/static/description/index.html b/l10n_br_account_withholding/static/description/index.html index 27bb533a3868..be407a7f9a27 100644 --- a/l10n_br_account_withholding/static/description/index.html +++ b/l10n_br_account_withholding/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -452,6 +453,8 @@

Configuration

Defina um fornecedor e o diário para a geração da fatura do imposto se necessário. Se um diário não for especificado, o módulo usará o diário da fatura de compra original. +
  • Definir uma Prefeitura para o ISSQN: Crie ou edite um parceiro, +vá até a aba “Fiscal” e marque a opção “É Prefeitura”.
  • @@ -463,6 +466,11 @@

    Usage

    aplique o imposto retido nas linhas necessárias.
  • Confirmação da Fatura: Ao confirmar a fatura de compra, o módulo gera automaticamente as faturas de retenção de impostos.
  • +
  • Definir uma Prefeitura para o ISSQN: Ao incluir um imposto de +retenção e informar a cidade correspondente para o ISSQN, o módulo +busca automaticamente o parceiro marcado como Prefeitura para essa +cidade. Caso não o encontre, ele retorna o parceiro padrão definido +no Grupo de Impostos.
  • @@ -498,7 +506,9 @@

    Contributors

    Maintainers

    This module is maintained by the OCA.

    -Odoo Community Association + +Odoo Community Association +

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    diff --git a/l10n_br_account_withholding/tests/test_account_wh_invoice.py b/l10n_br_account_withholding/tests/test_account_wh_invoice.py index c26b0841ecf5..0614dc45c095 100644 --- a/l10n_br_account_withholding/tests/test_account_wh_invoice.py +++ b/l10n_br_account_withholding/tests/test_account_wh_invoice.py @@ -310,3 +310,118 @@ def test_compra_para_revenda(self): 2, "The invoice should have 2 withholding invoices (PIS and COFINS).", ) + + def test_with_partner_issqn_without_city_partner(self): + "Test move with Partner defined and no ISSQN City Partner" + self.env.ref("l10n_br_fiscal.tax_group_pis_wh").generate_wh_invoice = False + self.env.ref("l10n_br_fiscal.tax_group_cofins_wh").generate_wh_invoice = False + product = self.env.ref("l10n_br_sale_commission.service_commission") + product.write( + { + "standard_price": 1000.0, + "tax_icms_or_issqn": "issqn", + "ncm_id": self.env.ref("l10n_br_fiscal.ncm_00000000").id, + "fiscal_genre_id": self.env.ref("l10n_br_fiscal.product_genre_00").id, + "fiscal_type": "09", + "taxes_id": False, + } + ) + tax_group = self.env.ref("l10n_br_fiscal.tax_group_issqn_wh") + tax_group.generate_wh_invoice = True + tax_group.journal_id = self.company_data["default_journal_purchase"].id + move_issqn = self.init_invoice( + "in_invoice", + products=[product], + partner=self.env.ref("l10n_br_base.res_partner_amd"), + document_type=self.env.ref("l10n_br_fiscal.document_55"), + fiscal_operation=self.env.ref("l10n_br_fiscal.fo_compras"), + fiscal_operation_lines=[self.env.ref("l10n_br_fiscal.fo_compras_servico")], + document_serie="1", + document_number="56", + ) + + for line_ids in move_issqn.invoice_line_ids: + line_ids.issqn_tax_id = None + line_ids.issqn_fg_city_id = self.env.ref("l10n_br_base.city_3550308") + line_ids.issqn_wh_tax_id = ( + self.env["l10n_br_fiscal.tax"] + .search([("name", "=", "ISSQN RET 5%")], order="id DESC", limit=1) + .id + ) + + move_issqn.action_post() + move_issqn._compute_wh_invoice_ids() + + partner_wh = self.env["res.partner"].search( + [ + ("city_id", "=", move_issqn.invoice_line_ids[0].issqn_fg_city_id.id), + ("wh_cityhall", "=", True), + ], + limit=1, + ) + + expected_partner_id = partner_wh if partner_wh else tax_group.partner_id + + self.assertTrue( + all( + wh_inv.partner_id == expected_partner_id + for wh_inv in move_issqn.wh_invoice_ids + ) + ) + + def test_with_partner_issqn_with_city_partner(self): + "Test move with Partner and ISSQN City Partner" + self.env.ref("l10n_br_fiscal.tax_group_pis_wh").generate_wh_invoice = False + self.env.ref("l10n_br_fiscal.tax_group_cofins_wh").generate_wh_invoice = False + product = self.env.ref("l10n_br_sale_commission.service_commission") + product.write( + { + "standard_price": 1000.0, + "tax_icms_or_issqn": "issqn", + "ncm_id": self.env.ref("l10n_br_fiscal.ncm_00000000").id, + "fiscal_genre_id": self.env.ref("l10n_br_fiscal.product_genre_00").id, + "fiscal_type": "09", + "taxes_id": False, + } + ) + tax_group = self.env.ref("l10n_br_fiscal.tax_group_issqn_wh") + tax_group.generate_wh_invoice = True + tax_group.journal_id = self.company_data["default_journal_purchase"].id + partner_cityhall = self.env["res.partner"].create( + { + "name": "Prefeitura de São Paulo", + "city_id": self.env.ref("l10n_br_base.city_3550308").id, + "state_id": self.env.ref("base.state_br_sp").id, + "country_id": self.env.ref("base.br").id, + "wh_cityhall": True, + } + ) + move_issqn = self.init_invoice( + "in_invoice", + products=[product], + partner=partner_cityhall, + document_type=self.env.ref("l10n_br_fiscal.document_55"), + fiscal_operation=self.env.ref("l10n_br_fiscal.fo_compras"), + fiscal_operation_lines=[self.env.ref("l10n_br_fiscal.fo_compras_servico")], + document_serie="1", + document_number="56", + ) + + for line_ids in move_issqn.invoice_line_ids: + line_ids.issqn_tax_id = None + line_ids.issqn_fg_city_id = self.env.ref("l10n_br_base.city_3550308") + line_ids.issqn_wh_tax_id = ( + self.env["l10n_br_fiscal.tax"] + .search([("name", "=", "ISSQN RET 5%")], order="id DESC", limit=1) + .id + ) + + move_issqn.action_post() + move_issqn._compute_wh_invoice_ids() + + self.assertTrue( + all( + wh_inv.partner_id == partner_cityhall.id + for wh_inv in move_issqn.wh_invoice_ids + ) + ) diff --git a/l10n_br_account_withholding/views/res_partner.xml b/l10n_br_account_withholding/views/res_partner.xml new file mode 100644 index 000000000000..08e4cf88f28e --- /dev/null +++ b/l10n_br_account_withholding/views/res_partner.xml @@ -0,0 +1,19 @@ + + + + + + l10n_br_fiscal.partner.form (in l10n_br_account_withholding) + res.partner + + + + + + + + +