Odoo Development Book

Public Channel / Odoo Development

Share on Social Networks

Share Link

Use permanent link to share in social media

Share with a friend

Please login to send this document by email!

Embed in your website

Select page to start with

Post comment with email address (confirmation of email is required in order to publish comment on website) or please login to post comment

2.

6. Odoo development Documentation, Release master 2 Contents

8. Odoo development Documentation, Release master 4 Chapter 1. First steps

5. Odoo development Documentation, Release master • Ask new questions: https://github.com/it-projects-llc/odoo-development/issues/new • Check open questions: https://github.com/it-projects-llc/odoo-development/issues • Push your answers and improvements: https://github.com/it-projects-llc/odoo-development Current content: Contents 1

82. Odoo development Documentation, Release master 78 Chapter 4. Git and Github

1. Odoo development Documentation Release master IT-Projects LLC September 21, 2016

62. Odoo development Documentation, Release master 58 Chapter 2. Module Development

94. Odoo development Documentation, Release master 90 Chapter 5. Odoo

72. Odoo development Documentation, Release master 68 Chapter 3. User documentation

100. Odoo development Documentation, Release master 96 Chapter 6. Odoo administration

61. Odoo development Documentation, Release master 8. Create new base and install all modules. 2.16. Other 57

108. Odoo development Documentation, Release master 104 Chapter 7. IDE

54. Odoo development Documentation, Release master Error: Missing dependencies For example, sometimes during page load displayed the error type: Missing dependencies: [...] Non loaded modules: [...] 50 Chapter 2. Module Development

107. Odoo development Documentation, Release master set -g status-fg white set -g status-bg default set -g status-attr default # default window title colors setw -g window-status-fg white setw -g window-status-bg default setw -g window-status-attr dim # active window title colors setw -g window-status-current-fg cyan setw -g window-status-current-bg default #setw -g window-status-current-attr bright setw -g window-status-current-attr underscore # command/message line colors set -g message-fg white set -g message-bg black set -g message-attr bright set-option -g status-keys vi set-option -g mode-keys vi # List of plugins set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' set -g @plugin 'tmux-plugins/tmux-resurrect' set -g @plugin 'tmux-plugins/tmux-continuum' set -g @continuum-save-interval '5' set -g @continuum-restore 'on' # Other examples: # set -g @plugin 'github_username/plugin_name' # set -g @plugin 'git@github.com/user/plugin' # set -g @plugin 'git@bitbucket.com/user/plugin' # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run '~/.tmux/plugins/tpm/tpm' 7.3. Tmux 103

7. CHAPTER 1 First steps • Install odoo • take the course Bulding a module • read the article Source diving • Configure git • read Company rules (For IT-Projects LLC employees only) • Get tasks from your Guru! • Fork repo, clone repo to you machine, make commits, push updates, create Pull Request 3

53. Odoo development Documentation, Release master 1. Go to error line into boot.js. 2. Turn on breakpoint. 3. Rerun script (click F5) 4. When script stop on error line move to console. 5. Type command: failed[ 0 ] . error 6. To receive the output 2.14. Debugging 49

104. Odoo development Documentation, Release master STEP #4 – give the user “postgres” a password Start the psql terminal: sudo -u postgres psql Give a password: ALTER USER postgres PASSWORD ‘yourpassword’; Leave the psql terminal: q STEP #5 Restart postgre server by executing this terminal command: sudo /etc/init.d/postgresql restart STEP #6 Start pgAdmin and add a connection to a server like this: You are ready! Original: http://odoo.guide/remote-access-with-pgadmin-to-odoo-postgre-database-on-ubuntu/ 100 Chapter 7. IDE

44. Odoo development Documentation, Release master Check the Technical Features box and reload odoo. Now we can see the Groups menu item! 40 Chapter 2. Module Development

111. CHAPTER 9 Indices and tables • genindex • modindex • search Note: We try our best to improve this manual, but if you still have difficults, we can offer private tutoring / advising / consultation on odoo development (resolve problem that developer(s) stack on, reveview code and pull requests ect). Feel free to hire us on upwork: • Ivan Yelizariev • Ildar Nasyrov For module development contact us by email or fill out request form : • it@it-projects.info • https://www.it-projects.info/page/website.contactus 107

