Skip to content

chore: merge '19.0' into the code review branch - #13

Merged
stopkovae merged 39 commits into
19.0-code_review-aifrom
19.0
Aug 31, 2026
Merged

chore: merge '19.0' into the code review branch#13
stopkovae merged 39 commits into
19.0-code_review-aifrom
19.0

Conversation

@stopkovae

Copy link
Copy Markdown
Collaborator

No description provided.

gal-adhoc and others added 30 commits July 22, 2026 13:22
Adds a "Grant Access to All" button to the portal access wizard
(portal.wizard) that grants portal access to every contact listed in
the wizard with a valid email in a single action, instead of having
to click "Grant Access" row by row.

closes ingadhoc#418

Related: ingadhoc/odoo-academic#431
Signed-off-by: Franco Leyes <lef@adhoc.com.ar>
…ry filters, fix stale widget after reload

Modules like academic nest their own ir.module.category under Advanced
Portal (parent_id) to keep their own subtitle in the widget. The three
methods deriving the Advanced Portal group hierarchy filtered categories
by exact id equality instead of the descendant set, so any nested
category (and its privileges/groups) was silently dropped from the
portal_advanced_group_ids widget while also leaking into the native
groups widget it's supposed to be excluded from.

Switch the category matching to child_of so nested categories are
included where they should be, and excluded where they shouldn't.

Also fix the portal_advanced_group_ids widget: it wrapped `record.data`
in a Proxy once in setup(), caching that reference forever. On a cold
reload the record can still be hydrating when setup() runs, and Odoo
later swaps in the fully-loaded `data` object rather than mutating the
placeholder in place, so the cached proxy kept reflecting the group
selected before the last edit until a second reload. Rebuild the data
proxy on every access instead of caching it, so it always reflects the
current `record.data` reference.

closes ingadhoc#421

Signed-off-by: matiasperalta1 <mnp@adhoc.com.ar>
closes ingadhoc#417

Signed-off-by: matiasperalta1 <mnp@adhoc.com.ar>
Fill the empty Spanish translation file for base_import_ux with the 20
source terms translated to es.

closes ingadhoc#426

Task: 68560
Signed-off-by: Matias Velazquez <mav@adhoc.com.ar>
The quick badges customization was only applied to the mail.activity.schedule
wizard, used when scheduling a new activity. Editing an existing activity opens
an act_window on mail.activity instead (view mail_activity_view_form_popup), so
that dialog kept rendering a badge for every activity type in the system.

Inherit that view with the same treatment and share the lookup of the suggested
types through mail.activity.type._get_quick_activity_types(). On mail.activity
the computed field also includes the type currently set on the record: without
it, editing an activity whose type is not among the suggested ones would not
render the stored value at all.

closes ingadhoc#428

Signed-off-by: Luciano Esperlazza <les@adhoc.inc>
Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate.

Translation: miscellaneous-19.0/miscellaneous-19.0-base_ux
Translate-URL: https://translation.dev-adhoc.com/projects/miscellaneous-19-0/miscellaneous-19-0-base_ux/
… and less cron churn

Serialization contention raised while *running* a job (SQLSTATE 40001, e.g. row
conflicts on discuss_channel_member from message posting) was retried instantly
and, once max_retries was hit, turned healthy jobs into permanent failures,
while finish() triggered every cron on each completed job, adding ir_cron churn.
Acquisition-time serialization is already retried in _cron_run_enqueued_jobs;
this covers the execution side.

- Serialization failures raised while running a job are retried with exponential
  backoff + jitter and their own budget (base_bg.serialization_max_retries,
  default 10), so a transient spike no longer fails healthy jobs.
- The job picker skips jobs still inside their backoff window (next_retry_at),
  and the runner re-trigger only counts eligible jobs.
- finish() no longer triggers the cron on every job; it relies on the runner's
  own re-trigger while eligible jobs remain.
