[19.0][IMP] edi_queue_oca: add timezone-aware daily ETA scheduling#312
[19.0][IMP] edi_queue_oca: add timezone-aware daily ETA scheduling#312Ricardoalso wants to merge 2 commits into
Conversation
d376ffd to
e36337d
Compare
simahawk
left a comment
There was a problem hiding this comment.
In addition to the existing remarks
| job_priority = fields.Integer() | ||
| eta_time = fields.Float( | ||
| string="Execute at (timezone aware)", | ||
| help="Hour of the day (decimal) at which jobs for this type should be " |
There was a problem hiding this comment.
This means that for a certain type you want jobs to accumulate till a certain hour, correct?
What is the use-case? It would be nice to mention that in the readme as well.
There was a problem hiding this comment.
Exactly, my specific business use-case is to accumulate resource-intensive EDI work into off-peak hours.
I pushed a fixup commit to document it
SilvioC2C
left a comment
There was a problem hiding this comment.
The idea is good, but I would go with a cleaner approach:
- use separate fields for hours and minutes instead of parsing strings
- let the user define the ETA TZ
- don't add utils, let the record itself compute its own ETA
| "fixed daily window, or to concentrate resource-intensive EDI work in " | ||
| "off-peak hours.", | ||
| ) | ||
| eta_time = fields.Float( |
There was a problem hiding this comment.
Personally, I'd split this field into 2 different fields, one for hours (values from 0 to 23) and another for minutes (values from 0 to 59), and add a field eta_tz that defines the timezone; then, simply have a computed, non-stored field to compute the ETA:
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pytz import timezone, utc
from odoo import api, fields, models
from odoo.addons.base.models.res_partner import _tzs as timezone_selection
class EdiExchangeType(models.Model):
[...]
eta_hour = fields.Selection(
list((x, str(x).zfill(2)) for x in range(24))),
string="Execution time - hour",
help="Hour of the day at which jobs for this type should be scheduled.",
required=True,
default="00",
)
eta_minute = fields.Selection(
list((x, str(x).zfill(2)) for x in range(60))),
string="Execution time - minute",
help="Minute of the hour at which jobs for this type should be scheduled.",
required=True,
default="00",
)
eta_tz = fields.Selection(
timezone_selection,
string="Execution time - timezone",
help="ETA's timezone for jobs of this type",
required=True,
default=lambda self: self._get_default_eta_tz(),
)
@api.model
def _get_default_eta_tz(self):
return self.env.user.tz or (timezone_selection and timezone_selection[0]) or "UTC"
def _get_eta(self):
"""Returns the ETA for the current type as timezone-naive datetime"""
self.ensure_one()
now = utc.localize(datetime.now())
eta = timezone(self.eta_time_tz).localize(datetime(now.year, now.month, now.day, self.eta_time_hour, self.eta_time_minute)).astimezone(utc)
if eta < now:
eta += relativedelta(days=1)
return eta.replace(tzinfo=None)
There was a problem hiding this comment.
Thanks for the suggestions! I initially took the more user-friendly approach using float_time, which is also used across core Odoo modules.
But I like the simplicity of having both eta_hour and eta_minute fields. Since this is linked to a technical setting, I think we can trade user-friendliness for a simpler and more efficient design.
| # Use timedelta from midnight rather than datetime.replace(hour=...) so that | ||
| # values near 24.0 (e.g. 23.992 → 1440 total minutes) wrap cleanly to 00:00 | ||
| # the next day instead of crashing with ValueError: hour must be in 0..23. | ||
| total_minutes = round(eta_time * 60) % 1440 |
There was a problem hiding this comment.
IMO it would be cleaner to build a datetime.time object that you can use to combine with datetime object. cf https://github.com/OCA/server-tools/blob/19.0/base_time_window/models/time_window_mixin.py#L125-L128 (to convert the float_time to time object)
There was a problem hiding this comment.
Thanks for pointing this code out ! 🚀
I finally decided to take the approach suggested by Silvio #312 (comment)
grindtildeath
left a comment
There was a problem hiding this comment.
Looks much better 👍
28cdcbc to
74640f6
Compare
| self.exchange_type_in.job_eta_hour = "22" | ||
| self.exchange_type_in.job_eta_minute = "00" | ||
| # job_eta_enabled defaults to False | ||
| record = self._make_record() |
There was a problem hiding this comment.
nitpicking: the record do not have any impact on this feature, it seems useless to create one record all the times. It could be done at class setup.
There was a problem hiding this comment.
Indeed, I took the opportunity to make a small improvement while squashing 😉
|
squash pls |
|
This PR has the |
Add a configurable daily execution time on EDI exchange types and inject the corresponding ETA into queued exchange record jobs. Added fields to `edi.exchange.type` for enabling ETA scheduling, configuring execution hour, minute, and timezone, and logic to compute the next scheduled runtime in UTC. This allows all jobs for a given exchange type to be held and released together at a fixed time each day, supporting off-peak processing and trading partner requirements. Enabling ETA scheduling on an exchange type causes every job created for that type to be held in the queue until the configured time of day, rather than being processed immediately. All jobs that arrive during the day accumulate and are released together at that scheduled time. When ETA scheduling is disabled, jobs are dispatched immediately as usual
…res and scheduling information
27e269f to
9527ab1
Compare
This pull request introduces an enhancement to the EDI Queue OCA module by allowing EDI exchange jobs to be scheduled and accumulated for release at a specific daily time, in addition to existing per-type channel and priority configuration.
New job scheduling and accumulation features:
edi.exchange.typefor enabling ETA scheduling, configuring execution hour, minute, and timezone, and logic to compute the next scheduled runtime in UTC. This allows all jobs for a given exchange type to be held and released together at a fixed time each day, supporting off-peak processing and trading partner requirements.Accumulating jobs until a fixed daily time
Enabling ETA scheduling on an exchange type causes every job created for that type to be held in the queue until the configured time of day, rather than being processed immediately. All jobs that arrive during the day accumulate and are released together at that scheduled time.
Typical use cases:
The execution time is configured using three fields:
At runtime, the configured time is converted to the next matching UTC datetime and set as the queue job ETA. If the target time for the current day has already passed, the job is automatically scheduled for the same time on the next day.
When ETA scheduling is disabled, jobs are dispatched immediately as usual.