2
2
import logging
3
3
import os
4
4
import re
5
- from contextlib import contextmanager
6
5
from operator import itemgetter
7
6
8
7
import lxml
12
11
from odoo import release
13
12
from odoo .tools .convert import xml_import
14
13
from odoo .tools .misc import file_open
15
- from odoo .tools .translate import xml_translate
16
14
except ImportError :
17
15
from openerp import release
18
16
from openerp .tools .convert import xml_import
19
17
from openerp .tools .misc import file_open
20
18
19
+ from . import views
21
20
from .const import NEARLYWARN
22
21
from .exceptions import MigrationError
23
22
from .helpers import _get_theme_models , _ir_values_value , _validate_model , model_of_table , table_of_model
42
41
table_exists ,
43
42
target_of ,
44
43
)
45
- from .report import add_to_migration_reports
46
44
47
45
_logger = logging .getLogger (__name__ )
48
46
53
51
basestring = unicode = str
54
52
55
53
56
- def remove_view (cr , xml_id = None , view_id = None , silent = False , key = None ):
57
- """
58
- Recursively delete the given view and its inherited views, as long as they
59
- are part of a module. Will crash as soon as a custom view exists anywhere
60
- in the hierarchy.
61
-
62
- Also handle multi-website COWed views.
63
- """
64
- assert bool (xml_id ) ^ bool (view_id )
65
- if xml_id :
66
- view_id = ref (cr , xml_id )
67
- if view_id :
68
- module , _ , name = xml_id .partition ("." )
69
- cr .execute ("SELECT model FROM ir_model_data WHERE module=%s AND name=%s" , [module , name ])
70
-
71
- [model ] = cr .fetchone ()
72
- if model != "ir.ui.view" :
73
- raise ValueError ("%r should point to a 'ir.ui.view', not a %r" % (xml_id , model ))
74
- else :
75
- # search matching xmlid for logging or renaming of custom views
76
- xml_id = "?"
77
- if not key :
78
- cr .execute ("SELECT module, name FROM ir_model_data WHERE model='ir.ui.view' AND res_id=%s" , [view_id ])
79
- if cr .rowcount :
80
- xml_id = "%s.%s" % cr .fetchone ()
81
-
82
- # From given or determined xml_id, the views duplicated in a multi-website
83
- # context are to be found and removed.
84
- if xml_id != "?" and column_exists (cr , "ir_ui_view" , "key" ):
85
- cr .execute ("SELECT id FROM ir_ui_view WHERE key = %s AND id != %s" , [xml_id , view_id ])
86
- for [v_id ] in cr .fetchall ():
87
- remove_view (cr , view_id = v_id , silent = silent , key = xml_id )
88
-
89
- if not view_id :
90
- return
91
-
92
- cr .execute (
93
- """
94
- SELECT v.id, x.module || '.' || x.name, v.name
95
- FROM ir_ui_view v LEFT JOIN
96
- ir_model_data x ON (v.id = x.res_id AND x.model = 'ir.ui.view' AND x.module !~ '^_')
97
- WHERE v.inherit_id = %s;
98
- """ ,
99
- [view_id ],
100
- )
101
- for child_id , child_xml_id , child_name in cr .fetchall ():
102
- if child_xml_id :
103
- if not silent :
104
- _logger .info (
105
- "remove deprecated built-in view %s (ID %s) as parent view %s (ID %s) is going to be removed" ,
106
- child_xml_id ,
107
- child_id ,
108
- xml_id ,
109
- view_id ,
110
- )
111
- remove_view (cr , child_xml_id , silent = True )
112
- else :
113
- if not silent :
114
- _logger .warning (
115
- "deactivate deprecated custom view with ID %s as parent view %s (ID %s) is going to be removed" ,
116
- child_id ,
117
- xml_id ,
118
- view_id ,
119
- )
120
- disable_view_query = """
121
- UPDATE ir_ui_view
122
- SET name = (name || ' - old view, inherited from ' || %%s),
123
- inherit_id = NULL
124
- %s
125
- WHERE id = %%s
126
- """
127
- # In 8.0, disabling requires setting mode to 'primary'
128
- extra_set_sql = ""
129
- if column_exists (cr , "ir_ui_view" , "mode" ):
130
- extra_set_sql = ", mode = 'primary' "
131
-
132
- # Column was not present in v7 and it's older version
133
- if column_exists (cr , "ir_ui_view" , "active" ):
134
- extra_set_sql += ", active = false "
135
-
136
- disable_view_query = disable_view_query % extra_set_sql
137
- cr .execute (disable_view_query , (key or xml_id , child_id ))
138
- add_to_migration_reports (
139
- {"id" : child_id , "name" : child_name },
140
- "Disabled views" ,
141
- )
142
- if not silent :
143
- _logger .info ("remove deprecated %s view %s (ID %s)" , key and "COWed" or "built-in" , key or xml_id , view_id )
144
-
145
- remove_records (cr , "ir.ui.view" , [view_id ])
146
-
147
-
148
- @contextmanager
149
- def edit_view (cr , xmlid = None , view_id = None , skip_if_not_noupdate = True , active = True ):
150
- """Contextmanager that may yield etree arch of a view.
151
- As it may not yield, you must use `skippable_cm`
152
-
153
- with util.skippable_cm(), util.edit_view(cr, 'xml.id') as arch:
154
- arch.attrib['string'] = 'My Form'
155
-
156
- When view_id is passed to identify a view, view's arch will always yield to be edited because
157
- we assume that xmlid for such view does not exist to check its noupdate flag.
158
-
159
- If view's noupdate=false then the arch will not be yielded for edit unless skip_if_not_noupdate=False,
160
- because when noupdate=False we assume it is a standard view that will be updated by the ORM later on anyways.
161
-
162
- If view's noupdate=True, the view will be yielded for edit.
163
-
164
- If the `active` argument is not None, the view will be (de)activated accordingly.
165
-
166
- For more details, see discussion in: https://github.com/odoo/upgrade-specific/pull/4216
167
- """
168
- assert bool (xmlid ) ^ bool (view_id ), "You Must specify either xmlid or view_id"
169
- noupdate = True
170
- if xmlid :
171
- if "." not in xmlid :
172
- raise ValueError ("Please use fully qualified name <module>.<name>" )
173
-
174
- module , _ , name = xmlid .partition ("." )
175
- cr .execute (
176
- """
177
- SELECT res_id, noupdate
178
- FROM ir_model_data
179
- WHERE module = %s
180
- AND name = %s
181
- """ ,
182
- [module , name ],
183
- )
184
- data = cr .fetchone ()
185
- if data :
186
- view_id , noupdate = data
187
-
188
- if view_id and not (skip_if_not_noupdate and not noupdate ):
189
- arch_col = "arch_db" if column_exists (cr , "ir_ui_view" , "arch_db" ) else "arch"
190
- jsonb_column = column_type (cr , "ir_ui_view" , arch_col ) == "jsonb"
191
- cr .execute (
192
- """
193
- SELECT {arch}
194
- FROM ir_ui_view
195
- WHERE id=%s
196
- """ .format (
197
- arch = arch_col ,
198
- ),
199
- [view_id ],
200
- )
201
- [arch ] = cr .fetchone () or [None ]
202
- if arch :
203
-
204
- def parse (arch ):
205
- arch = arch .encode ("utf-8" ) if isinstance (arch , unicode ) else arch
206
- return lxml .etree .fromstring (arch .replace (b" \n " , b"\n " ))
207
-
208
- if jsonb_column :
209
-
210
- def get_trans_terms (value ):
211
- terms = []
212
- xml_translate (terms .append , value )
213
- return terms
214
-
215
- translation_terms = {lang : get_trans_terms (value ) for lang , value in arch .items ()}
216
- arch_etree = parse (arch ["en_US" ])
217
- yield arch_etree
218
- new_arch = lxml .etree .tostring (arch_etree , encoding = "unicode" )
219
- terms_en = translation_terms ["en_US" ]
220
- arch_column_value = Json (
221
- {
222
- lang : xml_translate (dict (zip (terms_en , terms )).get , new_arch )
223
- for lang , terms in translation_terms .items ()
224
- }
225
- )
226
- else :
227
- arch_etree = parse (arch )
228
- yield arch_etree
229
- arch_column_value = lxml .etree .tostring (arch_etree , encoding = "unicode" )
230
-
231
- set_active = ", active={}" .format (bool (active )) if active is not None else ""
232
- cr .execute (
233
- "UPDATE ir_ui_view SET {arch}=%s{set_active} WHERE id=%s" .format (arch = arch_col , set_active = set_active ),
234
- [arch_column_value , view_id ],
235
- )
236
-
237
-
238
- def add_view (cr , name , model , view_type , arch_db , inherit_xml_id = None , priority = 16 ):
239
- inherit_id = None
240
- if inherit_xml_id :
241
- inherit_id = ref (cr , inherit_xml_id )
242
- if not inherit_id :
243
- raise ValueError (
244
- "Unable to add view '%s' because its inherited view '%s' cannot be found!" % (name , inherit_xml_id )
245
- )
246
- arch_col = "arch_db" if column_exists (cr , "ir_ui_view" , "arch_db" ) else "arch"
247
- jsonb_column = column_type (cr , "ir_ui_view" , arch_col ) == "jsonb"
248
- arch_column_value = Json ({"en_US" : arch_db }) if jsonb_column else arch_db
249
- cr .execute (
250
- """
251
- INSERT INTO ir_ui_view(name, "type", model, inherit_id, mode, active, priority, %s)
252
- VALUES(%%(name)s, %%(view_type)s, %%(model)s, %%(inherit_id)s, %%(mode)s, 't', %%(priority)s, %%(arch_db)s)
253
- RETURNING id
254
- """
255
- % arch_col ,
256
- {
257
- "name" : name ,
258
- "view_type" : view_type ,
259
- "model" : model ,
260
- "inherit_id" : inherit_id ,
261
- "mode" : "extension" if inherit_id else "primary" ,
262
- "priority" : priority ,
263
- "arch_db" : arch_column_value ,
264
- },
265
- )
266
- return cr .fetchone ()[0 ]
267
-
268
-
269
54
# fmt:off
270
55
if version_gte ("saas~14.3" ):
271
56
def remove_asset (cr , name ):
@@ -274,7 +59,7 @@ def remove_asset(cr, name):
274
59
remove_records (cr , "ir.asset" , [aid for aid , in cr .fetchall ()])
275
60
else :
276
61
def remove_asset (cr , name ):
277
- remove_view (cr , name , silent = True )
62
+ views . remove_view (cr , name , silent = True )
278
63
# fmt:on
279
64
280
65
@@ -305,7 +90,7 @@ def remove_record(cr, name):
305
90
# deleguate to the right method
306
91
if model == "ir.ui.view" :
307
92
_logger .log (NEARLYWARN , "Removing view %r" , name )
308
- return remove_view (cr , view_id = res_id )
93
+ return views . remove_view (cr , view_id = res_id )
309
94
310
95
if model == "ir.ui.menu" :
311
96
_logger .log (NEARLYWARN , "Removing menu %r" , name )
@@ -333,7 +118,7 @@ def remove_records(cr, model, ids):
333
118
)
334
119
if theme_copy_model == "ir.ui.view" :
335
120
for (view_id ,) in cr .fetchall ():
336
- remove_view (cr , view_id = view_id )
121
+ views . remove_view (cr , view_id = view_id )
337
122
else :
338
123
remove_records (cr , theme_copy_model , [rid for (rid ,) in cr .fetchall ()])
339
124
@@ -348,7 +133,7 @@ def remove_records(cr, model, ids):
348
133
remove_menus (cr , [menu_id for (menu_id ,) in cr .fetchall ()])
349
134
elif inh .model == "ir.ui.view" :
350
135
for (view_id ,) in cr .fetchall ():
351
- remove_view (cr , view_id = view_id )
136
+ views . remove_view (cr , view_id = view_id )
352
137
else :
353
138
remove_records (cr , inh .model , [rid for (rid ,) in cr .fetchall ()])
354
139
@@ -400,7 +185,7 @@ def _rm_refs(cr, model, ids=None):
400
185
if ref_model == "ir.ui.view" :
401
186
cr .execute ("SELECT id" + query_tail , [needle ])
402
187
for (view_id ,) in cr .fetchall ():
403
- remove_view (cr , view_id = view_id , silent = True )
188
+ views . remove_view (cr , view_id = view_id , silent = True )
404
189
elif ref_model == "ir.ui.menu" :
405
190
cr .execute ("SELECT id" + query_tail , [needle ])
406
191
menu_ids = tuple (m [0 ] for m in cr .fetchall ())
0 commit comments