3
3
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4
4
5
5
import logging
6
-
7
6
from contextlib import contextmanager
8
7
from datetime import datetime
9
8
10
9
import psycopg2
11
10
12
11
import odoo
13
12
from odoo import _
13
+
14
14
from odoo .addons .component .core import AbstractComponent
15
- from odoo .addons .connector .exception import ( IDMissingInBackend ,
16
- RetryableJobError )
15
+ from odoo .addons .connector .exception import IDMissingInBackend , RetryableJobError
16
+
17
17
from .backend_adapter import MAGENTO_DATETIME_FORMAT
18
18
19
19
_logger = logging .getLogger (__name__ )
35
35
class MagentoBaseExporter (AbstractComponent ):
36
36
""" Base exporter for Magento """
37
37
38
- _name = ' magento.base.exporter'
39
- _inherit = [' base.exporter' , ' base.magento.connector' ]
40
- _usage = ' record.exporter'
38
+ _name = " magento.base.exporter"
39
+ _inherit = [" base.exporter" , " base.magento.connector" ]
40
+ _usage = " record.exporter"
41
41
42
42
def __init__ (self , working_context ):
43
43
super (MagentoBaseExporter , self ).__init__ (working_context )
@@ -53,9 +53,9 @@ def _delay_import(self):
53
53
# force is True because the sync_date will be more recent
54
54
# so the import would be skipped
55
55
assert self .external_id
56
- self .binding .with_delay ().import_record (self . backend_record ,
57
- self .external_id ,
58
- force = True )
56
+ self .binding .with_delay ().import_record (
57
+ self . backend_record , self .external_id , force = True
58
+ )
59
59
60
60
def _should_import (self ):
61
61
""" Before the export, compare the update date
@@ -69,14 +69,12 @@ def _should_import(self):
69
69
sync = self .binding .sync_date
70
70
if not sync :
71
71
return True
72
- record = self .backend_adapter .read (self .external_id ,
73
- attributes = ['updated_at' ])
74
- if not record ['updated_at' ]:
72
+ record = self .backend_adapter .read (self .external_id , attributes = ["updated_at" ])
73
+ if not record ["updated_at" ]:
75
74
# in rare case it can be empty, in doubt, import it
76
75
return True
77
76
sync_date = odoo .fields .Datetime .from_string (sync )
78
- magento_date = datetime .strptime (record ['updated_at' ],
79
- MAGENTO_DATETIME_FORMAT )
77
+ magento_date = datetime .strptime (record ["updated_at" ], MAGENTO_DATETIME_FORMAT )
80
78
return sync_date < magento_date
81
79
82
80
def run (self , binding , * args , ** kwargs ):
@@ -102,7 +100,7 @@ def run(self, binding, *args, **kwargs):
102
100
# exports (due to dependencies) and one of them fails.
103
101
# The commit will also release the lock acquired on the binding
104
102
# record
105
- if not odoo .tools .config [' test_enable' ]:
103
+ if not odoo .tools .config [" test_enable" ]:
106
104
# pylint: disable=invalid-commit
107
105
self .env .cr .commit () # noqa
108
106
@@ -121,8 +119,8 @@ def _after_export(self):
121
119
class MagentoExporter (AbstractComponent ):
122
120
""" A common flow for the exports to Magento """
123
121
124
- _name = ' magento.exporter'
125
- _inherit = ' magento.base.exporter'
122
+ _name = " magento.exporter"
123
+ _inherit = " magento.base.exporter"
126
124
127
125
def __init__ (self , working_context ):
128
126
super (MagentoExporter , self ).__init__ (working_context )
@@ -144,19 +142,21 @@ def _lock(self):
144
142
on the binding record it has to export.
145
143
146
144
"""
147
- sql = ("SELECT id FROM %s WHERE ID = %%s FOR UPDATE NOWAIT" %
148
- self .model ._table )
145
+ sql = "SELECT id FROM %s WHERE ID = %%s FOR UPDATE NOWAIT" % self .model ._table
149
146
try :
150
- self .env .cr .execute (sql , (self .binding .id , ),
151
- log_exceptions = False )
147
+ self .env .cr .execute (sql , (self .binding .id ,), log_exceptions = False )
152
148
except psycopg2 .OperationalError :
153
- _logger .info ('A concurrent job is already exporting the same '
154
- 'record (%s with id %s). Job delayed later.' ,
155
- self .model ._name , self .binding .id )
149
+ _logger .info (
150
+ "A concurrent job is already exporting the same "
151
+ "record (%s with id %s). Job delayed later." ,
152
+ self .model ._name ,
153
+ self .binding .id ,
154
+ )
156
155
raise RetryableJobError (
157
- 'A concurrent job is already exporting the same record '
158
- '(%s with id %s). The job will be retried later.' %
159
- (self .model ._name , self .binding .id ))
156
+ "A concurrent job is already exporting the same record "
157
+ "(%s with id %s). The job will be retried later."
158
+ % (self .model ._name , self .binding .id )
159
+ )
160
160
161
161
def _has_to_skip (self ):
162
162
""" Return True if the export can be skipped """
@@ -187,17 +187,22 @@ def _retry_unique_violation(self):
187
187
except psycopg2 .IntegrityError as err :
188
188
if err .pgcode == psycopg2 .errorcodes .UNIQUE_VIOLATION :
189
189
raise RetryableJobError (
190
- 'A database error caused the failure of the job:\n '
191
- '%s\n \n '
192
- 'Likely due to 2 concurrent jobs wanting to create '
193
- 'the same record. The job will be retried later.' % err )
190
+ "A database error caused the failure of the job:\n "
191
+ "%s\n \n "
192
+ "Likely due to 2 concurrent jobs wanting to create "
193
+ "the same record. The job will be retried later." % err
194
+ )
194
195
else :
195
196
raise
196
197
197
- def _export_dependency (self , relation , binding_model ,
198
- component_usage = 'record.exporter' ,
199
- binding_field = 'magento_bind_ids' ,
200
- binding_extra_vals = None ):
198
+ def _export_dependency (
199
+ self ,
200
+ relation ,
201
+ binding_model ,
202
+ component_usage = "record.exporter" ,
203
+ binding_field = "magento_bind_ids" ,
204
+ binding_extra_vals = None ,
205
+ ):
201
206
"""
202
207
Export a dependency. The exporter class is a subclass of
203
208
``MagentoExporter``. If a more precise class need to be defined,
@@ -242,38 +247,44 @@ def _export_dependency(self, relation, binding_model,
242
247
wrap = relation ._name != binding_model
243
248
244
249
if wrap and hasattr (relation , binding_field ):
245
- domain = [('odoo_id' , '=' , relation .id ),
246
- ('backend_id' , '=' , self .backend_record .id )]
250
+ domain = [
251
+ ("odoo_id" , "=" , relation .id ),
252
+ ("backend_id" , "=" , self .backend_record .id ),
253
+ ]
247
254
binding = self .env [binding_model ].search (domain )
248
255
if binding :
249
256
assert len (binding ) == 1 , (
250
- ' only 1 binding for a backend is '
251
- 'supported in _export_dependency' )
257
+ " only 1 binding for a backend is " "supported in _export_dependency"
258
+ )
252
259
# we are working with a unwrapped record (e.g.
253
260
# product.category) and the binding does not exist yet.
254
261
# Example: I created a product.product and its binding
255
262
# magento.product.product and we are exporting it, but we need to
256
263
# create the binding for the product.category on which it
257
264
# depends.
258
265
else :
259
- bind_values = {'backend_id' : self .backend_record .id ,
260
- 'odoo_id' : relation .id }
266
+ bind_values = {
267
+ "backend_id" : self .backend_record .id ,
268
+ "odoo_id" : relation .id ,
269
+ }
261
270
if binding_extra_vals :
262
271
bind_values .update (binding_extra_vals )
263
272
# If 2 jobs create it at the same time, retry
264
273
# one later. A unique constraint (backend_id,
265
274
# odoo_id) should exist on the binding model
266
275
with self ._retry_unique_violation ():
267
- binding = (self .env [binding_model ]
268
- .with_context (connector_no_export = True )
269
- .sudo ()
270
- .create (bind_values ))
276
+ binding = (
277
+ self .env [binding_model ]
278
+ .with_context (connector_no_export = True )
279
+ .sudo ()
280
+ .create (bind_values )
281
+ )
271
282
# Eager commit to avoid having 2 jobs
272
283
# exporting at the same time. The constraint
273
284
# will pop if an other job already created
274
285
# the same binding. It will be caught and
275
286
# raise a RetryableJobError.
276
- if not odoo .tools .config [' test_enable' ]:
287
+ if not odoo .tools .config [" test_enable" ]:
277
288
# pylint: disable=invalid-commit
278
289
self .env .cr .commit () # noqa
279
290
else :
@@ -283,8 +294,7 @@ def _export_dependency(self, relation, binding_model,
283
294
binding = relation
284
295
285
296
if not rel_binder .to_external (binding ):
286
- exporter = self .component (usage = component_usage ,
287
- model_name = binding_model )
297
+ exporter = self .component (usage = component_usage , model_name = binding_model )
288
298
exporter .run (binding )
289
299
290
300
def _export_dependencies (self ):
@@ -361,11 +371,11 @@ def _run(self, fields=None):
361
371
if self .external_id :
362
372
record = self ._update_data (map_record , fields = fields )
363
373
if not record :
364
- return _ (' Nothing to export.' )
374
+ return _ (" Nothing to export." )
365
375
self ._update (record )
366
376
else :
367
377
record = self ._create_data (map_record , fields = fields )
368
378
if not record :
369
- return _ (' Nothing to export.' )
379
+ return _ (" Nothing to export." )
370
380
self .external_id = self ._create (record )
371
- return _ (' Record exported with ID %s on Magento.' ) % self .external_id
381
+ return _ (" Record exported with ID %s on Magento." ) % self .external_id
0 commit comments