From 4c1472f9e9546f907d35e7defaed1b8936ebdcc4 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Wed, 3 Apr 2024 11:24:25 +0200 Subject: [PATCH 1/9] [ADD] project_budget_subcontractor --- project_budget_subcontractor/README.md | 0 project_budget_subcontractor/__init__.py | 1 + project_budget_subcontractor/__manifest__.py | 25 ++++ .../models/__init__.py | 5 + .../models/account_move.py | 38 +++++ .../models/analytic_account.py | 13 ++ .../models/project.py | 47 ++++++ .../models/project_budget.py | 135 +++++++++++++++++ .../models/res_partner.py | 14 ++ .../security/ir.model.access.csv | 3 + .../views/account_move_view.xml | 19 +++ .../views/project_project_view.xml | 140 ++++++++++++++++++ .../views/res_partner_view.xml | 17 +++ .../odoo/addons/project_budget_subcontractor | 1 + setup/project_budget_subcontractor/setup.py | 6 + 15 files changed, 464 insertions(+) create mode 100644 project_budget_subcontractor/README.md create mode 100644 project_budget_subcontractor/__init__.py create mode 100644 project_budget_subcontractor/__manifest__.py create mode 100644 project_budget_subcontractor/models/__init__.py create mode 100644 project_budget_subcontractor/models/account_move.py create mode 100644 project_budget_subcontractor/models/analytic_account.py create mode 100644 project_budget_subcontractor/models/project.py create mode 100644 project_budget_subcontractor/models/project_budget.py create mode 100644 project_budget_subcontractor/models/res_partner.py create mode 100644 project_budget_subcontractor/security/ir.model.access.csv create mode 100644 project_budget_subcontractor/views/account_move_view.xml create mode 100644 project_budget_subcontractor/views/project_project_view.xml create mode 100644 project_budget_subcontractor/views/res_partner_view.xml create mode 120000 setup/project_budget_subcontractor/odoo/addons/project_budget_subcontractor create mode 100644 setup/project_budget_subcontractor/setup.py diff --git a/project_budget_subcontractor/README.md b/project_budget_subcontractor/README.md new file mode 100644 index 0000000..e69de29 diff --git a/project_budget_subcontractor/__init__.py b/project_budget_subcontractor/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/project_budget_subcontractor/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/project_budget_subcontractor/__manifest__.py b/project_budget_subcontractor/__manifest__.py new file mode 100644 index 0000000..85bbb2e --- /dev/null +++ b/project_budget_subcontractor/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2024 Akretion (https://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Project Budget Subcontractor", + "summary": "Add budget to projects", + "version": "14.0.1.0.0", + "development_status": "Alpha", + "category": "Uncategorized", + "website": "https://github.com/akretion/subcontractor", + "author": " Akretion", + "license": "AGPL-3", + "depends": [ + "project_invoicing_subcontractor", + "project_timeline", + ], + "data": [ + "security/ir.model.access.csv", + "views/account_move_view.xml", + "views/res_partner_view.xml", + "views/project_project_view.xml", + ], + "auto_install": True, +} diff --git a/project_budget_subcontractor/models/__init__.py b/project_budget_subcontractor/models/__init__.py new file mode 100644 index 0000000..77d68b4 --- /dev/null +++ b/project_budget_subcontractor/models/__init__.py @@ -0,0 +1,5 @@ +from . import account_move +from . import analytic_account +from . import project +from . import project_budget +from . import res_partner diff --git a/project_budget_subcontractor/models/account_move.py b/project_budget_subcontractor/models/account_move.py new file mode 100644 index 0000000..9203a68 --- /dev/null +++ b/project_budget_subcontractor/models/account_move.py @@ -0,0 +1,38 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class AccountMove(models.Model): + _inherit = "account.move" + + budget_date = fields.Date( + string="Budget Date", + compute="_compute_budget_date", + store=True, + readonly=False, + ) + use_budget = fields.Boolean(related="partner_id.use_budget") + + @api.depends("invoice_date") + def _compute_budget_date(self): + for move in self: + if not move.budget_date: + move.budget_date = move.invoice_date + + def _post(self, soft=True): + for move in self: + if move.use_budget: + if move.invoice_line_ids.filtered( + lambda line: not line.analytic_account_id + ): + raise UserError( + _( + "You can't post a move containing lines without analytic " + "account for a customer with budget enabled." + ) + ) + return super()._post(soft=soft) diff --git a/project_budget_subcontractor/models/analytic_account.py b/project_budget_subcontractor/models/analytic_account.py new file mode 100644 index 0000000..9d2d4bb --- /dev/null +++ b/project_budget_subcontractor/models/analytic_account.py @@ -0,0 +1,13 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountAnalyticAccount(models.Model): + _inherit = "account.analytic.account" + + invoice_line_ids = fields.One2many( + "account.move.line", inverse_name="analytic_account_id", string="Invoice Lines" + ) diff --git a/project_budget_subcontractor/models/project.py b/project_budget_subcontractor/models/project.py new file mode 100644 index 0000000..f5b09a2 --- /dev/null +++ b/project_budget_subcontractor/models/project.py @@ -0,0 +1,47 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# 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("project.budget", "project_id", string="Budgets") + use_budget = fields.Boolean(related="partner_id.use_budget") + + current_budget_id = fields.Many2one( + "project.budget", compute="_compute_current_budget_id" + ) + current_budget_amount = fields.Float( + related="current_budget_id.budget_amount", readonly=True + ) + current_invoiced_amount = fields.Float( + related="current_budget_id.invoiced_amount", readonly=True + ) + current_to_invoice_amount = fields.Float( + related="current_budget_id.to_invoice_amount", readonly=True + ) + current_remaining_amount = fields.Float( + related="current_budget_id.remaining_amount", readonly=True + ) + current_remaining_budget = fields.Float( + related="current_budget_id.remaining_budget", readonly=True + ) + current_budget_amount_prorata = fields.Float( + related="current_budget_id.budget_amount_prorata", readonly=True + ) + current_budget_progress = fields.Float( + related="current_budget_id.budget_progress", readonly=True + ) + current_time_progress = fields.Float( + related="current_budget_id.time_progress", readonly=True + ) + + @api.depends("budget_ids.start_date", "budget_ids.end_date") + def _compute_current_budget_id(self): + for project in self: + project.current_budget_id = project.budget_ids.filtered( + lambda b: b.start_date <= fields.Date.today() <= b.end_date + ) diff --git a/project_budget_subcontractor/models/project_budget.py b/project_budget_subcontractor/models/project_budget.py new file mode 100644 index 0000000..13f07c8 --- /dev/null +++ b/project_budget_subcontractor/models/project_budget.py @@ -0,0 +1,135 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProjectBudget(models.Model): + _name = "project.budget" + _description = "Project Budget" + _inherit = ["mail.thread", "mail.activity.mixin"] + + name = fields.Char(required=True) + project_id = fields.Many2one("project.project", required=True, tracking=True) + start_date = fields.Date(required=True, tracking=True) + end_date = fields.Date(required=True, tracking=True) + currency_id = fields.Many2one( + "res.currency", default=lambda self: self.env.company.currency_id + ) + budget_amount = fields.Float(required=True, tracking=True) + + invoiced_amount = fields.Float(compute="_compute_invoiced_amount") + to_invoice_amount = fields.Float(compute="_compute_to_invoice_amount") + remaining_amount = fields.Float(compute="_compute_remaining_amount") + remaining_budget = fields.Float(compute="_compute_remaining_budget") + budget_amount_prorata = fields.Float( + compute="_compute_budget_amount_prorata", string="Time Prorata" + ) + budget_progress = fields.Float(compute="_compute_budget_progress") + time_progress = fields.Float(compute="_compute_time_progress") + + @api.depends("budget_amount", "start_date", "end_date") + def _compute_budget_amount_prorata(self): + today = fields.Date.today() + for budget in self: + if ( + not budget.start_date + or not budget.end_date + or budget.start_date > today + ): + budget.budget_amount_prorata = 0.0 + continue + + if budget.end_date < today: + budget.budget_amount_prorata = budget.budget_amount + continue + + total_days = (budget.end_date - budget.start_date).days + 1 + spent_days = (today - budget.start_date).days + 1 + budget.budget_amount_prorata = ( + budget.budget_amount * spent_days / total_days + ) + + @api.depends("project_id.timesheet_ids.invoice_line_id", "start_date", "end_date") + def _compute_invoiced_amount(self): + for budget in self: + if not budget.start_date or not budget.end_date: + budget.invoiced_amount = 0.0 + continue + move_lines = ( + budget.project_id.analytic_account_id.invoice_line_ids.filtered( + lambda ml: ml.parent_state == "posted" + and ml.move_id.budget_date >= budget.start_date + and ml.move_id.budget_date <= budget.end_date + ) + ) + budget.invoiced_amount = sum(move_lines.mapped("price_subtotal")) + + @api.depends("project_id.timesheet_ids", "start_date", "end_date") + def _compute_to_invoice_amount(self): + today = fields.Date.today() + for budget in self: + if not budget.start_date or not budget.end_date or budget.end_date < today: + budget.to_invoice_amount = 0.0 + continue + account_analytic_line = budget.project_id.timesheet_ids.filtered( + lambda aal: ( + not aal.invoice_line_id + or aal.invoice_line_id.parent_state == "draft" + ) + ) + budget.to_invoice_amount = -sum( + budget.project_id.convert_hours_to_days( + aal.unit_amount * (1 - aal.discount / 100.0) + ) + * aal.amount + for aal in account_analytic_line + ) + + @api.depends( + "project_id.task_ids", "project_id.price_unit", "start_date", "end_date" + ) + def _compute_remaining_amount(self): + for budget in self: + if not budget.start_date or not budget.end_date: + budget.remaining_amount = 0.0 + continue + remaining_days = sum( + budget.project_id.task_ids.filtered( + lambda t: t.date_start + and t.date_end + and t.date_start.date() >= budget.start_date + and t.date_end.date() <= budget.end_date + and not t.stage_id.is_closed + ).mapped("remaining_days") + ) + budget.remaining_amount = remaining_days * budget.project_id.price_unit + + @api.depends("budget_amount", "invoiced_amount", "to_invoice_amount") + def _compute_remaining_budget(self): + for budget in self: + budget.remaining_budget = budget.budget_amount - ( + budget.invoiced_amount + budget.to_invoice_amount + ) + + @api.depends("budget_amount", "invoiced_amount", "to_invoice_amount") + def _compute_budget_progress(self): + for budget in self: + if not budget.budget_amount: + budget.budget_progress = 0.0 + continue + budget.budget_progress = ( + budget.invoiced_amount + budget.to_invoice_amount + ) / budget.budget_amount + + @api.depends("start_date", "end_date") + def _compute_time_progress(self): + for budget in self: + if not budget.start_date or not budget.end_date: + budget.time_progress = 0.0 + continue + today = fields.Date.today() + total_days = (budget.end_date - budget.start_date).days + 1 + spent_days = (today - budget.start_date).days + 1 + budget.time_progress = spent_days / total_days diff --git a/project_budget_subcontractor/models/res_partner.py b/project_budget_subcontractor/models/res_partner.py new file mode 100644 index 0000000..ac15827 --- /dev/null +++ b/project_budget_subcontractor/models/res_partner.py @@ -0,0 +1,14 @@ +# Copyright 2024 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + use_budget = fields.Boolean( + string="Use Budget", + help="If checked, this partner's projects will use budgets", + ) diff --git a/project_budget_subcontractor/security/ir.model.access.csv b/project_budget_subcontractor/security/ir.model.access.csv new file mode 100644 index 0000000..c8fbc73 --- /dev/null +++ b/project_budget_subcontractor/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 +project_budget_read_access,access_project_budget_read,model_project_budget,project.group_project_user,1,0,0,0 +project_budget_all_access,access_project_budget_all,model_project_budget,project.group_project_manager,1,1,1,1 diff --git a/project_budget_subcontractor/views/account_move_view.xml b/project_budget_subcontractor/views/account_move_view.xml new file mode 100644 index 0000000..8322de7 --- /dev/null +++ b/project_budget_subcontractor/views/account_move_view.xml @@ -0,0 +1,19 @@ + + + + + + account.move + + + + + + + + diff --git a/project_budget_subcontractor/views/project_project_view.xml b/project_budget_subcontractor/views/project_project_view.xml new file mode 100644 index 0000000..db76d08 --- /dev/null +++ b/project_budget_subcontractor/views/project_project_view.xml @@ -0,0 +1,140 @@ + + + + + project.project + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + project.project + + + + + + + + + + +
diff --git a/project_budget_subcontractor/views/res_partner_view.xml b/project_budget_subcontractor/views/res_partner_view.xml new file mode 100644 index 0000000..62c171d --- /dev/null +++ b/project_budget_subcontractor/views/res_partner_view.xml @@ -0,0 +1,17 @@ + + + + + + res.partner + + + + + + + + + diff --git a/setup/project_budget_subcontractor/odoo/addons/project_budget_subcontractor b/setup/project_budget_subcontractor/odoo/addons/project_budget_subcontractor new file mode 120000 index 0000000..65419f7 --- /dev/null +++ b/setup/project_budget_subcontractor/odoo/addons/project_budget_subcontractor @@ -0,0 +1 @@ +../../../../project_budget_subcontractor \ No newline at end of file diff --git a/setup/project_budget_subcontractor/setup.py b/setup/project_budget_subcontractor/setup.py new file mode 100644 index 0000000..28c57bb --- /dev/null +++ b/setup/project_budget_subcontractor/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 18bf1131755c3b1c5c49017cab958d07f7fa7462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Tue, 9 Jul 2024 18:16:14 +0200 Subject: [PATCH 2/9] project_budget_subcontractor: improve/fix budget --- project_budget_subcontractor/__manifest__.py | 1 + .../models/project_budget.py | 47 +++++++---- .../views/project_budget_view.xml | 82 +++++++++++++++++++ 3 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 project_budget_subcontractor/views/project_budget_view.xml diff --git a/project_budget_subcontractor/__manifest__.py b/project_budget_subcontractor/__manifest__.py index 85bbb2e..40ad6c7 100644 --- a/project_budget_subcontractor/__manifest__.py +++ b/project_budget_subcontractor/__manifest__.py @@ -20,6 +20,7 @@ "views/account_move_view.xml", "views/res_partner_view.xml", "views/project_project_view.xml", + "views/project_budget_view.xml", ], "auto_install": True, } diff --git a/project_budget_subcontractor/models/project_budget.py b/project_budget_subcontractor/models/project_budget.py index 13f07c8..51d5cec 100644 --- a/project_budget_subcontractor/models/project_budget.py +++ b/project_budget_subcontractor/models/project_budget.py @@ -12,6 +12,9 @@ class ProjectBudget(models.Model): name = fields.Char(required=True) project_id = fields.Many2one("project.project", required=True, tracking=True) + partner_id = fields.Many2one( + "res.partner", related="project_id.partner_id", store=True + ) start_date = fields.Date(required=True, tracking=True) end_date = fields.Date(required=True, tracking=True) currency_id = fields.Many2one( @@ -19,10 +22,18 @@ class ProjectBudget(models.Model): ) budget_amount = fields.Float(required=True, tracking=True) - invoiced_amount = fields.Float(compute="_compute_invoiced_amount") - to_invoice_amount = fields.Float(compute="_compute_to_invoice_amount") - remaining_amount = fields.Float(compute="_compute_remaining_amount") - remaining_budget = fields.Float(compute="_compute_remaining_budget") + invoiced_amount = fields.Float( + compute="_compute_invoiced_amount", string="Montant Facturé" + ) + to_invoice_amount = fields.Float( + compute="_compute_to_invoice_amount", string="Montant à Facturer" + ) + remaining_amount = fields.Float( + compute="_compute_remaining_amount", string="Montant Restant Estimé" + ) + remaining_budget = fields.Float( + compute="_compute_remaining_budget", string="Budget Restant" + ) budget_amount_prorata = fields.Float( compute="_compute_budget_amount_prorata", string="Time Prorata" ) @@ -69,22 +80,26 @@ def _compute_invoiced_amount(self): @api.depends("project_id.timesheet_ids", "start_date", "end_date") def _compute_to_invoice_amount(self): today = fields.Date.today() + data = self.env["account.analytic.line"].read_group( + [ + ("project_id", "in", self.project_id.ids), + "|", + ("invoice_line_id", "=", False), + ("invoice_line_id.parent_state", "=", "draft"), + ], + ["invoiceable_amount:sum"], + ["project_id"], + ) + p2hours = {item["project_id"][0]: item["invoiceable_amount"] for item in data} for budget in self: if not budget.start_date or not budget.end_date or budget.end_date < today: budget.to_invoice_amount = 0.0 continue - account_analytic_line = budget.project_id.timesheet_ids.filtered( - lambda aal: ( - not aal.invoice_line_id - or aal.invoice_line_id.parent_state == "draft" - ) - ) - budget.to_invoice_amount = -sum( - budget.project_id.convert_hours_to_days( - aal.unit_amount * (1 - aal.discount / 100.0) - ) - * aal.amount - for aal in account_analytic_line + project = budget.project_id + if isinstance(project.id, models.NewId): + project = project._origin + budget.to_invoice_amount = ( + project.convert_hours_to_days(p2hours[project.id]) * project.price_unit ) @api.depends( diff --git a/project_budget_subcontractor/views/project_budget_view.xml b/project_budget_subcontractor/views/project_budget_view.xml new file mode 100644 index 0000000..c609910 --- /dev/null +++ b/project_budget_subcontractor/views/project_budget_view.xml @@ -0,0 +1,82 @@ + + + + project.budget + + + + + + + + + + + + + + + + + + project.budget + + + + + + + + + + + + + Budget + ir.actions.act_window + project.budget + tree + + [] + {"search_default_current": 1} + + + + + From ebf9e5a100d0c2345a4a0c6b09c88313314e9d90 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 30 Sep 2024 14:49:31 +0200 Subject: [PATCH 3/9] [MIG] project_budget_subcontractor: Migration to 16.0 --- project_budget_subcontractor/__manifest__.py | 2 +- .../models/project.py | 1 - .../models/project_budget.py | 2 +- .../views/project_project_view.xml | 41 +++++++++++-------- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/project_budget_subcontractor/__manifest__.py b/project_budget_subcontractor/__manifest__.py index 40ad6c7..b6ca77a 100644 --- a/project_budget_subcontractor/__manifest__.py +++ b/project_budget_subcontractor/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Project Budget Subcontractor", "summary": "Add budget to projects", - "version": "14.0.1.0.0", + "version": "16.0.1.0.0", "development_status": "Alpha", "category": "Uncategorized", "website": "https://github.com/akretion/subcontractor", diff --git a/project_budget_subcontractor/models/project.py b/project_budget_subcontractor/models/project.py index f5b09a2..f0c3720 100644 --- a/project_budget_subcontractor/models/project.py +++ b/project_budget_subcontractor/models/project.py @@ -39,7 +39,6 @@ class ProjectProject(models.Model): related="current_budget_id.time_progress", readonly=True ) - @api.depends("budget_ids.start_date", "budget_ids.end_date") def _compute_current_budget_id(self): for project in self: project.current_budget_id = project.budget_ids.filtered( diff --git a/project_budget_subcontractor/models/project_budget.py b/project_budget_subcontractor/models/project_budget.py index 51d5cec..3893e4f 100644 --- a/project_budget_subcontractor/models/project_budget.py +++ b/project_budget_subcontractor/models/project_budget.py @@ -116,7 +116,7 @@ def _compute_remaining_amount(self): and t.date_end and t.date_start.date() >= budget.start_date and t.date_end.date() <= budget.end_date - and not t.stage_id.is_closed + and not t.is_closed ).mapped("remaining_days") ) budget.remaining_amount = remaining_days * budget.project_id.price_unit diff --git a/project_budget_subcontractor/views/project_project_view.xml b/project_budget_subcontractor/views/project_project_view.xml index db76d08..b5b7c9a 100644 --- a/project_budget_subcontractor/views/project_project_view.xml +++ b/project_budget_subcontractor/views/project_project_view.xml @@ -7,58 +7,60 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> project.project -
+ - - - - + + + - - - - - - + + - - - - + -
+ + - + -
+
Date: Mon, 7 Oct 2024 18:21:24 +0200 Subject: [PATCH 4/9] [FIX] project_budget_subcontractor: Charge related to computed fields to prevent warning --- .../models/project.py | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/project_budget_subcontractor/models/project.py b/project_budget_subcontractor/models/project.py index f0c3720..677c416 100644 --- a/project_budget_subcontractor/models/project.py +++ b/project_budget_subcontractor/models/project.py @@ -15,32 +15,51 @@ class ProjectProject(models.Model): "project.budget", compute="_compute_current_budget_id" ) current_budget_amount = fields.Float( - related="current_budget_id.budget_amount", readonly=True + string="Budget Amount", compute="_compute_current_budget_id" ) current_invoiced_amount = fields.Float( - related="current_budget_id.invoiced_amount", readonly=True + string="Invoiced Amount", compute="_compute_current_budget_id" ) current_to_invoice_amount = fields.Float( - related="current_budget_id.to_invoice_amount", readonly=True + string="To Invoice Amount", compute="_compute_current_budget_id" ) current_remaining_amount = fields.Float( - related="current_budget_id.remaining_amount", readonly=True + string="Remaining Amount", compute="_compute_current_budget_id" ) current_remaining_budget = fields.Float( - related="current_budget_id.remaining_budget", readonly=True + string="Remaining Budget", compute="_compute_current_budget_id" ) current_budget_amount_prorata = fields.Float( - related="current_budget_id.budget_amount_prorata", readonly=True + string="Budget Amount Prorata", compute="_compute_current_budget_id" ) current_budget_progress = fields.Float( - related="current_budget_id.budget_progress", readonly=True + string="Budget Progress", compute="_compute_current_budget_id" ) current_time_progress = fields.Float( - related="current_budget_id.time_progress", readonly=True + string="Time Progress", compute="_compute_current_budget_id" ) def _compute_current_budget_id(self): for project in self: - project.current_budget_id = project.budget_ids.filtered( + current = project.current_budget_id = project.budget_ids.filtered( lambda b: b.start_date <= fields.Date.today() <= b.end_date ) + + if current: + project.current_budget_amount = current.budget_amount + project.current_invoiced_amount = current.invoiced_amount + project.current_to_invoice_amount = current.to_invoice_amount + project.current_remaining_amount = current.remaining_amount + project.current_remaining_budget = current.remaining_budget + project.current_budget_amount_prorata = current.budget_amount_prorata + project.current_budget_progress = current.budget_progress + project.current_time_progress = current.time_progress + else: + project.current_budget_amount = False + project.current_invoiced_amount = False + project.current_to_invoice_amount = False + project.current_remaining_amount = False + project.current_remaining_budget = False + project.current_budget_amount_prorata = False + project.current_budget_progress = False + project.current_time_progress = False From 2e552fc2c1a51e92c5bacd4d7365855e8d44af21 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 7 Oct 2024 18:24:34 +0200 Subject: [PATCH 5/9] [IMP] project_budget_subcontractor:Improve current budget display --- .../views/project_project_view.xml | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/project_budget_subcontractor/views/project_project_view.xml b/project_budget_subcontractor/views/project_project_view.xml index b5b7c9a..e8b34f2 100644 --- a/project_budget_subcontractor/views/project_project_view.xml +++ b/project_budget_subcontractor/views/project_project_view.xml @@ -7,58 +7,58 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> project.project - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + @@ -70,7 +70,7 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> From b0f6cac88978e59e729914c0a678048b076ae495 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 7 Oct 2024 18:25:30 +0200 Subject: [PATCH 6/9] [FIX] project_budget_subcontractor: project.task date_start, date_end renames See: https://github.com/OCA/project/commit/55460f8ff563d436fe22c27f62e186e09088e78d --- project_budget_subcontractor/models/project_budget.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/project_budget_subcontractor/models/project_budget.py b/project_budget_subcontractor/models/project_budget.py index 3893e4f..61ec1fc 100644 --- a/project_budget_subcontractor/models/project_budget.py +++ b/project_budget_subcontractor/models/project_budget.py @@ -70,7 +70,7 @@ def _compute_invoiced_amount(self): continue move_lines = ( budget.project_id.analytic_account_id.invoice_line_ids.filtered( - lambda ml: ml.parent_state == "posted" + lambda ml, budget=budget: ml.parent_state == "posted" and ml.move_id.budget_date >= budget.start_date and ml.move_id.budget_date <= budget.end_date ) @@ -110,12 +110,13 @@ def _compute_remaining_amount(self): if not budget.start_date or not budget.end_date: budget.remaining_amount = 0.0 continue + remaining_days = sum( budget.project_id.task_ids.filtered( - lambda t: t.date_start - and t.date_end - and t.date_start.date() >= budget.start_date - and t.date_end.date() <= budget.end_date + lambda t, budget=budget: t.planned_date_start + and t.planned_date_end + and t.planned_date_start.date() >= budget.start_date + and t.planned_date_end.date() <= budget.end_date and not t.is_closed ).mapped("remaining_days") ) From 9d3eec6a2e563c5f667c013bd4561b663aa91e2e Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 7 Oct 2024 18:29:26 +0200 Subject: [PATCH 7/9] [LINT] --- .../models/account_move.py | 1 - .../models/project.py | 2 +- .../models/res_partner.py | 1 - .../views/project_project_view.xml | 58 +++++++++---------- 4 files changed, 30 insertions(+), 32 deletions(-) diff --git a/project_budget_subcontractor/models/account_move.py b/project_budget_subcontractor/models/account_move.py index 9203a68..e00e152 100644 --- a/project_budget_subcontractor/models/account_move.py +++ b/project_budget_subcontractor/models/account_move.py @@ -10,7 +10,6 @@ class AccountMove(models.Model): _inherit = "account.move" budget_date = fields.Date( - string="Budget Date", compute="_compute_budget_date", store=True, readonly=False, diff --git a/project_budget_subcontractor/models/project.py b/project_budget_subcontractor/models/project.py index 677c416..2a946e0 100644 --- a/project_budget_subcontractor/models/project.py +++ b/project_budget_subcontractor/models/project.py @@ -2,7 +2,7 @@ # @author Florian Mounier # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, fields, models +from odoo import fields, models class ProjectProject(models.Model): diff --git a/project_budget_subcontractor/models/res_partner.py b/project_budget_subcontractor/models/res_partner.py index ac15827..102d045 100644 --- a/project_budget_subcontractor/models/res_partner.py +++ b/project_budget_subcontractor/models/res_partner.py @@ -9,6 +9,5 @@ class ResPartner(models.Model): _inherit = "res.partner" use_budget = fields.Boolean( - string="Use Budget", help="If checked, this partner's projects will use budgets", ) diff --git a/project_budget_subcontractor/views/project_project_view.xml b/project_budget_subcontractor/views/project_project_view.xml index e8b34f2..a4122b3 100644 --- a/project_budget_subcontractor/views/project_project_view.xml +++ b/project_budget_subcontractor/views/project_project_view.xml @@ -18,43 +18,43 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> + name="current_budget_amount" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_invoiced_amount" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_to_invoice_amount" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_remaining_amount" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_remaining_budget" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_budget_amount_prorata" + widget="monetary" + options="{'currency_field': 'currency_id'}" + /> + name="current_budget_progress" + widget="percentage" + decoration-danger="current_budget_progress >= 100" + decoration-warning="current_budget_progress > current_time_progress and current_budget_progress < 100" + /> From 06ddc5072912296285db89d1de0c9b9ccab4396f Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Tue, 8 Oct 2024 18:05:58 +0200 Subject: [PATCH 8/9] [FIX] project_budget_subcontractor: Protect against falsy move date --- project_budget_subcontractor/models/project_budget.py | 1 + 1 file changed, 1 insertion(+) diff --git a/project_budget_subcontractor/models/project_budget.py b/project_budget_subcontractor/models/project_budget.py index 61ec1fc..3fd96ab 100644 --- a/project_budget_subcontractor/models/project_budget.py +++ b/project_budget_subcontractor/models/project_budget.py @@ -71,6 +71,7 @@ def _compute_invoiced_amount(self): move_lines = ( budget.project_id.analytic_account_id.invoice_line_ids.filtered( lambda ml, budget=budget: ml.parent_state == "posted" + and ml.move_id.budget_date and ml.move_id.budget_date >= budget.start_date and ml.move_id.budget_date <= budget.end_date ) From fb2ae15c97bbb8df122b9c4058f0383c2d8f78d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Wed, 6 Nov 2024 01:13:13 +0100 Subject: [PATCH 9/9] project_budget_subcontractor: fix budget_date --- project_budget_subcontractor/models/account_move.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project_budget_subcontractor/models/account_move.py b/project_budget_subcontractor/models/account_move.py index e00e152..8650c64 100644 --- a/project_budget_subcontractor/models/account_move.py +++ b/project_budget_subcontractor/models/account_move.py @@ -16,11 +16,11 @@ class AccountMove(models.Model): ) use_budget = fields.Boolean(related="partner_id.use_budget") - @api.depends("invoice_date") + @api.depends("date") def _compute_budget_date(self): for move in self: if not move.budget_date: - move.budget_date = move.invoice_date + move.budget_date = move.date def _post(self, soft=True): for move in self: