-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrss.xml
More file actions
236 lines (236 loc) · 51 KB
/
rss.xml
File metadata and controls
236 lines (236 loc) · 51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Odoo Open Treasures</title><link>http://blog.odooist.com/</link><description>Odoo discovered secrets</description><atom:link href="http://blog.odooist.com/rss.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2021 <a href="mailto:odooist@gmail.com">Odooist</a> </copyright><lastBuildDate>Fri, 05 Mar 2021 07:17:55 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Detect upgrade procedure</title><link>http://blog.odooist.com/posts/detect-upgrade-procedure/</link><dc:creator>Odooist</dc:creator><description><div><p>In Odoo it is possible to define model records in XML data files.</p>
<p>During module upgrade procedure Odoo reads XML datafiles and updates database records defined there.</p>
<p>But what if we need to have a conditional update? So that we do not update the records if
some condition is not met.</p>
<p>To have this done we need to redefine <em>write</em> method for the model and put there the following:</p>
<pre class="code python"><a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-1"></a><span class="k">def</span> <span class="nf">write</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">vals</span><span class="p">):</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-2"></a> <span class="k">for</span> <span class="n">rec</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-3"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'install_mode'</span><span class="p">)</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-4"></a> <span class="s1">'module'</span><span class="p">)</span> <span class="o">==</span> <span class="s1">'your_module_name'</span><span class="p">:</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-5"></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'We are in upgrade procedure!'</span><span class="p">)</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-6"></a> <span class="c1"># Check a condition</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-7"></a> <span class="k">if</span> <span class="kc">False</span><span class="p">:</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-8"></a> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Ignoring updated record.'</span><span class="p">)</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-9"></a> <span class="k">else</span><span class="p">:</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-10"></a> <span class="nb">super</span><span class="p">(</span><span class="n">MyCustomModel</span><span class="p">,</span> <span class="n">rec</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">vals</span><span class="p">)</span>
<a name="rest_code_3a20fca625c74136bd6cd83b2fc66b0f-11"></a> <span class="k">return</span> <span class="kc">True</span>
</pre></div></description><category>upgrade</category><category>xml</category><guid>http://blog.odooist.com/posts/detect-upgrade-procedure/</guid><pubDate>Sun, 10 Jan 2021 12:00:27 GMT</pubDate></item><item><title>How to set language for controller</title><link>http://blog.odooist.com/posts/how-to-set-language-for-controller/</link><dc:creator>Odooist</dc:creator><description><div><p>Imagine that you have a signup procedure, like this:</p>
<pre class="code python"><a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-1"></a><span class="k">class</span> <span class="nc">MobileAppBaseController</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">Controller</span><span class="p">):</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-2"></a> <span class="nd">@http.route</span><span class="p">(</span><span class="s1">'/barrier/verify_user/1'</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s1">'json'</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="s1">'public'</span><span class="p">,</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-3"></a> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">],</span> <span class="n">csrf</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-4"></a> <span class="k">def</span> <span class="nf">verify_user_step_1</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-5"></a> <span class="n">user_name</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">jsonrequest</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'username'</span><span class="p">)</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-6"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">user_name</span><span class="p">:</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-7"></a> <span class="k">return</span> <span class="p">{</span><span class="s1">'status'</span><span class="p">:</span> <span class="bp">False</span><span class="p">,</span> <span class="s1">'msg'</span><span class="p">:</span> <span class="n">_</span><span class="p">(</span><span class="s1">'User name not sent.'</span><span class="p">)}</span>
<a name="rest_code_dffdd4b638c9456d89b1c0f7dbd61622-8"></a> <span class="o">...</span>
</pre><p>When user name is not specified in JSON request it returns 'User name not sent' message.</p>
<p>Now we want this message to be returned in different languages.</p>
<p>After learning fron <em>odoo/tools/translation.py</em> and <em>odoo/http.py</em> two solutions where found.</p>
<div class="section" id="language-selection-by-client">
<h2>1. Language selection by client</h2>
<p>To request messages translated into specified language Accept-Language header is used:</p>
<pre class="code sh"><a name="rest_code_a81d41ce1073403aa20d236c1e7ecc7a-1"></a>http -vv --json <span class="s1">'http://127.0.0.1:38069/barrier/verify_user/1'</span> <span class="s2">"_username=user"</span> <span class="s1">'Accept-Language:ru'</span>
</pre><p>Result:</p>
<pre class="code sh"><a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-1"></a>odooist@MacBook-Pro app % http -v --json <span class="s1">'http://127.0.0.1:38069/barrier/verify_user/1'</span> <span class="s2">"_username=user"</span> <span class="s1">'Accept-Language:ru'</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-2"></a>POST /barrier/verify_user/1 HTTP/1.1
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-3"></a>Accept: application/json, */*
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-4"></a>Accept-Encoding: gzip, deflate
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-5"></a>Accept-Language: ru
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-6"></a>Connection: keep-alive
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-7"></a>Content-Length: <span class="m">21</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-8"></a>Content-Type: application/json
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-9"></a>Host: <span class="m">127</span>.0.0.1:38069
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-10"></a>User-Agent: HTTPie/1.0.3
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-11"></a>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-12"></a> <span class="o">{</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-13"></a> <span class="s2">"_username"</span>: <span class="s2">"user"</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-14"></a> <span class="o">}</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-15"></a>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-16"></a>HTTP/1.0 <span class="m">200</span> OK
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-17"></a>Content-Length: <span class="m">224</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-18"></a>Content-Type: application/json
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-19"></a>Date: Sat, <span class="m">28</span> Dec <span class="m">2019</span> <span class="m">11</span>:33:49 GMT
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-20"></a>Server: Werkzeug/0.16.0 Python/3.5.3
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-21"></a>Set-Cookie: <span class="nv">session_id</span><span class="o">=</span>7b62bc401c248052e8a0ffb7626b7122340f774a<span class="p">;</span> <span class="nv">Expires</span><span class="o">=</span>Fri, <span class="m">27</span>-Mar-2020 <span class="m">11</span>:33:49 GMT<span class="p">;</span> Max-Age<span class="o">=</span><span class="m">7776000</span><span class="p">;</span> HttpOnly<span class="p">;</span> <span class="nv">Path</span><span class="o">=</span>/
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-22"></a>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-23"></a><span class="o">{</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-24"></a> <span class="s2">"id"</span>: null,
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-25"></a> <span class="s2">"jsonrpc"</span>: <span class="s2">"2.0"</span>,
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-26"></a> <span class="s2">"result"</span>: <span class="o">{</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-27"></a> <span class="s2">"msg"</span>: <span class="s2">"Имя пользователя не отослано."</span>,
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-28"></a> <span class="s2">"status"</span>: <span class="nb">false</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-29"></a> <span class="o">}</span>
<a name="rest_code_c98b04c3539245a98816f9a10ddb8c4d-30"></a><span class="o">}</span>
</pre><p>As you can see in request headers Accept-Language is set to <em>ru</em>, and in result we got msg translated.</p>
</div>
<div class="section" id="define-response-language-at-server">
<h2>2. Define response language at server</h2>
<p>In <em>odoo/tools/translation.py</em> interesting code was found:</p>
<pre class="code python"><a name="rest_code_43bbe7e098114a0599efe7a694f44c68-1"></a><span class="k">def</span> <span class="nf">_get_lang</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">frame</span><span class="p">):</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-2"></a> <span class="c1"># try, in order: context.get('lang'), kwargs['context'].get('lang'),</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-3"></a> <span class="c1"># self.env.lang, self.localcontext.get('lang'), request.env.lang</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-4"></a> <span class="n">lang</span> <span class="o">=</span> <span class="bp">None</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-5"></a> <span class="k">if</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_locals</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'context'</span><span class="p">):</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-6"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_locals</span><span class="p">[</span><span class="s1">'context'</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'lang'</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-7"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-8"></a> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_locals</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'kwargs'</span><span class="p">,</span> <span class="p">{})</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-9"></a> <span class="k">if</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'context'</span><span class="p">):</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-10"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s1">'context'</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'lang'</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-11"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-12"></a> <span class="n">s</span> <span class="o">=</span> <span class="n">frame</span><span class="o">.</span><span class="n">f_locals</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'self'</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-13"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s1">'env'</span><span class="p">):</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-14"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">lang</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-15"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-16"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s1">'localcontext'</span><span class="p">):</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-17"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">localcontext</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'lang'</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-18"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-19"></a> <span class="k">try</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-20"></a> <span class="kn">from</span> <span class="nn">odoo.http</span> <span class="kn">import</span> <span class="n">request</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-21"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">lang</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-22"></a> <span class="k">except</span> <span class="ne">RuntimeError</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-23"></a> <span class="k">pass</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-24"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-25"></a> <span class="c1"># Last resort: attempt to guess the language of the user</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-26"></a> <span class="c1"># Pitfall: some operations are performed in sudo mode, and we</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-27"></a> <span class="c1"># don't know the original uid, so the language may</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-28"></a> <span class="c1"># be wrong when the admin language differs.</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-29"></a> <span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">dummy</span><span class="p">)</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_cr</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">allow_create</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-30"></a> <span class="n">uid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_uid</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-31"></a> <span class="k">if</span> <span class="n">cr</span> <span class="ow">and</span> <span class="n">uid</span><span class="p">:</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-32"></a> <span class="n">env</span> <span class="o">=</span> <span class="n">odoo</span><span class="o">.</span><span class="n">api</span><span class="o">.</span><span class="n">Environment</span><span class="p">(</span><span class="n">cr</span><span class="p">,</span> <span class="n">uid</span><span class="p">,</span> <span class="p">{})</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-33"></a> <span class="n">lang</span> <span class="o">=</span> <span class="n">env</span><span class="p">[</span><span class="s1">'res.users'</span><span class="p">]</span><span class="o">.</span><span class="n">context_get</span><span class="p">()[</span><span class="s1">'lang'</span><span class="p">]</span>
<a name="rest_code_43bbe7e098114a0599efe7a694f44c68-34"></a> <span class="k">return</span> <span class="n">lang</span>
</pre><p>So to define server response language we had to put a context dictionary on a
function level like this (line 5):</p>
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre><a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-1">1</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-2">2</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-3">3</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-4">4</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-5">5</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-6">6</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-7">7</a>
<a href="http://blog.odooist.com/posts/how-to-set-language-for-controller/#rest_code_173df031def64d8097e798c573744558-8">8</a></pre></div></td><td class="code"><pre class="code python"><a name="rest_code_173df031def64d8097e798c573744558-1"></a> <span class="k">class</span> <span class="nc">MobileAppBaseController</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">Controller</span><span class="p">):</span>
<a name="rest_code_173df031def64d8097e798c573744558-2"></a> <span class="nd">@http.route</span><span class="p">(</span><span class="s1">'/barrier/verify_user/1'</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s1">'json'</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="s1">'public'</span><span class="p">,</span>
<a name="rest_code_173df031def64d8097e798c573744558-3"></a> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s1">'POST'</span><span class="p">],</span> <span class="n">csrf</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<a name="rest_code_173df031def64d8097e798c573744558-4"></a> <span class="k">def</span> <span class="nf">verify_user_step_1</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<a name="rest_code_173df031def64d8097e798c573744558-5"></a> <span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'language'</span><span class="p">:</span> <span class="s1">'ru_RU'</span><span class="p">}</span>
<a name="rest_code_173df031def64d8097e798c573744558-6"></a> <span class="n">user_name</span> <span class="o">=</span> <span class="n">http</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">jsonrequest</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'username'</span><span class="p">)</span>
<a name="rest_code_173df031def64d8097e798c573744558-7"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">user_name</span><span class="p">:</span>
<a name="rest_code_173df031def64d8097e798c573744558-8"></a> <span class="k">return</span> <span class="p">{</span><span class="s1">'status'</span><span class="p">:</span> <span class="bp">False</span><span class="p">,</span> <span class="s1">'msg'</span><span class="p">:</span> <span class="n">_</span><span class="p">(</span><span class="s1">'User name not sent.'</span><span class="p">)}</span>
</pre></td></tr></table><p><strong>Notice</strong> that in the first case we added <em>Accept-Language: ru</em>, but in the second one we
set language to <em>ru_RU</em>.</p>
</div></div></description><category>controller</category><category>i18n</category><guid>http://blog.odooist.com/posts/how-to-set-language-for-controller/</guid><pubDate>Sat, 28 Dec 2019 11:25:16 GMT</pubDate></item><item><title>Working with Savepoint</title><link>http://blog.odooist.com/posts/working-with-savepoint/</link><dc:creator>Odooist</dc:creator><description><div><p>Here I'll write about Odoo transactions.</p>
<p>It's a general recommendation to let Odoo manage transactions and Odoo does it
quite well.</p>
<p>By default a new transaction is opened on every HTTP request thus covering the whole bunch of
operations the method executed.</p>
<p>If an exception happends during any method execution the whole transation is
rolled back and error is returned.</p>
<p>But sometimes we need to keep some amount of work done in the middle of request and if the rest of the request fails we are saved.</p>
<p>This is done by using <code class="docutils literal">self.env.cr.commit()</code> call.</p>
<div class="section" id="savepoint">
<h2>Savepoint</h2>
<p>Savepoint defines a new saving point in current transation. So when an error occurs the transation
is rolled back to that point.</p>
<p>If no error happens <code class="docutils literal">RELEASE SAVEPOINT</code> is called to keep the effects of commands
executed after the savepoint was established.</p>
<p>Here is the code snippet from <code class="docutils literal">odoo/sql_db.py</code>:</p>
<pre class="code python"><a name="rest_code_50ec7c82153a443f91a175e329d6d67a-1"></a><span class="nd">@contextmanager</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-2"></a><span class="nd">@check</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-3"></a><span class="k">def</span> <span class="nf">savepoint</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">flush</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-4"></a> <span class="sd">"""context manager entering in a new savepoint"""</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-5"></a> <span class="n">name</span> <span class="o">=</span> <span class="n">uuid</span><span class="o">.</span><span class="n">uuid1</span><span class="p">()</span><span class="o">.</span><span class="n">hex</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-6"></a> <span class="k">if</span> <span class="n">flush</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-7"></a> <span class="n">flush_env</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-8"></a> <span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">'SAVEPOINT "</span><span class="si">%s</span><span class="s1">"'</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-9"></a> <span class="k">try</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-10"></a> <span class="k">yield</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-11"></a> <span class="k">if</span> <span class="n">flush</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-12"></a> <span class="n">flush_env</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-13"></a> <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-14"></a> <span class="k">if</span> <span class="n">flush</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-15"></a> <span class="n">clear_env</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-16"></a> <span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">'ROLLBACK TO SAVEPOINT "</span><span class="si">%s</span><span class="s1">"'</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-17"></a> <span class="k">raise</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-18"></a> <span class="k">else</span><span class="p">:</span>
<a name="rest_code_50ec7c82153a443f91a175e329d6d67a-19"></a> <span class="bp">self</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s1">'RELEASE SAVEPOINT "</span><span class="si">%s</span><span class="s1">"'</span> <span class="o">%</span> <span class="n">name</span><span class="p">)</span>
</pre></div></div></description><guid>http://blog.odooist.com/posts/working-with-savepoint/</guid><pubDate>Thu, 21 Nov 2019 07:35:18 GMT</pubDate></item><item><title>Form's initial mode</title><link>http://blog.odooist.com/posts/forms-initial-mode/</link><dc:creator>Odooist</dc:creator><description><div><p>When you click on a tree view row a form view is opened and this form is opened
in read mode.</p>
<p>When you click the <code class="docutils literal">Create</code> button from a tree view, a new record form view is opened
in edit mode (how otherwise? :-)</p>
<p>But sometimes it's more usable to immediately open an existing record in edit mode.</p>
<p>This can be done using <code class="docutils literal">form</code> option <code class="docutils literal">initial_mode</code>.</p>
<p>In different Odoo versions this can be done in different ways:</p>
<div class="section" id="id1">
<h2>10.0</h2>
<p>In this version it can work in form declaration
(by chance as <a class="reference external" href="https://github.com/odoo/odoo/issues/22353">developers say</a>)
like in the following example:</p>
<pre class="code xml"><a name="rest_code_a48725e744924159998d37254391b81a-1"></a><span class="nt">&lt;form</span> <span class="na">options=</span><span class="s">"{'initial_mode': 'edit'}"</span><span class="nt">&gt;</span>
</pre><p>If transition from tree to form is done within python code:</p>
<pre class="code python"><a name="rest_code_b679e242d91d4c50880042a2c02bc972-1"></a><span class="k">return</span> <span class="p">{</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-2"></a> <span class="s1">'name'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-3"></a> <span class="s1">'help'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">help</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-4"></a> <span class="s1">'type'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">type</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-5"></a> <span class="s1">'views'</span><span class="p">:</span> <span class="p">[(</span><span class="n">form_id</span><span class="p">,</span> <span class="s1">'form'</span><span class="p">)],</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-6"></a> <span class="s1">'view_mode'</span><span class="p">:</span> <span class="s1">'action.view_mode'</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-7"></a> <span class="s1">'target'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">target</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-8"></a> <span class="s1">'context'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">context</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-9"></a> <span class="s1">'res_model'</span><span class="p">:</span> <span class="n">action</span><span class="o">.</span><span class="n">res_model</span><span class="p">,</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-10"></a> <span class="s1">'flags'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'initial_mode'</span><span class="p">:</span> <span class="s1">'edit'</span><span class="p">},</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-11"></a> <span class="s1">'res_id'</span><span class="p">:</span> <span class="n">record</span><span class="o">.</span><span class="n">id</span>
<a name="rest_code_b679e242d91d4c50880042a2c02bc972-12"></a><span class="p">}</span>
</pre><div class="section" id="id2">
<h3>11.0, 12.0, ...</h3>
<p>Next Odoo versions "fix" the above and now you should use <code class="docutils literal">context</code>:</p>
<pre class="code python"><a name="rest_code_506b10388df8463db4a62163394a2f51-1"></a><span class="n">context</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">context</span><span class="p">)</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-2"></a><span class="n">context</span><span class="p">[</span><span class="s1">'form_view_initial_mode'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'edit'</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-3"></a><span class="k">return</span> <span class="p">{</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-4"></a> <span class="s1">'type'</span><span class="p">:</span> <span class="s1">'ir.actions.act_window'</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-5"></a> <span class="s1">'view_type'</span><span class="p">:</span> <span class="s1">'form'</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-6"></a> <span class="s1">'view_mode'</span><span class="p">:</span> <span class="s1">'form'</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-7"></a> <span class="s1">'res_model'</span><span class="p">:</span> <span class="s1">'your.model'</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-8"></a> <span class="s1">'res_id'</span><span class="p">:</span> <span class="n">your_object_id</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-9"></a> <span class="s1">'context'</span><span class="p">:</span> <span class="n">context</span><span class="p">,</span>
<a name="rest_code_506b10388df8463db4a62163394a2f51-10"></a><span class="p">}</span>
</pre><p><span class="emoji">🙈</span></p>
</div>
</div></div></description><category>views</category><guid>http://blog.odooist.com/posts/forms-initial-mode/</guid><pubDate>Sat, 16 Nov 2019 03:21:21 GMT</pubDate></item><item><title>New xpath element named "move"</title><link>http://blog.odooist.com/posts/new-xpath-element-named-move/</link><dc:creator>Odooist</dc:creator><description><div><p>The position='move' has been introduced to move an element in an inherited
view.</p>
<p>It's used as</p>
<pre class="code xml"><a name="rest_code_c6277706fb6c4e20beeacfed7c97ea35-1"></a><span class="nt">&lt;xpath</span> <span class="na">expr=</span><span class="s">"//@target"</span> <span class="na">position=</span><span class="s">"after"</span><span class="nt">&gt;</span>
<a name="rest_code_c6277706fb6c4e20beeacfed7c97ea35-2"></a> <span class="nt">&lt;xpath</span> <span class="na">expr=</span><span class="s">"//@node"</span> <span class="na">position=</span><span class="s">"move"</span><span class="nt">/&gt;</span>
<a name="rest_code_c6277706fb6c4e20beeacfed7c97ea35-3"></a><span class="nt">&lt;/xpath&gt;</span>
</pre><p>Or also:</p>
<pre class="code xml"><a name="rest_code_df4c01ad88744672b049b26160be4835-1"></a><span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"target_field"</span> <span class="na">position=</span><span class="s">"after"</span><span class="nt">&gt;</span>
<a name="rest_code_df4c01ad88744672b049b26160be4835-2"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"my_field"</span> <span class="na">position=</span><span class="s">"move"</span><span class="nt">/&gt;</span>
<a name="rest_code_df4c01ad88744672b049b26160be4835-3"></a><span class="nt">&lt;/field&gt;</span>
</pre><p>In the above example <code class="docutils literal">my_field</code> is placed <em>after</em> <code class="docutils literal">target_field</code> in the parent form.</p>
<p>So now we can inherit and have the ability to manipulate fields order in views, not only add
new fields.</p></div></description><category>12.0</category><category>inherit</category><category>views</category><category>xml</category><guid>http://blog.odooist.com/posts/new-xpath-element-named-move/</guid><pubDate>Fri, 15 Nov 2019 13:37:56 GMT</pubDate></item><item><title>Hiding entire tree column with column_invisible</title><link>http://blog.odooist.com/posts/hiding-entire-tree-column-with-column_invisible/</link><dc:creator>Odooist</dc:creator><description><div><p>We all know a way to hide a field in tree &amp; form views using <code class="docutils literal"><span class="pre">attrs={'invisible':</span> <span class="pre">[(...)]}</span></code>.</p>
<p>We also know that we can hide <strong>entire column</strong> using <code class="docutils literal"><span class="pre">invisible="1"</span></code> attribute like this:</p>
<pre class="code xml"><a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-1"></a><span class="nt">&lt;tree</span> <span class="na">decoration-warning=</span><span class="s">"event_input_mode == True"</span><span class="nt">&gt;</span>
<a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-2"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"event_input_mode"</span> <span class="na">invisible=</span><span class="s">"1"</span><span class="nt">/&gt;</span>
<a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-3"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"description"</span><span class="nt">/&gt;</span>
<a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-4"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"facility"</span> <span class="na">invisible=</span><span class="s">"context.get('hide_facility')"</span><span class="nt">/&gt;</span>
<a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-5"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"uid"</span><span class="nt">/&gt;</span>
<a name="rest_code_ee345fe991a84a3482fdd2720fea7e2a-6"></a><span class="nt">&lt;/tree&gt;</span>
</pre><p>In the above example we need <code class="docutils literal">event_input_mode</code> column just to highlight a row if
it have <code class="docutils literal">event_input_mode</code> set so we hide it with <code class="docutils literal"><span class="pre">invisible="1"</span></code>.</p>
<p>We can also notice that we can use <code class="docutils literal">context</code> values in condition expression.
In the above example if <code class="docutils literal">context</code> has <code class="docutils literal">hide_facility</code> key then entire column is hidden.</p>
<div class="section" id="the-treasure">
<h2>The treasure</h2>
<p>But what if you need to hide entire column by a condition coming from complex business
logic implemented in Python?</p>
<p>Here <strong>column_invisible</strong> attribute comes!</p>
<p>See this examples:</p>
<pre class="code xml"><a name="rest_code_587fb9f953b8427fa3a2fc1a1d9bca7b-1"></a><span class="nt">&lt;tree&gt;</span>
<a name="rest_code_587fb9f953b8427fa3a2fc1a1d9bca7b-2"></a> ...
<a name="rest_code_587fb9f953b8427fa3a2fc1a1d9bca7b-3"></a> <span class="nt">&lt;field</span> <span class="na">name=</span><span class="s">"foo"</span> <span class="na">attrs=</span><span class="s">"{'column_invisible': [('parent.product_id', '!=', False)]}"</span><span class="nt">/&gt;</span>
<a name="rest_code_587fb9f953b8427fa3a2fc1a1d9bca7b-4"></a> ...
<a name="rest_code_587fb9f953b8427fa3a2fc1a1d9bca7b-5"></a><span class="nt">&lt;/tree&gt;</span>
</pre><p>By digging the source code I can see <code class="docutils literal">column_invisible</code> was introduced in Odoo 11.0.</p>
<p>Nice, but works <strong>only</strong> for <code class="docutils literal">many2one</code> and <code class="docutils literal">one2many</code> fields :-)</p>
</div></div></description><category>11.0</category><category>12.0</category><category>views</category><guid>http://blog.odooist.com/posts/hiding-entire-tree-column-with-column_invisible/</guid><pubDate>Fri, 15 Nov 2019 11:15:55 GMT</pubDate></item></channel></rss>