From 2a6c49b63a9da0feb93e80c6d674b7cc02440605 Mon Sep 17 00:00:00 2001 From: manu Date: Tue, 24 Oct 2023 11:50:57 +0200 Subject: [PATCH] [ADD]l10n_es_sigaus: manage sigaus expenses --- l10n_es_sigaus/README.rst | 126 +++++ l10n_es_sigaus/__init__.py | 4 + l10n_es_sigaus/__manifest__.py | 30 ++ l10n_es_sigaus/data/data.xml | 34 ++ l10n_es_sigaus/models/__init__.py | 17 + .../models/account_fiscal_position.py | 10 + l10n_es_sigaus/models/account_move.py | 219 ++++++++ l10n_es_sigaus/models/account_move_line.py | 26 + .../models/l10n_es_sigaus_amount.py | 67 +++ l10n_es_sigaus/models/product_category.py | 10 + l10n_es_sigaus/models/product_product.py | 19 + l10n_es_sigaus/models/product_template.py | 14 + l10n_es_sigaus/models/purchase_order.py | 128 +++++ l10n_es_sigaus/models/purchase_order_line.py | 31 ++ l10n_es_sigaus/models/res_company.py | 32 ++ l10n_es_sigaus/models/sale_order.py | 180 +++++++ l10n_es_sigaus/models/sale_order_line.py | 31 ++ l10n_es_sigaus/models/sigaus_line_mixin.py | 18 + l10n_es_sigaus/models/sigaus_mixin.py | 36 ++ l10n_es_sigaus/readme/CONFIGURE.rst | 20 + l10n_es_sigaus/readme/CONTRIBUTORS.rst | 4 + l10n_es_sigaus/readme/DESCRIPTION.rst | 1 + l10n_es_sigaus/readme/USAGE.rst | 21 + .../report/ir_actions_report_templates.xml | 21 + .../report/purchase_order_templates.xml | 21 + .../report/purchase_quotation_templates.xml | 21 + l10n_es_sigaus/security/ir.model.access.csv | 2 + l10n_es_sigaus/static/description/icon.png | Bin 0 -> 9455 bytes l10n_es_sigaus/static/description/index.html | 486 ++++++++++++++++++ l10n_es_sigaus/tests/__init__.py | 7 + l10n_es_sigaus/tests/common.py | 64 +++ .../test_l10n_es_sigaus_general_values.py | 42 ++ .../tests/test_l10n_es_sigaus_invoice.py | 183 +++++++ .../tests/test_l10n_es_sigaus_purchase.py | 227 ++++++++ .../tests/test_l10n_es_sigaus_sales.py | 395 ++++++++++++++ .../views/account_fiscal_position_views.xml | 24 + l10n_es_sigaus/views/account_move_views.xml | 63 +++ .../views/l10n_es_sigaus_amount_views.xml | 68 +++ .../views/product_category_views.xml | 14 + l10n_es_sigaus/views/product_views.xml | 14 + l10n_es_sigaus/views/purchase_views.xml | 63 +++ l10n_es_sigaus/views/report_invoice.xml | 18 + l10n_es_sigaus/views/res_company_views.xml | 30 ++ l10n_es_sigaus/views/sale_order_views.xml | 63 +++ .../l10n_es_sigaus/odoo/addons/l10n_es_sigaus | 1 + setup/l10n_es_sigaus/setup.py | 6 + 46 files changed, 2911 insertions(+) create mode 100644 l10n_es_sigaus/README.rst create mode 100644 l10n_es_sigaus/__init__.py create mode 100644 l10n_es_sigaus/__manifest__.py create mode 100644 l10n_es_sigaus/data/data.xml create mode 100644 l10n_es_sigaus/models/__init__.py create mode 100644 l10n_es_sigaus/models/account_fiscal_position.py create mode 100644 l10n_es_sigaus/models/account_move.py create mode 100644 l10n_es_sigaus/models/account_move_line.py create mode 100644 l10n_es_sigaus/models/l10n_es_sigaus_amount.py create mode 100644 l10n_es_sigaus/models/product_category.py create mode 100644 l10n_es_sigaus/models/product_product.py create mode 100644 l10n_es_sigaus/models/product_template.py create mode 100644 l10n_es_sigaus/models/purchase_order.py create mode 100644 l10n_es_sigaus/models/purchase_order_line.py create mode 100644 l10n_es_sigaus/models/res_company.py create mode 100644 l10n_es_sigaus/models/sale_order.py create mode 100644 l10n_es_sigaus/models/sale_order_line.py create mode 100644 l10n_es_sigaus/models/sigaus_line_mixin.py create mode 100644 l10n_es_sigaus/models/sigaus_mixin.py create mode 100644 l10n_es_sigaus/readme/CONFIGURE.rst create mode 100644 l10n_es_sigaus/readme/CONTRIBUTORS.rst create mode 100644 l10n_es_sigaus/readme/DESCRIPTION.rst create mode 100644 l10n_es_sigaus/readme/USAGE.rst create mode 100644 l10n_es_sigaus/report/ir_actions_report_templates.xml create mode 100644 l10n_es_sigaus/report/purchase_order_templates.xml create mode 100644 l10n_es_sigaus/report/purchase_quotation_templates.xml create mode 100644 l10n_es_sigaus/security/ir.model.access.csv create mode 100644 l10n_es_sigaus/static/description/icon.png create mode 100644 l10n_es_sigaus/static/description/index.html create mode 100644 l10n_es_sigaus/tests/__init__.py create mode 100644 l10n_es_sigaus/tests/common.py create mode 100644 l10n_es_sigaus/tests/test_l10n_es_sigaus_general_values.py create mode 100644 l10n_es_sigaus/tests/test_l10n_es_sigaus_invoice.py create mode 100644 l10n_es_sigaus/tests/test_l10n_es_sigaus_purchase.py create mode 100644 l10n_es_sigaus/tests/test_l10n_es_sigaus_sales.py create mode 100644 l10n_es_sigaus/views/account_fiscal_position_views.xml create mode 100644 l10n_es_sigaus/views/account_move_views.xml create mode 100644 l10n_es_sigaus/views/l10n_es_sigaus_amount_views.xml create mode 100644 l10n_es_sigaus/views/product_category_views.xml create mode 100644 l10n_es_sigaus/views/product_views.xml create mode 100644 l10n_es_sigaus/views/purchase_views.xml create mode 100644 l10n_es_sigaus/views/report_invoice.xml create mode 100644 l10n_es_sigaus/views/res_company_views.xml create mode 100644 l10n_es_sigaus/views/sale_order_views.xml create mode 120000 setup/l10n_es_sigaus/odoo/addons/l10n_es_sigaus create mode 100644 setup/l10n_es_sigaus/setup.py diff --git a/l10n_es_sigaus/README.rst b/l10n_es_sigaus/README.rst new file mode 100644 index 00000000000..19b3cec21d9 --- /dev/null +++ b/l10n_es_sigaus/README.rst @@ -0,0 +1,126 @@ +============== +L10n Es SIGAUS +============== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0b9e37c84abcb5a32f97a3d9a8bac4068c3f9085761220ae6438b48faf66110f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--spain-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-spain/tree/16.0/l10n_es_sigaus + :alt: OCA/l10n-spain +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-spain-16-0/l10n-spain-16-0-l10n_es_sigaus + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-spain&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Este módulo permite calcular y agregar a las ventas, compras y facturas la aportación SIGAUS. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Se tienen que configurar los siguientes aspectos: + +* La configuración del precio de la aportación SIGAUS que se aplica durante un periodo de tiempo se realiza desde Invoicing > Configuration > L10n Es Sigaus Amount. En caso de no rellenar el campo "Date To", el precio seleccionado se aplicará a partir de la fecha indicada en "Date To". El precio establecido dentro del periodo marcado se utilizará siempre que se calcule la aportación SIGAUS desde ventas, facturas o compras. + +* Es necesario indicar aquellas compañías en las que seaplicará la aportación SIGAUS. Para ello, hay que acceder a la pestaña SIGAUS de la configuración de la compañía y marcar la casilla "Enable SIGAUS". Dos opciones adicionales aparecen cuando esta opción está marcada: + * "Show detailed SIGAUS amount in report lines": Si la opción está marcada, se mostrará la aportación SIGAUS de cada una de las líneas de venta, compra y facturas en los informes. + * "Automate SIGAUS": Si la opción está marcada, la aportación SIGAUS se recalculará en los pedidos de venta de manera automática cada vez que se creen o se actualicen, sin necesidad de hacerlo manualmente y siempre que sea aplicable. Asimismo, en caso de que se marque la casilla "No subject to SIGAUS" en los pedidos de venta, se eliminarán las líneas de aportación SIGAUS en caso de haber alguna presente. + +* Se puede establecer que los productos de ciertas categorías de producto están sujetas a SIGAUS accediendo a la configuración de la categoría y marcando la casilla "Subject To Sigaus". + +* Desde la ficha de los productos, pueden establecerse varias opciones de sujeción a la aportación SIGAUS desde el campo "Subject To Sigaus". Existen tres opciones: + * "Category": La aplicación o no de la aportación SIGAUS para ese producto depende se si la casilla "Subject To Sigaus" está o no marcada en la categoría establecida. + * "Yes": Se aplica siempre la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto. + * "No": No se aplica nunca la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto. + +Cuando se calcule la aportación SIGAUS en ventas, compras y facturas, se tendrá en cuenta el peso de todos aquellos productos a los que se les aplica la aportación SIGAUS para determinar el importe. + +* Todos los productos a los que se le aplica la aportación SIGAUS deben tener un peso establecido. + +Usage +===== + +* Para aplicar la aportación SIGAUS en las ventas, las compras o las facturas, hay que pulsar en el botón "Apply Sigaus". + +* En caso de producirse cambios en las líneas, se puede recalcular la aportación SIGAUS pulsando en el botón "Recompute Sigaus". + +* El importe de la aportación SIGAUS se calculará a partir de los pesos de aquellos productos sujetos a dicha aportación y el precio establecido en "L10n Es Sigaus Amount" según la fecha actual. + +* Los productos sujetos a aportación SIGAUS son los siguientes: + * Aquellos que tienen establecida la opción "Yes" en el campo "Subject to SIGAUS" + * Aquellos que tienen establecida la opción "Category" en el campo "Subject to SIGAUS" y cuya categoría tenga marcada la opción "Subject to SIGAUS". + +* En caso de generar una factura parcial a partir de una venta o una compra, solamente se facturará la parte proporcional de la aportación SIGAUS correspondiente a los productos facturados. + +* En caso de generar una factura a partir de varios pedidos de venta o compra, se generará una línea de aportación SIGAUS por cada uno de los pedidos que contengan dicha aportación. + +* Saltará un error si al calcular la aportación SIGAUS, alguno de los productos sujetos no tiene un peso establecido. + +* La aportación SIGAUS establecida en ventas y compras se transfiere a las facturas. + +* En ventas y facturas, si se marca la opción "No subject to SIGAUS", no se aplicará la aportación SIGAUS. + +* Más información en https://www.sigaus.es + +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 +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Sygel + +Contributors +~~~~~~~~~~~~ + +* `Sygel `_: + * Manuel Regidor + * Harald Panten + * Valentín Vinagre + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/l10n-spain `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_es_sigaus/__init__.py b/l10n_es_sigaus/__init__.py new file mode 100644 index 00000000000..82e095d9f36 --- /dev/null +++ b/l10n_es_sigaus/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/l10n_es_sigaus/__manifest__.py b/l10n_es_sigaus/__manifest__.py new file mode 100644 index 00000000000..e7d392351dd --- /dev/null +++ b/l10n_es_sigaus/__manifest__.py @@ -0,0 +1,30 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "L10n Es SIGAUS", + "summary": "Apply SIGAUS to sales, purchases and invoices.", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Sygel, Odoo Community Association (OCA)", + "category": "Sales", + "website": "https://github.com/OCA/l10n-spain", + "depends": ["base", "account", "sale", "purchase", "base_automation"], + "data": [ + "data/data.xml", + "security/ir.model.access.csv", + "views/l10n_es_sigaus_amount_views.xml", + "views/product_category_views.xml", + "views/product_views.xml", + "views/sale_order_views.xml", + "views/purchase_views.xml", + "views/account_move_views.xml", + "views/report_invoice.xml", + "views/res_company_views.xml", + "views/account_fiscal_position_views.xml", + "report/ir_actions_report_templates.xml", + "report/purchase_order_templates.xml", + "report/purchase_quotation_templates.xml", + ], + "installable": True, +} diff --git a/l10n_es_sigaus/data/data.xml b/l10n_es_sigaus/data/data.xml new file mode 100644 index 00000000000..6498bdca3b4 --- /dev/null +++ b/l10n_es_sigaus/data/data.xml @@ -0,0 +1,34 @@ + + + + + Aportación SIGAUS (R.D. 679/2006) + + service + 0.0 + no + order + + + purchase + + + + + + + Aportación SIGAUS 2023 + 2023-1-1 + 2023-12-31 + 0.06 + + + + + Aportación SIGAUS 2024 + 2024-1-1 + 0.05 + + + diff --git a/l10n_es_sigaus/models/__init__.py b/l10n_es_sigaus/models/__init__.py new file mode 100644 index 00000000000..5df8fafad99 --- /dev/null +++ b/l10n_es_sigaus/models/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import sigaus_mixin +from . import sigaus_line_mixin +from . import l10n_es_sigaus_amount +from . import product_category +from . import product_template +from . import product_product +from . import sale_order +from . import sale_order_line +from . import purchase_order +from . import purchase_order_line +from . import account_move +from . import account_move_line +from . import res_company +from . import account_fiscal_position diff --git a/l10n_es_sigaus/models/account_fiscal_position.py b/l10n_es_sigaus/models/account_fiscal_position.py new file mode 100644 index 00000000000..e6b853bce24 --- /dev/null +++ b/l10n_es_sigaus/models/account_fiscal_position.py @@ -0,0 +1,10 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountFiscalPosition(models.Model): + _inherit = "account.fiscal.position" + + subject_to_sigaus = fields.Boolean() diff --git a/l10n_es_sigaus/models/account_move.py b/l10n_es_sigaus/models/account_move.py new file mode 100644 index 00000000000..d9a698efb0d --- /dev/null +++ b/l10n_es_sigaus/models/account_move.py @@ -0,0 +1,219 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class AccountMove(models.Model): + _name = "account.move" + _inherit = ["account.move", "sigaus.mixin"] + + @api.depends( + "company_id", + "invoice_date", + "no_sigaus", + "fiscal_position_id", + "invoice_line_ids", + "move_type", + ) + def _compute_is_sigaus(self): + sigaus_moves = self.filtered( + lambda a: a.company_id.enable_sigaus + and a.invoice_date + and a.invoice_date >= a.company_id.sigaus_date_from + and not a.no_sigaus + and (not a.fiscal_position_id or a.fiscal_position_id.subject_to_sigaus) + and any( + line.product_id.has_sigaus_amount + for line in a.invoice_line_ids.filtered(lambda a: a.product_id) + ) + and a.is_invoice() + ) + sigaus_moves.write({"is_sigaus": True}) + (self - sigaus_moves).write({"is_sigaus": False}) + + @api.depends("is_sigaus", "state", "invoice_line_ids") + def _compute_show_delete_sigaus_button(self): + show_delete_sigaus_button_moves = self.filtered( + lambda a: a.is_sigaus + and a.state == "draft" + and any(line.is_sigaus for line in a.invoice_line_ids) + ) + show_delete_sigaus_button_moves.show_delete_sigaus_button = True + (self - show_delete_sigaus_button_moves).show_delete_sigaus_button = False + + @api.depends("is_sigaus", "state") + def _compute_show_sigaus_button(self): + show_sigaus_button_moves = self.filtered( + lambda a: a.is_sigaus and a.state == "draft" + ) + show_sigaus_button_moves.show_sigaus_button = True + (self - show_sigaus_button_moves).show_sigaus_button = False + + @api.depends("invoice_line_ids") + def _compute_has_sigaus_line(self): + has_sigaus_line_moves = self.filtered( + lambda a: any(line.is_sigaus for line in a.invoice_line_ids) + ) + has_sigaus_line_moves.has_sigaus_line = True + (self - has_sigaus_line_moves).has_sigaus_line = False + + @api.depends("company_id") + def _compute_company_sigaus(self): + return super()._compute_company_sigaus() + + @api.onchange("invoice_line_ids") + def _onchange_recompute_sigaus(self): + self.ensure_one() + if self.invoice_line_ids.filtered("is_sigaus"): + self.recompute_sigaus = True + + def get_sigaus_vals(self, lines, order_line=False): + vals = dict() + sigaus_product_id = self.env.ref( + "l10n_es_sigaus.aportacion_sigaus_product_template" + ) + if not sigaus_product_id: + raise ValidationError(_("Sigaus product could not be found.")) + vals["product_id"] = sigaus_product_id.id + kg_uom_id = self.env.ref("uom.product_uom_kgm") + if not kg_uom_id: + raise ValidationError(_("Kg. UOM could not be found.")) + vals["product_uom_id"] = kg_uom_id.id + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount(self.invoice_date) + products_without_weight = lines.mapped("product_id").filtered( + lambda a: a.weight <= 0.0 + ) + if products_without_weight: + raise ValidationError( + _("The following products have no weight: %(prods)s.") + % {"prods": ", ".join(products_without_weight.mapped("name"))} + ) + weight = sum( + line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id) + * line.product_id.weight + for line in lines + ) + vals.update( + { + "move_id": self.id, + "quantity": weight, + "price_unit": price, + "is_sigaus": True, + } + ) + if order_line: + vals["sale_line_ids"] = [order_line.id] + return vals + + @api.model + def modify_sigaus_line(self, sigaus_line, lines): + weight = sum( + line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id) + * line.product_id.weight + for line in lines + ) + sigaus_line.write({"quantity": weight}) + + @api.model + def create_sigaus_line(self, lines, order_line=False): + values = self.get_sigaus_vals(lines, order_line) + self.env["account.move.line"].create(values) + + def manage_sales_sigaus_lines(self): + self.ensure_one() + sigaus_lines = self.invoice_line_ids.filtered( + lambda a: a.is_sigaus and a.sale_line_ids + ) + for sigaus_line in sigaus_lines: + order_id = sigaus_line.sale_line_ids.order_id[0] + lines_from_order = self.invoice_line_ids.filtered( + lambda a: a.sale_line_ids.order_id == order_id + and a.product_id + and a.product_id.has_sigaus_amount + ) + self.modify_sigaus_line(sigaus_line, lines_from_order) + + # In case Sigaus Lines do not exist in the invoice + # i.e. the line has been deleted in the invoice + sigaus_lines_in_orders = self.invoice_line_ids.mapped( + "sale_line_ids.order_id.order_line" + ).filtered(lambda a: a.is_sigaus) + not_used_sigaus_lines_in_orders = sigaus_lines_in_orders - sigaus_lines.mapped( + "sale_line_ids" + ) + for sigaus_line in not_used_sigaus_lines_in_orders: + order_id = sigaus_line.order_id + lines = self.invoice_line_ids.filtered( + lambda a: a.sale_line_ids.order_id == order_id + and a.product_id + and a.product_id.has_sigaus_amount + ) + if lines: + self.create_sigaus_line(lines, sigaus_line) + sigaus_lines = self.invoice_line_ids.filtered( + lambda a: a.is_sigaus and a.sale_line_ids + ) + if len(sigaus_lines) > 1: + for sigaus_line in sigaus_lines.filtered( + lambda a: a.sale_line_ids.order_id.name not in a.name + ): + sigaus_line.write( + { + "name": "{}: {}".format( + sigaus_line.sale_line_ids.order_id.name, sigaus_line.name + ) + } + ) + + def manage_purchase_sigaus_lines(self): + for sel in self: + for sigaus_line in sel.invoice_line_ids.filtered( + lambda a: a.is_sigaus and a.purchase_order_id + ): + order_id = sigaus_line.purchase_order_id + lines_from_order = sel.invoice_line_ids.filtered( + lambda a: a.purchase_order_id == order_id + and a.product_id + and a.product_id.has_sigaus_amount + ) + sel.modify_sigaus_line(sigaus_line, lines_from_order) + + def manage_independent_invoice_lines(self): + self.ensure_one() + self.invoice_line_ids.filtered( + lambda a: a.is_sigaus and not (a.sale_line_ids or a.purchase_order_id) + ).unlink() + # Invoice lines not related to sales or purchases + lines = self.invoice_line_ids.filtered( + lambda a: not (a.sale_line_ids or a.purchase_order_id) + and a.product_id + and a.product_id.has_sigaus_amount + ) + if lines: + self.create_sigaus_line(lines) + + def action_apply_sigaus(self): + for sel in self.filtered(lambda a: a.is_sigaus): + # Check Sigaus lines related to sale orders + if sel.move_type in ["out_invoice", "out_refund"]: + sel.manage_sales_sigaus_lines() + # Check Sigaus lines related to purchase orders + elif sel.move_type in ["in_invoice", "in_refund"]: + sel.manage_purchase_sigaus_lines() + # Check Sigaus lines not related to sale or purchase orders + sel.manage_independent_invoice_lines() + self.filtered(lambda a: a.is_sigaus).write({"recompute_sigaus": False}) + + def action_delete_sigaus(self): + self.filtered(lambda a: a.state == "draft").mapped("invoice_line_ids").filtered( + lambda b: b.is_sigaus + ).unlink() + + @api.model_create_multi + def create(self, vals_list): + moves = super().create(vals_list) + if self.env.context.get("from_purchase"): + moves.filtered("is_sigaus").manage_purchase_sigaus_lines() + return moves diff --git a/l10n_es_sigaus/models/account_move_line.py b/l10n_es_sigaus/models/account_move_line.py new file mode 100644 index 00000000000..4faea9cc46b --- /dev/null +++ b/l10n_es_sigaus/models/account_move_line.py @@ -0,0 +1,26 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountMoveLine(models.Model): + _name = "account.move.line" + _inherit = ["account.move.line", "sigaus.line.mixin"] + + recompute_sigaus = fields.Boolean(related="move_id.recompute_sigaus") + + def _compute_sigaus_amount(self): + sigaus_amount_lines = self.filtered( + lambda a: a.product_id and a.product_id.has_sigaus_amount + ) + for line in sigaus_amount_lines: + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount( + line.move_id.date + ) + quantity = line.product_uom_id._compute_quantity( + line.quantity, line.product_id.uom_id + ) + weight = quantity * line.product_id.weight + line.sigaus_amount = weight * price + (self - sigaus_amount_lines).sigaus_amount = False diff --git a/l10n_es_sigaus/models/l10n_es_sigaus_amount.py b/l10n_es_sigaus/models/l10n_es_sigaus_amount.py new file mode 100644 index 00000000000..3c1eeea95b7 --- /dev/null +++ b/l10n_es_sigaus/models/l10n_es_sigaus_amount.py @@ -0,0 +1,67 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class L10nEsSigausAmount(models.Model): + _name = "l10n.es.sigaus.amount" + _description = "L10n Es Sigaus Amount" + + name = fields.Char(required=True) + date_from = fields.Date(required=True) + date_to = fields.Date() + price = fields.Float(digits="Product Price", required=True) + + @api.constrains("date_from", "date_to") + def _check_dates(self): + for sel in self: + date_from = sel.date_from + date_to = sel.date_to + if date_to and date_to < date_from: + raise ValidationError( + _("The ending date must not be prior to the starting date.") + ) + domain = [ + ("id", "!=", sel.id), + "|", + "|", + "|", + "|", + "&", + ("date_from", "<=", sel.date_from), + "|", + ("date_to", ">=", sel.date_from), + ("date_to", "=", False), + "&", + ("date_from", "<=", sel.date_to), + ("date_to", ">=", sel.date_to), + "&", + ("date_from", "<=", sel.date_from), + ("date_to", ">=", sel.date_to), + "&", + ("date_from", ">=", sel.date_from), + ("date_to", "<=", sel.date_to), + "&", + ("date_from", ">=", sel.date_from), + ("date_from", "<=", sel.date_to), + ] + + if self.search_count(domain) > 0: + raise ValidationError(_("You can not have overlapping date ranges.")) + + @api.model + def get_sigaus_amount(self, date): + l10n_es_sigaus_amount_id = self.search( + [ + ("date_from", "<=", date), + "|", + ("date_to", ">=", date), + ("date_to", "=", False), + ], + limit=1, + ) + if not l10n_es_sigaus_amount_id: + raise ValidationError(_("There is not a price set for the current date.")) + return l10n_es_sigaus_amount_id.price diff --git a/l10n_es_sigaus/models/product_category.py b/l10n_es_sigaus/models/product_category.py new file mode 100644 index 00000000000..2cfa39bd8c2 --- /dev/null +++ b/l10n_es_sigaus/models/product_category.py @@ -0,0 +1,10 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + subject_to_sigaus = fields.Boolean() diff --git a/l10n_es_sigaus/models/product_product.py b/l10n_es_sigaus/models/product_product.py new file mode 100644 index 00000000000..4faa866f4cd --- /dev/null +++ b/l10n_es_sigaus/models/product_product.py @@ -0,0 +1,19 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + has_sigaus_amount = fields.Boolean(compute="_compute_has_sigaus_amount", store=True) + + @api.depends("subject_to_sigaus", "categ_id", "categ_id.subject_to_sigaus") + def _compute_has_sigaus_amount(self): + has_sigaus_amount_products = self.filtered( + lambda a: a.subject_to_sigaus == "yes" + or (a.subject_to_sigaus == "category" and a.categ_id.subject_to_sigaus) + ) + has_sigaus_amount_products.write({"has_sigaus_amount": True}) + (self - has_sigaus_amount_products).write({"has_sigaus_amount": False}) diff --git a/l10n_es_sigaus/models/product_template.py b/l10n_es_sigaus/models/product_template.py new file mode 100644 index 00000000000..9d2879efa57 --- /dev/null +++ b/l10n_es_sigaus/models/product_template.py @@ -0,0 +1,14 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + subject_to_sigaus = fields.Selection( + [("category", "Category"), ("yes", "Yes"), ("no", "No")], + default="category", + required=True, + ) diff --git a/l10n_es_sigaus/models/purchase_order.py b/l10n_es_sigaus/models/purchase_order.py new file mode 100644 index 00000000000..f7710190f81 --- /dev/null +++ b/l10n_es_sigaus/models/purchase_order.py @@ -0,0 +1,128 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class PurchaseOrder(models.Model): + _name = "purchase.order" + _inherit = ["purchase.order", "sigaus.mixin"] + + @api.depends( + "company_id", "date_order", "fiscal_position_id", "order_line", "no_sigaus" + ) + def _compute_is_sigaus(self): + is_sigaus_orders = self.filtered( + lambda a: a.company_id.enable_sigaus + and a.date_order + and a.date_order.date() >= a.company_id.sigaus_date_from + and (not a.fiscal_position_id or a.fiscal_position_id.subject_to_sigaus) + and any( + line.product_id.has_sigaus_amount + for line in a.order_line.filtered(lambda a: a.product_id) + ) + and not a.no_sigaus + ) + is_sigaus_orders.write({"is_sigaus": True}) + (self - is_sigaus_orders).write({"is_sigaus": False}) + + @api.depends("company_id") + def _compute_company_sigaus(self): + return super()._compute_company_sigaus() + + @api.depends("is_sigaus", "state") + def _compute_show_sigaus_button(self): + show_sigaus_button_orders = self.filtered( + lambda a: a.is_sigaus and a.state in ["draft", "sent"] + ) + show_sigaus_button_orders.show_sigaus_button = True + (self - show_sigaus_button_orders).show_sigaus_button = False + + @api.depends("is_sigaus", "state", "order_line") + def _compute_show_delete_sigaus_button(self): + show_delete_sigaus_button_orders = self.filtered( + lambda a: a.is_sigaus + and a.state in ["draft", "sent"] + and any(line.is_sigaus for line in a.order_line) + ) + show_delete_sigaus_button_orders.show_delete_sigaus_button = True + (self - show_delete_sigaus_button_orders).show_delete_sigaus_button = False + + @api.depends("order_line") + def _compute_has_sigaus_line(self): + has_sigaus_line_orders = self.filtered( + lambda a: any(line.is_sigaus for line in a.order_line) + ) + has_sigaus_line_orders.has_sigaus_line = True + (self - has_sigaus_line_orders).has_sigaus_line = False + + @api.onchange("order_line") + def _onchange_recompute_sigaus(self): + self.ensure_one() + if self.order_line.filtered("is_sigaus"): + self.recompute_sigaus = True + + def get_sigaus_line_vals(self): + self.ensure_one() + sigaus_vals = dict() + sigaus_product_id = self.env.ref( + "l10n_es_sigaus.aportacion_sigaus_product_template" + ) + if not sigaus_product_id: + raise ValidationError(_("Sigaus product could not be found.")) + sigaus_vals["product_id"] = sigaus_product_id.id + kg_uom_id = self.env.ref("uom.product_uom_kgm") + if not kg_uom_id: + raise ValidationError(_("Kg. UOM could not be found.")) + sigaus_vals["product_uom"] = kg_uom_id.id + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount(self.date_order) + self.order_line.filtered(lambda a: a.product_id == sigaus_product_id).unlink() + lines = self.order_line.filtered( + lambda a: a.product_id.subject_to_sigaus == "yes" + or ( + a.product_id.subject_to_sigaus == "category" + and a.product_id.categ_id.subject_to_sigaus + ) + ) + products_without_weight = lines.mapped("product_id").filtered( + lambda a: a.weight <= 0.0 + ) + if products_without_weight: + raise ValidationError( + _("The following products have no weight: %(prods)s.") + % {"prods": ", ".join(products_without_weight.mapped("name"))} + ) + weight = sum( + line.product_uom._compute_quantity(line.product_qty, line.product_id.uom_id) + * line.product_id.weight + for line in lines + ) + sigaus_vals.update( + { + "order_id": self.id, + "product_qty": weight, + "price_unit": price, + "is_sigaus": True, + } + ) + if self.order_line: + sigaus_vals["sequence"] = self.order_line[-1].sequence + 1 + return sigaus_vals + + def action_apply_sigaus(self): + for sel in self.filtered( + lambda a: a.is_sigaus and a.state in ["draft", "sent"] + ): + sigaus_vals = sel.get_sigaus_line_vals() + self.env["purchase.order.line"].create(sigaus_vals) + sel.recompute_sigaus = False + + def action_delete_sigaus(self): + self.filtered(lambda a: a.state in ["draft", "sent"]).mapped( + "order_line" + ).filtered(lambda b: b.is_sigaus).unlink() + + def action_create_invoice(self): + obj = self.with_context(from_purchase=True) + return super(PurchaseOrder, obj).action_create_invoice() diff --git a/l10n_es_sigaus/models/purchase_order_line.py b/l10n_es_sigaus/models/purchase_order_line.py new file mode 100644 index 00000000000..7b74549bd7f --- /dev/null +++ b/l10n_es_sigaus/models/purchase_order_line.py @@ -0,0 +1,31 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class PurchaseOrderLine(models.Model): + _name = "purchase.order.line" + _inherit = ["purchase.order.line", "sigaus.line.mixin"] + + recompute_sigaus = fields.Boolean(related="order_id.recompute_sigaus") + + def _compute_sigaus_amount(self): + sigaus_amount_lines = self.filtered( + lambda a: a.product_id and a.product_id.has_sigaus_amount + ) + for line in sigaus_amount_lines: + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount( + line.order_id.date_order + ) + quantity = line.product_uom._compute_quantity( + line.product_qty, line.product_id.uom_id + ) + weight = quantity * line.product_id.weight + line.sigaus_amount = weight * price + (self - sigaus_amount_lines).sigaus_amount = False + + def _prepare_account_move_line(self, move=False): + res = super()._prepare_account_move_line(move) + res["is_sigaus"] = self.is_sigaus + return res diff --git a/l10n_es_sigaus/models/res_company.py b/l10n_es_sigaus/models/res_company.py new file mode 100644 index 00000000000..47f1865de0f --- /dev/null +++ b/l10n_es_sigaus/models/res_company.py @@ -0,0 +1,32 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ResCompany(models.Model): + _inherit = "res.company" + + enable_sigaus = fields.Boolean() + sigaus_date_from = fields.Date(help="SIGAUS can only be applied from this date.") + show_sigaus_in_reports = fields.Boolean( + string="Show detailed SIGAUS amount in report lines", + help="If active, SIGAUS amount is shown in sales, " + "invoices, and purchases lines.", + ) + automate_sigaus_sales = fields.Boolean( + string="Automate SIGAUS", + help="If checked, SIGAUS will be automatically applied " + "in sale orders subjected to it with no need of any " + "manual action. It will also delete SIGAUS lines when the " + "option 'No subject to Sigaus' in sales is checked. These " + "actions are every time a sale order is created or updated.", + ) + + @api.constrains("enable_sigaus", "sigaus_date_from") + def _check_sigaus_date(self): + if self.filtered(lambda a: a.enable_sigaus and not a.sigaus_date_from): + raise ValidationError( + _("'Sigaus Date From' is mandatory for companies with SIGAUS enabled.") + ) diff --git a/l10n_es_sigaus/models/sale_order.py b/l10n_es_sigaus/models/sale_order.py new file mode 100644 index 00000000000..43cfcc6b4da --- /dev/null +++ b/l10n_es_sigaus/models/sale_order.py @@ -0,0 +1,180 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools import frozendict + + +class SaleOrder(models.Model): + _name = "sale.order" + _inherit = ["sale.order", "sigaus.mixin"] + + automate_sigaus = fields.Boolean(compute="_compute_automate_sigaus", store=True) + + @api.depends( + "company_id", "date_order", "no_sigaus", "fiscal_position_id", "order_line" + ) + def _compute_is_sigaus(self): + is_sigaus_orders = self.filtered( + lambda a: a.company_id.enable_sigaus + and a.date_order + and a.date_order.date() >= a.company_id.sigaus_date_from + and not a.no_sigaus + and (not a.fiscal_position_id or a.fiscal_position_id.subject_to_sigaus) + and any( + line.product_id.has_sigaus_amount + for line in a.order_line.filtered(lambda a: a.product_id) + ) + ) + is_sigaus_orders.write({"is_sigaus": True}) + (self - is_sigaus_orders).write({"is_sigaus": False}) + + @api.depends( + "is_sigaus", + "state", + "company_id", + "order_line", + ) + def _compute_show_delete_sigaus_button(self): + show_delete_sigaus_button_order = self.filtered( + lambda a: a.is_sigaus + and a.state in ["draft", "sent"] + and not a.company_id.automate_sigaus_sales + and any(line.is_sigaus for line in a.order_line) + ) + show_delete_sigaus_button_order.show_delete_sigaus_button = True + (self - show_delete_sigaus_button_order).show_delete_sigaus_button = False + + @api.depends( + "is_sigaus", + "state", + "company_id", + ) + def _compute_show_sigaus_button(self): + show_sigaus_button_order = self.filtered( + lambda a: a.is_sigaus + and a.state in ["draft", "sent"] + and not a.company_id.automate_sigaus_sales + ) + show_sigaus_button_order.show_sigaus_button = True + (self - show_sigaus_button_order).show_sigaus_button = False + + @api.depends("order_line") + def _compute_has_sigaus_line(self): + has_sigaus_line_orders = self.filtered( + lambda a: any(line.is_sigaus for line in a.order_line) + ) + has_sigaus_line_orders.has_sigaus_line = True + (self - has_sigaus_line_orders).has_sigaus_line = False + + @api.depends("company_id") + def _compute_company_sigaus(self): + return super()._compute_company_sigaus() + + @api.depends("is_sigaus", "company_id", "state") + def _compute_automate_sigaus(self): + automate_sigaus_orders = self.filtered( + lambda a: a.is_sigaus + and a.company_id.automate_sigaus_sales + and a.state in ["draft", "sent"] + ) + automate_sigaus_orders.automate_sigaus = True + (self - automate_sigaus_orders).automate_sigaus = False + + @api.onchange("order_line") + def _onchange_recompute_sigaus(self): + self.ensure_one() + if self.order_line.filtered("is_sigaus"): + self.recompute_sigaus = True + + def get_sigaus_line_vals(self): + self.ensure_one() + sigaus_vals = dict() + sigaus_product_id = self.env.ref( + "l10n_es_sigaus.aportacion_sigaus_product_template" + ) + if not sigaus_product_id: + raise ValidationError(_("Sigaus product could not be found.")) + sigaus_vals["product_id"] = sigaus_product_id.id + kg_uom_id = self.env.ref("uom.product_uom_kgm") + if not kg_uom_id: + raise ValidationError(_("Kg. UOM could not be found.")) + sigaus_vals["product_uom"] = kg_uom_id.id + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount(self.date_order) + self.order_line.filtered(lambda a: a.product_id == sigaus_product_id).unlink() + lines = self.order_line.filtered( + lambda a: a.product_id and a.product_id.has_sigaus_amount + ) + products_without_weight = lines.mapped("product_id").filtered( + lambda a: a.weight <= 0.0 + ) + if products_without_weight: + raise ValidationError( + _("The following products have no weight: %(prods)s.") + % {"prods": ", ".join(products_without_weight.mapped("name"))} + ) + weight = sum( + line.product_uom._compute_quantity( + line.product_uom_qty, line.product_id.uom_id + ) + * line.product_id.weight + for line in lines + ) + sigaus_vals.update( + { + "order_id": self.id, + "product_uom_qty": weight, + "price_unit": price, + "is_sigaus": True, + } + ) + if self.order_line: + sigaus_vals["sequence"] = self.order_line[-1].sequence + 1 + return sigaus_vals + + def action_apply_sigaus(self): + for sel in self.filtered( + lambda a: a.is_sigaus and a.state in ["draft", "sent"] + ): + sigaus_vals = sel.get_sigaus_line_vals() + self.env["sale.order.line"].create(sigaus_vals) + sel.recompute_sigaus = False + + def action_delete_sigaus(self): + self.filtered(lambda a: a.state in ["draft", "sent"]).mapped( + "order_line" + ).filtered(lambda b: b.is_sigaus).unlink() + + def _create_invoices(self, grouped=False, final=False, date=None): + moves = super()._create_invoices(grouped, final, date) + for move in moves.filtered("is_sigaus"): + move.manage_sales_sigaus_lines() + return moves + + def _prepare_invoice(self): + vals = super()._prepare_invoice() + vals["no_sigaus"] = self.no_sigaus + return vals + + def write(self, vals): + res = super().write(vals) + sigaus_sales = self.filtered(lambda a: a.is_sigaus and a.automate_sigaus) + for sale in sigaus_sales: + if self.env.context.get("avoid_recursion"): + continue + sale.with_context(avoid_recursion=True).action_apply_sigaus() + sale.env.context = frozendict( + {**sale.env.context, "avoid_recursion": False} + ) + (self - sigaus_sales).filtered( + lambda a: a.no_sigaus and a.has_sigaus_line + ).action_delete_sigaus() + return res + + @api.model_create_multi + def create(self, vals_list): + sales = super().create(vals_list) + for sale in sales.filtered(lambda a: a.is_sigaus and a.automate_sigaus): + sale.action_apply_sigaus() + return sales diff --git a/l10n_es_sigaus/models/sale_order_line.py b/l10n_es_sigaus/models/sale_order_line.py new file mode 100644 index 00000000000..47d057ddb6d --- /dev/null +++ b/l10n_es_sigaus/models/sale_order_line.py @@ -0,0 +1,31 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class SaleOrderLine(models.Model): + _name = "sale.order.line" + _inherit = ["sale.order.line", "sigaus.line.mixin"] + + recompute_sigaus = fields.Boolean(related="order_id.recompute_sigaus") + + def _compute_sigaus_amount(self): + sigaus_amount_lines = self.filtered( + lambda a: a.product_id and a.product_id.has_sigaus_amount + ) + for line in sigaus_amount_lines: + price = self.env["l10n.es.sigaus.amount"].get_sigaus_amount( + line.order_id.date_order + ) + quantity = line.product_uom._compute_quantity( + line.product_uom_qty, line.product_id.uom_id + ) + weight = quantity * line.product_id.weight + line.sigaus_amount = weight * price + (self - sigaus_amount_lines).sigaus_amount = False + + def _prepare_invoice_line(self, **optional_values): + res = super()._prepare_invoice_line(**optional_values) + res["is_sigaus"] = self.is_sigaus + return res diff --git a/l10n_es_sigaus/models/sigaus_line_mixin.py b/l10n_es_sigaus/models/sigaus_line_mixin.py new file mode 100644 index 00000000000..63632c8b5ad --- /dev/null +++ b/l10n_es_sigaus/models/sigaus_line_mixin.py @@ -0,0 +1,18 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class SigausLineMixin(models.AbstractModel): + _name = "sigaus.line.mixin" + _description = "Sigaus Line Mixin" + + recompute_sigaus = fields.Boolean() + is_sigaus = fields.Boolean(string="Sigaus From Sale", copy=False) + sigaus_amount = fields.Float( + compute="_compute_sigaus_amount", digits="Product Price" + ) + + def _compute_sigaus_amount(self): + self.sigaus_amount = 0.0 diff --git a/l10n_es_sigaus/models/sigaus_mixin.py b/l10n_es_sigaus/models/sigaus_mixin.py new file mode 100644 index 00000000000..0b1806716a8 --- /dev/null +++ b/l10n_es_sigaus/models/sigaus_mixin.py @@ -0,0 +1,36 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class SigausMixin(models.AbstractModel): + _name = "sigaus.mixin" + _description = "Sigaus Mixin" + + is_sigaus = fields.Boolean(compute="_compute_is_sigaus", store=True) + recompute_sigaus = fields.Boolean(copy=False) + no_sigaus = fields.Boolean(string="No subject to Sigaus") + show_delete_sigaus_button = fields.Boolean( + compute="_compute_show_delete_sigaus_button" + ) + show_sigaus_button = fields.Boolean(compute="_compute_show_sigaus_button") + has_sigaus_line = fields.Boolean(compute="_compute_has_sigaus_line") + company_sigaus = fields.Boolean(compute="_compute_company_sigaus") + + def _compute_is_sigaus(self): + self.is_sigaus = False + + def _compute_show_delete_sigaus_button(self): + self.show_delete_sigaus_button = False + + def _compute_show_sigaus_button(self): + self.show_sigaus_button = False + + def _compute_has_sigaus_line(self): + self.has_sigaus_line = False + + def _compute_company_sigaus(self): + company_sigaus_moves = self.filtered(lambda a: a.company_id.enable_sigaus) + company_sigaus_moves.company_sigaus = True + (self - company_sigaus_moves).company_sigaus = False diff --git a/l10n_es_sigaus/readme/CONFIGURE.rst b/l10n_es_sigaus/readme/CONFIGURE.rst new file mode 100644 index 00000000000..03d63449be8 --- /dev/null +++ b/l10n_es_sigaus/readme/CONFIGURE.rst @@ -0,0 +1,20 @@ +Se tienen que configurar los siguientes aspectos: + +* La configuración del precio de la aportación SIGAUS que se aplica durante un periodo de tiempo se realiza desde Invoicing > Configuration > L10n Es Sigaus Amount. En caso de no rellenar el campo "Date To", el precio seleccionado se aplicará a partir de la fecha indicada en "Date To". El precio establecido dentro del periodo marcado se utilizará siempre que se calcule la aportación SIGAUS desde ventas, facturas o compras. + +* Es necesario indicar aquellas compañías en las que seaplicará la aportación SIGAUS. Para ello, hay que acceder a la pestaña SIGAUS de la configuración de la compañía y marcar la casilla "Enable SIGAUS". Asimismo, es obligatorio indicar la fecha a partir de la cual la aportación SIGAUS se podrá aplicar en ventas, compras y facturas en el campo "SIGAUS Date From". Dos opciones adicionales aparecen cuando la opción "Enable SIGAUS" está marcada: + * "Show detailed SIGAUS amount in report lines": Si la opción está marcada, se mostrará la aportación SIGAUS de cada una de las líneas de venta, compra y facturas en los informes. + * "Automate SIGAUS": Si la opción está marcada, la aportación SIGAUS se recalculará en los pedidos de venta de manera automática cada vez que se creen o se actualicen, sin necesidad de hacerlo manualmente y siempre que sea aplicable. Asimismo, en caso de que se marque la casilla "No subject to SIGAUS" en los pedidos de venta, se eliminarán las líneas de aportación SIGAUS en caso de haber alguna presente. + +* Las posiciones fiscales con las que se aplicará la aportación SIGAUS tienen que indicarse. Para ellos hay que acceder a Invoicing > Configuration > Fiscal Positions y marcar la casilla "Subject to SIGAUS" en aquellas en las que se aplicará. + +* Se puede establecer que los productos de ciertas categorías de producto están sujetas a SIGAUS accediendo a la configuración de la categoría y marcando la casilla "Subject To Sigaus". + +* Desde la ficha de los productos, pueden establecerse varias opciones de sujeción a la aportación SIGAUS desde el campo "Subject To Sigaus". Existen tres opciones: + * "Category": La aplicación o no de la aportación SIGAUS para ese producto depende se si la casilla "Subject To Sigaus" está o no marcada en la categoría establecida. + * "Yes": Se aplica siempre la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto. + * "No": No se aplica nunca la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto. + +Cuando se calcule la aportación SIGAUS en ventas, compras y facturas, se tendrá en cuenta el peso de todos aquellos productos a los que se les aplica la aportación SIGAUS para determinar el importe. + +* Todos los productos a los que se le aplica la aportación SIGAUS deben tener un peso establecido. diff --git a/l10n_es_sigaus/readme/CONTRIBUTORS.rst b/l10n_es_sigaus/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..5e0fbb51132 --- /dev/null +++ b/l10n_es_sigaus/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `Sygel `_: + * Manuel Regidor + * Harald Panten + * Valentín Vinagre diff --git a/l10n_es_sigaus/readme/DESCRIPTION.rst b/l10n_es_sigaus/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..ae97db3617d --- /dev/null +++ b/l10n_es_sigaus/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Este módulo permite calcular y agregar a las ventas, compras y facturas la aportación SIGAUS. diff --git a/l10n_es_sigaus/readme/USAGE.rst b/l10n_es_sigaus/readme/USAGE.rst new file mode 100644 index 00000000000..d8e03f86dd5 --- /dev/null +++ b/l10n_es_sigaus/readme/USAGE.rst @@ -0,0 +1,21 @@ +* Para aplicar la aportación SIGAUS en las ventas, las compras o las facturas, hay que pulsar en el botón "Apply Sigaus". + +* En caso de producirse cambios en las líneas, se puede recalcular la aportación SIGAUS pulsando en el botón "Recompute Sigaus". + +* El importe de la aportación SIGAUS se calculará a partir de los pesos de aquellos productos sujetos a dicha aportación y el precio establecido en "L10n Es Sigaus Amount" según la fecha actual. + +* Los productos sujetos a aportación SIGAUS son los siguientes: + * Aquellos que tienen establecida la opción "Yes" en el campo "Subject to SIGAUS" + * Aquellos que tienen establecida la opción "Category" en el campo "Subject to SIGAUS" y cuya categoría tenga marcada la opción "Subject to SIGAUS". + +* En caso de generar una factura parcial a partir de una venta o una compra, solamente se facturará la parte proporcional de la aportación SIGAUS correspondiente a los productos facturados. + +* En caso de generar una factura a partir de varios pedidos de venta o compra, se generará una línea de aportación SIGAUS por cada uno de los pedidos que contengan dicha aportación. + +* Saltará un error si al calcular la aportación SIGAUS, alguno de los productos sujetos no tiene un peso establecido. + +* La aportación SIGAUS establecida en ventas y compras se transfiere a las facturas. + +* En ventas y facturas, si se marca la opción "No subject to SIGAUS", no se aplicará la aportación SIGAUS. + +* Más información en https://www.sigaus.es diff --git a/l10n_es_sigaus/report/ir_actions_report_templates.xml b/l10n_es_sigaus/report/ir_actions_report_templates.xml new file mode 100644 index 00000000000..e5433965658 --- /dev/null +++ b/l10n_es_sigaus/report/ir_actions_report_templates.xml @@ -0,0 +1,21 @@ + + + + diff --git a/l10n_es_sigaus/report/purchase_order_templates.xml b/l10n_es_sigaus/report/purchase_order_templates.xml new file mode 100644 index 00000000000..58c93b005a5 --- /dev/null +++ b/l10n_es_sigaus/report/purchase_order_templates.xml @@ -0,0 +1,21 @@ + + + + diff --git a/l10n_es_sigaus/report/purchase_quotation_templates.xml b/l10n_es_sigaus/report/purchase_quotation_templates.xml new file mode 100644 index 00000000000..5d2b7e17ec5 --- /dev/null +++ b/l10n_es_sigaus/report/purchase_quotation_templates.xml @@ -0,0 +1,21 @@ + + + + diff --git a/l10n_es_sigaus/security/ir.model.access.csv b/l10n_es_sigaus/security/ir.model.access.csv new file mode 100644 index 00000000000..76314d3c26e --- /dev/null +++ b/l10n_es_sigaus/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +l10n_es_sigaus_amount_manager,l10n.es.sigaus.amount.manager,model_l10n_es_sigaus_amount,account.group_account_manager,1,1,1,1 diff --git a/l10n_es_sigaus/static/description/icon.png b/l10n_es_sigaus/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/l10n_es_sigaus/static/description/index.html b/l10n_es_sigaus/static/description/index.html new file mode 100644 index 00000000000..ddd4b847aaa --- /dev/null +++ b/l10n_es_sigaus/static/description/index.html @@ -0,0 +1,486 @@ + + + + + + +L10n Es SIGAUS + + + +
+

