From 91cf8c52ce24b2c6049a175eb36078ffae791858 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?=
Date: Mon, 27 Jun 2022 10:07:02 +0200
Subject: [PATCH 01/15] [ADD] sale_timesheet_budget: New addon
---
sale_timesheet_budget/README.rst | 98 ++++
sale_timesheet_budget/__init__.py | 1 +
sale_timesheet_budget/__manifest__.py | 17 +
sale_timesheet_budget/i18n/es.po | 124 +++++
.../i18n/sale_timesheet_budget.pot | 119 +++++
sale_timesheet_budget/models/__init__.py | 3 +
.../models/project_project.py | 72 +++
sale_timesheet_budget/readme/CONTRIBUTORS.rst | 4 +
sale_timesheet_budget/readme/DESCRIPTION.rst | 1 +
sale_timesheet_budget/readme/ROADMAP.rst | 1 +
sale_timesheet_budget/readme/USAGE.rst | 5 +
.../security/ir.model.access.csv | 3 +
.../static/description/icon.png | Bin 0 -> 9455 bytes
.../static/description/index.html | 443 ++++++++++++++++++
sale_timesheet_budget/tests/__init__.py | 3 +
.../tests/test_sale_timesheet_budget.py | 45 ++
.../views/project_project_view.xml | 46 ++
17 files changed, 985 insertions(+)
create mode 100644 sale_timesheet_budget/README.rst
create mode 100644 sale_timesheet_budget/__init__.py
create mode 100644 sale_timesheet_budget/__manifest__.py
create mode 100644 sale_timesheet_budget/i18n/es.po
create mode 100644 sale_timesheet_budget/i18n/sale_timesheet_budget.pot
create mode 100644 sale_timesheet_budget/models/__init__.py
create mode 100644 sale_timesheet_budget/models/project_project.py
create mode 100644 sale_timesheet_budget/readme/CONTRIBUTORS.rst
create mode 100644 sale_timesheet_budget/readme/DESCRIPTION.rst
create mode 100644 sale_timesheet_budget/readme/ROADMAP.rst
create mode 100644 sale_timesheet_budget/readme/USAGE.rst
create mode 100644 sale_timesheet_budget/security/ir.model.access.csv
create mode 100644 sale_timesheet_budget/static/description/icon.png
create mode 100644 sale_timesheet_budget/static/description/index.html
create mode 100644 sale_timesheet_budget/tests/__init__.py
create mode 100644 sale_timesheet_budget/tests/test_sale_timesheet_budget.py
create mode 100644 sale_timesheet_budget/views/project_project_view.xml
diff --git a/sale_timesheet_budget/README.rst b/sale_timesheet_budget/README.rst
new file mode 100644
index 0000000000..0a719c8e38
--- /dev/null
+++ b/sale_timesheet_budget/README.rst
@@ -0,0 +1,98 @@
+=====================
+Sale timesheet budget
+=====================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |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%2Ftimesheet-lightgray.png?logo=github
+ :target: https://github.com/OCA/timesheet/tree/14.0/sale_timesheet_budget
+ :alt: OCA/timesheet
+.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
+ :target: https://translation.odoo-community.org/projects/timesheet-14-0/timesheet-14-0-sale_timesheet_budget
+ :alt: Translate me on Weblate
+.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
+ :target: https://runbot.odoo-community.org/runbot/117/14.0
+ :alt: Try me on Runbot
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+This addon adds the "Budget" tab to the projects to be able to set some prices (benefits/expenses) linked to sales orders.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Usage
+=====
+
+#. Go to *Projects* and create and create a new one and set Customer and analytic account.
+#. Go to *Sales -> Orders -> Quotations* and create a new one according to Customer and Analytic account previously created.
+#. Go to *Projects* and edit project previously created.
+#. Add some records (positive or negative) in "Budget" tab.
+#. Go to *Project Overview* smart-button and a new line related to *Profitability* block have been created.
+
+Known issues / Roadmap
+======================
+
+* Consider the planned hours of the tasks based on price/hour profiles.
+
+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 smashing it by providing a detailed and welcomed
+`feedback `_.
+
+Do not contact contributors directly about support or help with technical issues.
+
+Credits
+=======
+
+Authors
+~~~~~~~
+
+* Tecnativa
+
+Contributors
+~~~~~~~~~~~~
+
+* `Tecnativa `_:
+
+ * Víctor Martínez
+ * Pedro M. Baeza
+
+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-victoralmau| image:: https://github.com/victoralmau.png?size=40px
+ :target: https://github.com/victoralmau
+ :alt: victoralmau
+
+Current `maintainer `__:
+
+|maintainer-victoralmau|
+
+This module is part of the `OCA/timesheet `_ project on GitHub.
+
+You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/sale_timesheet_budget/__init__.py b/sale_timesheet_budget/__init__.py
new file mode 100644
index 0000000000..0650744f6b
--- /dev/null
+++ b/sale_timesheet_budget/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/sale_timesheet_budget/__manifest__.py b/sale_timesheet_budget/__manifest__.py
new file mode 100644
index 0000000000..6148842d52
--- /dev/null
+++ b/sale_timesheet_budget/__manifest__.py
@@ -0,0 +1,17 @@
+# Copyright 2022 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+{
+ "name": "Sale timesheet budget",
+ "version": "14.0.1.0.0",
+ "category": "Timesheet",
+ "website": "https://github.com/OCA/timesheet",
+ "author": "Tecnativa, Odoo Community Association (OCA)",
+ "license": "AGPL-3",
+ "depends": ["sale_timesheet"],
+ "installable": True,
+ "data": [
+ "security/ir.model.access.csv",
+ "views/project_project_view.xml",
+ ],
+ "maintainers": ["victoralmau"],
+}
diff --git a/sale_timesheet_budget/i18n/es.po b/sale_timesheet_budget/i18n/es.po
new file mode 100644
index 0000000000..5803370b9d
--- /dev/null
+++ b/sale_timesheet_budget/i18n/es.po
@@ -0,0 +1,124 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * sale_timesheet_budget
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-06-27 11:03+0000\n"
+"PO-Revision-Date: 2022-06-27 13:04+0200\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: \n"
+"X-Generator: Poedit 2.3\n"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__allowed_sale_order_ids
+msgid "Allowed Sale Order"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__amount
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+msgid "Amount"
+msgstr "Importe"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__analytic_account_id
+msgid "Analytic Account"
+msgstr "Cuenta analítica"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,help:sale_timesheet_budget.field_project_project_budget__analytic_account_id
+msgid ""
+"Analytic account to which this project is linked for financial management. "
+"Use an analytic account to record cost and revenue on your project."
+msgstr ""
+"Cuenta analítica a la que se vincula este proyecto para la gestión "
+"financiera. Utilice una cuenta analítica para registrar los costes y los "
+"ingresos de su proyecto."
+
+#. module: sale_timesheet_budget
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.timesheet_plan
+msgid "Budget"
+msgstr "Presupuesto"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_amount
+msgid "Budget Amount"
+msgstr "Importe de presupuesto"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_ids
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+msgid "Budgets"
+msgstr "Presupuestos"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_uid
+msgid "Created by"
+msgstr "Creado por"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_date
+msgid "Created on"
+msgstr "Creado el"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__display_name
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__display_name
+msgid "Display Name"
+msgstr "Nombre mostrado"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__id
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__id
+msgid "ID"
+msgstr "ID"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project____last_update
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget____last_update
+msgid "Last Modified on"
+msgstr "Última modificación el"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__write_uid
+msgid "Last Updated by"
+msgstr "Última Actualización por"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__write_date
+msgid "Last Updated on"
+msgstr "Actualizado el"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__price_unit
+msgid "Product Price"
+msgstr "Precio de producto"
+
+#. module: sale_timesheet_budget
+#: model:ir.model,name:sale_timesheet_budget.model_project_project
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__project_id
+msgid "Project"
+msgstr "Proyecto"
+
+#. module: sale_timesheet_budget
+#: model:ir.model,name:sale_timesheet_budget.model_project_project_budget
+msgid "Project Project Budget"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__quantity
+msgid "Quantity"
+msgstr "Cantidad"
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__sale_order_id
+msgid "Sale Order"
+msgstr "Pedido de venta"
diff --git a/sale_timesheet_budget/i18n/sale_timesheet_budget.pot b/sale_timesheet_budget/i18n/sale_timesheet_budget.pot
new file mode 100644
index 0000000000..442c33fd76
--- /dev/null
+++ b/sale_timesheet_budget/i18n/sale_timesheet_budget.pot
@@ -0,0 +1,119 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * sale_timesheet_budget
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-06-27 11:03+0000\n"
+"PO-Revision-Date: 2022-06-27 11:03+0000\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_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__allowed_sale_order_ids
+msgid "Allowed Sale Order"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__amount
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+msgid "Amount"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__analytic_account_id
+msgid "Analytic Account"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,help:sale_timesheet_budget.field_project_project_budget__analytic_account_id
+msgid ""
+"Analytic account to which this project is linked for financial management. "
+"Use an analytic account to record cost and revenue on your project."
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.timesheet_plan
+msgid "Budget"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_amount
+msgid "Budget Amount"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_ids
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+msgid "Budgets"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__display_name
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__id
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__id
+msgid "ID"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project____last_update
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__price_unit
+msgid "Product Price"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model,name:sale_timesheet_budget.model_project_project
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__project_id
+msgid "Project"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model,name:sale_timesheet_budget.model_project_project_budget
+msgid "Project Project Budget"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__quantity
+msgid "Quantity"
+msgstr ""
+
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__sale_order_id
+msgid "Sale Order"
+msgstr ""
diff --git a/sale_timesheet_budget/models/__init__.py b/sale_timesheet_budget/models/__init__.py
new file mode 100644
index 0000000000..c183898c17
--- /dev/null
+++ b/sale_timesheet_budget/models/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import project_project
diff --git a/sale_timesheet_budget/models/project_project.py b/sale_timesheet_budget/models/project_project.py
new file mode 100644
index 0000000000..c8fd41748f
--- /dev/null
+++ b/sale_timesheet_budget/models/project_project.py
@@ -0,0 +1,72 @@
+# Copyright 2022 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo import api, fields, models
+
+
+class ProjectProject(models.Model):
+ _inherit = "project.project"
+
+ budget_ids = fields.One2many(
+ comodel_name="project.project.budget",
+ inverse_name="project_id",
+ string="Budgets",
+ copy=False,
+ )
+ budget_amount = fields.Float(
+ compute="_compute_budget_amount", string="Budget Amount"
+ )
+
+ @api.depends("budget_ids")
+ def _compute_budget_amount(self):
+ for item in self:
+ item.budget_amount = sum(item.mapped("budget_ids.amount"))
+
+ def _plan_prepare_values(self):
+ res = super()._plan_prepare_values()
+ res["dashboard"]["profit"]["budget_amount"] = sum(self.mapped("budget_amount"))
+ res["dashboard"]["profit"]["total"] += sum(self.mapped("budget_amount"))
+ return res
+
+
+class ProjectProjectBudget(models.Model):
+ _name = "project.project.budget"
+ _description = "Project Project Budget"
+
+ project_id = fields.Many2one(
+ comodel_name="project.project", string="Project", required=True
+ )
+ allowed_sale_order_ids = fields.Many2many(
+ comodel_name="sale.order", compute="_compute_allowed_sale_order_ids"
+ )
+ sale_order_id = fields.Many2one(
+ comodel_name="sale.order",
+ string="Sale Order",
+ domain="[('id', 'in', allowed_sale_order_ids)]",
+ )
+ analytic_account_id = fields.Many2one(related="project_id.analytic_account_id")
+ quantity = fields.Float(
+ string="Quantity", digits="Account", default=1, required=True
+ )
+ price_unit = fields.Float(string="Product Price", digits="Account", required=True)
+ amount = fields.Float(compute="_compute_amount", string="Amount", store=True)
+
+ @api.depends("project_id")
+ def _compute_allowed_sale_order_ids(self):
+ sale_order_model = self.env["sale.order"].sudo()
+ for item in self:
+ item.allowed_sale_order_ids = sale_order_model.search(
+ [
+ ("partner_id", "=", item.project_id.partner_id.id),
+ (
+ "analytic_account_id",
+ "=",
+ item.project_id.analytic_account_id.id,
+ ),
+ ]
+ )
+
+ @api.depends("quantity", "price_unit")
+ def _compute_amount(self):
+ for item in self:
+ item.amount = item.quantity * item.price_unit
diff --git a/sale_timesheet_budget/readme/CONTRIBUTORS.rst b/sale_timesheet_budget/readme/CONTRIBUTORS.rst
new file mode 100644
index 0000000000..5fb7130530
--- /dev/null
+++ b/sale_timesheet_budget/readme/CONTRIBUTORS.rst
@@ -0,0 +1,4 @@
+* `Tecnativa `_:
+
+ * Víctor Martínez
+ * Pedro M. Baeza
diff --git a/sale_timesheet_budget/readme/DESCRIPTION.rst b/sale_timesheet_budget/readme/DESCRIPTION.rst
new file mode 100644
index 0000000000..e527ae62d9
--- /dev/null
+++ b/sale_timesheet_budget/readme/DESCRIPTION.rst
@@ -0,0 +1 @@
+This addon adds the "Budget" tab to the projects to be able to set some prices (benefits/expenses) linked to sales orders.
diff --git a/sale_timesheet_budget/readme/ROADMAP.rst b/sale_timesheet_budget/readme/ROADMAP.rst
new file mode 100644
index 0000000000..9347a7c403
--- /dev/null
+++ b/sale_timesheet_budget/readme/ROADMAP.rst
@@ -0,0 +1 @@
+* Consider the planned hours of the tasks based on price/hour profiles.
diff --git a/sale_timesheet_budget/readme/USAGE.rst b/sale_timesheet_budget/readme/USAGE.rst
new file mode 100644
index 0000000000..966fd19ebb
--- /dev/null
+++ b/sale_timesheet_budget/readme/USAGE.rst
@@ -0,0 +1,5 @@
+#. Go to *Projects* and create and create a new one and set Customer and analytic account.
+#. Go to *Sales -> Orders -> Quotations* and create a new one according to Customer and Analytic account previously created.
+#. Go to *Projects* and edit project previously created.
+#. Add some records (positive or negative) in "Budget" tab.
+#. Go to *Project Overview* smart-button and a new line related to *Profitability* block have been created.
diff --git a/sale_timesheet_budget/security/ir.model.access.csv b/sale_timesheet_budget/security/ir.model.access.csv
new file mode 100644
index 0000000000..a047a568e8
--- /dev/null
+++ b/sale_timesheet_budget/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
+access_project_project_budget_admin,project_project_budget_portal,model_project_project_budget,project.group_project_manager,1,1,1,1
+access_project_project_budget_user,project_project_budget_user,model_project_project_budget,project.group_project_user,1,0,0,0
diff --git a/sale_timesheet_budget/static/description/icon.png b/sale_timesheet_budget/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d
GIT binary patch
literal 9455
zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~!
zVpnB`o+K7|Al`Q_U;eD$B
zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA
z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__
zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_
zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I
z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U
z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)(
z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH
zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW
z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx
zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h
zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9
zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz#
z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA
zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K=
z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS
zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C
zuVl&0duN<;uOsB3%T9Fp8t{ED108)`y_~Hnd9AUX7h-H?jVuU|}My+C=TjH(jKz
zqMVr0re3S$H@t{zI95qa)+Crz*5Zj}Ao%4Z><+W(nOZd?gDnfNBC3>M8WE61$So|P
zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO
z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1
zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_
zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8
zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ>
zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN
z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h
zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d
zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB
zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz
z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I
zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X
zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD
z#z-)AXwSRY?OPefw^iI+
z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd
z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs
z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I
z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$
z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV
z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s
zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6
zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u
zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q
zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH
zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c
zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT
zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+
z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ
zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy
zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC)
zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a
zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x!
zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X
zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8
z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A
z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H
zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n=
z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK
z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z
zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h
z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD
z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW
zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@
zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz
z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y<
zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X
zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6
zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6%
z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(|
z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ
z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H
zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6
z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d}
z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A
zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB
z
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
Xviia!U7SGha1wx#SCgwmn*{w2TRX*I
literal 0
HcmV?d00001
diff --git a/sale_timesheet_budget/static/description/index.html b/sale_timesheet_budget/static/description/index.html
new file mode 100644
index 0000000000..7d49620830
--- /dev/null
+++ b/sale_timesheet_budget/static/description/index.html
@@ -0,0 +1,443 @@
+
+
+
+
+
+
+Sale timesheet budget
+
+
+
+
+
Sale timesheet budget
+
+
+

+
This addon adds the “Budget” tab to the projects to be able to set some prices (benefits/expenses) linked to sales orders.
+
Table of contents
+
+
+
+
+- Go to Projects and create and create a new one and set Customer and analytic account.
+- Go to Sales -> Orders -> Quotations and create a new one according to Customer and Analytic account previously created.
+- Go to Projects and edit project previously created.
+- Add some records (positive or negative) in “Budget” tab.
+- Go to Project Overview smart-button and a new line related to Profitability block have been created.
+
+
+
+
+
+- Consider the planned hours of the tasks based on price/hour profiles.
+
+
+
+
+
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 smashing it by providing a detailed and welcomed
+feedback.
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
+
+
+
+
+- Tecnativa:
+- Víctor Martínez
+- Pedro M. Baeza
+
+
+
+
+
+
+
This module is maintained by the OCA.
+

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

+
This module is part of the OCA/timesheet project on GitHub.
+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
+
+
+
+
+
diff --git a/sale_timesheet_budget/tests/__init__.py b/sale_timesheet_budget/tests/__init__.py
new file mode 100644
index 0000000000..34e6d3d843
--- /dev/null
+++ b/sale_timesheet_budget/tests/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from . import test_sale_timesheet_budget
diff --git a/sale_timesheet_budget/tests/test_sale_timesheet_budget.py b/sale_timesheet_budget/tests/test_sale_timesheet_budget.py
new file mode 100644
index 0000000000..e9b2e04505
--- /dev/null
+++ b/sale_timesheet_budget/tests/test_sale_timesheet_budget.py
@@ -0,0 +1,45 @@
+# Copyright 2022 Tecnativa - Víctor Martínez
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.tests import Form, common
+
+
+class TestSaleTimesheetBudget(common.SavepointCase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.customer = cls.env["res.partner"].create({"name": "Mr Odoo"})
+ cls.analytic_account = cls.env["account.analytic.account"].create(
+ {
+ "name": "Test account",
+ "partner_id": cls.customer.id,
+ }
+ )
+ cls.sale_order = cls.env["sale.order"].create(
+ {
+ "partner_id": cls.customer.id,
+ "analytic_account_id": cls.analytic_account.id,
+ }
+ )
+ cls.project = cls.env["project.project"].create(
+ {
+ "name": "Test project",
+ "partner_id": cls.customer.id,
+ "analytic_account_id": cls.analytic_account.id,
+ }
+ )
+
+ def test_project_budget(self):
+ project_form = Form(self.project)
+ with project_form.budget_ids.new() as budget_form:
+ budget_form.sale_order_id = self.sale_order
+ budget_form.quantity = 2
+ budget_form.price_unit = 10
+ with project_form.budget_ids.new() as budget_form:
+ budget_form.sale_order_id = self.sale_order
+ budget_form.quantity = -1
+ budget_form.price_unit = 10
+ project_form.save()
+ self.assertEqual(self.project.budget_amount, 10)
+ vals = self.project._plan_prepare_values()
+ self.assertEqual(vals["dashboard"]["profit"]["budget_amount"], 10)
diff --git a/sale_timesheet_budget/views/project_project_view.xml b/sale_timesheet_budget/views/project_project_view.xml
new file mode 100644
index 0000000000..277b34e3f5
--- /dev/null
+++ b/sale_timesheet_budget/views/project_project_view.xml
@@ -0,0 +1,46 @@
+
+
+ project.project.form
+ project.project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project.project.timesheet_plan
+ project.project
+
+
+
+
+ |
+
+ |
+ Budget |
+
+
+
+
+
From e1ff2f69a82c8f3a984db2d00cc38062d76adbae Mon Sep 17 00:00:00 2001
From: "Pedro M. Baeza"
Date: Sun, 3 Jul 2022 18:02:54 +0200
Subject: [PATCH 02/15] [IMP] sale_timesheet_budget: Some improvements
- Better view with optional fields and column invisible
- Better README
[UPD] Update sale_timesheet_budget.pot
[UPD] README.rst
---
sale_timesheet_budget/README.rst | 16 ++++++++-----
.../i18n/sale_timesheet_budget.pot | 16 +++++++++----
.../models/project_project.py | 9 ++++++--
sale_timesheet_budget/readme/DESCRIPTION.rst | 3 ++-
sale_timesheet_budget/readme/USAGE.rst | 13 +++++++----
.../static/description/index.html | 18 +++++++++------
.../views/project_project_view.xml | 23 +++++++++++++------
7 files changed, 66 insertions(+), 32 deletions(-)
diff --git a/sale_timesheet_budget/README.rst b/sale_timesheet_budget/README.rst
index 0a719c8e38..e341cb3898 100644
--- a/sale_timesheet_budget/README.rst
+++ b/sale_timesheet_budget/README.rst
@@ -25,7 +25,8 @@ Sale timesheet budget
|badge1| |badge2| |badge3| |badge4| |badge5|
-This addon adds the "Budget" tab to the projects to be able to set some prices (benefits/expenses) linked to sales orders.
+This module adds the "Budget" tab to the projects/sales orders to be able to set
+some additional lines (incomes/expenses) linked to a planned budget.
**Table of contents**
@@ -35,11 +36,14 @@ This addon adds the "Budget" tab to the projects to be able to set some prices (
Usage
=====
-#. Go to *Projects* and create and create a new one and set Customer and analytic account.
-#. Go to *Sales -> Orders -> Quotations* and create a new one according to Customer and Analytic account previously created.
-#. Go to *Projects* and edit project previously created.
-#. Add some records (positive or negative) in "Budget" tab.
-#. Go to *Project Overview* smart-button and a new line related to *Profitability* block have been created.
+#. Go to *Projects* and create a new one, setting Customer and analytic account.
+#. Go to *Sales -> Orders -> Quotations* and create a new one setting the same
+ customer and project previously created.
+#. Alternatively, you can create a sales order with lines that creates a project.
+#. Go to the project, and edit it.
+#. Add some records (positive or negative) in the "Budget" tab.
+#. Go to *Project Overview* smart-button and a new line called "Budget" in the
+ *Profitability* section will appear with the total amount of the lines.
Known issues / Roadmap
======================
diff --git a/sale_timesheet_budget/i18n/sale_timesheet_budget.pot b/sale_timesheet_budget/i18n/sale_timesheet_budget.pot
index 442c33fd76..bbfc8a18e4 100644
--- a/sale_timesheet_budget/i18n/sale_timesheet_budget.pot
+++ b/sale_timesheet_budget/i18n/sale_timesheet_budget.pot
@@ -6,8 +6,6 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-06-27 11:03+0000\n"
-"PO-Revision-Date: 2022-06-27 11:03+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -22,7 +20,7 @@ msgstr ""
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__amount
-#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.project_project_view_form
msgid "Amount"
msgstr ""
@@ -50,10 +48,15 @@ msgstr ""
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_ids
-#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.edit_project
+#: model_terms:ir.ui.view,arch_db:sale_timesheet_budget.project_project_view_form
msgid "Budgets"
msgstr ""
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__name
+msgid "Concept"
+msgstr ""
+
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_uid
msgid "Created by"
@@ -64,6 +67,11 @@ msgstr ""
msgid "Created on"
msgstr ""
+#. module: sale_timesheet_budget
+#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__date
+msgid "Date"
+msgstr ""
+
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__display_name
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__display_name
diff --git a/sale_timesheet_budget/models/project_project.py b/sale_timesheet_budget/models/project_project.py
index c8fd41748f..61b592a24a 100644
--- a/sale_timesheet_budget/models/project_project.py
+++ b/sale_timesheet_budget/models/project_project.py
@@ -23,16 +23,21 @@ def _compute_budget_amount(self):
item.budget_amount = sum(item.mapped("budget_ids.amount"))
def _plan_prepare_values(self):
+ """Inject the budget amounts in the project overview."""
res = super()._plan_prepare_values()
- res["dashboard"]["profit"]["budget_amount"] = sum(self.mapped("budget_amount"))
- res["dashboard"]["profit"]["total"] += sum(self.mapped("budget_amount"))
+ budget_amount = sum(self.mapped("budget_amount"))
+ res["dashboard"]["profit"]["budget_amount"] = budget_amount
+ res["dashboard"]["profit"]["total"] += budget_amount
return res
class ProjectProjectBudget(models.Model):
_name = "project.project.budget"
_description = "Project Project Budget"
+ _order = "date, id"
+ date = fields.Date()
+ name = fields.Char(string="Concept")
project_id = fields.Many2one(
comodel_name="project.project", string="Project", required=True
)
diff --git a/sale_timesheet_budget/readme/DESCRIPTION.rst b/sale_timesheet_budget/readme/DESCRIPTION.rst
index e527ae62d9..a2ef1abc85 100644
--- a/sale_timesheet_budget/readme/DESCRIPTION.rst
+++ b/sale_timesheet_budget/readme/DESCRIPTION.rst
@@ -1 +1,2 @@
-This addon adds the "Budget" tab to the projects to be able to set some prices (benefits/expenses) linked to sales orders.
+This module adds the "Budget" tab to the projects/sales orders to be able to set
+some additional lines (incomes/expenses) linked to a planned budget.
diff --git a/sale_timesheet_budget/readme/USAGE.rst b/sale_timesheet_budget/readme/USAGE.rst
index 966fd19ebb..f0e97cf2ac 100644
--- a/sale_timesheet_budget/readme/USAGE.rst
+++ b/sale_timesheet_budget/readme/USAGE.rst
@@ -1,5 +1,8 @@
-#. Go to *Projects* and create and create a new one and set Customer and analytic account.
-#. Go to *Sales -> Orders -> Quotations* and create a new one according to Customer and Analytic account previously created.
-#. Go to *Projects* and edit project previously created.
-#. Add some records (positive or negative) in "Budget" tab.
-#. Go to *Project Overview* smart-button and a new line related to *Profitability* block have been created.
+#. Go to *Projects* and create a new one, setting Customer and analytic account.
+#. Go to *Sales -> Orders -> Quotations* and create a new one setting the same
+ customer and project previously created.
+#. Alternatively, you can create a sales order with lines that creates a project.
+#. Go to the project, and edit it.
+#. Add some records (positive or negative) in the "Budget" tab.
+#. Go to *Project Overview* smart-button and a new line called "Budget" in the
+ *Profitability* section will appear with the total amount of the lines.
diff --git a/sale_timesheet_budget/static/description/index.html b/sale_timesheet_budget/static/description/index.html
index 7d49620830..e601d0efbf 100644
--- a/sale_timesheet_budget/static/description/index.html
+++ b/sale_timesheet_budget/static/description/index.html
@@ -3,7 +3,7 @@
-
+
Sale timesheet budget
-
-
Sale timesheet budget
+
+
+
+
+
+
+
Sale timesheet budget
-

+

This module adds the “Budget” tab to the projects/sales orders to be
able to set some additional lines (incomes/expenses) linked to a planned
budget.
@@ -388,7 +393,7 @@
Sale timesheet budget
-
+
- Go to Projects and create a new one, setting Customer, analytic
account and Billable.
@@ -404,13 +409,13 @@
-
+
- Consider the planned hours of the tasks based on price/hour profiles.
-
+
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
@@ -418,15 +423,15 @@
Do not contact contributors directly about support or help with technical issues.
+
From c7b9f28f62eb9e991638ebb48fb978aeb0bdfc0c Mon Sep 17 00:00:00 2001
From: Ed-Spain
Date: Thu, 16 Apr 2026 18:56:41 +0000
Subject: [PATCH 13/15] Translated using Weblate (Spanish)
Currently translated at 95.2% (20 of 21 strings)
Translation: timesheet-18.0/timesheet-18.0-sale_timesheet_budget
Translate-URL: https://translation.odoo-community.org/projects/timesheet-18-0/timesheet-18-0-sale_timesheet_budget/es/
---
sale_timesheet_budget/i18n/es.po | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/sale_timesheet_budget/i18n/es.po b/sale_timesheet_budget/i18n/es.po
index 3beaa01cdd..a674a4996a 100644
--- a/sale_timesheet_budget/i18n/es.po
+++ b/sale_timesheet_budget/i18n/es.po
@@ -7,15 +7,15 @@ msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-27 11:03+0000\n"
-"PO-Revision-Date: 2022-06-27 13:04+0200\n"
-"Last-Translator: \n"
+"PO-Revision-Date: 2026-04-16 21:45+0000\n"
+"Last-Translator: Ed-Spain \n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: \n"
-"X-Generator: Poedit 2.3\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 5.15.2\n"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__amount
@@ -40,6 +40,15 @@ msgid ""
"necessary.\n"
"An analytic account is required in order to use timesheets."
msgstr ""
+"Cuenta analítica vinculada a este proyecto, sus tareas y sus hojas de "
+"horas.. \n"
+"Realice un seguimiento de los costos e ingresos de su proyecto configurando "
+"esta cuenta analítica en los documentos relacionados (por ejemplo, pedidos "
+"de venta, facturas, órdenes de compra, facturas de proveedores, gastos, etc.)"
+".\n"
+"Esta cuenta analítica se puede modificar individualmente para cada tarea si "
+"es necesario.\n"
+"Se requiere una cuenta analítica para utilizar las hojas de horas."
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project__budget_amount
@@ -58,7 +67,7 @@ msgstr "Presupuestos"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__name
msgid "Concept"
-msgstr ""
+msgstr "Concepto"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__create_uid
@@ -73,7 +82,7 @@ msgstr "Creado el"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__date
msgid "Date"
-msgstr ""
+msgstr "Fecha"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__display_name
@@ -114,12 +123,12 @@ msgstr "Proyecto"
#. module: sale_timesheet_budget
#: model:ir.actions.act_window,name:sale_timesheet_budget.action_project_project_budget
msgid "Project Budgets"
-msgstr ""
+msgstr "Presupuestos Proyectos"
#. module: sale_timesheet_budget
#: model:ir.model,name:sale_timesheet_budget.model_project_project_budget
msgid "Project Project Budget"
-msgstr ""
+msgstr "Proyecto Presupuesto del Proyecto"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__quantity
@@ -135,4 +144,3 @@ msgstr "Pedido de venta"
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__sale_order_id_domain
msgid "Sale Order Id Domain"
msgstr ""
-
From c24f61b5fbc1cc0ce8869b379050739d3fb124e4 Mon Sep 17 00:00:00 2001
From: Ed-Spain
Date: Sun, 10 May 2026 09:26:46 +0000
Subject: [PATCH 14/15] Translated using Weblate (Spanish)
Currently translated at 100.0% (21 of 21 strings)
Translation: timesheet-18.0/timesheet-18.0-sale_timesheet_budget
Translate-URL: https://translation.odoo-community.org/projects/timesheet-18-0/timesheet-18-0-sale_timesheet_budget/es/
---
sale_timesheet_budget/i18n/es.po | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sale_timesheet_budget/i18n/es.po b/sale_timesheet_budget/i18n/es.po
index a674a4996a..baa862697e 100644
--- a/sale_timesheet_budget/i18n/es.po
+++ b/sale_timesheet_budget/i18n/es.po
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-27 11:03+0000\n"
-"PO-Revision-Date: 2026-04-16 21:45+0000\n"
+"PO-Revision-Date: 2026-05-10 09:27+0000\n"
"Last-Translator: Ed-Spain \n"
"Language-Team: \n"
"Language: es\n"
@@ -143,4 +143,4 @@ msgstr "Pedido de venta"
#. module: sale_timesheet_budget
#: model:ir.model.fields,field_description:sale_timesheet_budget.field_project_project_budget__sale_order_id_domain
msgid "Sale Order Id Domain"
-msgstr ""
+msgstr "Dominio del ID del pedido de venta"
From 3bdd82f58cec8bc3d5fb678ac77badf4a00eb2da Mon Sep 17 00:00:00 2001
From: uncannycs
Date: Mon, 18 May 2026 13:20:18 +0530
Subject: [PATCH 15/15] [MIG] sale_timesheet_budget : Migration to 19.0.
---
sale_timesheet_budget/README.rst | 10 ++++----
sale_timesheet_budget/__manifest__.py | 2 +-
sale_timesheet_budget/i18n/es.po | 2 +-
.../models/project_project.py | 20 +++++++++------
.../static/description/index.html | 6 ++---
.../tests/test_sale_timesheet_budget.py | 25 ++++++++++++++-----
6 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/sale_timesheet_budget/README.rst b/sale_timesheet_budget/README.rst
index ed9d923ee5..d5104915d5 100644
--- a/sale_timesheet_budget/README.rst
+++ b/sale_timesheet_budget/README.rst
@@ -21,13 +21,13 @@ Sale timesheet budget
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Ftimesheet-lightgray.png?logo=github
- :target: https://github.com/OCA/timesheet/tree/18.0/sale_timesheet_budget
+ :target: https://github.com/OCA/timesheet/tree/19.0/sale_timesheet_budget
:alt: OCA/timesheet
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
- :target: https://translation.odoo-community.org/projects/timesheet-18-0/timesheet-18-0-sale_timesheet_budget
+ :target: https://translation.odoo-community.org/projects/timesheet-19-0/timesheet-19-0-sale_timesheet_budget
: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/timesheet&target_branch=18.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/timesheet&target_branch=19.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -67,7 +67,7 @@ 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 `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -108,6 +108,6 @@ Current `maintainer `__:
|maintainer-victoralmau|
-This module is part of the `OCA/timesheet `_ project on GitHub.
+This module is part of the `OCA/timesheet `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/sale_timesheet_budget/__manifest__.py b/sale_timesheet_budget/__manifest__.py
index 3768171cc2..53dd6694af 100644
--- a/sale_timesheet_budget/__manifest__.py
+++ b/sale_timesheet_budget/__manifest__.py
@@ -2,7 +2,7 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Sale timesheet budget",
- "version": "18.0.1.0.0",
+ "version": "19.0.1.0.0",
"category": "Timesheet",
"website": "https://github.com/OCA/timesheet",
"author": "Tecnativa, Odoo Community Association (OCA)",
diff --git a/sale_timesheet_budget/i18n/es.po b/sale_timesheet_budget/i18n/es.po
index baa862697e..45207e7138 100644
--- a/sale_timesheet_budget/i18n/es.po
+++ b/sale_timesheet_budget/i18n/es.po
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-27 11:03+0000\n"
-"PO-Revision-Date: 2026-05-10 09:27+0000\n"
+"PO-Revision-Date: 2026-04-16 21:45+0000\n"
"Last-Translator: Ed-Spain \n"
"Language-Team: \n"
"Language: es\n"
diff --git a/sale_timesheet_budget/models/project_project.py b/sale_timesheet_budget/models/project_project.py
index 284dbcdf36..e83237ab6a 100644
--- a/sale_timesheet_budget/models/project_project.py
+++ b/sale_timesheet_budget/models/project_project.py
@@ -1,7 +1,7 @@
# Copyright 2022-2024 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import _lt, api, fields, models
+from odoo import api, fields, models
class ProjectProject(models.Model):
@@ -17,12 +17,12 @@ class ProjectProject(models.Model):
@api.depends("budget_ids")
def _compute_budget_amount(self):
- data = self.env["project.project.budget"].read_group(
+ data = self.env["project.project.budget"]._read_group(
domain=[("project_id", "in", self.ids)],
- fields=["project_id", "amount:sum"],
groupby=["project_id"],
+ aggregates=["amount:sum"],
)
- mapped_data = {x["project_id"][0]: x["amount"] for x in data}
+ mapped_data = {project.id: amount_sum for project, amount_sum in data}
for item in self:
item.budget_amount = mapped_data.get(item.id, 0)
@@ -35,18 +35,24 @@ def action_profitability_budget_item(self):
def _get_profitability_labels(self):
res = super()._get_profitability_labels()
- res["budgets"] = _lt("Budgets")
+ res["budgets"] = self.env._("Budgets")
+ return res
+
+ def _get_profitability_sequence_per_invoice_type(self):
+ res = super()._get_profitability_sequence_per_invoice_type()
+ res["budgets"] = 8
return res
def _get_profitability_items(self, with_action=True):
items = super()._get_profitability_items(with_action)
if not self.budget_ids:
return items
- last_sequence = len(items["revenues"]["data"])
items["revenues"]["data"].append(
{
"id": "budgets",
- "sequence": last_sequence + 1,
+ "sequence": self._get_profitability_sequence_per_invoice_type()[
+ "budgets"
+ ],
"invoiced": 0,
"to_invoice": self.budget_amount,
"action": {
diff --git a/sale_timesheet_budget/static/description/index.html b/sale_timesheet_budget/static/description/index.html
index 2017008179..5a52e8e616 100644
--- a/sale_timesheet_budget/static/description/index.html
+++ b/sale_timesheet_budget/static/description/index.html
@@ -374,7 +374,7 @@ Sale timesheet budget
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:f87109f6f4372bd1ff932d9dd90bd4c19896fda92a1e729aacd3678eea72c1e1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

This module adds the “Budget” tab to the projects/sales orders to be
able to set some additional lines (incomes/expenses) linked to a planned
budget.
@@ -419,7 +419,7 @@
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.
+feedback.
Do not contact contributors directly about support or help with technical issues.
diff --git a/sale_timesheet_budget/tests/test_sale_timesheet_budget.py b/sale_timesheet_budget/tests/test_sale_timesheet_budget.py
index 8427b45bfe..6b3004e870 100644
--- a/sale_timesheet_budget/tests/test_sale_timesheet_budget.py
+++ b/sale_timesheet_budget/tests/test_sale_timesheet_budget.py
@@ -19,12 +19,6 @@ def setUpClass(cls):
"plan_id": cls.plan.id,
}
)
- cls.sale_order = cls.env["sale.order"].create(
- {
- "partner_id": cls.customer.id,
- "project_account_id": cls.analytic_account.id,
- }
- )
cls.project = cls.env["project.project"].create(
{
"name": "Test project",
@@ -33,8 +27,27 @@ def setUpClass(cls):
"allow_billable": True,
}
)
+ cls.sale_order = cls.env["sale.order"].create(
+ {
+ "partner_id": cls.customer.id,
+ "project_id": cls.project.id,
+ }
+ )
def test_project_budget(self):
+ # Test project without budgets to cover early return in _get_profitability_items
+ data_no_budget = self.project.get_panel_data()
+ if "profitability_items" in data_no_budget:
+ self.assertNotIn(
+ "budgets",
+ [
+ item["id"]
+ for item in data_no_budget["profitability_items"]["revenues"][
+ "data"
+ ]
+ ],
+ )
+
project_form = Form(self.project)
with project_form.budget_ids.new() as budget_form:
budget_form.sale_order_id = self.sale_order