diff --git a/sale_order_invoice_date/README.rst b/sale_order_invoice_date/README.rst new file mode 100644 index 000000000..85fc47eae --- /dev/null +++ b/sale_order_invoice_date/README.rst @@ -0,0 +1,97 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================= +Sale Order Invoice Date +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0aed8f342f792d9dafd85814801c4ed5ba82f517c3542444be65f43bd2a2c6c5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fsale--reporting-lightgray.png?logo=github + :target: https://github.com/OCA/sale-reporting/tree/19.0/sale_order_invoice_date + :alt: OCA/sale-reporting +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/sale-reporting-19-0/sale-reporting-19-0-sale_order_invoice_date + :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/sale-reporting&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Display the invoice date on Sales Order analysis reports. + +The invoice date is considered to be the latest invoice date linked to +fully invoiced sales. + +**Table of contents** + +.. contents:: + :local: + +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 +------- + +* Camptocamp + +Contributors +------------ + +- `Camptocamp `__ + + - Iván Todorovich + +- `ArcheTI `__ + + - Alexei Rivera (Migration to 19.0) + +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. + +.. |maintainer-ivantodorovich| image:: https://github.com/ivantodorovich.png?size=40px + :target: https://github.com/ivantodorovich + :alt: ivantodorovich + +Current `maintainer `__: + +|maintainer-ivantodorovich| + +This module is part of the `OCA/sale-reporting `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_invoice_date/__init__.py b/sale_order_invoice_date/__init__.py new file mode 100644 index 000000000..40501e5e6 --- /dev/null +++ b/sale_order_invoice_date/__init__.py @@ -0,0 +1,3 @@ +from . import models +from . import reports +from .hooks import pre_init_hook diff --git a/sale_order_invoice_date/__manifest__.py b/sale_order_invoice_date/__manifest__.py new file mode 100644 index 000000000..1d6a6bcf6 --- /dev/null +++ b/sale_order_invoice_date/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Sale Order Invoice Date", + "summary": "Display the invoice date on Sales Order analysis reports", + "version": "19.0.1.0.0", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["ivantodorovich"], + "website": "https://github.com/OCA/sale-reporting", + "license": "AGPL-3", + "category": "Sales", + "depends": ["sale"], + "data": ["reports/sale_report.xml"], + "pre_init_hook": "pre_init_hook", +} diff --git a/sale_order_invoice_date/hooks.py b/sale_order_invoice_date/hooks.py new file mode 100644 index 000000000..a6faa58c6 --- /dev/null +++ b/sale_order_invoice_date/hooks.py @@ -0,0 +1,48 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo.tools.sql import column_exists, create_column + +_logger = logging.getLogger(__name__) + + +def pre_init_hook(env): + if not column_exists(env.cr, "sale_order_line", "invoice_date"): + create_column(env.cr, "sale_order_line", "invoice_date", "date") + if not column_exists(env.cr, "sale_order", "invoice_date"): + create_column(env.cr, "sale_order", "invoice_date", "date") + _logger.info("Initializing computed values for sale_order_line.invoice_date") + env.cr.execute( + """ + WITH sol AS ( + SELECT sol.id AS id, max(move.invoice_date) AS invoice_date + FROM sale_order_line_invoice_rel rel + INNER JOIN sale_order_line sol ON rel.order_line_id = sol.id + INNER JOIN account_move_line aml ON rel.invoice_line_id = aml.id + INNER JOIN account_move move ON aml.move_id = move.id + WHERE sol.invoice_status = 'invoiced' + GROUP BY sol.id + ) + UPDATE sale_order_line + SET invoice_date = sol.invoice_date + FROM sol WHERE sale_order_line.id = sol.id + """ + ) + _logger.info("Initializing computed values for sale_order.invoice_date") + env.cr.execute( + """ + WITH so AS ( + SELECT so.id AS id, max(sol.invoice_date) AS invoice_date + FROM sale_order_line sol + INNER JOIN sale_order so ON sol.order_id = so.id + WHERE so.invoice_status = 'invoiced' AND sol.invoice_date IS NOT NULL + GROUP BY so.id + ) + UPDATE sale_order + SET invoice_date = so.invoice_date + FROM so WHERE sale_order.id = so.id + """ + ) diff --git a/sale_order_invoice_date/i18n/es.po b/sale_order_invoice_date/i18n/es.po new file mode 100644 index 000000000..658c9daae --- /dev/null +++ b/sale_order_invoice_date/i18n/es.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_invoice_date +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-04-24 22:36+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__display_name +msgid "Display Name" +msgstr "Mostrar Nombre" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__id +msgid "ID" +msgstr "ID" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__invoice_date +#: model_terms:ir.ui.view,arch_db:sale_order_invoice_date.view_order_product_search +msgid "Invoice Date" +msgstr "Fecha Factura" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report____last_update +msgid "Last Modified on" +msgstr "Última Modificación el" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_report +msgid "Sales Analysis Report" +msgstr "Informe Analítico de Ventas" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order +msgid "Sales Order" +msgstr "Orden de venta" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de Orden de Ventas" diff --git a/sale_order_invoice_date/i18n/fr.po b/sale_order_invoice_date/i18n/fr.po new file mode 100644 index 000000000..e328c57d3 --- /dev/null +++ b/sale_order_invoice_date/i18n/fr.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_invoice_date +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-06-09 19:45+0000\n" +"PO-Revision-Date: 2022-06-09 19:45+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__id +msgid "ID" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__invoice_date +#: model_terms:ir.ui.view,arch_db:sale_order_invoice_date.view_order_product_search +msgid "Invoice Date" +msgstr "Date de facturation" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_report +msgid "Sales Analysis Report" +msgstr "Rapport d'analyse des ventes" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order +msgid "Sales Order" +msgstr "Bon de commande" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order_line +msgid "Sales Order Line" +msgstr "Ligne de bons de commande" diff --git a/sale_order_invoice_date/i18n/it.po b/sale_order_invoice_date/i18n/it.po new file mode 100644 index 000000000..cb8268430 --- /dev/null +++ b/sale_order_invoice_date/i18n/it.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_invoice_date +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-02-10 11:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__id +msgid "ID" +msgstr "ID" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__invoice_date +#: model_terms:ir.ui.view,arch_db:sale_order_invoice_date.view_order_product_search +msgid "Invoice Date" +msgstr "Data fattura" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_report +msgid "Sales Analysis Report" +msgstr "Resoconto analisi vendite" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" diff --git a/sale_order_invoice_date/i18n/sale_order_invoice_date.pot b/sale_order_invoice_date/i18n/sale_order_invoice_date.pot new file mode 100644 index 000000000..af01e44e6 --- /dev/null +++ b/sale_order_invoice_date/i18n/sale_order_invoice_date.pot @@ -0,0 +1,58 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_invoice_date +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__display_name +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__display_name +msgid "Display Name" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__id +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__id +msgid "ID" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line__invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report__invoice_date +#: model_terms:ir.ui.view,arch_db:sale_order_invoice_date.view_order_product_search +msgid "Invoice Date" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_order_line____last_update +#: model:ir.model.fields,field_description:sale_order_invoice_date.field_sale_report____last_update +msgid "Last Modified on" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_report +msgid "Sales Analysis Report" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_order_invoice_date +#: model:ir.model,name:sale_order_invoice_date.model_sale_order_line +msgid "Sales Order Line" +msgstr "" diff --git a/sale_order_invoice_date/models/__init__.py b/sale_order_invoice_date/models/__init__.py new file mode 100644 index 000000000..2d7ee6c3d --- /dev/null +++ b/sale_order_invoice_date/models/__init__.py @@ -0,0 +1,2 @@ +from . import sale_order +from . import sale_order_line diff --git a/sale_order_invoice_date/models/sale_order.py b/sale_order_invoice_date/models/sale_order.py new file mode 100644 index 000000000..63b13f3f9 --- /dev/null +++ b/sale_order_invoice_date/models/sale_order.py @@ -0,0 +1,25 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class SaleOrder(models.Model): + _inherit = "sale.order" + + invoice_date = fields.Date(compute="_compute_invoice_date", store=True) + + @api.depends("order_line.invoice_date") + def _compute_invoice_date(self): + data = {} + invoiced = self.filtered(lambda rec: rec.invoice_status == "invoiced") + if invoiced.ids: + groups = self.env["sale.order.line"]._read_group( + domain=[("order_id", "in", invoiced.ids)], + aggregates=["invoice_date:max"], + groupby=["order_id"], + ) + data = {order.id: invoice_date for order, invoice_date in groups} + for rec in self: + rec.invoice_date = data.get(rec.id, False) diff --git a/sale_order_invoice_date/models/sale_order_line.py b/sale_order_invoice_date/models/sale_order_line.py new file mode 100644 index 000000000..22405d674 --- /dev/null +++ b/sale_order_invoice_date/models/sale_order_line.py @@ -0,0 +1,22 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + invoice_date = fields.Date(compute="_compute_invoice_date", store=True) + + @api.depends("invoice_status", "invoice_lines.move_id.invoice_date") + def _compute_invoice_date(self): + invoiced = self.filtered(lambda rec: rec.invoice_status == "invoiced") + not_invoiced = self - invoiced + not_invoiced.invoice_date = False + for rec in invoiced: + rec.invoice_date = max( + [d for d in rec.invoice_lines.move_id.mapped("invoice_date") if d], + default=False, + ) diff --git a/sale_order_invoice_date/pyproject.toml b/sale_order_invoice_date/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/sale_order_invoice_date/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_order_invoice_date/readme/CONTRIBUTORS.md b/sale_order_invoice_date/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..6a13c20eb --- /dev/null +++ b/sale_order_invoice_date/readme/CONTRIBUTORS.md @@ -0,0 +1,5 @@ +- [Camptocamp](https://www.camptocamp.com) + - Iván Todorovich \<\> + +- [ArcheTI](https://www.archeti.com) + - Alexei Rivera \<\> (Migration to 19.0) diff --git a/sale_order_invoice_date/readme/DESCRIPTION.md b/sale_order_invoice_date/readme/DESCRIPTION.md new file mode 100644 index 000000000..30c668139 --- /dev/null +++ b/sale_order_invoice_date/readme/DESCRIPTION.md @@ -0,0 +1,4 @@ +Display the invoice date on Sales Order analysis reports. + +The invoice date is considered to be the latest invoice date linked to +fully invoiced sales. diff --git a/sale_order_invoice_date/reports/__init__.py b/sale_order_invoice_date/reports/__init__.py new file mode 100644 index 000000000..cd23411b8 --- /dev/null +++ b/sale_order_invoice_date/reports/__init__.py @@ -0,0 +1 @@ +from . import sale_report diff --git a/sale_order_invoice_date/reports/sale_report.py b/sale_order_invoice_date/reports/sale_report.py new file mode 100644 index 000000000..722d64d62 --- /dev/null +++ b/sale_order_invoice_date/reports/sale_report.py @@ -0,0 +1,22 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class SaleReport(models.Model): + _inherit = "sale.report" + + invoice_date = fields.Date(readonly=True) + + def _select_additional_fields(self): + res = super()._select_additional_fields() + res["invoice_date"] = "l.invoice_date" + return res + + def _group_by_sale(self): + res = super()._group_by_sale() + res += """, + l.invoice_date""" + return res diff --git a/sale_order_invoice_date/reports/sale_report.xml b/sale_order_invoice_date/reports/sale_report.xml new file mode 100644 index 000000000..3fc43ff5e --- /dev/null +++ b/sale_order_invoice_date/reports/sale_report.xml @@ -0,0 +1,29 @@ + + + + + sale.report + + + + + + + + + + + + diff --git a/sale_order_invoice_date/static/description/icon.png b/sale_order_invoice_date/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/sale_order_invoice_date/static/description/icon.png differ diff --git a/sale_order_invoice_date/static/description/index.html b/sale_order_invoice_date/static/description/index.html new file mode 100644 index 000000000..fdd60927a --- /dev/null +++ b/sale_order_invoice_date/static/description/index.html @@ -0,0 +1,440 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Sale Order Invoice Date