L10n Es SIGAUS

+ + +

Beta License: AGPL-3 OCA/l10n-spain Translate me on Weblate Try me on Runboat

+

Este módulo permite calcular y agregar a las ventas, compras y facturas la aportación SIGAUS.

+

Table of contents

+ +
+

Configuration

+

Se tienen que configurar los siguientes aspectos:

+
    +
  • La configuración del precio de la aportación SIGAUS que se aplica durante un periodo de tiempo se realiza desde Invoicing > Configuration > L10n Es Sigaus Amount. En caso de no rellenar el campo “Date To”, el precio seleccionado se aplicará a partir de la fecha indicada en “Date To”. El precio establecido dentro del periodo marcado se utilizará siempre que se calcule la aportación SIGAUS desde ventas, facturas o compras.
  • +
  • +
    Es necesario indicar aquellas compañías en las que seaplicará la aportación SIGAUS. Para ello, hay que acceder a la pestaña SIGAUS de la configuración de la compañía y marcar la casilla “Enable SIGAUS”. Dos opciones adicionales aparecen cuando esta opción está marcada:
    +
      +
    • “Show detailed SIGAUS amount in report lines”: Si la opción está marcada, se mostrará la aportación SIGAUS de cada una de las líneas de venta, compra y facturas en los informes.
    • +
    • “Automate SIGAUS”: Si la opción está marcada, la aportación SIGAUS se recalculará en los pedidos de venta de manera automática cada vez que se creen o se actualicen, sin necesidad de hacerlo manualmente y siempre que sea aplicable. Asimismo, en caso de que se marque la casilla “No subject to SIGAUS” en los pedidos de venta, se eliminarán las líneas de aportación SIGAUS en caso de haber alguna presente.
    • +
    +
    +
    +
  • +
  • Se puede establecer que los productos de ciertas categorías de producto están sujetas a SIGAUS accediendo a la configuración de la categoría y marcando la casilla “Subject To Sigaus”.
  • +
  • +
    Desde la ficha de los productos, pueden establecerse varias opciones de sujeción a la aportación SIGAUS desde el campo “Subject To Sigaus”. Existen tres opciones:
    +
      +
    • “Category”: La aplicación o no de la aportación SIGAUS para ese producto depende se si la casilla “Subject To Sigaus” está o no marcada en la categoría establecida.
    • +
    • “Yes”: Se aplica siempre la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto.
    • +
    • “No”: No se aplica nunca la aportación SIGAUS, independientemente de lo seleccionado en la categoría de producto.
    • +
    +
    +
    +
  • +
