diff --git a/project_purchase_link/README.rst b/project_purchase_link/README.rst new file mode 100644 index 0000000000..1459306325 --- /dev/null +++ b/project_purchase_link/README.rst @@ -0,0 +1,94 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +===================== +Project Purchase Link +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:58bc519786cdba00abecbf70c4dfc47c91c7dd091d2b89be65d4ec57d21ed390 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fproject-lightgray.png?logo=github + :target: https://github.com/OCA/project/tree/19.0/project_purchase_link + :alt: OCA/project +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/project-19-0/project-19-0-project_purchase_link + :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/project&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +With this module you can access to purchase orders and invoices related +to the project. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +1. Belong to the "Show Full Accounting Features" and "Analytic + Accounting" groups. +2. On the lines of purchase orders or invoices, indicate the analytical + account associated with the project. + +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 +------- + +* AvanzOSC + +Contributors +------------ + +- Oihane Crucelaegui +- Ana Juaristi +- Alberto Martín Cortada +- Zina Rasoamanana + +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/project `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/project_purchase_link/__init__.py b/project_purchase_link/__init__.py new file mode 100644 index 0000000000..afbde48052 --- /dev/null +++ b/project_purchase_link/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# Copyright 2026 Solomon Prabu - CIT Services +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import models diff --git a/project_purchase_link/__manifest__.py b/project_purchase_link/__manifest__.py new file mode 100644 index 0000000000..9ef9c47457 --- /dev/null +++ b/project_purchase_link/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2018 Gontzal Gomez - AvanzOSC +# Copyright 2026 Solomon Prabu - CIT Services +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + "name": "Project Purchase Link", + "version": "19.0.1.0.0", + "license": "AGPL-3", + "depends": ["project", "purchase", "hr_timesheet"], + "author": "AvanzOSC, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/project", + "category": "Project", + "data": ["views/project_project_view.xml"], + "installable": True, +} diff --git a/project_purchase_link/i18n/es.po b/project_purchase_link/i18n/es.po new file mode 100644 index 0000000000..dc85a2ef09 --- /dev/null +++ b/project_purchase_link/i18n/es.po @@ -0,0 +1,79 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_purchase_utilities +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-01-25 08:47+0000\n" +"PO-Revision-Date: 2023-09-03 13:36+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: \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: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_count +msgid "# Purchase" +msgstr "N.º de compras" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_count +msgid "# Purchase Invoice" +msgstr "N.º de facturas de compra" + +#. module: project_purchase_link +#: model:ir.model,name:project_purchase_link.model_project_project +msgid "Project" +msgstr "Proyecto" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Invoice Lines" +msgstr "Líneas de factura de compra" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoice Total" +msgstr "Total de facturas de compra" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoices" +msgstr "Facturas de compra" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order" +msgstr "Pedido de compra" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order Lines" +msgstr "Líneas de pedido de compra" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Total" +msgstr "Total de compras" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchases" +msgstr "Compras" + +#~ msgid "Purchase Lines" +#~ msgstr "Líneas de compra" diff --git a/project_purchase_link/i18n/it.po b/project_purchase_link/i18n/it.po new file mode 100644 index 0000000000..e62a4f9948 --- /dev/null +++ b/project_purchase_link/i18n/it.po @@ -0,0 +1,75 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_purchase_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-09-04 18:40+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 4.17\n" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_count +msgid "# Purchase" +msgstr "N° acquisto" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_count +msgid "# Purchase Invoice" +msgstr "N° fattura di acquisto" + +#. module: project_purchase_link +#: model:ir.model,name:project_purchase_link.model_project_project +msgid "Project" +msgstr "Progetto" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Invoice Lines" +msgstr "Righe fattura di acquisto" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoice Total" +msgstr "Totale fattura di acquisto" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoices" +msgstr "Fatture di acquisto" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order" +msgstr "Ordine di acquisto" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order Lines" +msgstr "Righe ordine di acquisto" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Total" +msgstr "Totale acquisti" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchases" +msgstr "Acquisti" diff --git a/project_purchase_link/i18n/project_purchase_link.pot b/project_purchase_link/i18n/project_purchase_link.pot new file mode 100644 index 0000000000..f8a095b131 --- /dev/null +++ b/project_purchase_link/i18n/project_purchase_link.pot @@ -0,0 +1,69 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_purchase_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_count +msgid "# Purchase" +msgstr "" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_count +msgid "# Purchase Invoice" +msgstr "" + +#. module: project_purchase_link +#: model:ir.model,name:project_purchase_link.model_project_project +msgid "Project" +msgstr "" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +msgid "Purchase Invoice Lines" +msgstr "" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoice Total" +msgstr "" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoices" +msgstr "" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +msgid "Purchase Order" +msgstr "" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +msgid "Purchase Order Lines" +msgstr "" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Total" +msgstr "" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchases" +msgstr "" diff --git a/project_purchase_link/i18n/pt_BR.po b/project_purchase_link/i18n/pt_BR.po new file mode 100644 index 0000000000..f9ad419e55 --- /dev/null +++ b/project_purchase_link/i18n/pt_BR.po @@ -0,0 +1,75 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_purchase_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-07-31 10:11+0000\n" +"Last-Translator: Adriano Prado \n" +"Language-Team: none\n" +"Language: pt_BR\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: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_count +msgid "# Purchase" +msgstr "# Compra" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_count +msgid "# Purchase Invoice" +msgstr "# Fatura de Compra" + +#. module: project_purchase_link +#: model:ir.model,name:project_purchase_link.model_project_project +msgid "Project" +msgstr "Projeto" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Invoice Lines" +msgstr "Linhas da Fatura de Compra" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoice Total" +msgstr "Total da Fatura de Compra" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoices" +msgstr "Faturas de Compra" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order" +msgstr "Pedido de Compra" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order Lines" +msgstr "Linhas do Pedido de Compra" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Total" +msgstr "Total Compra" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchases" +msgstr "Compras" diff --git a/project_purchase_link/i18n/sl.po b/project_purchase_link/i18n/sl.po new file mode 100644 index 0000000000..dbb48ffd2e --- /dev/null +++ b/project_purchase_link/i18n/sl.po @@ -0,0 +1,79 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * project_purchase_link +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-03-31 10:14+0000\n" +"Last-Translator: Matjaz Mozetic \n" +"Language-Team: none\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || " +"n%100==4 ? 2 : 3;\n" +"X-Generator: Weblate 3.10\n" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_count +msgid "# Purchase" +msgstr "# nabava" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_count +msgid "# Purchase Invoice" +msgstr "# prejeti račun" + +#. module: project_purchase_link +#: model:ir.model,name:project_purchase_link.model_project_project +msgid "Project" +msgstr "" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Invoice Lines" +msgstr "Postavke prejetega računa" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_invoice_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoice Total" +msgstr "Prejeti račun skupaj" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Invoices" +msgstr "Prejeti računi" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order" +msgstr "Nabavni nalog" + +#. module: project_purchase_link +#. odoo-python +#: code:addons/project_purchase_link/models/project_project.py:0 +#, python-format +msgid "Purchase Order Lines" +msgstr "Postavke nabavnega naloga" + +#. module: project_purchase_link +#: model:ir.model.fields,field_description:project_purchase_link.field_project_project__purchase_line_total +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchase Total" +msgstr "Skupaj nabava" + +#. module: project_purchase_link +#: model_terms:ir.ui.view,arch_db:project_purchase_link.project_project_view_form +msgid "Purchases" +msgstr "Nabave" + +#~ msgid "WBS element" +#~ msgstr "Projektni člen" diff --git a/project_purchase_link/models/__init__.py b/project_purchase_link/models/__init__.py new file mode 100644 index 0000000000..b0b99c5083 --- /dev/null +++ b/project_purchase_link/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# Copyright 2026 Solomon Prabu - CIT Services +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import project_project diff --git a/project_purchase_link/models/project_project.py b/project_purchase_link/models/project_project.py new file mode 100644 index 0000000000..54fb23488b --- /dev/null +++ b/project_purchase_link/models/project_project.py @@ -0,0 +1,181 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# Copyright 2026 Solomon Prabu - CIT Services +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import fields, models +from odoo.fields import Domain +from odoo.tools.safe_eval import safe_eval + + +class ProjectProject(models.Model): + _inherit = "project.project" + + purchase_count = fields.Integer( + compute="_compute_purchase_info", string="# Purchase" + ) + purchase_line_total = fields.Integer( + compute="_compute_purchase_info", string="Purchase Total" + ) + purchase_invoice_count = fields.Integer( + compute="_compute_purchase_invoice_info", string="# Purchase Invoice" + ) + purchase_invoice_line_total = fields.Float( + compute="_compute_purchase_invoice_info", string="Purchase Invoice Total" + ) + + def _domain_purchase_order(self): + query = self.env["purchase.order.line"]._search( + [ + ("order_id.state", "!=", "cancel"), + ] + ) + # check if analytic_distribution contains id of analytic account + query.add_where( + "purchase_order_line.analytic_distribution ?| array[%s]", + [str(project.account_id.id) for project in self], + ) + + query.order = None + query_sql = query.select( + "purchase_order_line.order_id as order_id", + ) + self.env.cr.execute(query_sql.code, query_sql.params) + purchase_lines_ids = [ + int(record.get("order_id")) for record in self.env.cr.dictfetchall() + ] + domain = Domain([("id", "in", purchase_lines_ids)]) + return domain + + def _domain_purchase_order_line(self): + query = self.env["purchase.order.line"]._search( + [ + ("order_id.state", "!=", "cancel"), + ] + ) + # check if analytic_distribution contains id of analytic account + query.add_where( + "purchase_order_line.analytic_distribution ?| array[%s]", + [str(project.account_id.id) for project in self], + ) + + query.order = None + query_sql = query.select( + "purchase_order_line.id as id", + ) + self.env.cr.execute(query_sql.code, query_sql.params) + purchase_lines_ids = [ + int(record.get("id")) for record in self.env.cr.dictfetchall() + ] + domain = Domain([("id", "in", purchase_lines_ids)]) + return domain + + def _domain_purchase_invoice(self): + query = self.env["account.move.line"]._search( + [ + ("move_id.state", "!=", "cancel"), + ] + ) + # check if analytic_distribution contains id of analytic account + query.add_where( + "account_move_line.analytic_distribution ?| array[%s]", + [str(project.account_id.id) for project in self], + ) + query.order = None + query_sql = query.select( + "DISTINCT(account_move_line.move_id) as move_id", + ) + self.env.cr.execute(query_sql.code, query_sql.params) + purchase_invoice_ids = [ + int(record.get("move_id")) for record in self.env.cr.dictfetchall() + ] + domain = Domain([("id", "in", purchase_invoice_ids)]) + return domain + + def _domain_purchase_invoice_line(self): + query = self.env["account.move.line"]._search( + [ + ("move_id.state", "!=", "cancel"), + ("move_id.move_type", "=", "in_invoice"), + ] + ) + # check if analytic_distribution contains id of analytic account + query.add_where( + "account_move_line.analytic_distribution ?| array[%s]", + [str(project.account_id.id) for project in self], + ) + query.order = None + query_sql = query.select( + "account_move_line.id as id", + ) + self.env.cr.execute(query_sql.code, query_sql.params) + purchase_invoice_lines_ids = [ + int(record.get("id")) for record in self.env.cr.dictfetchall() + ] + domain = Domain([("id", "in", purchase_invoice_lines_ids)]) + return domain + + def _compute_purchase_info(self): + for project in self: + groups = self.env["purchase.order.line"]._read_group( + project._domain_purchase_order_line(), + ["order_id"], + ["price_subtotal:sum"], + ) + project.purchase_count = len(groups) + project.purchase_line_total = sum( + price_subtotal for _order_id, price_subtotal in groups + ) + + def _compute_purchase_invoice_info(self): + for project in self: + groups = self.env["account.move.line"]._read_group( + project._domain_purchase_invoice_line(), + ["move_id"], + ["price_subtotal:sum"], + ) + project.purchase_invoice_count = len(groups) + project.purchase_invoice_line_total = sum( + price_subtotal for _move_id, price_subtotal in groups + ) + + def button_open_purchase_order(self): + self.ensure_one() + return { + "name": self.env._("Purchase Order"), + "domain": self._domain_purchase_order(), + "type": "ir.actions.act_window", + "view_mode": "list,form", + "res_model": "purchase.order", + } + + def button_open_purchase_order_line(self): + self.ensure_one() + return { + "name": self.env._("Purchase Order Lines"), + "domain": self._domain_purchase_order_line(), + "type": "ir.actions.act_window", + "view_mode": "list,form", + "res_model": "purchase.order.line", + } + + def button_open_purchase_invoice(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "account.action_move_in_invoice_type" + ) + domain = ( + Domain(safe_eval(action.get("domain", "[]"))) + & self._domain_purchase_invoice() + ) + action.update({"domain": domain}) + return action + + def button_open_purchase_invoice_line(self): + self.ensure_one() + return { + "name": self.env._("Purchase Invoice Lines"), + "domain": self._domain_purchase_invoice_line(), + "type": "ir.actions.act_window", + "view_mode": "list,form", + "res_model": "account.move.line", + } diff --git a/project_purchase_link/pyproject.toml b/project_purchase_link/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/project_purchase_link/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/project_purchase_link/readme/CONTRIBUTORS.md b/project_purchase_link/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..777ae72465 --- /dev/null +++ b/project_purchase_link/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- Oihane Crucelaegui \<\> +- Ana Juaristi \<\> +- Alberto Martín Cortada \<\> +- Zina Rasoamanana \<\> diff --git a/project_purchase_link/readme/DESCRIPTION.md b/project_purchase_link/readme/DESCRIPTION.md new file mode 100644 index 0000000000..ee283600f2 --- /dev/null +++ b/project_purchase_link/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +With this module you can access to purchase orders and invoices related +to the project. diff --git a/project_purchase_link/readme/USAGE.md b/project_purchase_link/readme/USAGE.md new file mode 100644 index 0000000000..8296de4097 --- /dev/null +++ b/project_purchase_link/readme/USAGE.md @@ -0,0 +1,6 @@ +To use this module, you need to: + +1. Belong to the "Show Full Accounting Features" and "Analytic + Accounting" groups. +2. On the lines of purchase orders or invoices, indicate the analytical + account associated with the project. diff --git a/project_purchase_link/static/description/icon.png b/project_purchase_link/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/project_purchase_link/static/description/icon.png differ diff --git a/project_purchase_link/static/description/index.html b/project_purchase_link/static/description/index.html new file mode 100644 index 0000000000..616671df50 --- /dev/null +++ b/project_purchase_link/static/description/index.html @@ -0,0 +1,444 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + + +
+ + diff --git a/project_purchase_link/tests/__init__.py b/project_purchase_link/tests/__init__.py new file mode 100644 index 0000000000..f60408dbde --- /dev/null +++ b/project_purchase_link/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import test_project_purchase_link diff --git a/project_purchase_link/tests/test_project_purchase_link.py b/project_purchase_link/tests/test_project_purchase_link.py new file mode 100644 index 0000000000..f5b6397750 --- /dev/null +++ b/project_purchase_link/tests/test_project_purchase_link.py @@ -0,0 +1,111 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# Copyright 2026 Solomon Prabu - CIT Services +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import Command +from odoo.fields import Domain +from odoo.tools.safe_eval import safe_eval + +from odoo.addons.base.tests.common import BaseCommon + + +class TestProjectPurchaseUtilities(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.project_model = cls.env["project.project"] + cls.project = cls.project_model.create({"name": "Test Project"}) + cls.purchase_model = cls.env["purchase.order"] + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + cls.product = cls.env["product.product"].create( + { + "name": "Product Product 4", + "standard_price": 500.0, + "list_price": 750.0, + "type": "consu", + "categ_id": cls.env["product.category"].search([], limit=1).id, + } + ) + cls.purchase = cls.purchase_model.create( + { + "partner_id": cls.partner.id, + } + ) + cls.invoice_model = cls.env["account.move"] + cls.invoice_line_model = cls.env["account.move.line"] + + def test_project_purchase(self): + self.assertTrue(self.purchase) + self.purchase.write({"invoice_status": "to invoice"}) + self.assertFalse(self.project.purchase_count) + self.assertFalse(self.project.purchase_line_total) + self.assertFalse(self.project.purchase_invoice_count) + self.assertFalse(self.project.purchase_invoice_line_total) + self.purchase.write( + { + "order_line": [ + Command.create( + { + "name": "Test line", + "analytic_distribution": {self.project.account_id.id: 100}, + "price_unit": 50, + "product_qty": 4, + "qty_received": 4, + "product_uom_id": self.product.uom_id.id, + "product_id": self.product.id, + } + ) + ] + } + ) + + self.env.invalidate_all() + + self.assertEqual(self.project.purchase_count, 1) + self.assertEqual(self.project.purchase_line_total, 200) + self.assertFalse(self.project.purchase_invoice_count) + self.assertFalse(self.project.purchase_invoice_line_total) + self.purchase.button_confirm() + invoice = self.invoice_model.create( + { + "partner_id": self.purchase.partner_id.id, + "purchase_id": self.purchase.id, + "move_type": "in_invoice", + } + ) + for line in self.purchase.order_line: + categ_id = line.product_id.categ_id + account_id = categ_id.property_account_expense_categ_id.id + vals = { + "move_id": invoice.id, + "name": line.name, + "account_id": account_id, + "analytic_distribution": line.analytic_distribution, + } + self.invoice_line_model.create(vals) + self.env.invalidate_all() + self.assertEqual(self.project.purchase_invoice_count, 1) + + purchase_domain = self.project._domain_purchase_order_line() + + lines = self.env["purchase.order.line"].search(purchase_domain) + order_domain = Domain([("id", "in", lines.mapped("order_id").ids)]) + purchase_dict = self.project.button_open_purchase_order() + self.assertEqual(purchase_dict.get("domain"), order_domain) + purchase_line_dict = self.project.button_open_purchase_order_line() + self.assertEqual(purchase_line_dict.get("domain"), purchase_domain) + + action = self.env.ref("account.action_move_in_invoice_type") + invoice_domain = ( + Domain(safe_eval(action.domain or "[]")) + & self.project._domain_purchase_invoice() + ) # only one test invoice (line) + + invoice_dict = self.project.button_open_purchase_invoice() + self.assertEqual(invoice_dict.get("domain"), invoice_domain) + + invoice_line_domain = self.project._domain_purchase_invoice_line() + + invoice_line_dict = self.project.button_open_purchase_invoice_line() + self.assertEqual(invoice_line_dict.get("domain"), invoice_line_domain) diff --git a/project_purchase_link/views/project_project_view.xml b/project_purchase_link/views/project_project_view.xml new file mode 100644 index 0000000000..1dfbfefa7d --- /dev/null +++ b/project_purchase_link/views/project_project_view.xml @@ -0,0 +1,55 @@ + + + + project.project + + +
+ + + + +
+
+
+