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