+

Cuando se calcule la aportación SIGAUS en ventas, compras y facturas, se tendrá en cuenta el peso de todos aquellos productos a los que se les aplica la aportación SIGAUS para determinar el importe.

+
    +
  • Todos los productos a los que se le aplica la aportación SIGAUS deben tener un peso establecido.
  • +
+
+
+

Usage

+
    +
  • Para aplicar la aportación SIGAUS en las ventas, las compras o las facturas, hay que pulsar en el botón “Apply Sigaus”.
  • +
  • En caso de producirse cambios en las líneas, se puede recalcular la aportación SIGAUS pulsando en el botón “Recompute Sigaus”.
  • +
  • El importe de la aportación SIGAUS se calculará a partir de los pesos de aquellos productos sujetos a dicha aportación y el precio establecido en “L10n Es Sigaus Amount” según la fecha actual.
  • +
  • +
    Los productos sujetos a aportación SIGAUS son los siguientes:
    +
      +
    • Aquellos que tienen establecida la opción “Yes” en el campo “Subject to SIGAUS”
    • +
    • Aquellos que tienen establecida la opción “Category” en el campo “Subject to SIGAUS” y cuya categoría tenga marcada la opción “Subject to SIGAUS”.
    • +
    +
    +
    +
  • +
  • En caso de generar una factura parcial a partir de una venta o una compra, solamente se facturará la parte proporcional de la aportación SIGAUS correspondiente a los productos facturados.
  • +
  • En caso de generar una factura a partir de varios pedidos de venta o compra, se generará una línea de aportación SIGAUS por cada uno de los pedidos que contengan dicha aportación.
  • +
  • Saltará un error si al calcular la aportación SIGAUS, alguno de los productos sujetos no tiene un peso establecido.
  • +
  • La aportación SIGAUS establecida en ventas y compras se transfiere a las facturas.
  • +
  • En ventas y facturas, si se marca la opción “No subject to SIGAUS”, no se aplicará la aportación SIGAUS.
  • +
  • Más información en https://www.sigaus.es
  • +
