diff --git a/l10n_br_sale_stock/README.rst b/l10n_br_sale_stock/README.rst index 5a78dd0de45b..4fced48ceee1 100644 --- a/l10n_br_sale_stock/README.rst +++ b/l10n_br_sale_stock/README.rst @@ -55,6 +55,16 @@ No configuration required. Changelog ========= +14.0.2.0.0 (2024-04-26) +~~~~~~~~~~~~~~~~~~~~~~~ +* [REF] Extraction to module sale_stock_picking_invoicing + https://github.com/OCA/account-invoicing/pull/1025 + +14.0.1.0.0 (2022-09-16) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration to version 14.0 + 12.0.1.0.0 (2020-05-29) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/l10n_br_sale_stock/__manifest__.py b/l10n_br_sale_stock/__manifest__.py index 185f3aaebcbc..d218d379900b 100644 --- a/l10n_br_sale_stock/__manifest__.py +++ b/l10n_br_sale_stock/__manifest__.py @@ -8,18 +8,13 @@ "license": "AGPL-3", "author": "Akretion, Odoo Community Association (OCA)", "website": "https://github.com/OCA/l10n-brazil", - "version": "14.0.1.4.0", + "version": "14.0.2.0.0", "maintainers": ["renatonlima", "mbcosta"], "depends": [ - "sale_stock", + "sale_stock_picking_invoicing", "l10n_br_sale", "l10n_br_stock_account", ], - "data": [ - "views/res_company_view.xml", - "views/res_config_settings_view.xml", - "views/sale_order_view.xml", - ], "demo": [ "demo/l10n_br_sale_stock_demo.xml", "demo/sale_order_demo.xml", diff --git a/l10n_br_sale_stock/demo/sale_order_demo.xml b/l10n_br_sale_stock/demo/sale_order_demo.xml index cce86702439a..d87ba01f52bc 100644 --- a/l10n_br_sale_stock/demo/sale_order_demo.xml +++ b/l10n_br_sale_stock/demo/sale_order_demo.xml @@ -7,22 +7,6 @@ no exemplo SP --> - - - True - - - - - - - + l10n_br_sale_stock - Endereço de Entrega e Faturamento diferentes @@ -45,20 +29,33 @@ draft + + 0 True - TESTE - TERMOS E CONDIÇÕES + TESTE - TERMOS E CONDIÇÕES 1 TESTE - CUSTOMER ADDITIONAL DATA + >TESTE - CUSTOMER ADDITIONAL DATA 1 TESTE - FISCAL ADDITIONAL DATA + >TESTE - FISCAL ADDITIONAL DATA 1 + Cliente Ref Test 1 + + + + + - - - Gaveta Preta + + + 2 @@ -69,12 +66,17 @@ - + - - - Cadeira de Escritório Preta + + + + 2 @@ -85,12 +87,28 @@ - + - - - Cadeira de Escritório Preta + + + This is a Note 1 + line_note + + + + + This is a Section 1 + line_section + + + + + 1 @@ -104,11 +122,11 @@ - + - + l10n_br_sale_stock - Produto e Serviço @@ -119,20 +137,36 @@ draft + + 0 True TESTE de criação de duas Notas de Serviço e Produto TESTE - CUSTOMER ADDITIONAL DATA + >TESTE - CUSTOMER ADDITIONAL DATA 2 TESTE - FISCAL ADDITIONAL DATA + >TESTE - FISCAL ADDITIONAL DATA 2 + Customer Ref Test 2 + + + + + - - - Gaveta Preta + + + 2 @@ -143,12 +177,28 @@ - + - - - Customized Odoo Development + + + This is a Note 2 + line_note + + + + + This is a Section 2 + line_section + + + + + 10 @@ -162,11 +212,11 @@ - + - + l10n_br_sale_stock - Agrupamento dos Pickings @@ -177,20 +227,33 @@ draft + + 0 True - TESTE - TERMOS E CONDIÇÕES + TESTE - TERMOS E CONDIÇÕES 3 TESTE - CUSTOMER ADDITIONAL DATA + >TESTE - CUSTOMER ADDITIONAL DATA 3 TESTE - FISCAL ADDITIONAL DATA + >TESTE - FISCAL ADDITIONAL DATA 3 + Cliente Ref Test 3 + + + + + - - - [FURN_8900] Gaveta Preta + + + 2 @@ -201,12 +264,16 @@ - + - - - Cadeira de Escritório Preta + + + 2 @@ -217,12 +284,28 @@ - + - - - Cadeira de Escritório Preta + + + This is a Note 3 + line_note + + + + + This is a Section 3 + line_section + + + + + 1 @@ -236,11 +319,11 @@ - + - + l10n_br_sale_stock - Agrupamento dos Pickings @@ -251,20 +334,33 @@ draft + + 0 True - TESTE - TERMOS E CONDIÇÕES + TESTE - TERMOS E CONDIÇÕES 4 TESTE - CUSTOMER ADDITIONAL DATA + >TESTE - CUSTOMER ADDITIONAL DATA 4 TESTE - FISCAL ADDITIONAL DATA + >TESTE - FISCAL ADDITIONAL DATA 4 + Cliente Ref Test 4 + + + + + - - - Gaveta Preta + + + 2 @@ -275,12 +371,16 @@ - + - - - Cadeira de Escritório Preta + + + 2 @@ -291,12 +391,28 @@ - + - - - Cadeira de Escritório Preta + + + This is a Note 4 + line_note + + + + + This is a Section 4 + line_section + + + + + 1 @@ -310,12 +426,12 @@ - + - + LC l10n_br_sale - Produtos @@ -325,13 +441,33 @@ draft - TESTE + + 0 + True + TESTE - TERMOS E CONDIÇÕES 1 + TESTE - CUSTOMER ADDITIONAL DATA 1 + TESTE - FISCAL ADDITIONAL DATA 1 + Customer Ref Test 1 + + + + + - - - Cadeira de Escritório Preta + + + 2 @@ -342,12 +478,28 @@ - + - - - Cadeira de Escritório Preta + + + This is a Note 1 + line_note + + + + + This is a Section 1 + line_section + + + + + 2 @@ -361,7 +513,7 @@ - + diff --git a/l10n_br_sale_stock/migrations/14.0.2.0.0/pre-migration.py b/l10n_br_sale_stock/migrations/14.0.2.0.0/pre-migration.py new file mode 100644 index 000000000000..560793e2ff5b --- /dev/null +++ b/l10n_br_sale_stock/migrations/14.0.2.0.0/pre-migration.py @@ -0,0 +1,39 @@ +# Copyright (C) 2024-Today - Akretion (). +# @author Magno Costa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openupgradelib import openupgrade + +_column_renames = { + "res_company": [ + ("sale_create_invoice_policy", "sale_invoicing_policy"), + ], +} + + +@openupgrade.migrate(use_env=True) +def migrate(env, version): + if openupgrade.column_exists(env.cr, "res_company", "sale_create_invoice_policy"): + openupgrade.logged_query( + env.cr, + """ + UPDATE res_company + SET sale_invoicing_policy = sale_create_invoice_policy; + """, + ) + + # Apagando campos para evitar mensagem 'HINT ...' + # Deleting field res.company.sale_create_invoice_policy + # (hint: fields should be explicitly removed by an upgrade script) + openupgrade.logged_query( + env.cr, + """ + DELETE FROM ir_model_fields WHERE name = 'sale_create_invoice_policy' + """, + ) + openupgrade.logged_query( + env.cr, + """ + DELETE FROM ir_model_fields WHERE name = 'button_create_invoice_invisible' + """, + ) diff --git a/l10n_br_sale_stock/models/sale_order.py b/l10n_br_sale_stock/models/sale_order.py index f20e8de1bff6..3d7bd80f7f41 100644 --- a/l10n_br_sale_stock/models/sale_order.py +++ b/l10n_br_sale_stock/models/sale_order.py @@ -1,42 +1,12 @@ # Copyright (C) 2020 Magno Costa - Akretion # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from odoo import api, fields, models +from odoo import api, models class SaleOrder(models.Model): _inherit = "sale.order" - # Make Invisible Invoice Button - button_create_invoice_invisible = fields.Boolean( - compute="_compute_get_button_create_invoice_invisible" - ) - - @api.depends("state", "order_line.invoice_status") - def _compute_get_button_create_invoice_invisible(self): - button_create_invoice_invisible = False - - lines = self.order_line.filtered( - lambda line: line.invoice_status == "to invoice" - ) - - # Somente depois do Pedido confirmado o botão pode aparecer - if self.state != "sale": - button_create_invoice_invisible = True - else: - if self.company_id.sale_create_invoice_policy == "stock_picking": - # A criação de Fatura de Serviços deve ser possível via Pedido - if not any(line.product_id.type == "service" for line in lines): - button_create_invoice_invisible = True - else: - # No caso da Politica de criação baseada no Pedido de Venda - # qdo acionado o Botão irá criar as Faturas automaticamente - # mesmo no caso de ter Produtos e Serviços - if not lines: - button_create_invoice_invisible = True - - self.button_create_invoice_invisible = button_create_invoice_invisible - @api.onchange("partner_shipping_id") def _onchange_partner_shipping_id(self): """ diff --git a/l10n_br_sale_stock/models/sale_order_line.py b/l10n_br_sale_stock/models/sale_order_line.py index 793e8cedc190..10390c0104a9 100644 --- a/l10n_br_sale_stock/models/sale_order_line.py +++ b/l10n_br_sale_stock/models/sale_order_line.py @@ -3,7 +3,7 @@ # Copyright (C) 2021 Magno Costa - Akretion # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from odoo import api, models +from odoo import models class SaleOrderLine(models.Model): @@ -19,40 +19,3 @@ def _prepare_procurement_values(self, group_id=False): values["invoice_state"] = "2binvoiced" return values - - # no trigger product_id.invoice_policy to avoid retroactively changing SO - @api.depends("qty_invoiced", "qty_delivered", "product_uom_qty", "order_id.state") - def _get_to_invoice_qty(self): - """ - Compute the quantity to invoice. If the invoice policy is order, - the quantity to invoice is calculated from the ordered quantity. - Otherwise, the quantity delivered is used. - """ - result = super()._get_to_invoice_qty() - - for line in self: - if line.order_id.state in ["sale", "done"]: - if line.product_id.invoice_policy == "order": - if ( - line.order_id.company_id.sale_create_invoice_policy - == "stock_picking" - and line.product_id.type == "product" - ): - # O correto seria que ao selecionar - # sale_create_invoice_policy 'stock_picking' os - # produtos tenham o campo invoice_policy definidos para - # 'delivery', porém para evitar que seja criada uma - # Fatura a partir do Pedido de Venda estamos - # alterando isso mesmo para os produtos definidos com - # 'order', já que a Politica de Criação da Fatura no - # caso do Tipo Produto está definida para ser a - # partir do stock.picking . - # TODO: Essa seria a melhor opção ? Por enquanto pelo - # que vi para ter o mesmo resultado, que é no caso - # sale_create_invoice_policy 'stock_picking' só ser - # possível criar a partir do sale.order Faturas das - # linhas que sejam type service sim, a outra opção - # seria sobre escrever o metodo action_invoice_create - # sem ser possível chamar o super. - line.qty_to_invoice = 0 - return result diff --git a/l10n_br_sale_stock/models/stock_move.py b/l10n_br_sale_stock/models/stock_move.py index f3b03160f8d1..91fce300b597 100644 --- a/l10n_br_sale_stock/models/stock_move.py +++ b/l10n_br_sale_stock/models/stock_move.py @@ -8,17 +8,6 @@ class StockMove(models.Model): _inherit = "stock.move" - def _get_price_unit_invoice(self, inv_type, partner, qty=1): - result = super()._get_price_unit_invoice(inv_type, partner, qty) - # Caso tenha Sale Line já vem desagrupado aqui devido ao KEY - if len(self) == 1: - # Caso venha apenas uma linha porem sem - # sale_line_id é preciso ignora-la - if self.sale_line_id and self.sale_line_id.price_unit != result: - result = self.sale_line_id.price_unit - - return result - def _get_new_picking_values(self): # IMPORTANTE: a sequencia de update dos dicionarios quando o # partner_shipping_id é diferente, o metodo do fiscal está diff --git a/l10n_br_sale_stock/models/stock_picking.py b/l10n_br_sale_stock/models/stock_picking.py index 30641d141ee1..89981f4a4091 100644 --- a/l10n_br_sale_stock/models/stock_picking.py +++ b/l10n_br_sale_stock/models/stock_picking.py @@ -7,19 +7,6 @@ class StockPicking(models.Model): _inherit = "stock.picking" - def _get_partner_to_invoice(self): - """ - If the partner has some invoicing contact defined - partner_invoice_id is auto filled, but it can also be changed. - partner_invoice_id is used if different from partner_id - """ - self.ensure_one() - partner_id = super()._get_partner_to_invoice() - if self.sale_id: - if partner_id != self.sale_id.partner_invoice_id.id: - partner_id = self.sale_id.partner_invoice_id.id - return partner_id - def _get_fiscal_partner(self): self.ensure_one() partner = super()._get_fiscal_partner() diff --git a/l10n_br_sale_stock/readme/HISTORY.rst b/l10n_br_sale_stock/readme/HISTORY.rst index 7423e2969d8e..25ef3d6c4aaa 100644 --- a/l10n_br_sale_stock/readme/HISTORY.rst +++ b/l10n_br_sale_stock/readme/HISTORY.rst @@ -1,3 +1,13 @@ +14.0.2.0.0 (2024-04-26) +~~~~~~~~~~~~~~~~~~~~~~~ +* [REF] Extraction to module sale_stock_picking_invoicing + https://github.com/OCA/account-invoicing/pull/1025 + +14.0.1.0.0 (2022-09-16) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [MIG] Migration to version 14.0 + 12.0.1.0.0 (2020-05-29) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/l10n_br_sale_stock/static/description/index.html b/l10n_br_sale_stock/static/description/index.html index bfaa389e1701..c7dad48e703b 100644 --- a/l10n_br_sale_stock/static/description/index.html +++ b/l10n_br_sale_stock/static/description/index.html @@ -379,16 +379,18 @@