- Optional global cap of concurrently running jobs (base_bg.max_concurrent_jobs,
  disabled by default) as an emergency brake with no deploy.

Part-of: ingadhoc#430
Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
- Transient (40001) retries use a dedicated serialization_retry_count so a
  contention spike no longer eats the normal max_retries budget; retry_count
  stays the total attempt count.
- _handle_job_error returns whether it re-enqueued (for overrides).
- Robust transient detection: walk the __cause__/__context__ chain for
  SerializationFailure/40001; drop the loose substring match.
- Safe integer parsing of base_bg.* system parameters; a malformed value no
  longer crashes the runner cron on every tick.
- Eligibility gate and start_time use a Python UTC timestamp bind param instead
  of SQL NOW() (session-tz safe; also fixes duration on non-UTC sessions).
- Concurrency cap ignores jobs stuck 'running' past the cron timeout (orphans)
  so they cannot saturate it; documented as best-effort, not a hard ceiling.
- Backoff schedules a cron wake-up at next_retry_at so a lone job does not wait
  for the periodic tick.
- fail()/cancel() clear next_retry_at; run() documents at-least-once semantics.
- Tests updated/added (mixed-error budget, malformed param, orphan cap, gate
  clearing, batch continuation); param mutations restored via addCleanup.

Part-of: ingadhoc#430
Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
…concerns)

- Reuse Odoo's PG_CONCURRENCY_EXCEPTIONS_TO_RETRY (serialization / deadlock /
  lock-not-available) instead of a hand-rolled 40001 check; broadens transient
  coverage to deadlocks and lock timeouts, which are equally retryable.
- Rename serialization_retry_count -> transient_retry_count and the parameter to
  base_bg.transient_max_retries to match the generic "transient" vocabulary.
- Move the concurrency throttle out of the _get_next_job locking SQL into a
  separate _can_acquire_job admission check called before acquisition; the picker
  is now a pure locker with no f-string SQL assembly.
- Extract _get_cron_timeout, shared by _can_acquire_job and _cron_check_running_jobs.
- Extract _give_up (fail + cancel + return False) shared by both permanent-failure
  paths; name non_transient_attempts; simplify the backoff exponent clamp.

Part-of: ingadhoc#430
Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
Part-of: ingadhoc#430
Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
The backoff + separate transient budget + reduced cron churn address the
contention directly. The global cap was an optional emergency valve that also
throttled unrelated jobs; drop it for now to keep the change focused. Can be
reintroduced (ideally per-model) if a future storm needs it.

Part-of: ingadhoc#430
Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
Addresses part B of ticket 124538: the Background Job Runner loops many jobs in
one long-lived cron process, and run() never released each job's ORM cache, so
memory accumulated between jobs and pushed already-tight pods toward OOM.

Call env.invalidate_all() after the successful commit and after the rollback in
the error path, flattening the runner's memory curve between jobs.

closes ingadhoc#430

Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate.

Translation: miscellaneous-19.0/miscellaneous-19.0-base_bg
Translate-URL: https://translation.dev-adhoc.com/projects/miscellaneous-19-0/miscellaneous-19-0-base_bg/
…company

_check_company_dependent_m2o() built a company domain for every
company_dependent Many2one, including the ones whose comodel is shared by
all companies (res.currency, uom.uom, ...) and has no company_id nor
company_ids field. On those models the domain is invalid, so any load() of
a record holding such a value raised "Invalid field res.currency.company_id
in condition ('company_id', 'in', [1, False])" and aborted the whole import.

Concretely, importing anything on res.partner (tags, for instance) failed
for every vendor with a supplier currency set. Module CSV data is loaded
through load() too, so it was exposed as well.

Skip those fields: with no company on the comodel there is nothing to
cross-check.

closes ingadhoc#432

Signed-off-by: Franco Leyes <lef@adhoc.com.ar>
…yee_overtime on hr.leave