3. Contents 1 First steps 3 2 Module Development 5 2.1 Docs and manifests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2 Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.3 Odoo Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.4 XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 2.5 HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 2.6 CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.7 YAML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.8 Javascript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.9 Frontend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.10 Point of Sale (POS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.11 Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.12 Hooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.13 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 2.14 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 2.15 Source Diving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 2.16 Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3 User documentation 59 3.1 static/description/index.html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.2 Screenshots tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.3 Module description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 3.4 Contact us block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.5 JS Tour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.6 Preview module on App Store . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.7 Image sizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4 Git and Github 69 4.1 Initial git & github configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 4.2 Porting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 4.3 Conflict resolving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 4.4 Multi Pull Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4.5 Cancel lame commit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.6 Pull request from console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.7 Check remote bundings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.8 Files relocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 i

46. Odoo development Documentation, Release master <field name="arch" type="xml"> <form string="Users"> <sheet> <field name="id" invisible="1"/> <div class="oe_form_box_info oe_text_center" style="margin-bottom: 10px" attrs="{'invisible': [('id', '>', 0)]}"> You are creating a new user. After saving, the user will receive an invite email containing a link to set its password. </div> <field name="image" widget='image' class="oe_avatar oe_left" options='{"preview_image": "image_medium"}'/> <div class="oe_title"> <label for="name" class="oe_edit_only"/> <h1><field name="name"/></h1> <field name="email" invisible="1"/> <label for="login" class="oe_edit_only" string="Email Address"/> <h2> <field name="login" on_change="on_change_login(login)" placeholder="email@yourcompany.com"/> </h2> <label for="company_id" class="oe_edit_only" groups="base.group_multi_company"/> <field name="company_id" context="{'user_preference': 0}" groups="base.group_multi_company"/> </div> <group> <label for="groups_id" string="Access Rights" attrs="{'invisible': [('id', '>', 0)]}"/> <div attrs="{'invisible': [('id', '>', 0)]}"> <field name="groups_id" readonly="1" widget="many2many_tags" style="display: inline;"/> You will be able to define additional access rights by edi ting the newly created user under the Settings / Users menu. </div> <field name="phone"/> <field name="mobile"/> <field name="fax"/> </group> </sheet> </form> </field> </record> Our current user is Administrator. By default he is not a member of the base.group_multicompany group. That is why the company_id isn’t visible for him on the form. 42 Chapter 2. Module Development

18. Odoo development Documentation, Release master Barcode Download Mail Download Pos Download Stock Download 14 Chapter 2. Module Development

79. Odoo development Documentation, Release master if [ -n "$2" ] then dest_repo=$2 echo $dest_repo else echo "Must be dest_repo" exit $E_WRONGARGS fi if [ -n "$3" ] then branch=$3 echo $branch else echo "Must be branch specified" exit $E_WRONGARGS fi cp -r $source_repo ../$module cd ../$module git remote rm origin git filter-branch --subdirectory-filter $module -- --all mkdir $module mv * $module git add . git commit -m "[MOV] module -- $module" cd $dest_repo git remote add repo_moved_module $source_repo/../$module git pull repo_moved_module $branch --no-edit git remote rm repo_moved_module rm -rf $source_repo/../$module In order to use it you should make the movemodule.sh file in your home directory and put all lines above there and make this file executable. $ cd ~ $ chmod +x movemodule.sh If you have installed git from official ubuntu 14.04 deb repository then you should first update it. You can update git using this instruction Update git To do the moving of group_menu_no_access from addons-yelizariev to access-addons with the movemodule.sh take the following steps. $ cd ~ $ git clone https://github.com/yelizariev/addons-yelizariev.git $ cd addons-yelizariev This part is the same as moving without the script. But then I type only one command instead of ten in case of fully manual approach. addons-yelizarie$ ../movemodule.sh group_menu_no_access ../access-addons 8.0 I assume here that the addons-yelizariev directory would be placed in your home directory along with the access- addons directory. Be sure that you are on the 8.0 branches in both of your addons-yelizariev and access-addons. 4.8. Files relocation 75

42. Odoo development Documentation, Release master On the picture above in Settings / Users we can see only Users menu. We know that there should be Groups menu also. Let Us see in ./openerp/addons/base/res/res_users_view.xml on the point of how me- nuitem can be hidden. <record id="action_res_groups" model="ir.actions.act_window"> <field name="name">Groups</field> <field name="type">ir.actions.act_window</field> <field name="res_model">res.groups</field> <field name="view_type">form</field> <field name="help">A group is a set of functional areas that will be assigned to the user in order to give them access and rights to specific applications and tasks in the system. You can create custom groups or edit the ones existing by default 38 Chapter 2. Module Development

109. CHAPTER 8 Other 8.1 RST format 8.1.1 Document Title / Subtitle The title of the whole document is distinct from section titles and may be formatted somewhat differently (e.g. the HTML writer by default shows it as a centered heading). To indicate the document title in reStructuredText, use a unique adornment style at the beginning of the document. To indicate the document subtitle, use another unique adornment style immediately after the document title. For example: ================ Document Title ================ ---------- Subtitle ---------- Section Title ============= ... Note that “Document Title” and “Section Title” above both use equals signs, but are distict and unrelated styles. The text of overline-and-underlined titles (but not underlined-only) may be inset for aesthetics. Sections • # with overline, for parts • * with overline, for chapters • =, for sections • -, for subsections • ^, for subsubsections • ”, for paragraphs 105

70. Odoo development Documentation, Release master Nginx Configure your nginx and use local link in src attribute.: <img src="static.local/path/to/image.png"/> You cannot use localhost due to security restrictions. So, you need to add some domain to /etc/hosts:: 127.0.0.1 static.local TODO instruction for nginx 3.7 Image sizes See also • Preview module on App Store • Adjust chromium window size script 66 Chapter 3. User documentation

20. Odoo development Documentation, Release master Raw RST This and next sentences are joined together. To split sentences to paragraphs you must add add empty line. Splited sentence 1. Splited sentence 2. Lists below doesn't rendered correctly, because extra line is required: * 1 * 2 * 3 The same for sublist: * 1 * 1.1 * 1.2 * 1.3 * 2 Correctly formated lists: * 1 * 2 * 3 * 3.1 * 3.2 * 3.3 * 4 Rendered RST This and next sentences are joined together. To split sentences to paragraphs you must add add empty line. Splited sentence 1. Splited sentence 2. Lists below doesn’t rendered correctly, because extra line is required: * 1 * 2 * 3 The same for sublist: • 1 * 1.1 * 1.2 * 1.3 • 2 Correctly formated lists: • 1 • 2 • 3 – 3.1 – 3.2 – 3.3 16 Chapter 2. Module Development

11. Odoo development Documentation, Release master Changelog • doc/changelog.rst Tested on Tested on Odoo 8.0 a40d48378d22309e53e6d38000d543de1d2f7a78 commit sha can be found as following cd /path/to/odoo git rev-parse HEAD doc/index.rst ============= Module name ============= Installation ============ * `Install <https://odoo-development.readthedocs.io/en/latest/odoo/usage/install-module.html>`__ this module in a usual way * OPTIONAL `Activate longpolling <https://odoo-development.readthedocs.io/en/latest/admin/longpolling.html>`__ * Additional notes if any Configuration ============= Instruction how to configure the module. * `Enable technical features <https://odoo-development.readthedocs.io/en/latest/odoo/usage/technical-features.html>`__ * Open menu ... * Click ... Usage ===== Instruction for daily usage. It should describe how to check that module works. What shall user do and what would user get. * Open menu ... * Click ... Uninstallation ============== Optional section for uninstallation notes. Delete it if you don't have notes for uninstallation. This description will be available at app store under Documentation tab. Example: https://www.odoo.com/apps/modules/8.0/pos_multi_session/ __openerp__.py 2.1. Docs and manifests 7

37. Odoo development Documentation, Release master 2.8 Javascript 2.8.1 Inheritance TODO 2.8.2 POS screen widget subclassing and modifying To create new screen widget (via the extend() method) or to modify existing screen widget (via the include() method) you need the target class. Usually you can get this class using following code: odoo.define('module_name.file_name', function (require) { "use strict"; var screens = require('point_of_sale.screens'); screens.OrderWidget.include({ ... But it is available only for widgets that are returned by main function in the file “point_of_sale/static/src/js/screens.js”. List of the screens: • ReceiptScreenWidget • ActionButtonWidget • define_action_button • ScreenWidget • PaymentScreenWidget • OrderWidget • NumpadWidget • ProductScreenWidget • ProductListWidget In other cases you can get targeted screen widget class using following code: odoo.define('module_name.file_name', function (require) { "use strict"; var gui = require('point_of_sale.gui'); gui.Gui.prototype.screen_classes.filter(function(el) { return el.name == 'clientlist'})[0].widget.include({ ... 2.8.3 core.bus core.bus (web.bus in 8.0) is used handle js events between modules. 2.8. Javascript 33

52. Odoo development Documentation, Release master boot.js Example is here: Failed modules Sources Allows you to check which client side files are loaded and which are not. To do this: 1. Turn on debug mode in the url. 2. Open Developer tools (F12), go to the Sources tab and reload page. 3. Open left panel (if it is not open yet) and search interested app. Example: Missing dependencies error in console Network Sometime error are not printed neither in Terminal, nor in Console. Then you can try to find some logs at Network tab of browser’s developer tool. To see original odoo js files i.e. not minimized versions, swich odoo in debug mode first. How to see html request initiator Suppose we want to know which part of our script initiate the request. If it is javascript we could see full program stack by putting mouse pointer on the initiator column’s element. 2.14.2 Typical errors Error: Failed modules If into server console no errors but boot.js raise exception that find out reason error next steps: 48 Chapter 2. Module Development

69. Odoo development Documentation, Release master Base64 • google: convert image to base64 • convert image to base64 with a tool you choosed. It must be some long string started with data:image/ : data:image/png;base64,iVBORw0KGgoAAAAcF8RMI3xAAA......AAElFTkSuQmCC • paste this line to src attribute of image tag – BEFORE – AFTER 3.6. Preview module on App Store 65

23. Odoo development Documentation, Release master 2.2 Guidelines Source: • https://www.odoo.com/documentation/8.0/reference/guidelines.html 2.2.1 Comments First of all, comments in the source are required if it’s not obvious why are doing something. Additionally, you can add comments about what are you doing, if it could be helpful. 2.3 Odoo Python 2.3.1 Python decoratos Original article http://odoo-new-api-guide-line.readthedocs.org/en/latest/decorator.html 2.2. Guidelines 19

93. Odoo development Documentation, Release master From addons path on server TODO 5.2.4 How to activate developer mode To activate developer mode, you need to add debug parameter to your url, e.g.: localhost:8069/web?debug=1 Also, you can use UI to do it • click button at top right-hand corner <User Name> -> About Odoo • click Activate the developer mode 5.2. How to use Odoo 89

78. Odoo development Documentation, Release master 4.8 Files relocation This article based on http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving- history/ Goal: • Move directory 1 from Git repository A to Git repository B. Constraints: • Git repository A contains other directories that we don’t want to move. • We’d like to perserve the Git commit history for the directory we are moving. $ cd ~ $ git clone https://github.com/yelizariev/addons-yelizariev.git $ cd addons-yelizariev Warning: Cloning - this is required step. It is temporary directory. It will removed all modules except the one that you want to move. We have the group_menu_no_access module that we are about to move from addons-yelizariev to the access-addons repo. addons-yelizariev$ git remote rm origin addons-yelizariev$ git filter-branch --subdirectory-filter group_menu_no_access -- --all addons-yelizariev$ mkdir group_menu_no_access addons-yelizariev$ mv * group_menu_no_access/ addons-yelizariev$ git add . addons-yelizariev$ git commit -m '[MOV] group_menu_no_access: ready to move' $ cd ../access-addons-8/ access-addons-8$ git remote add repo-addons-yelizariev-branch ../addons-yelizariev access-addons-8$ git pull repo-addons-yelizariev-branch 8.0 access-addons-8$ git push origin 8.0 Create pull request from your origin to upstream on github in your fork of https://github.com/yelizariev/access- addons.git . There must be the [MOV] commits along with the group_menu_no_access module ralated commits that was created earlier in the addons-yelizariev repo. After some time of typing the same commands to move several modules, I decided to make simple bash bash script. Here it is #!/bin/bash source_repo=$PWD echo $source_repo if [ -n "$1" ] then module=$1 echo $module else echo "Must be module name" exit $E_WRONGARGS fi 74 Chapter 4. Git and Github

66. Odoo development Documentation, Release master 3.4 Contact us block For every selling modules IT-Projects LLC adds following block at the end of module description 3.4.1 HTML <section class="oe_container"> <div class="oe_row oe_spaced"> <div class="oe_span12"> <h2>Need our service?</h2> <p class="oe_mt32">Contact us by <a href="mailto:it@it-projects.info">email</a> or fill out <a href="https://www.it-projects.info/page/website.contactus " target="_blank">request form</a></p> <ul> <li><a href="mailto:it@it-projects.info">it@it-projects.info <i class="fa fa-envelope-o"></i></a></li> <li><a href="https://www.it-projects.info/page/website.contactus " target="_blank">https://www.it-projects.info/page/website.contactus <i class="fa fa-list-alt"></i></a></li> </ul> </div> </div> </section> 3.4.2 README Only for selling modules without html description. Need our service? ----------------- Contact us by `email <mailto:it@it-projects.info>`__ or fill out `request form <https://www.it-projects.info/page/website.contactus>`__: * it@it-projects.info * https://www.it-projects.info/page/website.contactus 3.5 JS Tour Used to demonstrate module capabilities step by step with popup windows. It may be launched automatically or manually. 3.5.1 Creating Tour Tour is a simple JS file with some determined structure. Example: { id : ' mails_count_tour ' , name: _t( " Mails count Tour " ), mode: ' test ' , path: ' /web#id=3&model=res.partner ' , steps: [ { title: _t( " Mails count tutorial " ), content: _t( " Let ' s see how mails count work. " ), popover: { next : _t( " Start Tutorial " ), end: _t( " Skip " ) }, }, 62 Chapter 3. User documentation

45. Odoo development Documentation, Release master From Settings / Users / Groups we can see a list of existing groups. Here we also can assign users for groups. Hide fields In the ./openerp/addons/base/res/res_users_view.xml we can see the view_users_simple_form view. Note here that the company_id field is visible only for members of the base.group_multi_company group. <!-- res.users --> <record id="view_users_simple_form" model="ir.ui.view"> <field name="name">res.users.simplified.form</field> <field name="model">res.users</field> <field name="priority">1</field> 2.11. Access 41

47. Odoo development Documentation, Release master Model records: • restrict access to specified subset of records in model Model: • restrict access to all records of model 2.12 Hooks 2.13 Tests 2.13.1 Basic python tests This tests runs with -d [my_db] -u [module_to_be_tested] --test-enable --workers=0 pa- rameters. To make some tests do next steps: • Create folder named tests • Add __init__.py file • Create file that name begins from test_ • Add test methods that names start from test_ 2.12. Hooks 43

57. Odoo development Documentation, Release master 2.15.1 Source Diving Cases This section contains live examples of source diving. Each case contains problem description and possible solutions. Use problems as exercises and solutions as manual. Guidelines Use template below for new cases =========== CASE NAME =========== Context ======= What we have. E.g. some module, or out-of-box odoo version 8.0 * LINK1 * LINK2 Problem ======= What we need to do. E.g. port module to 9.0 * LINK1 * LINK2 Solution ======== :doc: `Possible solution <./answers/CASE_NAME>` 2.15.2 Overview: “Transformed the method” Quite often when porting a module from 8.0 to 9.0 there is a situation, when 8.0 is a object, but there is no 9.0. And it is not clear - it is outdated and it was removed or it was renamed. In very advanced cases, an object can be renamed and changed almost beyond recognition. To search you need to take several steps: 1. The default view that such an object exist, but it was renamed. 2. Look, what makes this object. 3. Search by name of methods that contains the given object, excluding common words (for example, init, start, destroy...). 4. If the result is not found that search by unique keywords which can be found by bringing the object. 5. If anything gave no results, then maybe the object is deleted as obsolete. Case Possible solution 2.15. Source Diving 53

76. Odoo development Documentation, Release master only. Make mergingchery-picking commits be only about merging and chery-picking, make porting commits separately. • If you don’t have conflicts, you do not need to make commit after cherry-pick because it creates commit by its own. 4.4 Multi Pull Request 4.4.1 Find last merged point To find last commit upstream/8.0 and upstream/9.0 were merged, use following commands git fetch git log upstream/8.0..upstream/9.0 --grep = "Merge remote-tracking branch 'origin/8.0'" --merges -n 3 # you will get something like that: # commit 5cb3652be72a05330c3988d270f3aef548511b29 # Merge: f1cd564 6cc2562 # Author: Ivan Yelizariev <yelizariev@it-projects.info> # Date: Sat Feb 27 16:00:42 2016 +0500 # # Merge remote-tracking branch 'origin/8.0' into 9.0-dev # # commit 14632a790aa01ee2a1ee9fe52152cf2fbfa86423 # Merge: 7a48b3a d66ba4f # Author: Ivan Yelizariev <yelizariev@it-projects.info> # Date: Thu Feb 25 11:31:43 2016 +0500 # # Merge remote-tracking branch 'origin/8.0' into 9.0-dev # # commit 6981c245afdccc39b2b49585f8205a784161f9c6 # Merge: 22081ed 6eb9f8d # Author: Ivan Yelizariev <yelizariev@it-projects.info> # Date: Fri Feb 19 19:14:15 2016 +0500 # # Merge remote-tracking branch 'origin/8.0' into 9.0-dev # take one commit sha from the list and check that it's in origin/9.0. git branch -r --contains 5cb3652be72a05330c3988d270f3aef548511b29 # possible output: # upstream/9.0 # origin/9.0-dev # if there is not upstream/9.0 in output, # then commit has not been merged yet and you cannot use it # for branch 9.0 use this commit sha 5cb3652be72a05330c3988d270f3aef548511b29 # for branch 8.0 need find which of two commits in ``Merge:`` line contains "upstream/8.0" git branch -r --contains f1cd564 git branch -r --contains 6cc2562 # Use commit sha to create new branches: 72 Chapter 4. Git and Github

77. Odoo development Documentation, Release master git checkout -b '9.0-new_branch_name' 5cb3652be72a05330c3988d270f3aef548511b29 git checkout -b '8.0-new_branch_name' 6cc2562 4.5 Cancel lame commit Imagine you make lame commit. Now to repair things do next: 1. git reset HEAD~1 –soft 2. git status You will see: Your branch is behind ‘origin/8.0’ by 1 commit, and can be fast-forwarded. (use “git pull” to update your local branch) 3. git add // Add here changed (fixed) files 4. git diff –cached //make sure everything is ok. 5. git status You will see: Your branch is behind ‘origin/8.0’ by 1 commit, and can be fast-forwarded. (use “git pull” to update your local branch) 6. git commit -m’I fixed my mistakes’ 7. git status You will see: Your branch and ‘origin/8.0’ have diverged, and have 1 and 1 different commit each, respectively. (use “git pull” to merge the remote branch into yours) Now finaly force is with you: 8. git push origin 8.0 -f 4.6 Pull request from console Yes it possible! Try this manual: https://github.com/github/hub Than in console: alias git=hub And pull request: git pull-request upstream 9.0 Nessesary to add some header for pull request. Save it. If everything is ok you will got link to your pull request. 4.7 Check remote bundings Check current branch: git branch -vv Local branch must be bind to origin. If its no do next: git push -u origin 9.0-pos_ms 4.5. Cancel lame commit 73

4. 4.9 Commit comment prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.10 Git stash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.11 Update Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.12 Squash commits into one . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5 Odoo 79 5.1 Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 5.2 How to use Odoo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 6 Odoo administration 91 6.1 Odoo installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 6.2 Longpolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 6.3 About longpolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 6.4 --workers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 6.5 --addons-path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 6.6 --log-handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 7 IDE 97 7.1 Emacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 7.2 PyCharm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 7.3 Tmux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 8 Other 105 8.1 RST format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 8.2 Adjust chromium window size script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 9 Indices and tables 107 ii

27. Odoo development Documentation, Release master 2.3.7 Fields Based on: http://odoo-new-api-guide-line.readthedocs.io/en/latest/fields.html Now fields are class property: from openerp import models, fields class AModel(models.Model): _name = 'a_name' name = fields.Char( string="Name", # Optional label of the field compute="_compute_name_custom", # Transform the fields in computed fields store=True, # If computed it will store the result select=True, # Force index on field readonly=True, # Field will be readonly in views inverse="_write_name" # On update trigger required=True, # Mandatory field translate=True, # Translation enable help='blabla', # Help tooltip text company_dependent=True, # Transform columns to ir.property search='_search_function' # Custom search function mainly used with compute ) # The string key is not mandatory # by default it wil use the property name Capitalized name = fields.Char() # Valid definition Field inheritance One of the new features of the API is to be able to change only one attribute of the field: name = fields . Char(string = ' New Value ' ) Field types Boolean Boolean type field: abool = fields . Boolean() Char Store string with variable len.: achar = fields . Char() Specific options: • size: data will be trimmed to specified size 2.3. Odoo Python 23

22. Odoo development Documentation, Release master ============================= No space at the end of title ============================= ======================================= Incorrect number of signs in title ======================================== ================ Incorrect number of signs in title ================ Incorrect number of signs in section ===================================== Incorrect number of signs in section =================================== Difference of doc files README.rst Contains information interested for developers index.rst Usage instruction. Used by end users after purchasing the module. It shall give an answer to the question “How to check that module works (how to install, how to configure, how to use)?” . Also, it may cover the question “How to safely uninstall the module” . index.html Module representation. It shall give an answer to the questions “Do I need this module? Should I buy it?” . Content intersection While every file has its own purpose, the content may intersect. If you don’t want duplicate content, use the following priority: • index.html • index.rst • README.rst 18 Chapter 2. Module Development

41. Odoo development Documentation, Release master this . gui . screen_instances[ ' products ' ] . action_buttons[ ' guests ' ] . renderElement(); While you can make call and even replace function with new one, you are not able to make inheritance via extend or include functions. It’s because we cannot reach Class and only get access to instance of that class. This kind of approach make sense only for those widgets: DiscountButton ReprintButton TableGuestsButton SubmitOrderButton OrderlineNoteButton PrintBillButton SplitbillButton set_fiscal_position_button 2.11 Access 2.11.1 Security tutorial Resources: • http://odoo-docs.readthedocs.org/en/latest/04_security.html • https://www.odoo.com/documentation/9.0/howtos/backend.html#security • https://www.odoo.com/documentation/9.0/reference/security.html Odoo is very flexible on the subject of security. We can control what users can do and what they cannot on different levels. Also we can control independently each of the four basic operations: read, write, create, unlink. I.e. allow only read, allow only create, grant permission to create or delete only. On fields/menu level we can: • hide fields or menus for some users and show them for others • make fields readonly for some users and make them editable for others • show different variants to pick on the Selection fields for different users On the fields level of security res.users and res.groups models are used. These models relate to each other as many2many. This means that a user can be a member of many groups and one group can be assigned to many users. One example of how we can hide menu in regard to current user’s groups is the following. 2.11. Access 37

35. Odoo development Documentation, Release master Use variable in condition Code: <label t-if="foobar"> <p>foobar is true</p> </label> Get variable transmitted by render() in XML template Code: t - att - value = " my_var " my_var is element of ‘values’ dictionary (second argument of render()). 2.4.4 Inherit Collisions and priority If two or more xml templates inherit same parent template they can have same priorities. It may produce conflicts and unexpected behavior. What you need is just set priority explicitly in your template: <template id="..." inherit_id="..." priority="8" ..> <xpath expr="..." position="..."> ... </xpath> </template> <!-- or --> <record id="..." model="ir.ui.view"> ... <field name="inherit_id" ref="..."/> <field name="priority" eval="8" /> <field name="arch" type="xml"> <xpath expr="..." position="..."> </xpath> </field> </record> Less priority means prior execution. Default priority is 16. 2.5 HTML 2.5.1 Active elements Link-button that calls controller Code: 2.5. HTML 31

16. Odoo development Documentation, Release master `1.0.0` ------- - Init version Guidlines .. _changelog: Updates ======= `2.0.0` ------- - ADD: absolutely new way of .. `1.2.0` ------- - ADD: new interface for .. `1.0.1` ------- - FIX: issue about ... - FIX: another issue about ... `1.0.0` ------- - Init version icon.png File icon.png must be located at /static/description/icon.png IT-Projects LLC Icons for IT-Projects LLC modules: TODO 12 Chapter 2. Module Development

83. CHAPTER 5 Odoo 5.1 Models Section helps in understanding built-in models 5.1.1 ir.config_parameter XML operations Create new setting Code: <record id="myid" model="ir.config_parameter"> <field name="key">mymodule.mykey</field> <field name="value">True</value> </record> Use this approach only to manipulate keys you created. It’s not recommended to change others modules this way. For example such like this: <record model="ir.config_parameter" id="website.google_app_key"> Search addons for model=”ir.config_parameter” for more examples. Such record usually used with <data noupdate=”1”>. Change existing setting Code: <function model="ir.config_parameter" name="set_param" eval="('auth_signup.allow_uninvited', True)" /> Prons: works if you are not sure whether key already used or not Cons: record is not deleted on uninstalling 79

56. Odoo development Documentation, Release master Source 2.14.4 Emulation of slow internet connections in browser 2.14.5 Emulation barcode Barcode scanner connected with computer work as keyboard. E.g. after scanning send sequence of symbols as if fast typing on the keyboard. Install xdotool app if you haven’t it yet. sudo apt-get install xdotool Emulation scanning barcode: sleep 3 && echo '1234567890128' | grep -o . | xargs xdotool key && xargs xdotool key \n & or so: sleep 3 && echo '3333333333338' | grep -o . | xargs xdotool key && xargs xdotool key \n & Where: 3 - sleep seconds; 3333333333338 - barcode. After successfully scanning you will see ‘3333333333338’ in the command line. If toggle to other window that symbols appear in the input field in the this window. So we can send sequence in the app as if we scanning it. 2.15 Source Diving Source Diving is a way to find answers to your questions. 52 Chapter 2. Module Development

101. CHAPTER 7 IDE 7.1 Emacs 7.1.1 Emacs Install emacs 24.4+ http://askubuntu.com/questions/437255/how-to-install-emacs-24-4-on-ubuntu • Open Emacs • Press Alt-x package-list-packages • install packages: click i and then x • some packages require dependencies, that have to be installed via terminal * flymake * loccur * flymake-css * flymake-jslint * flymake-python-pyflakes sudo pip install flake8 – magit – js3-mode 7.1.2 Spacemacs Requirements • emacs version 24 or newer. Installation Install spacemacs from github https://github.com/syl20bnr/spacemacs Documentation http://spacemacs.org/doc/DOCUMENTATION.html 97

21. Odoo development Documentation, Release master • 4 References to menu Use double back-quotes with spaced slash for menus: OK: * Open menu ``Settings / Parameters / System Parameters`` BAD * Open menu ``Settings/Parameters/System Parameters`` * Open menu "Settings / Parameters / System Parameters" * Open menu ''Settings / Parameters / System Parameters'' * Open menu ``Settings \ Parameters \ System Parameters`` Fields Use bold format for fields: * Set ** Name ** and ** Date ** values Buttons Use square brackets in double back-quotes to name buttons. Keep letter cases the same as in UI. OK: * click ``[Save]`` Bad: * click ``[save]`` Selections Use arrow symbol -> to specify value in selection and many2one fields: * Choose ``Partner -> Administrator`` Titles and sections OK: =========================== Correctly formatted Title =========================== Correctly formatted section =========================== BAD: =========================================== No spaces at the beggining and end of title =========================================== 2.1. Docs and manifests 17

106. Odoo development Documentation, Release master set -g @plugin 'tmux-plugins/tmux-resurrect' Hit prefix + I to fetch the plugin and source it. You should now be able to use the plugin. Based on: https://github.com/tmux-plugins/tmux-resurrect Install tmux-continuum Last saved environment is automatically restored when tmux is started. Put the following lines in tmux.conf : set -g @continuum-save-interval '5' set -g @continuum-restore 'on' Your environment will be automatically saved every 5 minutes. When you start tmux it will automatically restore Based on: https://github.com/tmux-plugins/tmux-continuum 7.3.2 Tmux configuration Create a file with the name .tmux.conf in your home directory. An example of .tmux.conf : # Global settings # Set prefix key to Ctrl-a # unbind-key C-b # set-option -g prefix C-a # send the prefix to client inside window # bind-key C-a send-prefix # scrollback buffer n lines set -g history-limit 10000 # tell tmux to use 256 colour terminal set -g default-terminal "screen-256color" # enable wm window titles set -g set-titles on # reload settings bind-key R source-file ~/.tmux.conf # Statusbar settings # toggle statusbar bind-key s set status # use vi-style key bindings in the status line set -g status-keys vi # amount of time for which status line messages and other indicators # are displayed. time is in milliseconds. set -g display-time 2000 # default statusbar colors 102 Chapter 7. IDE

58. Odoo development Documentation, Release master 2.15.3 Case: “Transformed the method” Context When porting module mail_move_message in the file static/src/js/mail_move_message.js there is a method ses- sion.web.form.FormOpenPopup(this) . Problem In 9.0 not found such object. What object would be the analogue of the object? What you need to do to find this object? Solution Possible solution 2.16 Other 2.16.1 Dynamic records While XML allows you create only static records, there is a way to create record dynamically via python code. You need dynamic records, for example, to add support both for enterprise and community releases or to add some records to each company in database etc. There several ways to execute code on installation: • TODO • TODO • TODO The problem with dynamic records is that odoo considers such records as ones, which were in xml files, but now deleted. It means that odoo will delete such dynamic records right after updating. There are two ways to resolve it. noupdate=False Simply add update=True to your ir.model.data record: debt_account = registry[ ' account.account ' ] . create(cr, SUPERUSER_ID, { ' name ' : ' Debt ' , ' code ' : ' XDEBT ' , ' user_type_id ' : registry . get( ' ir.model.data ' ) . get_object_reference(cr, SUPERUSER_ID, ' account ' , ' data_account_type_current_assets ' )[ 1 ], ' company_id ' : company . id, ' note ' : ' code " XDEBT " should not be modified as it is used to compute debt ' , }) registry[ ' ir.model.data ' ] . create(cr, SUPERUSER_ID, { ' name ' : ' debt_account_ ' + str (company . id), ' model ' : ' account.account ' , ' module ' : ' pos_debt_notebook ' , ' res_id ' : debt_account, ' noupdate ' : True , # If it's False, target record (res_id) will be removed while module update }) 54 Chapter 2. Module Development

97. Odoo development Documentation, Release master git checkout somebranch-or-revision git tag 8_0-honduras.local # everytime run odoo this way: git checkout 8_0-client1.local && ./odoo.py --config = /path/to/.openerp_serverrc-8 # or git checkout 8_0-project1.local && ./odoo.py --config = /path/to/.openerp_serverrc-8 --auto-reload # or git checkout 9_0-project1.local && ./odoo.py --config = /path/to/.openerp_serverrc-9 --dev # etc. # then open database you need, e.g. (type http:// explicitly, because browser could understand it as search request) # http://8_0-client1.local/ # (database name should be 8_0-client1.local ) nginx_odoo.conf server { listen 80 default_server; server_name .local; proxy_buffers 16 64k; proxy_buffer_size 128k; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; #proxy_redirect http:// https://; proxy_read_timeout 600s; client_max_body_size 100m; location /longpolling { proxy_pass http://127.0.0.1:8072; } location / { proxy_pass http://127.0.0.1:8069; } } 6.1.2 Production installation • https://github.com/yelizariev/install-odoo 6.2 Longpolling Longpolling is a way to deliver instant notification to web client (e.g. in chats). To activate longpolling: • install gevent and psycogreen python -c "import gevent" || sudo pip install gevent python -c "import psycogreen" || sudo pip install psycogreen • set non-zero value for workers parameter 6.2. Longpolling 93

98. Odoo development Documentation, Release master • configure nginx location /longpolling { proxy_pass http://127.0.0.1:8072; } location / { proxy_pass http://127.0.0.1:8069; } • if you install odoo 9.0 via deb package, then you have to restore openerp-gevent file (see #10207 ): cd /usr/bin/ wget https://raw.githubusercontent.com/odoo/odoo/9.0/openerp-gevent chmod +x openerp-gevent Read more about longpolling 6.3 About longpolling What is HTTP Long Polling? Web applications were originally developed around a client/server model, where the Web client is always the initiator of transactions, requesting data from the server. Thus, there was no mechanism for the server to independently send, or push, data to the client without the client first making a request. In a Nutshell: HTTP Long Polling To overcome this deficiency, Web app developers can implement a technique called HTTP long polling, where the client polls the server requesting new information. The server holds the request open until new data is available. Once available, the server responds and sends the new information. When the client receives the new information, it immediately sends another request, and the operation is repeated. This effectively emulates a server push feature. Thus, each data packet means new connection which will remain open until the server sends the information. In practice the connection usually reinstalls once per 20-30 seconds to get rid of possible problems (mistakes) , e.g. problems connected with HTTP-proxy. In contradiction to usual polling, such notice appears faster. Delay = connection installing + data transfer Advantages of longpolling • The loading to the server is reduced unlike usual polling • Reduced traffic • Supporting in all modern browsers Thus, longpolling helps the client to receive data as soon as they appear in the server in contrast to periodic, which send requests according to interval specified. 6.4 --workers Non-zero values for --workers activates Multiprocessing. Multiprocessing increases stability, makes somewhat better use of computing resources and can be better monitored and resource-restricted. 94 Chapter 6. Odoo administration

84. Odoo development Documentation, Release master 5.1.2 res.users TODO 5.1.3 res.groups TODO 5.1.4 ir.model.access TODO 5.1.5 ir.rule TODO 5.1.6 product.template The stores have products that differ from some other only a one or few properties. Such goods it makes no sense to separate as individual products. They are join in a group of similar goods, which are called template . shop: product pages use product.template (when order is created, then product.product is used). 5.1.7 product.product The product, unlike the template , it is a separate product that can be calculated, set the price, to assign a discount. product.product is used: • sale.order • stock • pos 5.1.8 ir.actions.todo The model is used for executing actions (records in the “ir.actions.act_window” model). The model allows to set conditions and sequence of appearance of wizards. Also you can specify a regular interface window but only as last action. Code: <record id="sce.initial_setup" model="ir.actions.todo"> <field name="action_id" ref="action_initial_setup"/> <field name="state">open</field> <field name="sequence">1</field> <field name="type">automatic</field> </record> The startup type can be one of the following: • manual: Launched manually. 80 Chapter 5. Odoo

74. Odoo development Documentation, Release master 4.2 Porting If you add some feature to one branch and need to add it to anoher branch, then you have to make port . See also: • Conflicts resolving 4.2.1 Forward-port It’s the simplest case. You merge commits from older branch (e.g. 8.0) to newer branch (e.g. 9.0) git checkout 9.0 git merge origin/8.0 # [Resolve conflicts if needed] git push After git merge you probably need to make some minor changes. In that case just add new commits to newer branch git add ... git commit -m "...." git push 4.2.2 Back-port If you need to port new feature from newer branch (e.g. 9.0) to older one (e.g. 8.0), then you have to make back-port . The problem here is that newer branch has commits which should be applied for newer branch only. That is you cannot just make git merge 9.0 , because it brings 9.0-only commits to 8.0 branch. Possible solutions here are: 4.2.3 git cherry-pick Apply commits from newer branch (e.g. 9.0) to older branch (e.g. 8.0) git checkout 8.0 git cherry-pick <commit-1> # [Resolve conflicts if needed] git cherry-pick <commit-2> # [Resolve conflicts if needed] # ... git push Also possible to pick the commit from any remote repository. Add this repository to your remotes. Do fetch from it. And then cherry-pick. 70 Chapter 4. Git and Github

39. Odoo development Documentation, Release master 'depends' : '[website]' then add the website=True flag on the controller, this sets up a few new variables on the request object and allows using the website layout in our template. Creating pages 1 way Write the following code in controllers.py : from openerp import http classNewPage ( http.Controller ) : @http.route ( '/new-page/' ,auth = 'public' , website = True ) def index ( self, ** kw ) : return http.request.render ( 'newpage.index' ) The new web page will appear by adding - /new-page/ http.request.render(’newpage.index’) – downloading a tamplate for a new page A pattern templates.xml <openerp> <data> < templateid = "index" > <t t-call = "website.layout" > <t t-set = "title" >New page</t> <div class = "oe_structure" > <div class = "container" > <h1>My first web page</h1> <p>Hello, world!</p> </div> </div> </t> </template> </data> </openerp> website.layout means that the elements of pattern website are used. After restarting the server while updating the module (in order to update the manifest and template) access http://localhost:8069/new-page/ . You will see a new page with a title ‘My first web page’ and with text ‘Hello, world!’ 2 way Write in pattern the following: <template name = "Services page" id = "website.services" page = "True" > <t t-call = "website.layout" > <div id = "wrap" > <div class = "container" > <h1>Our Services</h1> <ul class = "services" > <li>Cloud Hosting</li> <li>Support</li> <li>Unlimited space</li> </ul> </div> </div> </t> </template> 2.9. Frontend 35

73. CHAPTER 4 Git and Github 4.1 Initial git & github configuration 4.1.1 ssh keys Configure github ssh keys: https://help.github.com/articles/generating-ssh-keys/ 4.1.2 github emails IT-Projects LLC employees only: • https://github.com/settings/profile – public email should be personal address . . . @it-projects.info • https://github.com/settings/emails – primary email should be personal address . . . @it-projects.info – “Keep my email address private” should be turned off 4.1.3 git email • Configure email in git . Email must be the same as in github settings: git config --global user.email "your_email@example.com" 4.1.4 gitignore • Configure global gitignore Possible content for ~/.gitignore_global : * ~ * .pyc 69

36. Odoo development Documentation, Release master <form action="/shop/checkout" name="myform" method="post"> <a class="btn btn-primary a-submit">My button</a> </form> Here action=”/shop/checkout” sets controller address. Class a-submit usually means do what in ‘action’ of form. Submit with button Code: <form action="/my_page" name="myform" method="post"> <button type="submit" class="btn btn-default">My button</button> </form> Wherein in controller in **post will be available some values from source form, those like <input/>. 2.6 CSS 2.6.1 CSS tips and tricks Add your css on template Code: <template id="my_module_frontend" name="my_module assets" inherit_id="website_sale.assets_frontend"> <xpath expr="//link[@rel='stylesheet']" position="after"> <link rel="stylesheet" href="/my_module/static/src/css/main.css"/> </xpath> </template> website_sale.assets_frontend is what you inherits. Hide fields Hide all children (that have attribute bill=‘1’) of oe_website_sale class owner (that have attribute bill_enabled=‘0’): .oe_website_sale[bill_enabled='0'] [bill='1']{ display:none; } 2.7 YAML 2.7.1 Pure YAML TODO 2.7.2 YAML in odoo TODO 32 Chapter 2. Module Development

10. Odoo development Documentation, Release master Sponsors -------- * `IT-Projects LLC <https://it-projects.info> `_ Further information =================== Demo: http://runbot.it-projects.info/demo/REPO-NAME/BRANCH HTML Description: https://apps.odoo.com/apps/modules/VERSION/TECHNICAL_NAME/ Usage instructions: `<doc/index.rst>`_ Changelog: `<doc/changelog.rst>`_ Tested on Odoo 8.0 ODOO_COMMIT_SHA_TO_BE_UPDATED OCA’s README • https://raw.githubusercontent.com/OCA/maintainer-tools/master/template/module/README.rst Demo Link to the runbot. Supported repo names are below. Change branche name if needed. Demo: http://runbot.it-projects.info/demo/access-addons/9.0 Demo: http://runbot.it-projects.info/demo/addons-dev/misc-addons-9.0-some_feature Demo: http://runbot.it-projects.info/demo/l10n-addons/9.0 Demo: http://runbot.it-projects.info/demo/mail-addons/9.0 Demo: http://runbot.it-projects.info/demo/misc-addons/9.0 Demo: http://runbot.it-projects.info/demo/odoo-saas-tools/9.0 Demo: http://runbot.it-projects.info/demo/odoo-telegram/9.0 Demo: http://runbot.it-projects.info/demo/pos-addons/9.0 Demo: http://runbot.it-projects.info/demo/rental-addons/9.0 Demo: http://runbot.it-projects.info/demo/website-addons/9.0 addons-dev In most cases, if you work in addons-dev, you shall not use demo link to addons-dev (e.g. http://runbot.it-projects.info/demo/addons-dev/misc-addons-9.0-some_feature ). Use a link for target repo instead (e.g. http://runbot.it-projects.info/demo/misc-addons/9.0 ). You can use links to addons-dev only if you know who will use it. HTML Description Link to app store, e.g. HTML Description: https://apps.odoo.com/apps/modules/9.0/web_debranding/ You have to prepare this link even if the module is not published yet, i.e. link returns 404 error. Usage instructions • doc/index.rst 6 Chapter 2. Module Development

13. Odoo development Documentation, Release master " static/src/xml/QWEBFILE1.xml " , ], " demo " : [ " demo/DEMOFILE1.xml " , ], " post_load " : None , " pre_init_hook " : None , " post_init_hook " : None , " auto_install " : False , " installable " : True , } See also: • OCA’s template: https://github.com/OCA/maintainer-tools/blob/master/template/module/__openerp__.py name It must be non-technical name of the module summary Short description of the module. E.g. you can describe here which problem is solved by the module. It could sound as a slogan. category Categories from the list below are preferred. • Accounting • Discuss • Document Management • eCommerce • Human Resources • Industries • Localization • Manufacturing 2.1. Docs and manifests 9

19. Odoo development Documentation, Release master Website Download Website_Sale Download Misc Download 2.1.2 Notes RST Requirements Don’t forget to keep correct rst format. • Extra lines • References to menu • Fields • Buttons • Selections • Titles and sections Extra lines Dont’ forget about additional lines for correct formatting 2.1. Docs and manifests 15

55. Odoo development Documentation, Release master You can find out reason in the Developer Tool in the tab Sources as described above. Likely you can not find files included in the Missing dependencies list. Then you need to check they are included in the view (.xml) files. 2.14.3 QWeb The javascript QWeb implementation provides a few debugging hooks: t-log takes an expression parameter, evaluates the expression during rendering and logs its result with console.log : <t t-set="foo" t-value="42"/> <t t-log="foo"/> will print 42 to the console t-debug triggers a debugger breakpoint during template rendering: <t t-if="a_test"> <t t-debug=""> </t> will stop execution if debugging is active (exact condition depend on the browser and its development tools) t-js the node’s body is javascript code executed during template rendering. Takes a context parameter, which is the name under which the rendering context will be available in the t-js ‘s body: <t t-set="foo" t-value="42"/> <t t-js="ctx"> console.log("Foo is", ctx.foo); </t> 2.14. Debugging 51

110. Odoo development Documentation, Release master Code block Enter double colon (::) and then empty line and then at least one space and finaly you can enter your code. Also you can use inplace code reference by using ‘‘ ‘‘. 8.1.2 Selection • ** bold ** • * italic * • ‘‘code‘‘ 8.1.3 Lists • * - not numerated • #. - numerated • 1,2,3, ... - numerated 8.1.4 Links • internal link: :doc:`Link Text<../relative/path/to/article>` • external link: `Link Text <https://google.com/>`_ 8.1.5 More documentations • http://docutils.sourceforge.net/docs/user/rst/quickref.html 8.2 Adjust chromium window size script You can make screenshot with size exactly you need. Open chromium. Do not expand window (or in wount work). Run this command: wmctrl -a chromium -e 1,0,0,760,451 Last two arguments is width and height. Consider to add chromium window borders to your screenshot size. In my case it 10px to width and 80px to height. Likely you got same. So for 750 x 371 it be 760 x 451. 106 Chapter 8. Other

30. Odoo development Documentation, Release master When extending a model, if you want to add possible values to a selection field, you may use the selection_add keyword argument: class SomeModel (models . Model): _inherits = ' some.model ' type = fields . Selection(selection_add = [( ' b ' , ' B ' ), ( ' c ' , ' C ' )]) Reference Store an arbitrary reference to a model and a row: aref = fields . Reference([( ' model_name ' , ' String ' )]) aref = fields . Reference(selection = [( ' model_name ' , ' String ' )]) aref = fields . Reference(selection = ' a_function_name ' ) Specific options: • selection: a list of tuple or a callable name that take recordset as input Many2one Store a relation against a co-model: arel_id = fields . Many2one( ' res.users ' ) arel_id = fields . Many2one(comodel_name = ' res.users ' ) an_other_rel_id = fields . Many2one(comodel_name = ' res.partner ' , delegate = True ) Specific options: • comodel_name: name of the opposite model • delegate: set it to True to make fields of the target model accessible from the current model (corresponds to _inherits ) One2many Store a relation against many rows of co-model: arel_ids = fields . One2many( ' res.users ' , ' rel_id ' ) arel_ids = fields . One2many(comodel_name = ' res.users ' , inverse_name = ' rel_id ' ) Specific options: • comodel_name: name of the opposite model • inverse_name: relational column of the opposite model Many2many Store a relation against many2many rows of co-model: arel_ids = fields . Many2many( ' res.users ' ) arel_ids = fields . Many2many(comodel_name = ' res.users ' , relation = ' table_name ' , column1 = ' col_name ' , column2 = ' other_col_name ' ) 26 Chapter 2. Module Development

95. CHAPTER 6 Odoo administration Official docs: * https://www.odoo.com/documentation/8.0/setup/install.html * https://www.odoo.com/documentation/8.0/setup/deploy.html 6.1 Odoo installation Contents • Odoo installation – Local installation * nginx_odoo.conf – Production installation 6.1.1 Local installation sudo apt-get update sudo apt-get install git python-pip htop moreutils tree nginx gimp wmctrl postgresql-server-dev-all sudo apt-get upgrade ################### Github # configure ssh keys: https://help.github.com/articles/generating-ssh-keys/ ################### Odoo # download odoo from git: cd /some/dir/ git clone https://github.com/odoo/odoo.git # install dependencies: wget http://nightly.odoo.com/9.0/nightly/deb/odoo_9.0.latest_all.deb sudo dpkg -i odoo_9.0.latest_all.deb # shows errors -- just ignore them and execute next command: sudo apt-get -f install sudo apt-get remove odoo # install wkhtmltox cd /usr/local/src lsb_release -a uname -i # check version of your OS and download appropriate package 91

17. Odoo development Documentation, Release master • SaaS • Telegram • Access • Barcode • Mail • Pos • Stock • Website • Website_Sale • Misc SaaS Download Telegram Download Access Download 2.1. Docs and manifests 13

68. Odoo development Documentation, Release master Some docs is here (begin from 10 slide): http://www.slideshare.net/openobject/how-to-develop-automated-tests Also checkout here: https://github.com/odoo/odoo/blob/9.0/addons/web/static/src/js/tour.js You can launch tour by entering in browser address like this mydatabase/web#/tutorial.mails_count_tour=true where after tutorial. is id of your tour. 3.5.2 Automatic tour launch To run tour after module installation do next steps. • Create ToDo • Create Action ToDo is some queued web actions that may call Action like this: <record id="base.open_menu" model="ir.actions.todo"> <field name="action_id" ref="action_website_tutorial"/> <field name="state">open</field> </record> Action is like this: <record id="res_partner_mails_count_tutorial" model="ir.actions.act_url"> <field name="name">res_partner_mails_count Tutorial</field> <field name="url">/web#id=3&amp;model=res.partner&amp;/#tutorial_extra.mails_count_tour=true</field> <field name="target">self</field> </record> Here tutorial_extra.**mails_count_tour** is tour id. Use eval to compute some python code if needed: <field name="url" eval="'/web?debug=1&amp;res_partner_mails_count=tutorial#id='+str(ref('base.partner_root'))+'&amp;view_type=form&amp;model=res.partner&amp;/#tutorial_extra.mails_count_tour=true'"/> 3.6 Preview module on App Store Browser’s dev tools allows to preview Module in App Store before actual uploading. • open https://www.odoo.com/apps • click Inspect Element on some application • change text and images • Done! Now can decide do you need make changes or keep current images and text • Preview image – Base64 – Nginx 3.6.1 Preview image While it’s easy to change text, it’s not obvious how to preview image. 64 Chapter 3. User documentation

99. Odoo development Documentation, Release master • Number of workers should be based on the number of cores in the machine (possibly with some room for cron workers depending on how much cron work is predicted) • Worker limits can be configured based on the hardware configuration to avoid resources exhaustion Warning: multiprocessing mode currently isn’t available on Windows 6.4.1 Longpolling Hidden feature of Multiprocessing is automatic run gevent process for longpolling support. Longpolling is an extra proccess, i.e. if you have --workers=2 then you will get 2 worker processes and 1 gevent process 6.5 --addons-path 6.5.1 Duplicate addons If you have two folder with the same module and you have reason to add both folders to addons_path , then first found version of the module will be used. That is folder in the begging of addons_path list has more priority. 6.6 --log-handler --log-handler=PREFIX:LEVEL Setups a handler at LEVEL for a given PREFIX. This option can be repeated. For example, if you want to have DEBUG level for module telegram only, you can run it with parameter: --log-handler=openerp.addons.telegram:DEBUG To disable werkzeug logs add following parameter: --log-handler=werkzeug:CRITICAL 6.5. --addons-path 95

24. Odoo development Documentation, Release master @api.one api.one is meant to be used when method is called only on one record. It makes sure, that there are no multiple records when calling method with api.one decorator. Let say you got record partner = res.partner(1,). It is only one record and there is method for example (in res.partner): @api.one def get_name ( self ): return self . name #self here means one record calling it like this works: partner . get_name() But if there would be more records, like: partners = res . partner( 1 , 2 ,) calling it, would raise Warning, telling you that you can only call it on one record. @api.multi something. For example: @api.multi def get_partner_names(self): names = [] for rec in self: names.append(rec.name) return ', '.join(names) And api.model is considered to be used when you need to do something with model itself and don’t need to mod- ify/check some exact model’s record/records. For example there could be method that returns some meta info about model’s structure or some helper methods, etc. Also in documentation it is said that this api is good to use when mi- grating from old api, because it “politely” converts code to new api. Also in my own experience, if you need method to return something, model decorator is good for it. api.one returns empty list, so it might lead to unexpected behavior when using api.one on method when it is supposed to return something. 2.3.2 Pure Python Compare two arrays a = set(pos_config_obj.floor_ids.ids) b = set(rec.floor_ids.ids) diff = a.difference(b) 2.3.3 res.config.settings Based on https://github.com/odoo/odoo/blob/9.0/openerp/addons/base/res/res_config.py res.config.settings is a base configuration wizard for application settings. It provides support for setting default values, assigning groups to employee users, and installing modules. To make such a ‘settings’ wizard, define a model like: class my_config_wizard (osv . osv_memory): _name = ' my.settings ' _inherit = ' res.config.settings ' 20 Chapter 2. Module Development

102. Odoo development Documentation, Release master Layers for Odoo development Use the following layers: • auto-completion • better-defaults • emacs-lisp • git • syntax-checking • version-control • pyhton • eyebrowse • sql • python • semantic Syntax-checking in python uses pylint package ( http://liuluheng.github.io/wiki/public_html/Python/flycheck-pylint- emacs-with-python.html ). Install it by sudo pip install pylint 7.1.3 Replace text in recursively found files 1. M-x find-name-dired : you will be prompted for a root directory and a filename pattern. 2. Press t to “toggle mark” for all files found. 3. Press Q for “Query-Replace in Files...”: you will be prompted for query/substitution regexps. 4. Proceed as with query-replace-regexp : SPACE to replace and move to next match, n to skip a match, etc. Based on: http://stackoverflow.com/questions/270930/using-emacs-to-recursively-find-and-replace-in-text-files-not- already-open 7.1.4 Pylint Pylint is a tool that checks for errors in Python code, tries to enforce a coding standard and looks for code smells. It can also look for certain type errors, it can recommend suggestions about how particular blocks can be refactored and can offer you details about the code’s complexity. https://pylint.readthedocs.io/en/latest/ Install pylint. sudo pip install pylint With the Flycheck emacs extension, pylint’s output will be shown right inside your emacs buffers. Spacemacs has flycheck in his syntax-checking layer. M-x package-install RET flycheck Configure pylint by using a pylintrc file. 98 Chapter 7. IDE

96. Odoo development Documentation, Release master # http://wkhtmltopdf.org/downloads.html # e.g. apt-get install xfonts-base xfonts-75dpi apt-get -f install wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2.1/wkhtmltox-0.12.2.1_linux-trusty-amd64.deb dpkg -i wkhtmltox- * .deb # requirements.txt cd /path/to/odoo sudo pip install -r requirements.txt sudo pip install watchdog # fix error with jpeg (if you get it) # uninstall PIL sudo pip uninstall PIL # install libjpeg-dev with apt sudo apt-get install libjpeg-dev # reinstall pillow pip install -I pillow # (from here https://github.com/odoo/odoo/issues/612 ) # fix issue with lessc # install Less CSS via nodejs according to this instruction: # https://www.odoo.com/documentation/8.0/setup/install.html # create postgres user: sudo su - postgres -c " createuser -s $USER " # Create new config file if you don't have it yet: cd /path/to/odoo ./openerp-server --save # then edit it, e.g. via emacs emacs -nw ~/.openerp_serverrc # set dbfilter = ^%h$ # set workers = 2 # to make longpolling\bus\im work # create different versions of conf file: cp ~/.openerp_serverrc ~/.openerp_serverrc-9 cp ~/.openerp_serverrc ~/.openerp_serverrc-8 ################### /etc/hosts # /etc/hosts must contains domains you use, e.g: sudo bash -c "echo '127.0.0.1 8_0-project1.local' >> /etc/hosts" sudo bash -c "echo '127.0.0.1 8_0-project2.local' >> /etc/hosts" sudo bash -c "echo '127.0.0.1 9_0-project1.local' >> /etc/hosts" ################### nginx # put nginx_odoo.conf to /etc/nginx/sites-enabled/ # delete default configuration: cd /etc/nginx/sites-enabled/ rm default # restart nginx sudo /etc/init.d/nginx restart ################### run Odoo cd /path/to/odoo 92 Chapter 6. Odoo administration

43. Odoo development Documentation, Release master in order to customize the view of the menu that users will be able to see. Whether they can have a read, write, create and delete access right can be managed from here. </field> </record> <menuitem action="action_res_groups" id="menu_action_res_groups" parent="base.menu_users" groups="base.group_no_one"/> The groups attribute in the menuitem element shows us that only the members of base.group_no_one group can see the Groups menu item. The base.group_no_one xmlid is defined in the ./openerp/addons/base/security/base_security.xml as follows. <record model="res.groups" id="group_erp_manager"> <field name="name">Access Rights</field> </record> <record model="res.groups" id="group_system"> <field name="name">Settings</field> <field name="implied_ids" eval="[(4, ref('group_erp_manager'))]"/> <field name="users" eval="[(4, ref('base.user_root'))]"/> </record> <record model="res.groups" id="group_user"> <field name="name">Employee</field> <field name="users" eval="[(4, ref('base.user_root'))]"/> </record> <record model="res.groups" id="group_multi_company"> <field name="name">Multi Companies</field> </record> <record model="res.groups" id="group_multi_currency"> <field name="name">Multi Currencies</field> </record> <record model="res.groups" id="group_no_one"> <field name="name">Technical Features</field> </record> <record id="group_sale_salesman" model="res.groups"> <field name="name">User</field> </record> <record id="group_sale_manager" model="res.groups"> <field name="name">Manager</field> <field name="implied_ids" eval="[(4, ref('group_sale_salesman'))]"/> </record> Here we can see the group_no_one along with the other base groups. Note that group_no_one has Technical Features name. Let us include our user in the Technical Features group. Since we have no access to the Groups menu item, the only way we can do it is from the Users menu item. See the picture below. 2.11. Access 39

31. Odoo development Documentation, Release master Specific options: • comodel_name: name of the opposite model • relation: relational table name • columns1: relational table left column name • columns2: relational table right column name Name Conflicts Note: fields and method name can conflict. When you call a record as a dict it will force to look on the columns. Fields Defaults Default is now a keyword of a field: You can attribute it a value or a function name = fields . Char(default = ' A name ' ) # or name = fields . Char(default = a_fun) #... def a_fun ( self ): return self . do_something() Using a fun will force you to define function before fields definition. Computed Fields There is no more direct creation of fields.function. Instead you add a compute kwarg. The value is the name of the function as a string or a function. This allows to have fields definition atop of class: class AModel (models . Model): _name = ' a_name ' computed_total = fields . Float(compute = ' compute_total ' ) def compute_total ( self ): . . . self . computed_total = x The function can be void. It should modify record property in order to be written to the cache: self . name = new_value Be aware that this assignation will trigger a write into the database. If you need to do bulk change or must be careful about performance, you should do classic call to write 2.3. Odoo Python 27

28. Odoo development Documentation, Release master • translate: field can be translated Text Used to store long text.: atext = fields . Text() Specific options: • translate: field can be translated HTML Used to store HTML, provides an HTML widget.: anhtml = fields . Html() Specific options: • translate: field can be translated Integer Store integer value. No NULL value support. If value is not set it returns 0: anint = fields . Integer() Float Store float value. No NULL value support. If value is not set it returns 0.0 If digits option is set it will use numeric type: afloat = fields . Float() afloat = fields . Float(digits = ( 32 , 32 )) afloat = fields . Float(digits = lambda cr: ( 32 , 32 )) Specific options: • digits: force use of numeric type on database. Parameter can be a tuple (int len, float len) or a callable that return a tuple and take a cursor as parameter Date Store date. The field provides some helpers: • context_today returns current day date string based on tz • today returns current system date string • from_string returns datetime.date() from string • to_string returns date string from datetime.date : 24 Chapter 2. Module Development

48. Odoo development Documentation, Release master Example (will result testing error): from openerp.tests.common import TransactionCase class TestMessage (TransactionCase): at_install = False post_install = True def test_count ( self ): self . assertEqual( 1 , 0 ) Test class From openerp/tests/common.py : class BaseCase (unittest . TestCase): """ Subclass of TestCase for common OpenERP-specific code. This class is abstract and expects self.registry, self.cr and self.uid to be initialized by subclasses. """ class TransactionCase (BaseCase): """ TestCase in which each test method is run in its own transaction, and with its own cursor. The transaction is rolled back and the cursor is closed after each test. """ class SingleTransactionCase (BaseCase): """ TestCase in which all test methods are run in the same transaction, the transaction is started with the first test method and rolled back at the end of the last. """ class SavepointCase (SingleTransactionCase): """ Similar to :class:`SingleTransactionCase` in that all test methods are run in a single transaction * but * each test case is run inside a rollbacked savepoint (sub-transaction). Useful for test cases containing fast tests but with significant database setup common to all cases (complex in-db test data): :meth:`~.setUpClass` can be used to generate db test data once, then all test cases use the same data without influencing one another but without having to recreate the test data either. """ class HttpCase (TransactionCase): """ Transactional HTTP TestCase with url_open and phantomjs helpers. """ at_install, post_install By default, odoo runs test with paramaters: at_install = False post_install = True at_install - run tests right after loading module’s files. It runs only in demo mode. 44 Chapter 2. Module Development

34. Odoo development Documentation, Release master 2.4.2 Xpath Add some attributes to node Code: <xpath expr="//some/xpath" position="attributes"> <attribute name="some_field"> </xpath> Qweb expression: <attribute name="t-att-another_field">website.get_another_field_value()</attribute> After rendering it becomes regular attribute: <.... another_field="value" ...> Important Inside of <xpath expr="//some/xpath" position="attributes"> ... </xpath> you can put only <attribute name= and nothing more. 2.4.3 Basic stuff Call method of some model and put result in variable Code: <t t-set="order" t-value="website.sale_get_order()"/> Here website means you use website=True in controller. TODO my be wrong. Get value of some setting ir.config_parameter and put it in variable Code: <t t-set="foobar" t-value="website.env['ir.config_parameter'].get_param('my_module.foobar')"/> Show value of variable Code: <p><t t-esc="foobar"/></p> 30 Chapter 2. Module Development

60. Odoo development Documentation, Release master registry[ ' ir.model.data ' ] . create(cr, SUPERUSER_ID, { ' name ' : name, ' model ' : ' ir.ui.view ' , ' module ' : MODULE, ' res_id ' : view_id, ' noupdate ' : noupdate, }) return view_id yaml file - !python { model : ir.ui.view }: | self._create_debranding_views(cr, uid) __openerp__.py ' uninstall_hook ' : ' uninstall_hook ' , ' data ' : [ ' path/to/file.yml ' ] __init__.py from openerp import SUPERUSER_ID MODULE = ' _web_debranding ' def uninstall_hook (cr, registry): registry[ ' ir.model.data ' ] . _module_data_uninstall(cr, SUPERUSER_ID, [MODULE]) 2.16.2 Odoo database Many to many For every many to many field odoo creating new relations table for example pos_multi_rel with _rel postfix. 2.16.3 Odoo way of shaman What to do if something not work but should to 1. Refresh page 2. Update module 3. Check openerp file depends , demo and other important fields 4. Check odoo config you use to run odoo. Especially adons paths 5. Uninstall and install again modules in depends 6. Clean browser cache 7. Carefully check logs. Look up if needed files loaded or not. May be some errors. 56 Chapter 2. Module Development

91. Odoo development Documentation, Release master cd path/to/odoo sed -i 's/matches="[^"] * "//g' addons/web/static/src/xml/base.xml 2. update html code via Inspect Element tool You must remove the matches field value. odoo/usage/../images/odoo/usage/create-database-change_html.png From terminal 9.0+ To create new database simple add -d parameter when you run odoo, e.g.: ./openerp-server -d database1 – will create new database with name database1 5.2.2 How to enable Technical Features 8.0 • open Settings / Users / Users • select your user • click [Edit] • switch Technical Features on • click [Save] • refresh web page (click F5 ) 9.0+ Since Odoo 9.0 to enable Technical Features you only need to activate developer mode . 5.2.3 How to install/update module There are several ways to installupdate module 5.2. How to use Odoo 87

105. Odoo development Documentation, Release master 7.3 Tmux 7.3.1 Tmux installation Install Tmux sudo apt-get install tmux Check version tmux - V If you have 1.8 or older then you should update. Here are update commands for ubuntu 14.04 sudo apt-get update sudo apt-get install -y python-software-properties software-properties-common sudo add-apt-repository -y ppa:pi-rho/dev sudo apt-get update sudo apt-get install -y tmux=2.0-1~ppa1~t Now if you do tmux -V it should show tmux 2.0 which is a good version for tmux plugins. Based on: http://stackoverflow.com/questions/25940944/ugrade-tmux-from-1-8-to-1-9-on-ubuntu-14-04 Install Tmux Plugin Manager Requirements: tmux version 1.9 (or higher), git , bash Clone TPM: $ git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm Put this at the bottom of .tmux.conf: # List of plugins set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' # Other examples: # set -g @plugin 'github_username/plugin_name' # set -g @plugin 'git@github.com/user/plugin' # set -g @plugin 'git@bitbucket.com/user/plugin' # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run '~/.tmux/plugins/tpm/tpm' Reload TMUX environment so TPM is sourced: # type this in terminal $ tmux source ~/.tmux.conf Based on: https://github.com/tmux-plugins/tpm Install Tmux Resurrect Add plugin to the list of TPM plugins in .tmux.conf: 7.3. Tmux 101

103. Odoo development Documentation, Release master pylint --generate-rcfile >.pylintrc Pylint Odoo plugin Install pylint odoo plugin https://github.com/OCA/pylint-odoo pip install --upgrade git+https://github.com/oca/pylint-odoo.git or pip install --upgrade --pre pylint-odoo Add the plugin in pylintrc. load - plugins = pylint_odoo Useful configurations By default there is 100 characters per line allowed. Allow 120 characters max - line - length = 120 To disable certain warning add its code to disable list in pylintrc. For example, If you don’t like this mes- sage Missing method docstring with code C0111 or this Use of super on an old style class (E1002) disable = E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,C0111,E1002 You can find other codes here: http://pylint-messages.wikidot.com/ Flychek highlights odoo import lines as from openerp import models, fields, api with error message F0401: Unable to import... . There are two options to fix it - http://stackoverflow.com/questions/1899436/pylint-unable-to-import-error-how-to-set-pythonpath . Edit pylintrc to include your odoo directory like this: init - hook = ' import sys; sys.path.append( " /path/to/odoo " ) ' 7.2 PyCharm 7.2.1 PyCharm Remote access with pgAdmin to Odoo postgre database on Ubuntu This is for PgAdmin integration, but same method working with PyCharm. STEP #1 – get pgAdmin Install pgAdmin from pgadmin.org STEP #2 – allow postgre server remote connections from everywhere Open etc/postgresql/9.x/main/pg_hba.conf and add following line: host all all all md5 STEP #3 – let the postgre server listen to everyone Open etc/postgresql/9.x/main/postgresql.conf and change following line: listen_addresses = ‘*’ 7.2. PyCharm 99

85. Odoo development Documentation, Release master • automatic: Runs whenever the system is reconfigured. The launch takes place either after install/upgrade any module or after calling the “execute” method in the “res.config” model. • once: After having been launched manually, it sets automatically to Done. 5.1.9 bus.bus Bus Bus is a module for instant notifications via longpolling. Add it to dependencies list: ' depends ' : [ ' bus ' ] Note: Mail module in odoo 9.0 is already depended on module bus. Warning: Don’t mistake longpolling bus with core.bus which is client-side only and part of web module. What is longpolling • About longpolling • How to enable Longpolling in odoo How to implement longpolling • Scheme of work • Channel identifier • Listened channels • Binding notification event • Start polling • Sending notification • Handling notifications Scheme of work • Specify channels that current client is listening • Bind notification event to your handler • Start polling • Send notification to some channel via python code Channel identifier Channel identifier - is a way to distinguish one channel from another. In the main, channel contains dbname, some string and some id. Added via js identifiers can be string only. 5.1. Models 81

49. Odoo development Documentation, Release master post_install - run test after full installation process. It differs from at_install , because • it runs after calling registry.setup_models(cr) • it runs after calling model._register_hook(cr) Assert Methods https://docs.python.org/2.7/library/unittest.html#assert-methods 2.13.2 JS Testing Regular phantom JS tests For automatic web tests odoo uses phantom_js. You can test you module web mechanics behavior using phantom js. What you need is: • Install phantom. sudo apt-get install phantomjs • Create folder named tests • Add __init__.py file • Create file that name begins from test_ • Add test methods than names start from test_ Example: import openerp.tests @openerp.tests.common.at_install ( False ) @openerp.tests.common.post_install ( True ) class TestUi (openerp . tests . HttpCase): def test_01_mail_sent ( self ): # wait till page loaded and then click and wait again code = """ setTimeout(function () { $( " .mail_sent " ).click(); if (location.href.indexOf( ' channel_sent ' )!=-1) { throw new Error( ' Already on channel_sent. ' ); } setTimeout(function () { if (location.href.indexOf( ' channel_sent ' )==-1) { throw new Error( ' End page is not channel_sent. ' ); } console.log( ' ok ' ); }, 3000); }, 1000); """ link = ' /web#action= %s ' % self . ref( ' mail.mail_channel_action_client_chat ' ) self . phantom_js(link, code, " odoo.__DEBUG__.services[ ' mail_sent.sent ' ] " , login = " demo " ) You need to call phantom_js and give to it arguments: • Starting url • JS code intended for execution 2.13. Tests 45

81. Odoo development Documentation, Release master git tag 9.0-new-module-backup Remote backup git push origin 9.0-new-module:9.0-new-module-backup To restore original state you can use following command: # be sure that you on the branch you are going to change git status # restore from tag git rebase 9.0-new-module-backup -X theirs # restore from remote branchtag git rebase origin/9.0-new-module-backup -X theirs 4.12.2 git commit --amend Instead of creating new commit, adds updates to the latest commit. 4.12.3 git rebase -i Interactive squashing git rebase -i <your-first-commit>^ # e.g. git rebase -i 7801c8b^ Then edit opened file and keep pick for the first commit and and replace pick with squash for the rest ones. E.g. Origin: TODO Edited: TODO Warning: If you remove a line here THAT COMMIT WILL BE LOST. 4.12.4 Push git push -f origin 9.0-new-module 4.12. Squash commits into one 77

12. Odoo development Documentation, Release master • Guidlines • name • summary • category – Hidden • version – version in OCA • author – author in OCA • license • external_dependencies Guidlines Use example below as template. What are important here: • order of attributes • not used attributes are represented • quote characters ( " , """ ) • empty lines • no description attribute • price and currency attributes are commented-out if not used • comma after last item in list (e.g. in ‘depends’ attribute) • add new line symbol at the end of file (i.e. right after last } ) # - * - coding: utf-8 - * - { " name " : """ MODULE_NAME """ , " summary " : """ SHORT_DESCRIPTION_OF_THE_MODULE """ , " category " : " SOME_CATEGORY " , " images " : [], " version " : " 1.0.0 " , " application " : False , " author " : " IT-Projects LLC, DEVELOPER_NAME " , " website " : " https://it-projects.info " , " license " : " GPL-3 " , # "price": 9.00, # "currency": "EUR", " depends " : [ " DEPENDENCY1 " , " DEPENDENCY2 " , ], " external_dependencies " : { " python " : [], " bin " : []}, " data " : [ " FILE1.xml " , " FILE2.xml " , ], " qweb " : [ 8 Chapter 2. Module Development

71. Odoo development Documentation, Release master • __openerp__.py -> ‘images’ • description/index.html 3.7.1 __openerp__.py -> ‘images’ This images is displayed on application page ( example ) and in application list ( example ) Displayed size: • app page: 750 x 400 • app list: 262,5 x 130 Recommended size (aspect) to fit both usage: 750 x 371 You can scale picture, saving proportion. Note: Appearance in app list is more important, as there is less chance that user open app page , if small sized image in app list is not attractive enough. 3.7.2 description/index.html All values assumed, that you put the code inside .oe_container and .oe_row , e.g.: <section class="oe_container"> <div class="oe_row oe_spaced"> ... <div class="oe_demo oe_picture oe_screenshot"> <img class="img img-responsive" src="1.png"/> </div> ... </div> </section> oe_span6 img.oe_demo.oe_picture.oe_screenshot :: max-width: 362px; max-height: 382px; img.oe_demo.oe_picture.oe_screenshot :: max-width: 761px; max-height: 382px; img.oe_demo.oe_screenshot :: max-width: 928px; 3.7. Image sizes 67

80. Odoo development Documentation, Release master 4.9 Commit comment prefix Based on: https://www.odoo.com/documentation/8.0/reference/guidelines.html • [ORIG] for copy-pasted code • [DOC] for documentation. Don’t use any other tags when you improve, fix, refactor documentation • [PORT] for porting • [IMP] for improvements • [FIX] for bug fixes • [REF] for refactoring • [ADD] for adding new resources (new modules or files). • [REM] for removing of resources • [REL] for releases 4.9.1 Forbidden Don’t use tags below • [WIP] , [DEV] – instead of noting that work in progress make message as if your work is already done. 4.10 Git stash • book: https://git-scm.com/book/no-nb/v1/Git-Tools-Stashing • man: https://git-scm.com/docs/git-stash 4.11 Update Git Ubuntu 14.04 official deb repository has 1.9 version of Git. It is too old and have to be updated. http://askubuntu.com/questions/579589/upgrade-git-version-on-ubuntu-14-04 sudo apt-get remove git sudo add-apt-repository ppa:git-core/ppa sudo apt-get update sudo apt-get install git git --version 4.12 Squash commits into one 4.12.1 Backup Before making a squash consider to “backup” your commits. Local backup: 76 Chapter 4. Git and Github

15. Odoo development Documentation, Release master • fix made in 8.0 and ported to 9.0 – [8.0] 1.2.2 – [9.0] 1.2.2 i.e. two module branches cannot have same versions with a different meaning version in OCA While OCA use odoo version in module version (e.g. 8.0.1.0.0 ), we specify odoo version in README.rst file and use three numbers in version (e.g. 1.0.0 ). author Use company first and then developer(s): "author": "IT-Projects LLC, Developer Name", In the main, if module already exists and you make small updatesfixes, you should not add your name to authors. author in OCA For OCA’s repositories put company name first, then OCA. Developers are listed in README file: "author": "IT-Projects LLC, Odoo Community Association (OCA)", license IT-Projects LLC uses following licences: • "GPL-3" for odoo 8.0 and below • "LGPL-3" for odoo 9.0 and above For OCA’s repositories use "AGPL-3" . external_dependencies Check if some python library exists: "external_dependencies": {"python" : ["openid"]} Check if some sytem application exists: "external_dependencies": {"bin" : ["libreoffice"]} doc/changelog.rst Template Use this for new modules .. _changelog: Updates ======= 2.1. Docs and manifests 11

40. Odoo development Documentation, Release master page="True" creates a page as follows below: http://localhost:8069/page/services/ If add in view.xml : <record id = "services_page_link" model = "website.menu" > <field name = "name" >Services</field> <field name = "url" >/page/services</field> <field name = "parent_id" ref = "website.main_menu" /> <field name = "sequence" type = "int" >99</field> </record> This code will add a link to the main menu. 2.10 Point of Sale (POS) 2.10.1 Add new field in the model of POS module To add new field in POS modules necessary in models.js override PosModel in the parent models which we take from “point_of_sale.models”. For example: var models = require( 'point_of_sale.models' ); var _super_posmodel = models.PosModel.prototype; models.PosModel = models.PosModel.extend({ initialize : function (session, attributes) { // New code var partner_model = _.find( this .models, function (model){ return model.model === 'product.product' ; }); partner_model.fields.push( 'qty_available' ); // Inheritance return _super_posmodel.initialize.call( this , session, attributes); }, }); 2.10.2 JS access and inheritance action_button Here you will find explanation of how to get/inherit action_button POS objects. For example we have definition in this file : odoo.define('pos_reprint.pos_reprint', function (require) { ... screens.define_action_button({ 'name': 'guests', 'widget': TableGuestsButton, 'condition': function() This defenition doesn’t return class ReprintButton. So, we cannot inherit it in a usual way. In order to reach that object we need get instance of it using gui . Then we can inherit it To make clear what this is like look up example where guests number button renderings: 36 Chapter 2. Module Development

75. Odoo development Documentation, Release master cherry-pick range of commits The command git cherry-pick A..B applies commits betwwen A and B, but without A (A must be older than B). To apply inclusive range of commits use format as follows: git cherry-pick A^..B For example, to backport this PR https://github.com/it-projects-llc/odoo-saas-tools/pull/286/commits , use command: git cherry-pick 6ee4fa07d4c0adc837d7061e09da14638d8abf8d^..9133939a25f9e163f52e6662045fc2dc6010ac14 4.3 Conflict resolving After making git merge or git cherry-pick there could be conflicts, because some commits try to make changes on the same line. So, you need to choose which change shall be use. It could be one variant, both variants or new variant. What to do if you got conflicts: • Check status git status • Resolve conflicts: – either edit files manually: * open file with conflicts * search for <<< or >>> and delete obsolete variant or make a mix of both variants. – or use following commands, if you are sure which version should be kept git checkout --ours -- <file> # or git checkout --theirs -- <file> • Mark files as resolved via git add command • Done. git push 4.3.1 Deleted files Sometimes, changes can be conflicted because files are not exist anymore in ours version, but updated in theirs . In that case execute the code below in order to ignore such changes: .. code:: bash git status | grep ‘deleted by us’ | awk ‘{print $4}’ | xargs git rm 4.3.2 Notes • It’s important, that on resolving conflict stage you should not make any updates inside conflicting lines. You can only choose which lines should be kept and which deleted. E.g. if you resolve conflicts due to porting some updatefeature from one odoo version (e.g. 8.0) to another (e.g. 9.0), then such changes some time must be tuned to make updatefeature work on target odoo version. But you have to make such tuning on a new commit 4.3. Conflict resolving 71

50. Odoo development Documentation, Release master • Ready criteria. Some JS object that indicates preparedness of web page. In 9.0 it may be odoo.define(‘ mail_archives.archives ‘ ... • User name Use throw new Error(‘Error text’); for errors handling. JS phantom tests using Tours It is possible to run js phantom tests using Tour as JS testing code. To run test automatically after installing module you will need: • Install phantomjs if dont have yet • Inject JS Tour file on web page • Create test as described higher • Call tour Call tour example: class TestUi (openerp . tests . HttpCase): def test_01_res_partner_mails_to_count ( self ): self . phantom_js( ' / ' , " openerp.Tour.run( ' mails_count_tour ' , ' test ' ) " , " openerp.Tour.tours.mails_count_tour " , login = " admin " ) Also odoo must be started with -d , –test-enable and without db-filter , workers . If assumes ti run test only on install or update use -i or -u . Werkzeug must be 0.11.5 or higher. Look up js tour page for details. 2.13.3 Paypal testing To test paypal payments you need to: • Create developer account • Add seller and buyer in developer sandbox • Configure odoo • Directly testing Create developer account Go to https://developer.paypal.com/ and create new account. Add seller and buyer • Go to Dashboard->Sand box->Accounts . Create business (seller) and personal (buyer) accounts. • Add some money to buyer (type amount in according field). • Go to http://sandbox.paypal.com and login as seller. May be you will be forced to apply unconfirmed ssl certificate. • Go to Profile . • Copy protected seller code . 46 Chapter 2. Module Development

9. CHAPTER 2 Module Development 2.1 Docs and manifests 2.1.1 Files All files from this section ought to be fully * 0 prepared before any other files in new module. It helps you to review requirements again before you start. README.rst • Guidlines – OCA’s README • Demo – addons-dev • HTML Description • Usage instructions • Changelog • Tested on Guidlines ============= Module Name ============= Put some short introduction first. Then add more detailed description, technical specifications, any other information that could be interested for other developers. Don't forget that Usage instructions is a separated and has to be located in doc/index.rst file. Credits ======= Contributors ------------ * DEVELOPER_NAME <PERSON@it-projects.info> 0 The only exception could be made for “data” field in __openerp__.py file. 5

67. Odoo development Documentation, Release master { title: _t( " New fields " ), content: _t( " Here is new fields with mails counters. Press one of it. " ), element: ' .mails_to ' , }, { waitNot: ' .mails_to:visible ' , title: _t( " Send message from here " ), placement: ' left ' , content: _t( " Now you can see corresponding mails. You can send mail to this partner right from here. Press <em> ' Send a mesage ' </em>. " ), element: ' .oe_mail_wall .oe_msg.oe_msg_composer_compact>div>.oe_compose_post ' , }, ] } What you do here is describing steps that got to be proceeded by user or phantom (phantomjs). In odoo 8 tour defines this way: (function () { 'use strict'; var _t = openerp._t; openerp.Tour.register({ ... In odoo 9 tour defines that way: odoo.define('account.tour_bank_statement_reconciliation', function(require) { 'use strict'; var core = require('web.core'); var Tour = require('web.Tour'); var _t = core._t; Tour.register({ ... Important details: • id - need to call this tour • path - from this path tour will be started in test mode Next step occurs when all conditions are satisfied and popup window will appear near (chose position in placement ) element specified in element . Element must contain css selector of corresponding node. Conditions may be: • waitFor - this step will not start if waitFor node absent. • waitNot - this step will not start if waitNot node exists. • wait - just wait some amount of milliseconds before next step. • element - similar to waitFor , but element must be visible • closed window - if popup window have close button it must be closed before next step. Opened popup window (from previous step) will close automatically and new window (next step) will be shown. Inject JS Tour file on page: <template id="res_partner_mails_count_assets_backend" name="res_partner_mails_count_assets_backend" inherit_id="web.assets_backend"> <xpath expr="." position="inside"> <script src="/res_partner_mails_count/static/src/js/res_partner_mails_count_tour.js" type="text/javascript"></script> </xpath> </template> 3.5. JS Tour 63

87. Odoo development Documentation, Release master Note: You don’t need to call bus.start_polling(); if it was already started by other module. When polling starts, request /longpolling/poll is sent, so you can find and check it via Network tool in your browser Sending notification You can send notification only through a python. If you need to do it through the client send a signal to server in a usual way first (e.g. via controllers ). self . env[ ' bus.bus ' ] . sendmany([(channel1, message1), (channel2, message2), . . . ]) # or self . env[ ' bus.bus ' ] . sendone(channel, message) Handling notifications on_notification : function (notifications) { // Old versions passes single notification item here. Convert it to the latest format. if ( typeof notification[ 0 ][ 0 ] === 'string' ) { notification = [notification] } for ( var i = 0 ; i < notification.length; i ++ ) { var channel = notification[i][ 0 ]; var message = notification[i][ 1 ]; // proceed a message as you need // ... } }, Examples pos_multi_session: • add channel (python) • bind event • send notification chess: • add channel (js) • bind event • send notification mail_move_message: • add channel (python) • bind event • send notification 5.1. Models 83

32. Odoo development Documentation, Release master To provide a search function on a non stored computed field you have to add a search kwarg on the field. The value is the name of the function as a string or a reference to a previously defined method. The function takes the second and third member of a domain tuple and returns a domain itself def search_total ( self , operator, operand): . . . return domain # e.g. [('id', 'in', ids)] Inverse The inverse key allows to trigger call of the decorated function when the field is written/”created” Multi Fields To have one function that compute multiple values: @api.multi @api.depends ( ' field.relation ' , ' an_otherfield.relation ' ) def _amount ( self ): for x in self : x . total = an_algo x . untaxed = an_algo Related Field There is not anymore fields.related fields. Instead you just set the name argument related to your model: participant_nick = fields . Char(string = ' Nick name ' , related = ' partner_id.name ' ) The type kwarg is not needed anymore. Setting the store kwarg will automatically store the value in database. With new API the value of the related field will be automatically updated, sweet. participant_nick = fields . Char(string = ' Nick name ' , store = True , related = ' partner_id.name ' ) Note: When updating any related field not all translations of related field are translated if field is stored!! Chained related fields modification will trigger invalidation of the cache for all elements of the chain. Property Field There is some use cases where value of the field must change depending of the current company. To activate such behavior you can now use the company_dependent option. A notable evolution in new API is that “property fields” are now searchable. 28 Chapter 2. Module Development

29. Odoo development Documentation, Release master >>> from openerp import fields >>> adate = fields . Date() >>> fields . Date . today() '2014-06-15' >>> fields . Date . context_today( self ) '2014-06-15' >>> fields . Date . context_today( self , timestamp = datetime . datetime . now()) '2014-06-15' >>> fields . Date . from_string(fields . Date . today()) datetime.datetime(2014, 6, 15, 19, 32, 17) >>> fields . Date . to_string(datetime . datetime . today()) '2014-06-15' DateTime Store datetime. The field provide some helper: • context_timestamp returns current day date string based on tz • now returns current system date string • from_string returns datetime.date() from string • to_string returns date string from datetime.date : >>> fields . Datetime . context_timestamp( self , timestamp = datetime . datetime . now()) datetime.datetime(2014, 6, 15, 21, 26, 1, 248354, tzinfo=<DstTzInfo 'Europe/Brussels' CEST+2:00:00 DST>) >>> fields . Datetime . now() '2014-06-15 19:26:13' >>> fields . Datetime . from_string(fields . Datetime . now()) datetime.datetime(2014, 6, 15, 19, 32, 17) >>> fields . Datetime . to_string(datetime . datetime . now()) '2014-06-15 19:26:13' Binary Store file encoded in base64 in bytea column: abin = fields . Binary() Selection Store text in database but propose a selection widget. It induces no selection constraint in database. Selection must be set as a list of tuples or a callable that returns a list of tuples: aselection = fields . Selection([( ' a ' , ' A ' )]) aselection = fields . Selection(selection = [( ' a ' , ' A ' )]) aselection = fields . Selection(selection = ' a_function_name ' ) Specific options: • selection: a list of tuple or a callable name that take recordset as input • size: the option size=1 is mandatory when using indexes that are integers, not strings 2.3. Odoo Python 25

38. Odoo development Documentation, Release master Usage // 8.0 var bus = openerp.web.bus; // 9.0+ var core = require( 'web.core' ); var bus = core.bus; // bind event handler bus.on( 'barcode_scanned' , this , function (barcode) { //... }) // trigger event bus.trigger( 'barcode_scanned' , barcode); 2.8.4 Remote Procedure Call (RPC) Call method / ** * Call a method (over RPC) on the bound OpenERP model. * * @param {String} method name of the method to call * @param {Array} [args] positional arguments * @param {Object} [kwargs] keyword arguments * @param {Object} [options] additional options for the rpc() method * @returns {jQuery.Deferred<>} call result call: function (method, args, kwargs, options) { * / How to call wizard method from js var compose_model = new Model( 'mail.compose.message' ); return compose_model.call( 'create' , [msg, {default_parent_id : options.parent_id}]) .then( function (id){ return compose_model.call( 'send_mail_action' , [id, {}]); }); 2.9 Frontend 2.9.1 Web page Common Open a new project: ./odoo.py scaffold newpage addons Add website as a dependency to newpage : 34 Chapter 2. Module Development

51. Odoo development Documentation, Release master Configure odoo • Install payment_paypal module • Go to Settings->Payments->Payments->Paypal . • Pres Edit . • Enter here Paypal Email ID - it is seller account (like seller@mail.ru ). • Enter Paypal Merchant ID - paste protected seller code . • Set price list currency same as in paypal account. Directly testing Open web shop. Buy some goods and pay with paypal. When you will be redirected on paypal page use buyer login and password. 2.14 Debugging 2.14.1 Logs There are several places where you can get logs. It’s better to activate developer (debug) mode in browser when you are looging for logs. • Error Message • Terminal • Console – boot.js • Sources • Network – How to see html request initiator Error Message It’s a first place where you can see error message. But in most time, it doesn’t contain enough information to resolve problem. Check other possbile ways to get log messages below. Terminal It’s a place where you run odoo. Any errors related to python can be found here Console It’s a short term for browser’s console. Click F12 in browser to open console. It can contain error and warning about client part. 2.14. Debugging 47

65. Odoo development Documentation, Release master < section class = "oe_container" > </ section > < section class = "oe_container" > <!-- Contact us block --> </ section > 3.2 Screenshots tools • Nimbus Screen Screenshot: http://nimbus.everhelper.me/screenshot.php • Shutter: http://shutter-project.org/ sudo add-apt-repository ppa:shutter/ppa sudo apt-get update && sudo apt-get install shutter 3.3 Module description 3.3.1 Main screenshot The main screenshot displayed only in Odoo Apps should be located in the path_to_module/images/ directory and its size should not exceed 1500x1000 px. Next, in the __openerp__.py file you need make the relevant record: 'images' : [ 'images/main-screenshot.png' ] 3.3.2 Icon and index.html The module icon needs to be located at path_to_module/static/description/ and it must be called icon.png . Also in this directory you need to create index.html , where will be contained necessary HTML tags, text description and screenshots (the recommended size is 752x352 px). See also: See the official template https://github.com/odoo/odoo/blob/master/addons/crm/static/description/index.html It is important that index.html and screenshots it contains should be included at the same folder. The result of the index.html and icon appearance can be checked by opening the module in “Local Modules” of your Odoo instance. 3.3.3 Summary This is an overview of content that provides a reader with the overaching theme, but does not expand on specific details. Summary should be included at __openerp__.py as ’summary’: """Summary text""" . For example: 'summary' : "" "Use multiple POS for handling orders" "" 3.2. Screenshots tools 61

92. Odoo development Documentation, Release master • From App store (install) – 8.0 – 9.0+ • From App store (update) – 8.0 – 9.0+ • From zip archive • From addons path on server From App store (install) 8.0 • navigate to Settings / Modules / Apps • remove Featured [x] filter • search module you need • click [Install] 9.0+ • activate developer mode . • navigate to Apps menu • click on second Apps menu in left side bar • remove Featured [x] filter • search module you need • click [Install] From App store (update) 8.0 • navigate to Settings / Modules / Updates 9.0+ • navigate to Apps menu • click Updates menu in left side bar From zip archive TODO 88 Chapter 5. Odoo

33. Odoo development Documentation, Release master WIP copyable option There is a dev running that will prevent to redefine copy by simply setting a copy option on fields: copy = False # !! WIP to prevent redefine copy 2.3.8 Model constraints Odoo provides two ways to set up automatically verified invariants: Python constraints and SQL constraints . A Python constraint is defined as a method decorated with constrains() , and invoked on a recordset. The deco- rator specifies which fields are involved in the constraint, so that the constraint is automatically evaluated when one of them is modified. The method is expected to raise an exception if its invariant is not satisfied: from openerp.exceptions import ValidationError @api.constrains ( ' age ' ) def _check_something ( self ): for record in self : if record . age > 20 : raise ValidationError( " Your record is too old: %s " % record . age) # all records passed the test, don't return anything SQL constraints are defined through the model attribute _sql_constraints . The latter is assigned to a list of triples of strings (name, sql_definition, message) , where name is a valid SQL constraint name, sql_definition is a table_constraint_ expression, and message is the error message. 2.4 XML 2.4.1 Create record of model Create new record: <openerp> <data> <record id="demo_multi_session" model="pos.multi_session"> <field name="name">multi session demo</field> </record> </data> openerp> If model exist it will be modifyed. Record creating in module it declareted. To change model created in another module add mule name before id: <openerp> <data> <record id="point_of_sale.pos_config_main" model="pos.config"> <field name="multi_session_id" ref="demo_multi_session"/> </record> </data> openerp> 2.4. XML 29

59. Odoo development Documentation, Release master noupdate=True If for some reason you cannot use noupdate=False, you can use following trick. Here is the example from web_debranding module. To create records in ir.model.data we use name _web_debranding . Then odoo will consider such records as belonging to another module ( _web_debranding ) and will not delete them. But it also means, that odoo will not delete them after uninstalling. For later case, we need to use uninstall_hook . Contents • Dynamic records – noupdate=False – noupdate=True * python file * yaml file * __openerp__.py * __init__.py python file from openerp import SUPERUSER_ID, models, tools, api MODULE = ' _web_debranding ' class view (models . Model): _inherit = ' ir.ui.view ' def _create_debranding_views ( self , cr, uid): self . _create_view(cr, uid, ' menu_secondary ' , ' web.menu_secondary ' , ''' <xpath expr= " //div[@class= ' oe_footer ' ] " position= " replace " > <div class= " oe_footer " ></div> </xpath> ''' ) def _create_view ( self , cr, uid, name, inherit_id, arch, noupdate = False , type = ' qweb ' ): registry = self . pool view_id = registry[ ' ir.model.data ' ] . xmlid_to_res_id(cr, SUPERUSER_ID, " %s . %s " % (MODULE, name)) if view_id: registry[ ' ir.ui.view ' ] . write(cr, SUPERUSER_ID, [view_id], { ' arch ' : arch, }) return view_id try : view_id = registry[ ' ir.ui.view ' ] . create(cr, SUPERUSER_ID, { ' name ' : name, ' type ' : type , ' arch ' : arch, ' inherit_id ' : registry[ ' ir.model.data ' ] . xmlid_to_res_id(cr, SUPERUSER_ID, inherit_id, raise_if_not_found = True ) }) except : import traceback traceback . print_exc() return 2.16. Other 55

86. Odoo development Documentation, Release master var channel = JSON.stringify([dbname, 'model.name' , uid]); Added via python identifiers can be a string or any data structure. # tuple channel = (request . db, ' model.name ' , request . uid) # or a string channel = ' [ " %s " , " %s " , " %s " ] ' % (request . db, ' model.name ' , request . uid) Warning: JSON.stringify in js and json.dumps in python could give a different result. Listened channels You can add channels in two ways: either on the server side via _poll function in bus controller or in js file using the method bus.add_channel() . With controllers: # In odoo 8.0: import openerp.addons.bus.bus.Controller as BusController # In odoo 9.0: import openerp.addons.bus.controllers.main.BusController class Controller (BusController): def _poll ( self , dbname, channels, last, options): if request . session . uid: registry, cr, uid, context = request . registry, request . cr, request . session . uid, request . context new_channel = (request . db, ' module.name ' , request . uid) channels . append(new_channel) return super (Controller, self ) . _poll(dbname, channels, last, options) In the js file: // 8.0 var bus = openerp.bus.bus; // 9.0+ var bus = require( 'bus.bus' ).bus; var channel = JSON.stringify([dbname, 'model.name' , uid]); bus.add_channel(new_channel); Binding notification event In js file: bus.on( "notification" , this , this .on_notification); Start polling In js file: bus.start_polling(); 82 Chapter 5. Odoo

90. Odoo development Documentation, Release master Consider a scenario where multiple users are working in a single project.Various parameters for that project are already configured like deadline,Initially Planned Hours etc. Now one of the user changes the value of Planned Hours. So now it is important to know which user has changed it and what was the previous value. We can track it by creating message subtypes in Odoo as following. It needs to be defined in XML which will have following syntax. <record id= "mt_task_planned_hours" model= "mail.message.subtype" > <field name= "name" > Task planned hours changed </field> <field name= "res_model" > project.task </field> <field name= "default" eval= "True" /> <field name= "description" > Task planned hours changed </field> </record> Users can also have a mail.message.subtype that depends on an other to act through a relation field. For the planned hours, we can have following sysntax for it. <record id= "mt_task_planned_hours_change" model= "mail.message.subtype" > <field name= "name" > Task planned hours changed </field> <field name= "sequence" > 10 </field> <field name= "res_model" > project.task </field> <field name= "parent_id" eval= "ref('mt_task_planned_hours')" /> <field name= "relation_field" > project_id </field> </record> Odoo provide feature to track various events related with one particular document with the help of _track attribute. If we inherit mail.thread object then with the help of _track attribute, user can sent notification also to keep aware others about changes happening against this particular document. The syntax can be as follow. _track = { 'planned_hours' : { 'module_name.mt_task_planned_hours' : lambda self, cr, uid, obj, ctx = None: obj.planned_hours, } , In order to track changes related with any field,Odoo provides an attribute named as track_visibility.It has to be defined at field level which has below syntax. planned_hours = fields.Float ( string = 'Initially Planned Hours' , track_visibility = 'onchange' , help = 'Estimated time to do the task, it is project manager when the task is in draft state.' ) Hence, it is easy to track the changes done so far against any particular document by different users. 5.2 How to use Odoo 5.2.1 How to create database From UI To create new database open /web/database/manager 8.0- Database with dots Early version of odoo doesn’t allow to create databases with dots. You can remove this restric- tion in two ways: 1. Updates sources: 86 Chapter 5. Odoo

14. Odoo development Documentation, Release master • Marketing • Point of Sale • Productivity • Project • Purchases • Sales • Warehouse • Website • Extra Tools Hidden For technical modules Hidden category can be used: "category": "Hidden", Such modules are excluded from search results on app store. version Note: whenever you change version, you have to add a record in changelog.rst The x.y.z version numbers follow the semantics breaking.feature.fix : • x increments when the data model or the views had significant changes. Data migration might be needed, or depending modules might be affected. • y increments when non-breaking new features are added. A module upgrade will probably be needed. • z increments when bugfixes were made. Usually a server restart is needed for the fixes to be made available. On each version change a record in doc/changelog.rst should be added. If a module ported to different odoo versions (e.g. 8 and 9) and some update is added only to one version (e.g. 9), then version is changed as in example below: • init – [8.0] 1.0.0 – [9.0] 1.0.0 • feature added to 8.0 and ported to 9.0 – [8.0] 1.1.0 – [9.0] 1.1.0 • feature added to 9.0 only and not going to be ported to 8.0: – [8.0] 1.1.0 – [9.0] 1.2.0 • fix made in 9.0 only and not going to be ported to 8.0: – [8.0] 1.1.0 – [9.0] 1.2.1 10 Chapter 2. Module Development

63. CHAPTER 3 User documentation 3.1 static/description/index.html • Image sizes • Templates – Title – Text + Image – Image + Text – Text, Image – Contact us • oe_dark 3.1.1 Image sizes • Image Sizes 3.1.2 Templates Title < section class = "oe_container" > < div class = "oe_row oe_spaced" > < div class = "oe_span12" > < h2 class = "oe_slogan" >NAME</ h2 > < h3 class = "oe_slogan" >SUMMARY OR SLOGAN</ h3 > </ div > </ div > </ section > Text + Image < section class = "oe_container oe_dark" > < div class = "oe_row oe_spaced" > < div class = "oe_span6" > < p class = "oe_mt32" > 59

88. Odoo development Documentation, Release master 5.1.10 ir.cron Creating automated actions in Odoo Schedulers are automated actions that run automatically over a time period and can do a lot of things. They give the ability to execute actions database without needing manual interaction. Odoo makes running a background job easy: simply insert a record to ir.cron table and Odoo will execute it as defined. 1. Creating the model and method of this model. class model_name ( models.Model ) : _name = "model.name" # fields def method_name ( self, cr, uid, context = None ) : # method of this model # your code 2. Creating the automated action If you want to build new modules in the guidelines from Odoo you should add the code for an automated action under yourDefaultModule/data/ in a separate XML file. An important thing to note with automated actions is that they should always be defined within a noupdate field since this shouldn’t be updated when you update your module. <openerp > <data noupdate= "1" > <record id= "unique_name" model= "ir.cron" > <field name= "name" > Name </field> <field name= "active" eval= "True" /> <field name= "user_id" ref= "base.user_root" /> <field name= "interval_number" > 1 </field> <field name= "interval_type" > days </field> <field name= "numbercall" > -1 </field> <field name= "doal" > 1 </field> <!-- <field name="nextcall" >2016 - 12 - 31 23:59:59</field> --> <field name= "model" eval= "'model.name '" /> <field name= "function" eval= "'method_name '" /> <field name= "args" eval= "" /> <!-- <field name="priority" eval="5" /> --> </record> </data> </openerp> The first thing you notice is the data noupdate="1" , this is telling Odoo that all code within this tag shouldn’t be updated when you update your module. <record id= "unique_name" model= "ir.cron" > The id is an unique identifier for Odoo to know what record is linked to which id. The model called (“ir.cron”) is the model specifically made by Odoo for all automated actions. This model contains all automated actions and should always be specified. <field name= "name" > Name </field> The next line is the name. <field name= "active" eval= "True" /> Boolean value indicating whether the cron job is active or not. 84 Chapter 5. Odoo

25. Odoo development Documentation, Release master _columns = { ' default_foo ' : fields . type( . . . , default_model = ' my.model ' ), ' group_bar ' : fields . boolean( . . . , group = ' base.group_user ' , implied_group = ' my.group ' ), ' module_baz ' : fields . boolean( . . . ), ' other_field ' : fields . type( . . . ), } The method execute ( Apply button) provides some support based on a naming convention: • For a field like default_XXX , execute sets the (global) default value of the field XXX in the model named by default_model to the field’s value. • For a boolean field like group_XXX , execute adds/removes ‘implied_group’ to/from the implied groups of ‘group’, depending on the field’s value. By default ‘group’ is the group Employee. Groups are given by their xml id. The attribute ‘group’ may contain several xml ids, separated by commas. • For a boolean field like module_XXX , execute triggers the immediate installation of the module named XXX if the field has value True . • For the other fields, the method execute invokes all methods with a name that starts with set_ ; such methods can be defined to implement the effect of those fields. The method default_get retrieves values that reflect the current status of the fields like default_XXX , group_XXX and module_XXX . It also invokes all methods with a name that starts with get_default_ ; such methods can be defined to provide current values for other fields. Example This for website.config.settings but it is similar to res.config.settings: class website_config_settings (models . TransientModel): _inherit = ' website.config.settings ' nobill_noship = fields_new_api . Boolean( " Pickup and pay at store " ) #When you press Apply def set_nobill_noship ( self , cr, uid, ids, context = None ): config_parameters = self . pool . get( " ir.config_parameter " ) for record in self . browse(cr, uid, ids, context = context): config_parameters . set_param(cr, uid, " website_sale_checkout_store.nobill_noship " , record . nobill_noship or ' ' , context = context) #When page loads def get_default_nobill_noship ( self , cr, uid, ids, context = None ): nobill_noship = self . pool . get( " ir.config_parameter " ) . get_param(cr, uid, " website_sale_checkout_store.nobill_noship " , default = False , context = context) return { ' nobill_noship ' : nobill_noship} #website_sale_checkout_store - is your module 2.3.4 Update settings on module install To update settings from any res.config.settings do as follows: default_XXX TODO group_XXX Add implied group(s) to a group via implied_ids field: 2.3. Odoo Python 21

26. Odoo development Documentation, Release master <record model="res.groups" id="base.group_user"> <field name="implied_ids" eval="[ (4, ref('my.group')) ]"/> </record> module_XXX Add XXX to the “depends” parameter in the __openerp__.py file 2.3.5 Web controllers Send values to web page If you need to transmit on rendering page some vars, you need to put that vars in dictionary and place it as second argument: @http.route(['/shop/checkout'], type='http', auth="public", website=True) def checkout(self, ** post): ... values['order'] = order return request.website.render("website_sale.checkout", values) 2.3.6 x2many values filling To fill or manipulate one2many or many2many field with according values (records) you need to use special command as says below. This format is a list of triplets executed sequentially, where each triplet is a command to execute on the set of records. Not all commands apply in all situations. Possible commands are: • (0, _, values) adds a new record created from the provided value dict. • (1, id, values) updates an existing record of id id with the values in values . Can not be used in ~.create . • (2, id, _) removes the record of id id from the set, then deletes it (from the database). Can not be used in ~.create . • (3, id, _) removes the record of id id from the set, but does not delete it. Can not be used on ~open- erp.fields.One2many . Can not be used in ~.create . • (4, id, _) adds an existing record of id id to the set. Can not be used on ~openerp.fields.One2many . • (5, _, _) removes all records from the set, equivalent to using the command 3 on every record explicitly. Can not be used on ~openerp.fields.One2many . Can not be used in ~.create . • (6, _, ids) replaces all existing records in the set by the ids list, equivalent to using the command 5 followed by a command 4 for each id in ids . Can not be used on ~openerp.fields.One2many . Note: Values marked as _ in the list above are ignored and can be anything, generally 0 or False . Taken from https://github.com/odoo/odoo/blob/9.0/openerp/models.py 22 Chapter 2. Module Development

64. Odoo development Documentation, Release master TEXT </ p > </ div > < div class = "oe_span6" > < div class = "oe_row_img oe_centered" > < img class = "oe_demo oe_picture oe_screenshot" src = "IMAGE.png" /> </ div > </ div > </ div > </ section > Image + Text TODO Text, Image < section class = "oe_container oe_dark" > < div class = "oe_row oe_spaced" > < div class = "oe_span12 text-center" > < p class = "oe_mt32" > TEXT </ p > </ div > < div class = "oe_row_img oe_centered" > < img class = "oe_demo oe_picture oe_screenshot" src = "IMAGE.png" /> </ div > </ div > </ section > Contact us • Contact us block 3.1.3 oe_dark Use oe_dark class on every even section . Don’t use oe_dark on the last section Contact us . < section class = "oe_container" > <!-- Title --> </ section > < section class = "oe_container" > </ section > < section class = "oe_container oe_dark" > </ section > < section class = "oe_container" > </ section > < section class = "oe_container oe_dark" > </ section > 60 Chapter 3. User documentation

89. Odoo development Documentation, Release master <field name= "user_id" ref= "base.user_root" /> This user id is referring to a specific user, in most cases this will be base.user_root. <field name= "interval_number" > 1 </field> Number of times the scheduler is to be called based on the “interval_type” <field name= "interval_type" > days </field> Interval Unit. It should be one value for the list: minutes , hours , days , weeks , months . <field name= "numbercall" > -1 </field> An integer value specifying how many times the job is executed. A negative value means no limit. <field name= "doal" > 1 </field> A boolean value indicating whether missed occurrences should be executed when the server restarts. <field name= "nextcall" > 2016-12-31 23:59:59 </field> <!-- notice the date/time format --> Next planned execution date for this job. <field name= "model" eval= "'model.name '" /> The field model specifies on which model the automated action should be called. <field name= "function" eval= "'method_name '" /> Name of the method to be called when this job is processed. <field name= "args" eval= "" /> The arguments to be passed to the method. <field name= "priority" eval= "5" /> The priority of the job, as an integer: 0 means higher priority, 10 means lower priority. Defaults. Name Definition nextcall lambda * a: time.strftime(DEFAULT_SERVER_DATETIME_FORMAT priority 5 user_id lambda obj,cr,uid,context: uid interval_number 1 interval_type months numbercall 1 active 1 doall 1 5.1.11 mail.message Message Subtypes in Odoo Most of the time in Odoo multiple users work upon one particular record or document like sale order,Invoice ,Tasks etc. In such scenarios,it becomes extremely important to track changes done by every individual against that document. It helps management to find any possible reason in case of any issue occurs. Odoo provides this feature to great extent with the help of OpenChatter Integration. 5.1. Models 85

Views

  • 276 Total Views
  • 209 Website Views
  • 67 Embeded Views

Actions

  • 0 Social Shares
  • 0 Likes
  • 0 Dislikes
  • 0 Comments

Share count

  • 0 Facebook
  • 0 Twitter
  • 0 LinkedIn
  • 0 Google+

Embeds 1

  • 2 www.elsaka.com