72
72
"web_editor.assets" ,
73
73
]
74
74
75
- models_with_user_id = [
75
+ MODELS_WITH_USER_ID = [
76
76
'crm.lead' ,
77
77
'event.event' ,
78
78
'knowledge.article.favorite' ,
@@ -142,6 +142,7 @@ def _check_files_in_path(self, module):
142
142
self ._check_static_files_usage_in_xml (tree , in_use_files )
143
143
self ._check_fields (tree , file_name )
144
144
self ._check_change_theme_method (tree , file_name )
145
+ self ._check_dates_are_relative (tree , file_name )
145
146
if root .split ('/' )[- 1 ] == 'data' :
146
147
self ._check_view_active (tree , file_name )
147
148
self ._check_is_published_false (tree , file_name )
@@ -207,14 +208,14 @@ def _check_manifest(self, s, need_studio, escape_studio_test):
207
208
_logger .warning ("'web_studio' should not be in the dependencies." )
208
209
209
210
def _check_studio (self , root , file_name ):
210
- models_for_studio = [
211
+ MODELS_FOR_STUDIO = [
211
212
"ir.actions.act_window" ,
212
213
"ir.actions.server" ,
213
214
"ir.model" ,
214
215
"ir.model.fields" ,
215
216
"ir.ui.menu" ,
216
217
]
217
- for model in models_for_studio :
218
+ for model in MODELS_FOR_STUDIO :
218
219
if root .xpath (f"//record[@model='{ model } ']" ):
219
220
_logger .info ("%s found in %s, needs studio" , model , file_name )
220
221
return True
@@ -227,18 +228,18 @@ def _check_studio(self, root, file_name):
227
228
return False
228
229
229
230
def _check_xml_style (self , s , root , module , file_name ):
230
- starts_with = [
231
+ STARTS_WITH = [
231
232
"<?xml version='1.0' encoding='UTF-8'?>" ,
232
233
"<?xml version='1.0' encoding=\" UTF-8\" ?>" ,
233
234
"<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>" ,
234
235
"<?xml version=\" 1.0\" encoding='UTF-8'?>" ,
235
236
"<?xml version=\" 1.0\" encoding=\" utf-8\" ?>" ,
236
237
]
237
238
first_line = s .split ('\n ' )[0 ]
238
- if not any (first_line == start_line for start_line in starts_with ):
239
+ if not any (first_line == start_line for start_line in STARTS_WITH ):
239
240
_logger .warning (
240
241
"XML files should begin with the following line: %s, but %s starts with %s" ,
241
- starts_with [0 ],
242
+ STARTS_WITH [0 ],
242
243
file_name ,
243
244
first_line ,
244
245
)
@@ -442,7 +443,7 @@ def _check_view_active(self, root, file_name):
442
443
443
444
def _check_user_is_set (self , root , previous_records ):
444
445
records = previous_records
445
- for model in models_with_user_id :
446
+ for model in MODELS_WITH_USER_ID :
446
447
for record in root .xpath (f"//record[@model='{ model } ']" ):
447
448
record_id = record .get ('id' )
448
449
user_field = record .xpath (".//field[@name='user_id']" )
@@ -466,3 +467,31 @@ def _check_change_theme_method(self, root, file_name):
466
467
"You should use button_choose_theme instead of _theme_load in %s." ,
467
468
file_name ,
468
469
)
470
+
471
+ def _check_dates_are_relative (self , root , file_name ):
472
+ RELATIVE_DATES = [
473
+ 'Time.' ,
474
+ 'time.' ,
475
+ ]
476
+ for record in root .xpath ("//record" ):
477
+ model_name = record .get ('model' )
478
+ if not model_name :
479
+ continue
480
+ model = self .env .get (model_name )
481
+ fields_set_in_record = {
482
+ field for field in record .xpath ('.//field' )
483
+ if field .getparent ().get ('id' , False ) == record .get ('id' ) # nested record definitions
484
+ }
485
+ for field in fields_set_in_record :
486
+ field_name = field .get ('name' )
487
+ field_type = model ._fields .get (field_name ).type
488
+ if field_type not in ('date' , 'datetime' ):
489
+ continue
490
+ field_eval = field .get ('eval' )
491
+ if not field_eval or not any (date in field_eval for date in RELATIVE_DATES ):
492
+ _logger .warning (
493
+ "Date field '%s' in model '%s' is hard coded (file: %s). " ,
494
+ field_name ,
495
+ model_name ,
496
+ file_name ,
497
+ )
0 commit comments