Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.

Commit c761ca2

Browse files
committed
[FIX] keep context
1 parent 5c74dbe commit c761ca2

File tree

9 files changed

+95
-13
lines changed

9 files changed

+95
-13
lines changed

base_import_async/models/base_import_import.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ def do(self, fields, options, dryrun=False):
6565
(translated_model_name, self.file_name)
6666
attachment = self._create_csv_attachment(
6767
import_fields, data, options, self.file_name)
68-
delayed_job = self.with_delay(description=description)._split_file(
68+
delayed_job = self.with_delay(
69+
description=description,
70+
keep_context=True
71+
)._split_file(
6972
model_name=self.res_model,
7073
translated_model_name=translated_model_name,
7174
attachment=attachment,
@@ -166,8 +169,11 @@ def _split_file(self, model_name, translated_model_name,
166169
fields, data[row_from:row_to + 1], options,
167170
file_name=root + '-' + chunk + ext)
168171
delayed_job = self.with_context(
169-
job_batch=batch).with_delay(
170-
description=description, priority=priority)._import_one_chunk(
172+
job_batch=batch.id).with_delay(
173+
description=description,
174+
priority=priority,
175+
keep_context=True
176+
)._import_one_chunk(
171177
model_name=model_name,
172178
attachment=attachment,
173179
options=options)

queue_job/fields.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@ def convert_to_cache(self, value, record, validate=True):
2828
class JobEncoder(json.JSONEncoder):
2929
"""Encode Odoo recordsets so that we can later recompose them"""
3030

31+
def _get_record_context(self, obj):
32+
context = obj.env.context.copy()
33+
return context
34+
3135
def default(self, obj):
3236
if isinstance(obj, models.BaseModel):
37+
context = self._get_record_context(obj)
3338
return {'_type': 'odoo_recordset',
3439
'model': obj._name,
3540
'ids': obj.ids,
3641
'uid': obj.env.uid,
42+
'context': context,
3743
}
3844
elif isinstance(obj, datetime):
3945
return {'_type': 'datetime_isoformat',
@@ -61,6 +67,8 @@ def object_hook(self, obj):
6167
type_ = obj['_type']
6268
if type_ == 'odoo_recordset':
6369
model = self.env[obj['model']]
70+
if obj.get("context"):
71+
model = model.with_context(**obj.get("context"))
6472
if obj.get('uid'):
6573
model = model.sudo(obj['uid'])
6674
return model.browse(obj['ids'])

queue_job/job.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
import functools
66
import hashlib
77
import logging
8+
import json
9+
import yaml
810
import uuid
911
import sys
1012
from datetime import datetime, timedelta
1113

1214
import odoo
15+
from odoo.tools.safe_eval import safe_eval
1316

1417
from .exception import (NoSuchJobError,
1518
FailedJobError,
@@ -55,14 +58,15 @@ class DelayableRecordset(object):
5558

5659
def __init__(self, recordset, priority=None, eta=None,
5760
max_retries=None, description=None, channel=None,
58-
identity_key=None):
61+
identity_key=None, keep_context=False):
5962
self.recordset = recordset
6063
self.priority = priority
6164
self.eta = eta
6265
self.max_retries = max_retries
6366
self.description = description
6467
self.channel = channel
6568
self.identity_key = identity_key
69+
self.keep_context = keep_context
6670

6771
def __getattr__(self, name):
6872
if name in self.recordset:
@@ -87,7 +91,9 @@ def delay(*args, **kwargs):
8791
eta=self.eta,
8892
description=self.description,
8993
channel=self.channel,
90-
identity_key=self.identity_key)
94+
identity_key=self.identity_key,
95+
keep_context=self.keep_context
96+
)
9197
return delay
9298

9399
def __str__(self):
@@ -297,6 +303,7 @@ def _load_from_db_record(cls, job_db_record):
297303
if stored.company_id:
298304
job_.company_id = stored.company_id.id
299305
job_.identity_key = stored.identity_key
306+
job_.keep_context = stored.context or {}
300307
return job_
301308

302309
def job_record_with_same_identity_key(self):
@@ -311,7 +318,7 @@ def job_record_with_same_identity_key(self):
311318
@classmethod
312319
def enqueue(cls, func, args=None, kwargs=None,
313320
priority=None, eta=None, max_retries=None, description=None,
314-
channel=None, identity_key=None):
321+
channel=None, identity_key=None, keep_context=None):
315322
"""Create a Job and enqueue it in the queue. Return the job uuid.
316323
317324
This expects the arguments specific to the job to be already extracted
@@ -324,7 +331,8 @@ def enqueue(cls, func, args=None, kwargs=None,
324331
new_job = cls(func=func, args=args,
325332
kwargs=kwargs, priority=priority, eta=eta,
326333
max_retries=max_retries, description=description,
327-
channel=channel, identity_key=identity_key)
334+
channel=channel, identity_key=identity_key,
335+
keep_context=keep_context)
328336
if new_job.identity_key:
329337
existing = new_job.job_record_with_same_identity_key()
330338
if existing:
@@ -355,7 +363,8 @@ def db_record_from_uuid(env, job_uuid):
355363
def __init__(self, func,
356364
args=None, kwargs=None, priority=None,
357365
eta=None, job_uuid=None, max_retries=None,
358-
description=None, channel=None, identity_key=None):
366+
description=None, channel=None,
367+
identity_key=None, keep_context=False):
359368
""" Create a Job
360369
361370
:param func: function to execute
@@ -381,6 +390,8 @@ def __init__(self, func,
381390
as argument)
382391
:param env: Odoo Environment
383392
:type env: :class:`odoo.api.Environment`
393+
:param keep_context: Determine if the current context should be restored
394+
:type keep_context: :bool or list
384395
"""
385396
if args is None:
386397
args = ()
@@ -397,6 +408,7 @@ def __init__(self, func,
397408

398409
recordset = func.__self__
399410
env = recordset.env
411+
self.keep_context = keep_context
400412
self.model_name = recordset._name
401413
self.method_name = func.__name__
402414
self.recordset = recordset
@@ -500,6 +512,10 @@ def store(self):
500512
}
501513

502514
dt_to_string = odoo.fields.Datetime.to_string
515+
context = {}
516+
if self.keep_context:
517+
context = self.env.context.copy()
518+
vals.update({"context": json.dumps(context)})
503519
if self.date_enqueued:
504520
vals['date_enqueued'] = dt_to_string(self.date_enqueued)
505521
if self.date_started:
@@ -516,6 +532,9 @@ def store(self):
516532
db_record.write(vals)
517533
else:
518534
date_created = dt_to_string(self.date_created)
535+
# We store the original context used at import on create
536+
ctx = self.env.context.copy() or '{}'
537+
vals.update({'original_context': json.dumps(ctx) or ''})
519538
# The following values must never be modified after the
520539
# creation of the job
521540
vals.update({'uuid': self.uuid,
@@ -532,14 +551,40 @@ def store(self):
532551
if self.channel:
533552
vals.update({'channel': self.channel})
534553

535-
self.env[self.job_model_name].sudo().create(vals)
554+
job = self.env[self.job_model_name].sudo().create(vals)
536555

537556
def db_record(self):
538557
return self.db_record_from_uuid(self.env, self.uuid)
539558

559+
def _get_abs_context(self, original_ctx, ctx):
560+
try:
561+
import_ctx = json.loads(original_ctx)
562+
current_ctx = json.loads(ctx)
563+
except Exception as e:
564+
_logger.error("\n\nERROR CONTEXT JSON CONVERSION: %s\n\n" % e)
565+
return self.env.context.copy()
566+
else:
567+
if isinstance(import_ctx, dict) and isinstance(current_ctx, dict):
568+
import_ctx.update(current_ctx)
569+
return import_ctx
570+
return self.env.context.copy()
571+
572+
def _get_record_context(self):
573+
"""
574+
Get the context to execute the job
575+
"""
576+
ctx = self._get_abs_context(self.db_record().original_context,
577+
self.db_record().context)
578+
if self.company_id:
579+
ctx.update({'allowed_company_ids': [self.company_id]})
580+
if self.uuid:
581+
ctx.update({"job_uuid": self.uuid})
582+
return ctx
583+
540584
@property
541585
def func(self):
542-
recordset = self.recordset.with_context(job_uuid=self.uuid)
586+
context = self._get_record_context()
587+
recordset = self.recordset.with_context(**context)
543588
recordset = recordset.sudo(self.user_id)
544589
return getattr(recordset, self.method_name)
545590

queue_job/models/base.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _register_hook(self):
3434
@api.multi
3535
def with_delay(self, priority=None, eta=None,
3636
max_retries=None, description=None,
37-
channel=None, identity_key=None):
37+
channel=None, identity_key=None, keep_context=False):
3838
""" Return a ``DelayableRecordset``
3939
4040
The returned instance allow to enqueue any method of the recordset's
@@ -62,6 +62,9 @@ def with_delay(self, priority=None, eta=None,
6262
:param identity_key: key uniquely identifying the job, if specified
6363
and a job with the same key has not yet been run,
6464
the new job will not be added.
65+
:param keep_context: boolean to set if the current context
66+
should be restored on the recordset
67+
(default: False).
6568
:return: instance of a DelayableRecordset
6669
:rtype: :class:`odoo.addons.queue_job.job.DelayableRecordset`
6770
@@ -90,4 +93,6 @@ def with_delay(self, priority=None, eta=None,
9093
max_retries=max_retries,
9194
description=description,
9295
channel=channel,
93-
identity_key=identity_key)
96+
identity_key=identity_key,
97+
keep_context=keep_context
98+
)