+ +

Beta License: AGPL-3 OCA/sale-reporting Translate me on Weblate Try me on Runboat

+

Display the invoice date on Sales Order analysis reports.

+

The invoice date is considered to be the latest invoice date linked to +fully invoiced sales.

+

Table of contents

+ +
+

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

+
    +
  • Camptocamp
  • +
+
+
+

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.

+

Current maintainer:

+

ivantodorovich

+

This module is part of the OCA/sale-reporting project on GitHub.

+

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

+
+
+
+
+ + diff --git a/sale_order_invoice_date/tests/__init__.py b/sale_order_invoice_date/tests/__init__.py new file mode 100644 index 000000000..f8ff7a573 --- /dev/null +++ b/sale_order_invoice_date/tests/__init__.py @@ -0,0 +1 @@ +from . import test_sale_order_invoice_date diff --git a/sale_order_invoice_date/tests/test_sale_order_invoice_date.py b/sale_order_invoice_date/tests/test_sale_order_invoice_date.py new file mode 100644 index 000000000..1cdd79adc --- /dev/null +++ b/sale_order_invoice_date/tests/test_sale_order_invoice_date.py @@ -0,0 +1,80 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields +from odoo.tests import TransactionCase + + +class TestSaleInvoiceDate(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env["res.partner"].create([{"name": "Partner 1"}]) + cls.product = cls.env["product.product"].create( + { + "name": "Test Product", + "invoice_policy": "order", + "list_price": 10.0, + } + ) + cls.order = cls.env["sale.order"].create( + { + "partner_id": cls.partner.id, + "order_line": [ + ( + 0, + 0, + { + "name": cls.product.name, + "product_id": cls.product.id, + "product_uom_qty": 5.0, + "product_uom_id": cls.product.uom_id.id, + "price_unit": cls.product.list_price, + }, + ) + ], + } + ) + cls.order.action_confirm() + + def _create_invoice(self, order, quantity=None, invoice_date=None, post=True): + invoice_vals = order._prepare_invoice() + invoice_line_vals = order.order_line._prepare_invoice_line() + if quantity is not None: + invoice_line_vals["quantity"] = quantity + invoice_vals["invoice_line_ids"].append((0, 0, invoice_line_vals)) + if invoice_date is not None: + invoice_vals["invoice_date"] = invoice_date + invoice = self.env["account.move"].create(invoice_vals) + if post: + invoice.action_post() + return invoice + + def test_sale_invoice_date(self): + self.assertFalse(self.order.invoice_date) + self.assertFalse(self.order.order_line.invoice_date) + self._create_invoice(self.order, quantity=1.0, invoice_date="2022-01-01") + self.assertFalse(self.order.invoice_date) + self.assertFalse(self.order.order_line.invoice_date) + self._create_invoice(self.order, quantity=2.0, invoice_date="2022-01-02") + self.assertFalse(self.order.invoice_date) + self.assertFalse(self.order.order_line.invoice_date) + self._create_invoice(self.order, quantity=2.0, invoice_date="2022-01-03") + self.assertEqual( + self.order.order_line.invoice_date, + fields.Date.to_date("2022-01-03"), + ) + self.assertEqual( + self.order.invoice_date, + fields.Date.to_date("2022-01-03"), + ) + + def test_sale_report(self): + self._create_invoice(self.order, quantity=5.0, invoice_date="2022-01-03") + self.env.cr.flush() + res = self.env["sale.report"]._read_group( + [("name", "=", self.order.name)], + groupby=["invoice_date:month"], + ) + self.assertEqual(res[0][0], fields.Date.to_date("2022-01-01"))