From ad47ce0d098aeeed887dce40e3c8c5092c16a66b Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Thu, 19 Oct 2023 18:07:58 +0200 Subject: [PATCH] [REF] joint_buying_base : model joint.buying.tour.line : start_hour and arrival_hour are now computed on the fly, to avoid timezone errors model joint.buying.tour.line : add start_date and arrival_date, stored field. minor refactor --- joint_buying_base/__manifest__.py | 2 +- joint_buying_base/demo/joint_buying_tour.xml | 10 +++++++ .../migrations/12.0.5.0.0/post-migration.py | 18 +++++++++++ .../migrations/12.0.5.0.0/pre-migration.py | 21 +++++++++++++ joint_buying_base/models/joint_buying_tour.py | 30 +++++++++---------- .../models/joint_buying_tour_line.py | 24 +++++++++++++-- .../views/view_joint_buying_tour.xml | 2 ++ .../wizards/joint_buying_wizard_set_tour.py | 2 +- 8 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 joint_buying_base/migrations/12.0.5.0.0/post-migration.py create mode 100644 joint_buying_base/migrations/12.0.5.0.0/pre-migration.py diff --git a/joint_buying_base/__manifest__.py b/joint_buying_base/__manifest__.py index f2529daa..2e599fc2 100644 --- a/joint_buying_base/__manifest__.py +++ b/joint_buying_base/__manifest__.py @@ -3,7 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Joint Buying - Base", - "version": "12.0.4.0.0", + "version": "12.0.5.0.0", "category": "GRAP - Logistics", "author": "GRAP,La Jardinière,Hashbang", "website": "https://github.com/grap/odoo-addons-logistics", diff --git a/joint_buying_base/demo/joint_buying_tour.xml b/joint_buying_base/demo/joint_buying_tour.xml index a7d9a370..18e5b624 100644 --- a/joint_buying_base/demo/joint_buying_tour.xml +++ b/joint_buying_base/demo/joint_buying_tour.xml @@ -270,4 +270,14 @@ + + + + --> + diff --git a/joint_buying_base/migrations/12.0.5.0.0/post-migration.py b/joint_buying_base/migrations/12.0.5.0.0/post-migration.py new file mode 100644 index 00000000..2c8015e2 --- /dev/null +++ b/joint_buying_base/migrations/12.0.5.0.0/post-migration.py @@ -0,0 +1,18 @@ +# Copyright (C) 2023 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from openupgradelib import openupgrade + +_logger = logging.getLogger(__name__) + + +@openupgrade.migrate(use_env=True) +def migrate(env, version): + tours = env["joint.buying.tour"].search([]) + _logger.info( + "Initialize new start and arrival dates fields" f" for {len(tours)} tours" + ) + tours.recompute_dates() diff --git a/joint_buying_base/migrations/12.0.5.0.0/pre-migration.py b/joint_buying_base/migrations/12.0.5.0.0/pre-migration.py new file mode 100644 index 00000000..77b33b85 --- /dev/null +++ b/joint_buying_base/migrations/12.0.5.0.0/pre-migration.py @@ -0,0 +1,21 @@ +# Copyright (C) 2023-Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from openupgradelib import openupgrade + +_logger = logging.getLogger(__name__) + + +@openupgrade.migrate() +def migrate(env, version): + + _logger.info( + "Drop start_hour and arrival_hour column in joint_buying_tour_line" + " as there are now computed on the fly" + ) + + env.cr.execute("ALTER TABLE joint_buying_tour_line DROP COLUMN start_hour;") + env.cr.execute("ALTER TABLE joint_buying_tour_line DROP COLUMN arrival_hour;") diff --git a/joint_buying_base/models/joint_buying_tour.py b/joint_buying_base/models/joint_buying_tour.py index a3d929c1..3ce8132f 100644 --- a/joint_buying_base/models/joint_buying_tour.py +++ b/joint_buying_base/models/joint_buying_tour.py @@ -9,6 +9,7 @@ from bokeh.palettes import Category20c from bokeh.plotting import figure from bokeh.transform import cumsum +from dateutil.relativedelta import relativedelta from odoo import _, api, fields, models @@ -280,27 +281,26 @@ def copy(self, default=None): @api.multi def write(self, vals): res = super().write(vals) - if "start_date" in vals: - self.recompute_start_hours() + if {"start_date", "line_ids"}.intersection(vals.keys()): + self.recompute_dates() return res def estimate_route(self): - self.mapped("line_ids").estimate_route() - self.recompute_start_hours() - - def recompute_start_hours(self): - def _time_to_float(time): - return time.hour + time.minute / 60 + self.mapped("line_ids")._estimate_route() + self.recompute_dates() + def recompute_dates(self): for tour in self: - if not tour.line_ids: - continue - date_tz = fields.Datetime.context_timestamp(self, tour.start_date) - start_hour = _time_to_float(date_tz.time()) + start_date = tour.start_date for line in tour.line_ids: - line.start_hour = start_hour - line.arrival_hour = start_hour + line.duration - start_hour += line.duration + arrival_date = start_date + relativedelta(hours=line.duration) + line.write( + { + "start_date": start_date, + "arrival_date": arrival_date, + } + ) + start_date = arrival_date def see_steps(self): self.ensure_one() diff --git a/joint_buying_base/models/joint_buying_tour_line.py b/joint_buying_base/models/joint_buying_tour_line.py index c92b1760..6249babb 100644 --- a/joint_buying_base/models/joint_buying_tour_line.py +++ b/joint_buying_base/models/joint_buying_tour_line.py @@ -36,9 +36,13 @@ class JointBuyingTourLine(models.Model): distance = fields.Float() - start_hour = fields.Float() + start_date = fields.Datetime() - arrival_hour = fields.Float() + arrival_date = fields.Datetime() + + start_hour = fields.Float(compute="_compute_hours") + + arrival_hour = fields.Float(compute="_compute_hours") starting_point_id = fields.Many2one( comodel_name="res.partner", context=_JOINT_BUYING_PARTNER_CONTEXT @@ -60,6 +64,20 @@ class JointBuyingTourLine(models.Model): compute="_compute_costs", store=True, currency_field="currency_id" ) + @api.depends("start_date", "arrival_date") + def _compute_hours(self): + for line in self: + start_date = fields.Datetime.context_timestamp(self, line.start_date) + arrival_date = fields.Datetime.context_timestamp(self, line.arrival_date) + line.start_hour = ( + start_date.hour + start_date.minute / 60 + start_date.second / 3600 + ) + line.arrival_hour = ( + arrival_date.hour + + arrival_date.minute / 60 + + arrival_date.second / 3600 + ) + @api.depends( "tour_id.hourly_cost", "tour_id.kilometer_cost", "duration", "distance" ) @@ -98,7 +116,7 @@ def _estimate_route_project_osrm(self): "duration": result.get("duration") / 3600, } - def estimate_route(self): + def _estimate_route(self): no_coordinate_partners = self.env["res.partner"] for line in self.filtered(lambda x: x.sequence_type == "journey"): if ( diff --git a/joint_buying_base/views/view_joint_buying_tour.xml b/joint_buying_base/views/view_joint_buying_tour.xml index a4f0112d..e28a0a2e 100644 --- a/joint_buying_base/views/view_joint_buying_tour.xml +++ b/joint_buying_base/views/view_joint_buying_tour.xml @@ -105,7 +105,9 @@ There may be traffic jams, delays, unforeseen events, etc... + + diff --git a/joint_buying_base/wizards/joint_buying_wizard_set_tour.py b/joint_buying_base/wizards/joint_buying_wizard_set_tour.py index ade417cf..a1b9278e 100644 --- a/joint_buying_base/wizards/joint_buying_wizard_set_tour.py +++ b/joint_buying_base/wizards/joint_buying_wizard_set_tour.py @@ -63,6 +63,7 @@ def _default_line_ids(self): @api.multi def set_tour(self): self.ensure_one() + # TODO - Optimize. do not delete lines, if lines are the same self.tour_id.line_ids.unlink() current_starting_point = self.starting_point_id line_vals = [] @@ -87,5 +88,4 @@ def set_tour(self): current_starting_point = wizard_line.point_id if line_vals: self.tour_id.write({"line_ids": line_vals}) - self.tour_id.recompute_start_hours() return True