queue_job/models/queue_job.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ class QueueJob(models.Model):
4444
company_id = fields.Many2one(comodel_name='res.company',
4545
string='Company', index=True)
4646
name = fields.Char(string='Description', readonly=True)
47+
context = fields.Char(
48+
string="Context Value",
49+
default="{}",
50+
help="Context dictionary as Python expression, empty by default "
51+
"(Default: {})",
52+
readonly=True,
53+
)
54+
original_context = fields.Char(
55+
string="Original Context Value",
56+
default="{}",
57+
help="This is the context dictionary that was used on import"
58+
)
4759

4860
model_name = fields.Char(string='Model', readonly=True)
4961
method_name = fields.Char(readonly=True)

queue_job/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
from . import test_runner_runner
33
from . import test_json_field
44
from . import test_model_job_channel
5+

queue_job/tests/test_json_field.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def test_encoder_recordset(self):
2323
"_type": "odoo_recordset",
2424
"model": "res.partner",
2525
"ids": [partner.id],
26+
"context": {},
2627
}]
2728
self.assertEqual(json.loads(value_json), expected)
2829

queue_job/views/queue_job_views.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@
5353
<field name="date_done"/>
5454
</group>
5555
</group>
56+
<group name="context_grp">
57+
<field name="context"/>
58+
<field name="original_context"/>
59+
</group>
5660
<group colspan="4">
5761
<div>
5862
<label for="retry" string="Current try / max. retries" />

test_queue_job_batch/tests/test_queue_job_batch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def test_batch(self):
88
batch = self.env['queue.job.batch'].get_new_batch('TEST')
99
self.assertFalse(batch.job_ids)
1010
model = self.env['test.queue.job'].with_context(
11-
job_batch=batch
11+
job_batch=batch.id
1212
)
1313
job_1 = model.with_delay().testing_method()
1414
self.assertEqual(job_1.db_record().state, 'pending')

0 commit comments

Comments
 (0)