[FIX] Report should not have name None.pdf.
[odoo/odoo.git] / doc / addons.rst
1 Developing OpenERP Web Addons
2 =============================
3
4 An OpenERP Web addon is simply a Python package with an openerp
5 descriptor (a ``__openerp__.py`` file) which follows a few structural
6 and namespacing rules.
7
8 Structure
9 ---------
10
11 .. literalinclude:: addon-structure.txt
12
13 ``__openerp__.py``
14   The addon's descriptor, contains the following information:
15
16   ``name: str``
17     The addon name, in plain, readable english
18   ``version: str``
19     The addon version, following `Semantic Versioning`_ rules
20   ``depends: [str]``
21     A list of addons this addon needs to work correctly. ``base`` is
22     an implied dependency if the list is empty.
23   ``css: [str]``
24     An ordered list of CSS files this addon provides and needs. The
25     file paths are relative to the addon's root. Because the Web
26     Client *may* perform concatenations and other various
27     optimizations on CSS files, the order is important.
28   ``js: [str]``
29     An ordered list of Javascript files this addon provides and needs
30     (including dependencies files). As with CSS files, the order is
31     important as the Web Client *may* perform contatenations and
32     minimizations of files.
33   ``active: bool``
34     Whether this addon should be enabled by default any time it is
35     found, or whether it will be enabled through other means (on a
36     by-need or by-installation basis for instance).
37
38 ``controllers/``
39   All of the Python controllers and JSON-RPC endpoints.
40
41 ``static/``
42   The static files directory, may be served via a separate web server.
43
44 ``static/lib/``
45   Third-party libraries used by the addon.
46
47 ``static/src/{css,js,img,xml}``
48   Location for (respectively) the addon's static CSS files, its JS
49   files, its various image resources as well as the template files
50
51 ``static/test``
52   Javascript tests files
53
54 ``test/``
55   The directories in which all tests for the addon are located.
56
57 Some of these are guidelines (and not enforced by code), but it's
58 suggested that these be followed. Code which does not fit into these
59 categories can go wherever deemed suitable.
60
61 Namespacing
62 -----------
63
64 Python
65 ++++++
66
67 Because addons are also Python packages, they're inherently namespaced
68 and nothing special needs to be done on that front.
69
70 JavaScript
71 ++++++++++
72
73 The JavaScript side of an addon has to live in the namespace
74 ``openerp.$addon_name``. For instance, everything created by the addon
75 ``base`` lives in ``openerp.base``.
76
77 The root namespace of the addon is a function which takes a single
78 parameter ``openerp``, which is an OpenERP client instance. Objects
79 (as well as functions, registry instances, etc...) should be added on
80 the correct namespace on that object.
81
82 The root function will be called by the OpenERP Web client when
83 initializing the addon.
84
85 .. code-block:: javascript
86
87     // root namespace of the openerp.example addon
88     /** @namespace */
89     openerp.example = function (openerp) {
90         // basic initialization code (e.g. templates loading)
91         openerp.example.SomeClass = openerp.base.Class.extend(
92             /** @lends openerp.example.SomeClass# */{
93             /**
94              * Description for SomeClass's constructor here
95              *
96              * @constructs
97              */
98             init: function () {
99                 // SomeClass initialization code
100             }
101             // rest of SomeClass
102         });
103
104         // access an object in an other addon namespace to replace it
105         openerp.base.SearchView = openerp.base.SearchView.extend({
106             init: function () {
107                 this._super.apply(this, arguments);
108                 console.log('Search view initialized');
109             }
110         });
111     }
112
113 Creating new standard roles
114 ---------------------------
115
116 Views
117 +++++
118
119 Views are the standard high-level component in OpenERP. A view type corresponds
120 to a way to display a set of data (coming from an OpenERP model).
121
122 In OpenERP Web, views are standard objects registered against a dedicated
123 object registry, so the :js:class:`~openerp.base.ViewManager` knows where to
124 find and how to call them.
125
126 Although not mandatory, it is recommended that views inherit from
127 :js:class:`openerp.base.View`, which provides a view useful services to its
128 children.
129
130 Registering a view
131 ~~~~~~~~~~~~~~~~~~
132
133 This is the first task to perform when creating a view, and the simplest by
134 far: simply call ``openerp.base.views.add(name, object_path)`` to register
135 the object of path ``object_path`` as the view for the view name ``name``.
136
137 The view name is the name you gave to your new view in the OpenERP server.
138
139 From that point onwards, OpenERP Web will be able to find your object and
140 instantiate it.
141
142 Standard view behaviors
143 ~~~~~~~~~~~~~~~~~~~~~~~
144
145 In the normal OpenERP Web flow, views have to implement a number of methods so
146 view managers can correctly communicate with them:
147
148 ``start()``
149     This method will always be called after creating the view (via its
150     constructor), but not necessarily immediately.
151
152     It is called with no arguments and should handle the heavy setup work,
153     including remote call (to load the view's setup data from the server via
154     e.g. ``fields_view_get``, for instance).
155
156     ``start`` should return a `promise object`_ which *must* be resolved when
157     the view's setup is completed. This promise is used by view managers to
158     know when they can start interacting with the view.
159
160 ``do_hide()``
161     Called by the view manager when it wants to replace this view by an other
162     one, but wants to keep this view around to re-activate it later.
163
164     Should put the view in some sort of hibernation mode, and *must* hide its
165     DOM elements.
166
167 ``do_show()``
168     Called when the view manager wants to re-display the view after having
169     hidden it. The view should refresh its data display upon receiving this
170     notification
171
172 ``do_search(domain: Array, context: Object, group_by: Array)``
173     If the view is searchable, this method is called to notify it of a search
174     against it.
175
176     It should use the provided query data to perform a search and refresh its
177     internal content (and display).
178
179     All views are searchable by default, but they can be made non-searchable
180     by setting the property ``searchable`` to ``false``.
181
182     This can be done either on the view class itself (at the same level as
183     defining e.g. the ``start`` method) or at the instance level (in the
184     class's ``init``), though you should generally set it on the class.
185
186 Frequent development tasks
187 --------------------------
188
189 There are a number of tasks which OpenERP Web developers do or will need to
190 perform quite regularly. To make these easier, we have written a few guides
191 to help you get started:
192
193 .. toctree::
194     :maxdepth: 1
195
196     guides/client-action
197     guides/sidebar-protocol
198
199 Translations
200 ------------
201
202 OpenERP Web should provide most of the tools needed to correctly translate your
203 addons via the tool of your choice (OpenERP itself uses `Launchpad's own
204 translation tool`_.
205
206 Making strings translatable
207 +++++++++++++++++++++++++++
208
209 QWeb
210 ~~~~
211
212 QWeb automatically marks all text nodes (any text which is not in an XML
213 attribute and not part of an XML tag) as translatable, and handles the
214 replacement for you. There is nothing special to do to mark template text as
215 translatable
216
217 JavaScript
218 ~~~~~~~~~~
219
220 OpenERP Web provides two functions to translate human-readable strings in
221 javascript code. These functions should be "imported" in your module by
222 aliasing them to their bare name:
223
224 .. code-block:: javascript
225
226     var _t = openerp.web._t,
227        _tl = openerp.web._tl;
228
229 importing those functions under any other name is not guaranteed to work.
230
231 .. note:: only import them if necessary, and only the necessary one(s), no need
232           to clutter your module's namespace for nothing
233
234 .. js:function:: openerp.web._t(s)
235
236     Base translation function, eager, works much like :manpage:`gettext(3)`
237
238     :type s: String
239     :rtype: String
240
241 .. js:function:: openerp.web._lt(s)
242
243     Lazy equivalent to :js:func:`~openerp.web._t`, this function will postpone
244     fetching the translation to its argument until the last possible moment.
245
246     To use in contexts evaluated before the translation database can be
247     fetched, usually your module's toplevel and the attributes of classes
248     defined in it (class attributes, not instance attributes set in the
249     constructor).
250
251     :type s: String
252     :rtype: LazyString
253
254 Text formatting & translations
255 """"""""""""""""""""""""""""""
256
257 A difficulty when translating is integrating data (from the code) into the
258 translated string. In OpenERP Web addons, this should be done by wrapping the
259 text to translate in an :manpage:`sprintf(3)` call. For OpenERP Web,
260 :manpage:`sprintf(3)` is provided by `underscore.string
261 <http://epeli.github.com/underscore.string/>`_.
262
263 As much as possible, you should use the "named argument" form of sprintf:
264
265 .. code-block:: javascript
266
267     var translated_string = _.str.sprintf(
268         _t("[%(first_record)d to %(last_record)d] of %(records_count)d"), {
269             first_record: first + 1,
270             last_record: last,
271             records_count: total
272         }));
273
274 named arguments make the string to translate much clearer for translators, and
275 allows them to "move" sections around based on the requirements of their
276 language (not all language order text like english).
277
278 Named arguments are specified using the following pattern: ``%($name)$type``
279 where
280
281 ``$name``
282   the name of the argument, this is the key in the object/dictionary provided
283   as second parameter to ``sprintf``
284 ``$type``
285   a type/format specifier, `see the list for all possible types
286   <http://www.diveintojavascript.com/projects/javascript-sprintf>`_.
287
288 .. note:: positional arguments are acceptable if the translated string has
289           *a single* argument and its content is easy to guess from the text
290           around it. Named arguments should still be preferred.
291
292 .. warning:: you should *never* use string concatenation as it robs the
293              translator of context and make result in a completely incorrect
294              translation
295
296 Extracting strings
297 ~~~~~~~~~~~~~~~~~~
298
299 .. program:: gen_translations.sh
300
301 Once strings have been marked for translation, they need to be extracted into
302 :abbr:`POT (Portable Object Template)` files, from which most translation tools
303 can build a database.
304
305 This can be done via the provided :program:`gen_translations.sh`.
306
307 It can be called either as :option:`gen_translations.sh -a` or by providing
308 two parameters, a path to the addons and the complete path in which to put the
309 extracted POT file.
310
311 .. option:: -a
312
313     Extracts translations from all standard OpenERP Web addons (addons bundled
314     with OpenERP Web itself) and puts the extracted templates into the right
315     directory for `Rosetta`_ to handle them
316
317 Utility behaviors
318 -----------------
319
320 JavaScript
321 ++++++++++
322
323 * All javascript objects inheriting from
324   :js:class:`openerp.base.BasicConroller` will have all methods
325   starting with ``on_`` or ``do_`` bound to their ``this``. This means
326   they don't have to be manually bound (via ``_.bind`` or ``$.proxy``)
327   in order to be useable as bound event handlers (event handlers
328   keeping their object as ``this`` rather than taking whatever
329   ``this`` object they were called with).
330
331   Beware that this is only valid for methods starting with ``do_`` and
332   ``on_``, any other method will have to be bound manually.
333
334 .. _addons-testing:
335
336 Testing
337 -------
338
339 Python
340 ++++++
341
342 OpenERP Web uses unittest2_ for its testing needs. We selected
343 unittest2 rather than unittest_ for the following reasons:
344
345 * autodiscovery_ (similar to nose, via the ``unit2``
346   CLI utility) and `pluggable test discovery`_.
347
348 * `new and improved assertions`_ (with improvements in type-specific
349   inequality reportings) including `pluggable custom types equality
350   assertions`_
351
352 * neveral new APIs, most notably `assertRaises context manager`_,
353   `cleanup function registration`_, `test skipping`_ and `class- and
354   module-level setup and teardown`_
355
356 * finally, unittest2 is a backport of Python 3's unittest. We might as
357   well get used to it.
358
359 To run tests on addons (from the root directory of OpenERP Web) is as
360 simple as typing ``PYTHONPATH=. unit2 discover -s addons`` [#]_. To
361 test an addon which does not live in the ``addons`` directory, simply
362 replace ``addons`` by the directory in which your own addon lives.
363
364 .. note:: unittest2 is entirely compatible with nose_ (or the
365      other way around). If you want to use nose as your test
366      runner (due to its addons for instance) you can simply install it
367      and run ``nosetests addons`` instead of the ``unit2`` command,
368      the result should be exactly the same.
369
370 Python
371 ++++++
372
373 .. autoclass:: web.common.session.OpenERPSession
374     :members:
375
376 .. autoclass:: web.common.openerplib.main.Model
377     :members:
378
379 * Addons lifecycle (loading, execution, events, ...)
380
381   * Python-side
382   * JS-side
383
384 * Handling static files
385 * Overridding a Python controller (object?)
386 * Overridding a Javascript controller (object?)
387 * Extending templates
388   .. how do you handle deploying static files via e.g. a separate lighttpd?
389 * Python public APIs
390 * QWeb templates description?
391 * OpenERP Web modules (from OpenERP modules)
392
393 .. [#] the ``-s`` parameter tells ``unit2`` to start trying to
394        find tests in the provided directory (here we're testing
395        addons). However a side-effect of that is to set the
396        ``PYTHONPATH`` there as well, so it will fail to find (and
397        import) ``openerpweb``.
398
399        The ``-t`` parameter lets us set the ``PYTHONPATH``
400        independently, but it doesn't accept multiple values and here
401        we really want to have both ``.`` and ``addons`` on the
402        ``PYTHONPATH``.
403
404        The solution is to set the ``PYTHONPATH`` to ``.`` on start,
405        and the ``start-directory`` to ``addons``. This results in a
406        correct ``PYTHONPATH`` within ``unit2``.
407
408 .. _unittest:
409     http://docs.python.org/library/unittest.html
410
411 .. _unittest2:
412     http://www.voidspace.org.uk/python/articles/unittest2.shtml
413
414 .. _autodiscovery:
415     http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-discovery
416
417 .. _pluggable test discovery:
418     http://www.voidspace.org.uk/python/articles/unittest2.shtml#load-tests
419
420 .. _new and improved assertions:
421     http://www.voidspace.org.uk/python/articles/unittest2.shtml#new-assert-methods
422
423 .. _pluggable custom types equality assertions:
424     http://www.voidspace.org.uk/python/articles/unittest2.shtml#add-new-type-specific-functions
425
426 .. _assertRaises context manager:
427     http://www.voidspace.org.uk/python/articles/unittest2.shtml#assertraises
428
429 .. _cleanup function registration:
430     http://www.voidspace.org.uk/python/articles/unittest2.shtml#cleanup-functions-with-addcleanup
431
432 .. _test skipping:
433     http://www.voidspace.org.uk/python/articles/unittest2.shtml#test-skipping
434
435 .. _class- and module-level setup and teardown:
436     http://www.voidspace.org.uk/python/articles/unittest2.shtml#class-and-module-level-fixtures
437
438 .. _Semantic Versioning:
439     http://semver.org/
440
441 .. _nose:
442     http://somethingaboutorange.com/mrl/projects/nose/1.0.0/
443
444 .. _promise object:
445     http://api.jquery.com/deferred.promise/
446
447 .. _Rosetta:
448 .. _Launchpad's own translation tool:
449     https://help.launchpad.net/Translations