2
2
# Copyright 2020 Tecnativa - Pedro M. Baeza
3
3
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
4
4
5
- from odoo import api , exceptions , fields , models , _
5
+ from odoo import _ , api , exceptions , fields , models
6
6
from odoo .tools .safe_eval import safe_eval
7
7
8
8
9
9
class ChainedSwapper (models .Model ):
10
10
_name = "chained.swapper"
11
11
_description = "Chained Swapper"
12
12
13
- name = fields .Char (
14
- required = True ,
15
- translate = True ,
16
- index = 1 ,
17
- )
13
+ name = fields .Char (required = True , translate = True , index = 1 ,)
18
14
model_id = fields .Many2one (
19
- comodel_name = ' ir.model' ,
15
+ comodel_name = " ir.model" ,
20
16
required = True ,
21
17
help = "Model is used for Selecting Field. This is editable "
22
- "until Contextual Action is not created." ,
18
+ "until Contextual Action is not created." ,
23
19
)
24
20
allowed_field_ids = fields .Many2many (
25
- comodel_name = 'ir.model.fields' ,
26
- compute = '_compute_allowed_field_ids'
21
+ comodel_name = "ir.model.fields" , compute = "_compute_allowed_field_ids"
27
22
)
28
23
field_id = fields .Many2one (
29
- comodel_name = ' ir.model.fields' ,
24
+ comodel_name = " ir.model.fields" ,
30
25
required = True ,
31
26
domain = "[('id', 'in', allowed_field_ids)]" ,
32
27
)
33
28
sub_field_ids = fields .One2many (
34
- comodel_name = ' chained.swapper.sub.field' ,
35
- inverse_name = ' chained_swapper_id' ,
36
- string = ' Sub-fields' ,
29
+ comodel_name = " chained.swapper.sub.field" ,
30
+ inverse_name = " chained_swapper_id" ,
31
+ string = " Sub-fields" ,
37
32
)
38
33
constraint_ids = fields .One2many (
39
- comodel_name = ' chained.swapper.constraint' ,
40
- inverse_name = ' chained_swapper_id' ,
41
- string = ' Constraints' ,
34
+ comodel_name = " chained.swapper.constraint" ,
35
+ inverse_name = " chained_swapper_id" ,
36
+ string = " Constraints" ,
42
37
)
43
38
ref_ir_act_window_id = fields .Many2one (
44
- comodel_name = ' ir.actions.act_window' ,
45
- string = ' Action' ,
39
+ comodel_name = " ir.actions.act_window" ,
40
+ string = " Action" ,
46
41
readonly = True ,
47
42
help = "Action to make this template available on records "
48
- "of the related document model." ,
43
+ "of the related document model." ,
49
44
)
50
45
group_ids = fields .Many2many (
51
46
comodel_name = "res.groups" ,
@@ -56,39 +51,44 @@ class ChainedSwapper(models.Model):
56
51
)
57
52
58
53
_sql_constraints = [
59
- ('model_id_field_id_unique' , 'unique (model_id, field_id)' ,
60
- 'Model and Field must be unique!' ),
54
+ (
55
+ "model_id_field_id_unique" ,
56
+ "unique (model_id, field_id)" ,
57
+ "Model and Field must be unique!" ,
58
+ ),
61
59
]
62
60
63
- @api .depends (' model_id' )
61
+ @api .depends (" model_id" )
64
62
def _compute_allowed_field_ids (self ):
65
- model_obj = self .env [' ir.model' ]
66
- field_obj = self .env [' ir.model.fields' ]
63
+ model_obj = self .env [" ir.model" ]
64
+ field_obj = self .env [" ir.model.fields" ]
67
65
for record in self :
68
66
allowed_field_ids = False
69
67
if record .model_id :
70
68
all_models = record .model_id
71
69
active_model_obj = self .env [record .model_id .model ]
72
70
if active_model_obj ._inherits :
73
71
keys = list (active_model_obj ._inherits .keys ())
74
- all_models |= model_obj .search ([('model' , 'in' , keys )])
75
- allowed_field_ids = field_obj .search ([
76
- ('ttype' , 'not in' , ['reference' , 'function' , 'one2many' ]),
77
- ('model_id' , 'in' , all_models .ids ),
78
- ])
72
+ all_models |= model_obj .search ([("model" , "in" , keys )])
73
+ allowed_field_ids = field_obj .search (
74
+ [
75
+ ("ttype" , "not in" , ["reference" , "function" , "one2many" ]),
76
+ ("model_id" , "in" , all_models .ids ),
77
+ ]
78
+ )
79
79
record .allowed_field_ids = allowed_field_ids
80
80
81
- @api .constrains (' model_id' , ' field_id' )
81
+ @api .constrains (" model_id" , " field_id" )
82
82
def _check_sub_field_ids (self ):
83
- self .mapped (' sub_field_ids' )._check_sub_field_chain ()
83
+ self .mapped (" sub_field_ids" )._check_sub_field_chain ()
84
84
85
- @api .onchange (' model_id' )
85
+ @api .onchange (" model_id" )
86
86
def _onchange_model_id (self ):
87
87
self .field_id = False
88
88
89
89
def write (self , vals ):
90
90
res = super ().write (vals )
91
- if ' name' in vals :
91
+ if " name" in vals :
92
92
self .mapped ("ref_ir_act_window_id" ).write ({"name" : vals ["name" ]})
93
93
return res
94
94
@@ -100,25 +100,27 @@ def unlink(self):
100
100
@api .multi
101
101
def add_action (self ):
102
102
self .ensure_one ()
103
- action = self .env ['ir.actions.act_window' ].create ({
104
- 'name' : _ ("Chained swap" ) + ": " + self .name ,
105
- 'type' : 'ir.actions.act_window' ,
106
- 'res_model' : 'chained.swapper.wizard' ,
107
- 'src_model' : self .model_id .model ,
108
- 'groups_id' : [(4 , x .id ) for x in self .group_ids ],
109
- 'view_type' : 'form' ,
110
- 'context' : "{'chained_swapper_id': %d}" % (self .id ),
111
- 'view_mode' : 'form' ,
112
- 'target' : 'new' ,
113
- 'binding_model_id' : self .model_id .id ,
114
- 'binding_type' : 'action' ,
115
- })
116
- self .write ({'ref_ir_act_window_id' : action .id })
103
+ action = self .env ["ir.actions.act_window" ].create (
104
+ {
105
+ "name" : _ ("Chained swap" ) + ": " + self .name ,
106
+ "type" : "ir.actions.act_window" ,
107
+ "res_model" : "chained.swapper.wizard" ,
108
+ "src_model" : self .model_id .model ,
109
+ "groups_id" : [(4 , x .id ) for x in self .group_ids ],
110
+ "view_type" : "form" ,
111
+ "context" : "{'chained_swapper_id': %d}" % (self .id ),
112
+ "view_mode" : "form" ,
113
+ "target" : "new" ,
114
+ "binding_model_id" : self .model_id .id ,
115
+ "binding_type" : "action" ,
116
+ }
117
+ )
118
+ self .write ({"ref_ir_act_window_id" : action .id })
117
119
return True
118
120
119
121
@api .multi
120
122
def unlink_action (self ):
121
- self .mapped (' ref_ir_act_window_id' ).unlink ()
123
+ self .mapped (" ref_ir_act_window_id" ).unlink ()
122
124
return True
123
125
124
126
@@ -127,59 +129,61 @@ class ChainedSwapperSubField(models.Model):
127
129
_description = "Chained Swapper Sub-field"
128
130
129
131
chained_swapper_id = fields .Many2one (
130
- comodel_name = ' chained.swapper' , ondelete = "cascade"
132
+ comodel_name = " chained.swapper" , ondelete = "cascade"
131
133
)
132
134
sub_field_chain = fields .Char (
133
135
required = True ,
134
136
help = "You can specify here a field of related fields as "
135
- "dotted names. Ex.: 'child_ids.lang'."
137
+ "dotted names. Ex.: 'child_ids.lang'." ,
136
138
)
137
139
138
- @api .constrains (' chained_swapper_id' , ' sub_field_chain' )
140
+ @api .constrains (" chained_swapper_id" , " sub_field_chain" )
139
141
def _check_sub_field_chain (self ):
140
142
for rec in self :
141
143
# Check sub-field exist
142
144
try :
143
- chain_list = rec .sub_field_chain .split ('.' )
145
+ chain_list = rec .sub_field_chain .split ("." )
144
146
chain_field_name = chain_list .pop ()
145
147
chain_model = self .env [rec .chained_swapper_id .model_id .model ]
146
148
for name in chain_list :
147
149
chain_model = chain_model [name ]
148
150
chain_model [chain_field_name ] # pylint: disable=W0104
149
151
except KeyError :
150
152
raise exceptions .ValidationError (
151
- _ ("Incorrect sub-field expression:" ) + " " +
152
- rec . sub_field_chain )
153
+ _ ("Incorrect sub-field expression:" ) + " " + rec . sub_field_chain
154
+ )
153
155
# Check sub-field and original field are the same type
154
156
swap_field = rec .chained_swapper_id .field_id
155
- chain_field = self .env ['ir.model.fields' ].search ([
156
- ('model_id' , '=' , rec .chained_swapper_id .model_id .id ),
157
- ('name' , '=' , chain_field_name ),
158
- ])
159
- if (chain_field .ttype != swap_field .ttype or
160
- chain_field .relation != swap_field .relation ):
157
+ chain_field = self .env ["ir.model.fields" ].search (
158
+ [
159
+ ("model_id" , "=" , rec .chained_swapper_id .model_id .id ),
160
+ ("name" , "=" , chain_field_name ),
161
+ ]
162
+ )
163
+ if (
164
+ chain_field .ttype != swap_field .ttype
165
+ or chain_field .relation != swap_field .relation
166
+ ):
161
167
raise exceptions .ValidationError (
162
- _ ("The sub-field '%s' is not compatible with the main"
163
- " field." ) % rec .sub_field_chain )
168
+ _ ("The sub-field '%s' is not compatible with the main" " field." )
169
+ % rec .sub_field_chain
170
+ )
164
171
165
172
166
173
class ChainedSwapperConstraint (models .Model ):
167
174
_name = "chained.swapper.constraint"
168
175
_description = "Chained Swapper Constraint"
169
176
170
177
chained_swapper_id = fields .Many2one (
171
- comodel_name = 'chained.swapper' , ondelete = "cascade"
172
- )
173
- name = fields .Char (
174
- required = True ,
175
- translate = True ,
178
+ comodel_name = "chained.swapper" , ondelete = "cascade"
176
179
)
180
+ name = fields .Char (required = True , translate = True ,)
177
181
expression = fields .Text (
178
- string = ' Constraint expression' ,
182
+ string = " Constraint expression" ,
179
183
required = True ,
180
184
help = "Boolean python expression. You can use the keyword "
181
- "'records' as the records selected to execute the "
182
- "contextual action. Ex.: bool(records.mapped('parent_id'))" ,
185
+ "'records' as the records selected to execute the "
186
+ "contextual action. Ex.: bool(records.mapped('parent_id'))" ,
183
187
default = "True" ,
184
188
)
185
189
@@ -188,8 +192,8 @@ def _check_expression(self):
188
192
for record in self :
189
193
model = self .env [record .chained_swapper_id .model_id .model ]
190
194
try :
191
- safe_eval (record .expression , {' records' : model })
195
+ safe_eval (record .expression , {" records" : model })
192
196
except Exception :
193
- raise exceptions .ValidationError (_ (
194
- "Invalid constraint expression:" + " " + record .expression
195
- ))
197
+ raise exceptions .ValidationError (
198
+ _ ( "Invalid constraint expression:" + " " + record .expression )
199
+ )
0 commit comments