hr_holidays_attendance defines employee_overtime on both hr.leave and
hr.leave.allocation restricted to base.group_user. This module already
extends the field groups on hr.leave.allocation so its portal backend
holiday group can read it, but never did the same on hr.leave — and the
leave form it exposes to that group contains an element that depends on
the field.

Since Odoo 19, view validation flags this as an access rights
inconsistency on every update:

    This view may not work for all users: some users may have a
    combination of groups where the elements <div> are displayed, but
    they depend on the field employee_overtime that is not accessible.

Extend the field groups on hr.leave exactly like the allocation one.
Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate.

Translation: miscellaneous-19.0/miscellaneous-19.0-portal_holidays
Translate-URL: https://translation.dev-adhoc.com/projects/miscellaneous-19-0/miscellaneous-19-0-portal_holidays/
closes ingadhoc#420

Signed-off-by: Franco Leyes <lef@adhoc.com.ar>
Failing a job whose target records were deleted raised MissingError: fail()
browsed those ids to link them in the notification, and browsing a dropped id is
truthy. That aborted the whole _cron_check_running_jobs loop, so the poisoned job
stayed running forever and none of the other stuck jobs were ever handled.

Check real existence before linking the records, and handle each job -- and the
recovery path itself -- in its own savepoint, so an override that raises no
longer takes the reaper down with it.

closes ingadhoc#437

Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
Override base_import.import._parse_float_from_data and _parse_date_from_data
so a single badly-formatted number or date no longer raises
ImportValidationError and cancels the whole import. The raw value is deferred
to the per-record ORM converter, which reports it with its row number
alongside every other field/record error in a single pass. Well-formed values
are still pre-cleaned (currency symbols, thousands/decimal separators) as
before; genuinely unexpected (non-ValueError) date failures are still raised.

closes ingadhoc#429

Signed-off-by: Juan Carreras <jc@adhoc.com.ar>
Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate.

Translation: miscellaneous-19.0/miscellaneous-19.0-base_import_ux
Translate-URL: https://translation.dev-adhoc.com/projects/miscellaneous-19-0/miscellaneous-19-0-base_import_ux/
nicomacr and others added 9 commits August 21, 2026 20:24
A job can outlive its records: a GC or an FK cascade deletes them while the
job is still enqueued, waiting or running. Such a job did not fail — there is
nothing left to run it on — but it ended up failed (timeout or retries
exhausted) with its batch canceled as "Previous job in batch failed",
polluting failure metrics and notifying about nothing actionable.

The runner and the reaper now detect a job whose records are all gone and
cancel it (and the rest of its batch) instead, without notifying. Jobs that
point to no records at all (model-level methods) and jobs with surviving
records are untouched.

closes ingadhoc#438

Signed-off-by: Nicolas Mac Rouillon (ADV) <nmr@adhoc.inc>
Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate.

Translation: miscellaneous-19.0/miscellaneous-19.0-base_bg
Translate-URL: https://translation.dev-adhoc.com/projects/miscellaneous-19-0/miscellaneous-19-0-base_bg/
Granting base.group_user to the parent menus without group was done while
loading the menus, but /web/webclient/load_menus is a readonly route, so
the write breaks its cursor with "cannot execute INSERT in a read-only
transaction". The request itself survives -it is retried with a read/write
cursor- but the failed query is already logged as an error, which is enough
to turn a test run red. On a real database it happened once, since the retry
commits the group; on tests it happens on every tour that loads the
webclient, because each test rolls that write back.

Doing it on _register_hook keeps the case covered -another module installing
a parent menu without internal group after portal_backend- and runs on a
read/write cursor: the hook is called when the registry is loaded, which is
what installing or updating a module does.

closes ingadhoc#436

Related: ingadhoc/stock#1004
Related: ingadhoc/account-financial-tools#984
Related: ingadhoc/product#937
Signed-off-by: Filoquin adhoc <maq@adhoc.com.ar>
@stopkovae
stopkovae merged commit 8ba14b7 into 19.0-code_review-ai Aug 31, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.