+
+
+

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 +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Sygel
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+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.

+

This module is part of the OCA/l10n-spain project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_es_sigaus/tests/__init__.py b/l10n_es_sigaus/tests/__init__.py new file mode 100644 index 00000000000..8a6b35af7f5 --- /dev/null +++ b/l10n_es_sigaus/tests/__init__.py @@ -0,0 +1,7 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_l10n_es_sigaus_general_values +from . import test_l10n_es_sigaus_sales +from . import test_l10n_es_sigaus_invoice +from . import test_l10n_es_sigaus_purchase diff --git a/l10n_es_sigaus/tests/common.py b/l10n_es_sigaus/tests/common.py new file mode 100644 index 00000000000..4f6d3fccbf0 --- /dev/null +++ b/l10n_es_sigaus/tests/common.py @@ -0,0 +1,64 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestL10nEsSigausCommon(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref("base.main_company") + cls.company.write({"enable_sigaus": True, "sigaus_date_from": "2022-01-01"}) + cls.partner = cls.env["res.partner"].create({"name": "Test"}) + cls.category_sigaus = cls.env["product.category"].create( + {"name": "Sigaus Category", "subject_to_sigaus": True} + ) + cls.product_no_sigaus = cls.env["product.product"].create( + { + "name": "Product-1", + "subject_to_sigaus": "no", + "weight": 1, + "invoice_policy": "order", + "purchase_method": "purchase", + } + ) + cls.product_sigaus_in_product = cls.env["product.product"].create( + { + "name": "Product (SIGAUS in product)", + "subject_to_sigaus": "yes", + "weight": 1, + "invoice_policy": "order", + "purchase_method": "purchase", + } + ) + cls.product_sigaus_in_category = cls.env["product.product"].create( + { + "name": "Product (SIGAUS in category)", + "subject_to_sigaus": "category", + "weight": 2, + "categ_id": cls.category_sigaus.id, + "invoice_policy": "order", + "purchase_method": "purchase", + } + ) + cls.product_sigaus_in_category_excluded = cls.env["product.product"].create( + { + "name": "Product (SIGAUS in category excluded)", + "subject_to_sigaus": "no", + "weight": 3, + "categ_id": cls.category_sigaus.id, + "invoice_policy": "order", + "purchase_method": "purchase", + } + ) + cls.product_sigaus_no_weight = cls.env["product.product"].create( + { + "name": "Product (SIGAUS no weight)", + "subject_to_sigaus": "yes", + "weight": 0, + "invoice_policy": "order", + "purchase_method": "purchase", + } + ) diff --git a/l10n_es_sigaus/tests/test_l10n_es_sigaus_general_values.py b/l10n_es_sigaus/tests/test_l10n_es_sigaus_general_values.py new file mode 100644 index 00000000000..9c41bc7c158 --- /dev/null +++ b/l10n_es_sigaus/tests/test_l10n_es_sigaus_general_values.py @@ -0,0 +1,42 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError + +from .common import TestL10nEsSigausCommon + + +class TestL10nEsSigausPriceRange(TestL10nEsSigausCommon): + def test_wrong_date(self): + with self.assertRaises(ValidationError): + self.env["l10n.es.sigaus.amount"].create( + { + "name": "Test", + "price": 0.1, + "date_from": "2021-01-01", + "date_to": "2020-01-01", + } + ) + + def test_overlapping_dates(self): + self.env["l10n.es.sigaus.amount"].create( + { + "name": "Test-1", + "price": 0.1, + "date_from": "2020-01-01", + "date_to": "2021-01-01", + } + ) + with self.assertRaises(ValidationError): + self.env["l10n.es.sigaus.amount"].create( + { + "name": "Test-2", + "price": 0.1, + "date_from": "2020-01-07", + "date_to": "2021-01-07", + } + ) + + def test_sigaus_date_from_required(self): + with self.assertRaises(ValidationError): + self.company.write({"sigaus_date_from": False}) diff --git a/l10n_es_sigaus/tests/test_l10n_es_sigaus_invoice.py b/l10n_es_sigaus/tests/test_l10n_es_sigaus_invoice.py new file mode 100644 index 00000000000..5e6e7919883 --- /dev/null +++ b/l10n_es_sigaus/tests/test_l10n_es_sigaus_invoice.py @@ -0,0 +1,183 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError + +from .common import TestL10nEsSigausCommon + + +class TestL10nEsSigausInvoice(TestL10nEsSigausCommon): + def test_invoice_without_sigaus_products(self): + invoice = self.env["account.move"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "invoice_date": "2023-01-01", + "move_type": "out_invoice", + } + ) + invoice.write( + { + "invoice_line_ids": [ + ( + 0, + False, + { + "product_id": self.product_no_sigaus.id, + "quantity": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(invoice.show_sigaus_button, False) + invoice.action_apply_sigaus() + self.assertEqual(invoice.has_sigaus_line, False) + self.assertEqual(invoice.amount_untaxed, 2) + + def test_invoice_with_sigaus_products_no_weight(self): + invoice = self.env["account.move"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "invoice_date": "2023-01-01", + "move_type": "out_invoice", + } + ) + invoice.write( + { + "invoice_line_ids": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_no_weight.id, + "quantity": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(invoice.company_sigaus, True) + self.assertEqual(invoice.show_sigaus_button, True) + with self.assertRaises(ValidationError): + invoice.action_apply_sigaus() + + def test_invoice_with_sigaus(self): + invoice = self.env["account.move"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "invoice_date": "2023-01-01", + "move_type": "out_invoice", + "no_sigaus": True, + } + ) + invoice.write( + { + "invoice_line_ids": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "quantity": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "quantity": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "quantity": 3.0, + "price_unit": 4, + }, + ), + ] + } + ) + self.assertEqual(invoice.show_sigaus_button, False) + invoice.action_apply_sigaus() + self.assertEqual(invoice.has_sigaus_line, False) + self.assertEqual(invoice.amount_untaxed, 20.00) + product_sigaus_in_product_line = invoice.invoice_line_ids.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_line = invoice.invoice_line_ids.filtered( + lambda a: a.product_id == self.product_sigaus_in_category + ) + self.assertEqual(product_sigaus_in_category_line.sigaus_amount, 0.24) + product_sigaus_in_product_line = invoice.invoice_line_ids.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_excluded_line = invoice.invoice_line_ids.filtered( + lambda a: a.product_id == self.product_sigaus_in_category_excluded + ) + self.assertEqual(product_sigaus_in_category_excluded_line.sigaus_amount, 0.00) + + invoice.write({"no_sigaus": False}) + self.assertEqual(invoice.show_sigaus_button, True) + invoice.action_apply_sigaus() + self.assertEqual(invoice.has_sigaus_line, True) + self.assertEqual(invoice.amount_untaxed, 20.3) + invoice.write( + { + "invoice_line_ids": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "quantity": 1.0, + "price_unit": 2, + }, + ) + ] + } + ) + self.assertEqual(invoice.show_delete_sigaus_button, True) + invoice.action_apply_sigaus() + self.assertEqual(invoice.amount_untaxed, 22.36) + invoice.action_delete_sigaus() + self.assertEqual(invoice.amount_untaxed, 22.00) + + def test_invoice_error_date(self): + invoice = self.env["account.move"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "invoice_date": "2022-01-06", + "move_type": "out_invoice", + } + ) + invoice.write( + { + "invoice_line_ids": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "quantity": 1.0, + "price_unit": 2, + }, + ), + ] + } + ) + with self.assertRaises(ValidationError): + invoice.action_apply_sigaus() diff --git a/l10n_es_sigaus/tests/test_l10n_es_sigaus_purchase.py b/l10n_es_sigaus/tests/test_l10n_es_sigaus_purchase.py new file mode 100644 index 00000000000..07c0d7486a3 --- /dev/null +++ b/l10n_es_sigaus/tests/test_l10n_es_sigaus_purchase.py @@ -0,0 +1,227 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError + +from .common import TestL10nEsSigausCommon + + +class TestL10nEsSigausPurchase(TestL10nEsSigausCommon): + def test_purchase_without_sigaus_products(self): + purchase = self.env["purchase.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_no_sigaus.id, + "product_qty": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(purchase.company_sigaus, True) + self.assertEqual(purchase.show_sigaus_button, False) + purchase.action_apply_sigaus() + self.assertEqual(purchase.has_sigaus_line, False) + self.assertEqual(purchase.amount_untaxed, 2) + + def test_purchase_with_sigaus_products_no_weight(self): + purchase = self.env["purchase.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_no_weight.id, + "product_qty": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(purchase.show_sigaus_button, True) + with self.assertRaises(ValidationError): + purchase.action_apply_sigaus() + + def test_purchase_with_sigaus(self): + purchase = self.env["purchase.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + "no_sigaus": True, + } + ) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_qty": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "product_qty": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "product_qty": 3.0, + "price_unit": 4, + }, + ), + ] + } + ) + self.assertEqual(purchase.show_sigaus_button, False) + purchase.action_apply_sigaus() + self.assertEqual(purchase.has_sigaus_line, False) + self.assertEqual(purchase.amount_untaxed, 20.00) + product_sigaus_in_product_line = purchase.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_line = purchase.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_category + ) + self.assertEqual(product_sigaus_in_category_line.sigaus_amount, 0.24) + product_sigaus_in_product_line = purchase.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_excluded_line = purchase.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_category_excluded + ) + self.assertEqual(product_sigaus_in_category_excluded_line.sigaus_amount, 0.00) + + purchase.write({"no_sigaus": False}) + self.assertEqual(purchase.show_sigaus_button, True) + purchase.action_apply_sigaus() + self.assertEqual(purchase.has_sigaus_line, True) + self.assertEqual(purchase.amount_untaxed, 20.3) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_qty": 1.0, + "price_unit": 2, + }, + ) + ] + } + ) + self.assertEqual(purchase.show_delete_sigaus_button, True) + purchase.action_apply_sigaus() + self.assertEqual(purchase.amount_untaxed, 22.36) + purchase.action_delete_sigaus() + self.assertEqual(purchase.amount_untaxed, 22.00) + + def test_single_invoice_from_purchase(self): + purchase = self.env["purchase.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_qty": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "product_qty": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "product_qty": 3.0, + "price_unit": 4, + }, + ), + ] + } + ) + purchase.action_apply_sigaus() + purchase.button_confirm() + purchase.action_create_invoice() + invoice = purchase.invoice_ids[0] + self.assertEqual(invoice.has_sigaus_line, True) + self.assertEqual(invoice.amount_untaxed, 20.3) + + def test_purchase_error_date(self): + purchase = self.env["purchase.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2022-01-06", + } + ) + purchase.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_qty": 1.0, + "price_unit": 2, + }, + ), + ] + } + ) + with self.assertRaises(ValidationError): + purchase.action_apply_sigaus() diff --git a/l10n_es_sigaus/tests/test_l10n_es_sigaus_sales.py b/l10n_es_sigaus/tests/test_l10n_es_sigaus_sales.py new file mode 100644 index 00000000000..9d51735f288 --- /dev/null +++ b/l10n_es_sigaus/tests/test_l10n_es_sigaus_sales.py @@ -0,0 +1,395 @@ +# Copyright 2023 Manuel Regidor +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import ValidationError + +from .common import TestL10nEsSigausCommon + + +class TestL10nEsSigausSales(TestL10nEsSigausCommon): + def test_sale_without_sigaus_products(self): + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_no_sigaus.id, + "product_uom_qty": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(sale.company_sigaus, True) + self.assertEqual(sale.show_sigaus_button, False) + sale.action_apply_sigaus() + self.assertEqual(sale.has_sigaus_line, False) + self.assertEqual(sale.amount_untaxed, 2) + + def test_sale_with_sigaus_products_no_weight(self): + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_no_weight.id, + "product_uom_qty": 2.0, + "price_unit": 1, + }, + ), + ] + } + ) + self.assertEqual(sale.show_sigaus_button, True) + with self.assertRaises(ValidationError): + sale.action_apply_sigaus() + + def test_sale_with_sigaus(self): + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + "no_sigaus": True, + } + ) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "product_uom_qty": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "product_uom_qty": 3.0, + "price_unit": 4, + }, + ), + ] + } + ) + self.assertEqual(sale.show_sigaus_button, False) + sale.action_apply_sigaus() + self.assertEqual(sale.has_sigaus_line, False) + self.assertEqual(sale.amount_untaxed, 20.00) + product_sigaus_in_product_line = sale.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_line = sale.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_category + ) + self.assertEqual(product_sigaus_in_category_line.sigaus_amount, 0.24) + product_sigaus_in_product_line = sale.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_product + ) + self.assertEqual(product_sigaus_in_product_line.sigaus_amount, 0.06) + product_sigaus_in_category_excluded_line = sale.order_line.filtered( + lambda a: a.product_id == self.product_sigaus_in_category_excluded + ) + self.assertEqual(product_sigaus_in_category_excluded_line.sigaus_amount, 0.00) + + sale.write({"no_sigaus": False}) + self.assertEqual(sale.show_sigaus_button, True) + sale.action_apply_sigaus() + self.assertEqual(sale.has_sigaus_line, True) + self.assertEqual(sale.amount_untaxed, 20.3) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ) + ] + } + ) + self.assertEqual(sale.show_delete_sigaus_button, True) + sale.action_apply_sigaus() + self.assertEqual(sale.amount_untaxed, 22.36) + sale.action_delete_sigaus() + self.assertEqual(sale.amount_untaxed, 22.00) + + def test_sale_with_sigaus_auto(self): + self.company.write({"automate_sigaus_sales": True}) + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + "order_line": [ + ( + 0, + 0, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + 0, + { + "product_id": self.product_sigaus_in_category.id, + "product_uom_qty": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + 0, + { + "name": "order 2 section 2", + "display_type": "line_section", + }, + ), + ( + 0, + 0, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "product_uom_qty": 3.0, + "price_unit": 4, + }, + ), + ], + } + ) + self.assertEqual(sale.show_sigaus_button, False) + self.assertEqual(sale.has_sigaus_line, True) + self.assertEqual(sale.amount_untaxed, 20.3) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ) + ] + } + ) + self.assertEqual(sale.show_delete_sigaus_button, False) + self.assertEqual(sale.amount_untaxed, 22.36) + sale.write({"no_sigaus": True}) + self.assertEqual(sale.amount_untaxed, 22.00) + + def test_invoice_from_single_sale(self): + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "product_uom_qty": 2.0, + "price_unit": 3, + }, + ), + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category_excluded.id, + "product_uom_qty": 3.0, + "price_unit": 4, + }, + ), + ] + } + ) + sale.action_apply_sigaus() + sale.action_done() + invoice = sale._create_invoices() + self.assertEqual(invoice.has_sigaus_line, True) + self.assertEqual(invoice.amount_untaxed, 20.3) + invoice.write({"invoice_date": "2023-01-01"}) + + # Delete SIGAUS line from invoice a recreate it. + # It needs to be related to the SIGAUS line in the sale order. + invoice.invoice_line_ids.filtered(lambda a: a.is_sigaus).unlink() + invoice.action_apply_sigaus() + sigaus_line_in_order = sale.order_line.filtered(lambda a: a.is_sigaus) + sigaus_line_in_invoice = invoice.invoice_line_ids.filtered( + lambda a: a.is_sigaus + ) + self.assertEqual(sigaus_line_in_order, sigaus_line_in_invoice.sale_line_ids) + + def test_invoice_from_multiple_sales(self): + sale_1 = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + sale_1.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ), + ] + } + ) + sale_2 = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2023-01-01", + } + ) + sale_2.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_category.id, + "product_uom_qty": 2.0, + "price_unit": 3, + }, + ), + ] + } + ) + + sale_1.action_apply_sigaus() + sale_1_sigaus_line = sale_1.order_line.filtered(lambda a: a.is_sigaus) + sale_1.action_done() + sale_2.action_apply_sigaus() + sale_2_sigaus_line = sale_2.order_line.filtered(lambda a: a.is_sigaus) + sale_2.action_done() + invoice = (sale_1 + sale_2)._create_invoices() + sigaus_lines = invoice.invoice_line_ids.filtered(lambda a: a.is_sigaus) + self.assertEqual(len(sigaus_lines), 2) + invoice_sale_1_sigaus_line = invoice.invoice_line_ids.filtered( + lambda a: a.sale_line_ids == sale_1_sigaus_line + ) + self.assertTrue(invoice_sale_1_sigaus_line) + invoice_sale_2_sigaus_line = invoice.invoice_line_ids.filtered( + lambda a: a.sale_line_ids == sale_2_sigaus_line + ) + self.assertTrue(invoice_sale_2_sigaus_line) + + # Delete one of the SIGAUS lines in invoice + invoice_sale_1_sigaus_line.unlink() + sigaus_lines = invoice.invoice_line_ids.filtered(lambda a: a.is_sigaus) + self.assertEqual(len(sigaus_lines), 1) + + # Regenerate SIGAUS the deleted SIGAUS line + invoice.write({"invoice_date": "2023-01-01"}) + invoice.action_apply_sigaus() + sigaus_lines = invoice.invoice_line_ids.filtered(lambda a: a.is_sigaus) + self.assertEqual(len(sigaus_lines), 2) + invoice_sale_1_sigaus_line = invoice.invoice_line_ids.filtered( + lambda a: a.sale_line_ids == sale_1_sigaus_line + ) + self.assertTrue( + invoice_sale_1_sigaus_line.price_subtotal, sale_1_sigaus_line.price_subtotal + ) + self.assertTrue(invoice_sale_1_sigaus_line) + invoice_sale_2_sigaus_line = invoice.invoice_line_ids.filtered( + lambda a: a.sale_line_ids == sale_2_sigaus_line + ) + self.assertTrue( + invoice_sale_2_sigaus_line.price_subtotal, sale_2_sigaus_line.price_subtotal + ) + self.assertTrue(invoice_sale_2_sigaus_line) + + def test_sale_error_date(self): + sale = self.env["sale.order"].create( + { + "company_id": self.company.id, + "partner_id": self.partner.id, + "date_order": "2022-01-06", + } + ) + sale.write( + { + "order_line": [ + ( + 0, + False, + { + "product_id": self.product_sigaus_in_product.id, + "product_uom_qty": 1.0, + "price_unit": 2, + }, + ), + ] + } + ) + with self.assertRaises(ValidationError): + sale.action_apply_sigaus() diff --git a/l10n_es_sigaus/views/account_fiscal_position_views.xml b/l10n_es_sigaus/views/account_fiscal_position_views.xml new file mode 100644 index 00000000000..7bd805f1783 --- /dev/null +++ b/l10n_es_sigaus/views/account_fiscal_position_views.xml @@ -0,0 +1,24 @@ + + + + l10n.es.sigaus.view.account.position.form + account.fiscal.position + + + + + + + + + l10n.es.sigaus.view.account.position.tree + account.fiscal.position + + + + + + + + diff --git a/l10n_es_sigaus/views/account_move_views.xml b/l10n_es_sigaus/views/account_move_views.xml new file mode 100644 index 00000000000..a3df1aa1dda --- /dev/null +++ b/l10n_es_sigaus/views/account_move_views.xml @@ -0,0 +1,63 @@ + + + + l10n.es.sigaus.view.move.form + account.move + + + +
+ + + +
+
+ + + + + + + + + + + + + + recompute_sigaus and is_sigaus + +
+
+
diff --git a/l10n_es_sigaus/views/l10n_es_sigaus_amount_views.xml b/l10n_es_sigaus/views/l10n_es_sigaus_amount_views.xml new file mode 100644 index 00000000000..3651c5875e2 --- /dev/null +++ b/l10n_es_sigaus/views/l10n_es_sigaus_amount_views.xml @@ -0,0 +1,68 @@ + + + + l10n.es.sigaus.amount.form.view + l10n.es.sigaus.amount + +
+ + + + + + + + + + + +
+
+ + l10n.es.sigaus.amount.tree.view + l10n.es.sigaus.amount + + + + + + + + + + + L10n Es Sigaus Amount + l10n.es.sigaus.amount + tree,form + + + + +
diff --git a/l10n_es_sigaus/views/product_category_views.xml b/l10n_es_sigaus/views/product_category_views.xml new file mode 100644 index 00000000000..9d58ea1f0c2 --- /dev/null +++ b/l10n_es_sigaus/views/product_category_views.xml @@ -0,0 +1,14 @@ + + + + l10n.es.sigaus.product.category.form.view + product.category + + + + + + + + diff --git a/l10n_es_sigaus/views/product_views.xml b/l10n_es_sigaus/views/product_views.xml new file mode 100644 index 00000000000..e2d0c358d60 --- /dev/null +++ b/l10n_es_sigaus/views/product_views.xml @@ -0,0 +1,14 @@ + + + + l10n.es.sigaus.product.template.form.view + product.template + + + + + + + + diff --git a/l10n_es_sigaus/views/purchase_views.xml b/l10n_es_sigaus/views/purchase_views.xml new file mode 100644 index 00000000000..4cab8443334 --- /dev/null +++ b/l10n_es_sigaus/views/purchase_views.xml @@ -0,0 +1,63 @@ + + + + l10n.es.sigaus.purchase.order.form + purchase.order + + + +
+ + + +
+
+
+ + +
+ + + + + + + + + + recompute_sigaus and is_sigaus + +
+
+
diff --git a/l10n_es_sigaus/views/report_invoice.xml b/l10n_es_sigaus/views/report_invoice.xml new file mode 100644 index 00000000000..7729574d39c --- /dev/null +++ b/l10n_es_sigaus/views/report_invoice.xml @@ -0,0 +1,18 @@ + + + + diff --git a/l10n_es_sigaus/views/res_company_views.xml b/l10n_es_sigaus/views/res_company_views.xml new file mode 100644 index 00000000000..9d904b7b380 --- /dev/null +++ b/l10n_es_sigaus/views/res_company_views.xml @@ -0,0 +1,30 @@ + + + + l10n.es.sigaus.view.company.form + res.company + + + + + + + + + + + + + + + diff --git a/l10n_es_sigaus/views/sale_order_views.xml b/l10n_es_sigaus/views/sale_order_views.xml new file mode 100644 index 00000000000..a19dc079069 --- /dev/null +++ b/l10n_es_sigaus/views/sale_order_views.xml @@ -0,0 +1,63 @@ + + + + l10n.es.sigaus.view.order.form + sale.order + + + +
+ + + +
+
+ + + + + + + + + + + + + + recompute_sigaus and is_sigaus + + +
+
diff --git a/setup/l10n_es_sigaus/odoo/addons/l10n_es_sigaus b/setup/l10n_es_sigaus/odoo/addons/l10n_es_sigaus new file mode 120000 index 00000000000..58fecda2291 --- /dev/null +++ b/setup/l10n_es_sigaus/odoo/addons/l10n_es_sigaus @@ -0,0 +1 @@ +../../../../l10n_es_sigaus \ No newline at end of file diff --git a/setup/l10n_es_sigaus/setup.py b/setup/l10n_es_sigaus/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/l10n_es_sigaus/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)