Brazilian Localization Sales and Warehouse

  • Installation
  • Configuration
  • Changelog
  • -
  • Bug Tracker
  • -
  • Credits @@ -409,20 +411,33 @@

    Configuration

    Changelog

    -

    12.0.1.0.0 (2020-05-29)

    +

    14.0.2.0.0 (2024-04-26)

    -

    10.0.1.0.0 (2019-09-13)

    +

    14.0.1.0.0 (2022-09-16)

    +
      +
    • [MIG] Migration to version 14.0
    • +
    +
    +
    +

    12.0.1.0.0 (2020-05-29)

    +
      +
    • [MIG] Migration to version 12.0
    • +
    +
    +
    +

    10.0.1.0.0 (2019-09-13)

    • [MIG] Migration to version 10.0
    -

    Bug Tracker

    +

    Bug Tracker

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -430,15 +445,15 @@

    Bug Tracker

    Do not contact contributors directly about support or help with technical issues.

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Akretion
    -

    Contributors

    +

    Contributors

    -

    Other credits

    +

    Other credits

    The development of this module has been financially supported by:

    • Aketion LTDA
    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association diff --git a/l10n_br_sale_stock/tests/test_sale_stock.py b/l10n_br_sale_stock/tests/test_sale_stock.py index e413f7d84785..cd5d1f8c700e 100644 --- a/l10n_br_sale_stock/tests/test_sale_stock.py +++ b/l10n_br_sale_stock/tests/test_sale_stock.py @@ -6,6 +6,7 @@ # from stock_picking_invoicing # https://github.com/OCA/account-invoicing/blob/16.0/ # stock_picking_invoicing/tests/common.py +from odoo import exceptions from odoo.tests import Form, tagged from odoo.addons.l10n_br_stock_account.tests.common import TestBrPickingInvoicingCommon @@ -16,6 +17,29 @@ class TestSaleStock(TestBrPickingInvoicingCommon): @classmethod def setUpClass(cls): super().setUpClass() + # Problem in sale_stock_picking_invoicing + # In order to avoid errors in the tests CI environment when the tests + # Create of Invoice by Sale Order using sale.advance.payment.inv object + # is necessary let default policy as sale_order, just affect demo data. + # TODO: Is there other form to avoid this problem? + # cls.companies = cls.env["res.company"].search( + # [("sale_invoicing_policy", "=", "sale_order")] + # ) + # for company in cls.companies: + # company.sale_invoicing_policy = "stock_picking" + + def set_sale_invoicing_policy(self): + # Isso deveria estar sendo feito no setupUpClass mas retorna erro: + # l10n_br_sale_stock/tests/test_sale_stock.py", line 53, in setUpClass + # cls.companies = cls.env["res.company"].search( + # AttributeError: type object 'TestSaleStock' has no attribute 'env' + # TODO: Na v16 isso não parece acontecer, pode ser algo referente ao ORM, + # ver na migração + self.companies = self.env["res.company"].search( + [("sale_invoicing_policy", "=", "sale_order")] + ) + for company in self.companies: + company.sale_invoicing_policy = "stock_picking" def test_02_sale_stock_return(self): """ @@ -24,6 +48,7 @@ def test_02_sale_stock_return(self): of the picking. Check that a refund invoice is well generated. """ # intial so + self.set_sale_invoicing_policy() self.partner = self.env.ref("l10n_br_base.res_partner_address_ak2") self.product = self.env.ref("product.product_delivery_01") so_vals = { @@ -129,8 +154,8 @@ def test_picking_sale_order_product_and_service(self): """ Test Sale Order with product and service """ - - sale_order_2 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_2") + self.set_sale_invoicing_policy() + sale_order_2 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_2") sale_order_2.action_confirm() # Forma encontrada para chamar o metodo @@ -143,7 +168,7 @@ def test_picking_sale_order_product_and_service(self): # Deve existir apenas a Fatura/Documento Fiscal de Serviço self.assertEqual(1, sale_order.invoice_count) for invoice in sale_order.invoice_ids: - for line in invoice.invoice_line_ids: + for line in invoice.invoice_line_ids.filtered(lambda ln: ln.product_id): self.assertEqual(line.product_id.type, "service") # Confirmando a Fatura de Serviço invoice.action_post() @@ -163,6 +188,15 @@ def test_picking_sale_order_product_and_service(self): # Usado para validar a transferencia dos campos da linha # do Pedido de Venda para a linha da Fatura/Invoice sale_order_line = move.sale_line_id + # AssertionError: 0.0 != 1000.0 : + # Field amount_fiscal failed to transfer from sale.order.line + # to account.move.line + sale_order_line._onchange_product_uom() + # AssertionError: + # l10n_br_fiscal.comment() != l10n_br_fiscal.comment(2,) : + # Field comment_ids failed to transfer from sale.order.line + # to account.move.line + sale_order_line._onchange_fiscal_operation_line_id() self.assertEqual(sale_order_line.product_uom, move.product_uom) self.picking_move_state(picking) @@ -182,7 +216,9 @@ def test_picking_sale_order_product_and_service(self): self.assertEqual(invoice.invoice_payment_term_id, sale_order_2.payment_term_id) # Apenas a Fatura com a linha do produto foi criada - self.assertEqual(len(invoice.invoice_line_ids), 1) + self.assertEqual( + len(invoice.invoice_line_ids.filtered(lambda ln: ln.product_id)), 1 + ) # No Pedido de Venda devem existir duas Faturas/Documentos Fiscais # de Serviço e Produto @@ -217,26 +253,14 @@ def test_picking_sale_order_product_and_service(self): # a copia entre os objetos é testada tanto no stock.move acima # quanto na account.move.line abaixo "uom_id", - # Ao chamar o _onchange_product_id_fiscal no stock.move o - # partner_id usado no mapeamento é o do objeto, nesse teste - # 'Akretion Aluminio - SP' por ser o Endereço de Entrega - # partner_shipping_id, porém esse não é o partner_invoice_id - # 'Akretion Sao Paulo' essa diferença ocasiona diferentes - # 'Linhas de Operações Fiscal'/fiscal_operation_line_id entre: - # Objeto | Linha de Operações Fiscal - # _______________________________|____________________________ - # sale.order.line | 'Revenda não Contribuinte' - # stock.move e account.move.line | 'Revenda' - # TODO: O mapeamento da 'Linha de Operações Fiscal' precisa - # considerar os casos onde o partner_id do objeto não é o - # partner_invoice_id. Por enquanto o campo não está sendo validado - # para evitar erros aqui já que isso precisa ser resolvido em outro - # modulo ou talvez aqui porém seria apenas uma correção temporaria. - "fiscal_operation_line_id", + # Field sequence add in creation of Invoice + "sequence", ] common_fields = list(set(acl_fields) & set(sol_fields) - set(skipped_fields)) - invoice_lines = picking.invoice_ids.invoice_line_ids + invoice_lines = picking.invoice_ids.invoice_line_ids.filtered( + lambda ln: ln.product_id == sale_order_line.product_id + ) for field in common_fields: self.assertEqual( @@ -288,12 +312,13 @@ def test_picking_invoicing_partner_shipping_invoiced(self): picking and 3 moves per picking, but Partner to Shipping is different from Partner to Invoice. """ - sale_order_1 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_1") + self.set_sale_invoicing_policy() + sale_order_1 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_1") sale_order_1.action_confirm() picking = sale_order_1.picking_ids self.picking_move_state(picking) - sale_order_2 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_2") + sale_order_2 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_2") sale_order_2.action_confirm() picking2 = sale_order_2.picking_ids @@ -318,8 +343,14 @@ def test_picking_invoicing_partner_shipping_invoiced(self): # Not grouping products with different sale line, # 3 products from sale_order_1 and 1 product from sale_order_2 - self.assertEqual(len(invoice.invoice_line_ids), 4) - for inv_line in invoice.invoice_line_ids: + # sale_order_1 | 3 products | 1 Note | 1 Section + # sale_order_2 | 1 product -1 service | 1 Note | 1 Section | + len_sale_lines = len(sale_order_1.order_line) + ( + len(sale_order_2.order_line) - 1 + ) + + self.assertEqual(len(invoice.invoice_line_ids), len_sale_lines) + for inv_line in invoice.invoice_line_ids.filtered(lambda ln: ln.product_id): # TODO: No travis falha o browse aqui # l10n_br_stock_account/models/stock_invoice_onshipping.py:105 # isso não acontece no caso da empresa de Lucro Presumido @@ -340,20 +371,20 @@ def test_ungrouping_pickings_partner_shipping_different(self): picking and 3 moves per picking, the 3 has the same Partner to Invoice but one has Partner to Shipping so shouldn't be grouping. """ - - sale_order_1 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_1") + self.set_sale_invoicing_policy() + sale_order_1 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_1") sale_order_1.action_confirm() picking = sale_order_1.picking_ids self.picking_move_state(picking) - sale_order_3 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_3") + sale_order_3 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_3") sale_order_3.action_confirm() picking3 = sale_order_3.picking_ids self.picking_move_state(picking3) self.assertEqual(picking.state, "done") self.assertEqual(picking3.state, "done") - sale_order_4 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_4") + sale_order_4 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_4") sale_order_4.action_confirm() picking4 = sale_order_4.picking_ids self.picking_move_state(picking4) @@ -398,7 +429,8 @@ def test_synchronize_sale_partner_shipping_in_stock_picking(self): """ Test the synchronize Sale Partner Shipping in Stock Picking """ - sale_order_1 = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_1") + self.set_sale_invoicing_policy() + sale_order_1 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_1") sale_order_1.action_confirm() picking = sale_order_1.picking_ids sale_order_1.partner_shipping_id = self.env.ref( @@ -412,9 +444,7 @@ def test_lucro_presumido_company(self): Test Lucro Presumido Company """ self._change_user_company(self.env.ref("l10n_br_base.empresa_lucro_presumido")) - sale_order_1 = self.env.ref( - "l10n_br_sale_stock.l10n_br_sale_stock_lucro_presumido" - ) + sale_order_1 = self.env.ref("l10n_br_sale_stock.lucro_presumido-sale_order_1") sale_order_form = Form(sale_order_1) sale_order = sale_order_form.save() sale_order.incoterm = self.env.ref("account.incoterm_FOB") @@ -424,7 +454,7 @@ def test_lucro_presumido_company(self): self.picking_move_state(picking) invoice = self.create_invoice_wizard(picking) self.assertEqual(len(invoice), 1) - for inv_line in invoice.invoice_line_ids: + for inv_line in invoice.invoice_line_ids.filtered(lambda ln: ln.product_id): # TODO: No Travis quando a empresa main_company falha esse browse aqui # l10n_br_stock_account/models/stock_invoice_onshipping.py:105 # isso não acontece no caso da empresa de Lucro Presumido ou quando é @@ -432,50 +462,12 @@ def test_lucro_presumido_company(self): # seguida o l10n_br_stock_account. self.assertTrue(inv_line.tax_ids, "Error to map Sale Tax in invoice.line.") - def test_button_create_bill_in_view(self): - """ - Test Field to make Button Create Bill invisible. - """ - sale_order_form = Form(self.env.ref("l10n_br_sale.main_so_only_products")) - sale_products = sale_order_form.save() - # Caso do Pedido de Vendas em Rascunho - self.assertTrue( - sale_products.button_create_invoice_invisible, - "Field to make invisible the Button Create Bill should be" - " invisible when Sale Order is not in state Sale or Done.", - ) - sale_products.action_confirm() - self.assertTrue( - sale_products.button_create_invoice_invisible, - "Field to make invisible the button Create Bill should be" - " invisible when Sale Order has only products.", - ) - - # Caso somente Serviços - sale_order_form = Form(self.env.ref("l10n_br_sale.main_so_only_services")) - sale_only_service = sale_order_form.save() - sale_only_service.action_confirm() - self.assertFalse( - sale_only_service.button_create_invoice_invisible, - "Field to make invisible the Button Create Bill should be" - " False when the Sale Order has only Services.", - ) - - # Caso Produto e Serviço - sale_order_form = Form(self.env.ref("l10n_br_sale.main_so_product_service")) - sale_service_product = sale_order_form.save() - sale_service_product.action_confirm() - self.assertFalse( - sale_only_service.button_create_invoice_invisible, - "Field to make invisible the Button Create Bill should be" - " False when the Sale Order has Service and Product.", - ) - def test_compatible_with_international_case(self): """ Test compatibility with international cases or without Fiscal Operation. """ + self.set_sale_invoicing_policy() so_international = self.env.ref("sale.sale_order_3") so_international.fiscal_operation_id = False so_international.action_confirm() @@ -499,7 +491,8 @@ def test_compatible_with_international_case(self): def test_form_stock_picking(self): """Test Stock Picking with Form""" - sale_order = self.env.ref("l10n_br_sale_stock.main_so_l10n_br_sale_stock_1") + self.set_sale_invoicing_policy() + sale_order = self.env.ref("l10n_br_sale_stock.main_company-sale_order_1") sale_order.action_confirm() picking = sale_order.picking_ids self.picking_move_state(picking) @@ -512,3 +505,80 @@ def test_form_stock_picking(self): picking_form.invoice_state = "2binvoiced" self.assertEqual(sale_order.fiscal_operation_id, picking.fiscal_operation_id) picking_form.save() + + def test_down_payment(self): + """Test the case with Down Payment""" + self.set_sale_invoicing_policy() + sale_order_1 = self.env.ref("l10n_br_sale_stock.main_company-sale_order_1") + sale_order_1.action_confirm() + # Create Invoice Sale + context = { + "active_model": "sale.order", + "active_id": sale_order_1.id, + "active_ids": sale_order_1.ids, + } + # Test Create Invoice Policy + payment = ( + self.env["sale.advance.payment.inv"] + .with_context(context) + .create( + { + "advance_payment_method": "delivered", + } + ) + ) + with self.assertRaises(exceptions.UserError): + payment.with_context(context).create_invoices() + + # DownPayment + payment_wizard = ( + self.env["sale.advance.payment.inv"] + .with_context(context) + .create( + { + "advance_payment_method": "percentage", + "amount": 50, + } + ) + ) + payment_wizard.create_invoices() + + invoice_down_payment = sale_order_1.invoice_ids[0] + invoice_down_payment.action_post() + payment_register = Form( + self.env["account.payment.register"].with_context( + active_model="account.move", + active_ids=invoice_down_payment.ids, + ) + ) + journal_cash = self.env["account.journal"].search( + [ + ("type", "=", "cash"), + ("company_id", "=", invoice_down_payment.company_id.id), + ], + limit=1, + ) + payment_register.journal_id = journal_cash + payment_method_manual_in = self.env.ref( + "account.account_payment_method_manual_in" + ) + payment_register.payment_method_id = payment_method_manual_in + payment_register.amount = invoice_down_payment.amount_total + payment_register.save()._create_payments() + + picking = sale_order_1.picking_ids + self.picking_move_state(picking) + invoice = self.create_invoice_wizard(picking) + # 3 Products, 1 Section, 1 Note, 1 Down Payment and 1 Section + # of DownPayment added during the creation of Invoice + sale_lines = len(sale_order_1.order_line) + 1 + self.assertEqual(len(invoice.invoice_line_ids), sale_lines) + line_section = invoice.invoice_line_ids.filtered( + lambda line: line.display_type == "line_section" + ) + assert line_section, "Invoice without Line Section for Down Payment." + down_payment_line = invoice.invoice_line_ids.filtered( + lambda line: line.sale_line_ids.is_downpayment + ) + assert down_payment_line, "Invoice without Down Payment line." + invoice.action_post() diff --git a/l10n_br_sale_stock/views/res_company_view.xml b/l10n_br_sale_stock/views/res_company_view.xml deleted file mode 100644 index 745c0dc121bf..000000000000 --- a/l10n_br_sale_stock/views/res_company_view.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - l10n_br_fiscal.res.company.form - res.company - - - - - - - - - diff --git a/l10n_br_sale_stock/views/res_config_settings_view.xml b/l10n_br_sale_stock/views/res_config_settings_view.xml deleted file mode 100644 index c6f4be48273d..000000000000 --- a/l10n_br_sale_stock/views/res_config_settings_view.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - l10n_br_sale_stock.res.config.settings.form - res.config.settings - - - -
    -
    -
    -
    -
    -
    -
    - -
    diff --git a/l10n_br_sale_stock/views/sale_order_view.xml b/l10n_br_sale_stock/views/sale_order_view.xml deleted file mode 100644 index 33829f3bac45..000000000000 --- a/l10n_br_sale_stock/views/sale_order_view.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - l10n_br_sale_stock.order.form - sale.order - - 99 - - - - - - {'invisible': [('button_create_invoice_invisible', '=', True)]} - - - - {'invisible': ['|', ('button_create_invoice_invisible', '=', True), ('state', '=', 'sale')]} - - - - - diff --git a/l10n_br_sale_stock/wizards/stock_invoice_onshipping.py b/l10n_br_sale_stock/wizards/stock_invoice_onshipping.py index fd28edd2e5db..a4a66c8a3164 100644 --- a/l10n_br_sale_stock/wizards/stock_invoice_onshipping.py +++ b/l10n_br_sale_stock/wizards/stock_invoice_onshipping.py @@ -1,7 +1,7 @@ # Copyright 2020 KMEE # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import models class StockInvoiceOnshipping(models.TransientModel): @@ -15,88 +15,47 @@ def _build_invoice_values_from_pickings(self, pickings): """ invoice, values = super()._build_invoice_values_from_pickings(pickings) - pick = fields.first(pickings) - if pick.sale_id: - values.update( - { - "partner_id": pick.sale_id.partner_invoice_id.id, - } - ) - - if pick.sale_id.payment_term_id.id != values.get("invoice_payment_term_id"): - values.update( - {"invoice_payment_term_id": pick.sale_id.payment_term_id.id} - ) - - # O campo payment_mode_id é implementado com a instalação do - # l10n_br_account_nfe mas o l10n_br_sale_stock não tem - # dependencia direta desse modulo, para evitar a necessidade - # de um 'glue' modulo para resolver isso é feita a verificação - # se o campo existe antes de preenche-lo - if hasattr(pick.sale_id, "payment_mode_id"): - if pick.sale_id.payment_mode_id.id != values.get("payment_mode_id"): - values.update({"payment_mode_id": pick.sale_id.payment_mode_id.id}) - if pick.sale_id.incoterm.id != values.get("invoice_incoterm_id"): - values.update({"invoice_incoterm_id": pick.sale_id.incoterm.id}) - - if pick.sale_id.copy_note and pick.sale_id.note: + sale_pickings = pickings.filtered(lambda pk: pk.sale_id) + + # Refund case don't get values from Sale Dict + # TODO: Should get any value? + if sale_pickings and self._get_invoice_type() != "out_refund": + # Case more than one Sale Order the fields below will be join + # the others will be overwritting, as done in sale module, + # one more field include here Note + customer_data = set() + fiscal_data = set() + for picking in sale_pickings: + # TODO: Avaliar se isso deveria ser feito no l10n_br_sale, + # porque dessa forma evitaria a necessidade de ser feito aqui + picking.sale_id._prepare_invoice() + # Fields to Join # Evita enviar False quando não tem nada + # {False} {''} additional_data = "" - if pick.sale_id.manual_customer_additional_data: + if picking.sale_id.manual_customer_additional_data: additional_data = "{}".format( - pick.sale_id.manual_customer_additional_data + picking.sale_id.manual_customer_additional_data ) + customer_data.add(additional_data) + values["manual_customer_additional_data"] = additional_data + # Evita enviar False quando não tem nada + fiscal_additional_data = "" + if picking.sale_id.manual_fiscal_additional_data: + fiscal_additional_data = "{}".format( + picking.sale_id.manual_fiscal_additional_data + ) + fiscal_data.add(fiscal_additional_data) + values["manual_fiscal_additional_data"] = fiscal_additional_data + + # Fields to join + if len(sale_pickings) > 1: values.update( { - "manual_customer_additional_data": additional_data - + " TERMOS E CONDIÇÕES: {}".format(pick.sale_id.note), + "manual_customer_additional_data": ", ".join(customer_data), + "manual_fiscal_additional_data": ", ".join(fiscal_data), } ) return invoice, values - - def _get_move_key(self, move): - """ - Get the key based on the given move - :param move: stock.move recordset - :return: key - """ - key = super()._get_move_key(move) - if move.sale_line_id: - # Apesar da linha da Fatura permitir ter mais de uma linha de - # pedido de venda associada(campo sale_line_ids na invoice line) - # existe um erro a ser resolvido - # Issue https://github.com/odoo/odoo/issues/77028 - # PR https://github.com/odoo/odoo/pull/77195 - # Além disso é preciso verificar outras questões - # por exemplo datas de entrega diferentes, informações - # comerciais que são discriminadas por itens e etc. - key = key + (move.sale_line_id,) - - return key - - def _get_invoice_line_values(self, moves, invoice_values, invoice): - """ - Create invoice line values from given moves - :param moves: stock.move - :param invoice: account.invoice - :return: dict - """ - - values = super()._get_invoice_line_values(moves, invoice_values, invoice) - # Devido ao KEY com sale_line_id aqui - # vem somente um registro - if len(moves) == 1: - # Caso venha apenas uma linha porem sem - # sale_line_id é preciso ignora-la - if moves.sale_line_id: - values["sale_line_ids"] = [(6, 0, moves.sale_line_id.ids)] - values[ - "analytic_account_id" - ] = moves.sale_line_id.order_id.analytic_account_id.id - values["analytic_tag_ids"] = [ - (6, 0, moves.sale_line_id.analytic_tag_ids.ids) - ] - - return values