+++ /dev/null
-======
-Guides
-======
-
-.. toctree::
- :titlesonly:
-
- guides/forms
- guides/themes
- guides/snippets
- guides/workflows
- guides/deployment
+++ /dev/null
-.. _guides/deployment:
-
-=======================
-Deploying to production
-=======================
+++ /dev/null
-.. highlight:: xml
-
-.. _form-view-guidelines:
-
-Form Views Guidelines
-=====================
-
-.. sectionauthor:: Aline Preillon, Raphael Collet
-
-This document presents functional and technical guidelines for
-creating/organizing form views in Odoo. For each item, both the functional and
-technical aspects are explained. The goal of the new style of forms is to make
-Odoo easier to use, and to guide users through the system.
-
-Business Views
---------------
-
-Business views are targeted at regular users, not advanced users. Examples
-are: Opportunities, Products, Partners, Tasks, Projects, etc.
-
-.. image:: forms/oppreadonly.png
- :class: img-responsive
-
-In general, a business view is composed of
-
-1. a status bar on top (with technical or business flow),
-2. a sheet in the middle (the form itself),
-3. a bottom part with History and Comments.
-
-Technically, the new form views are structured as follows in XML::
-
- <form>
- <header> ... content of the status bar ... </header>
- <sheet> ... content of the sheet ... </sheet>
- <div class="oe_chatter"> ... content of the bottom part ... </div>
- </form>
-
-The Status Bar
-''''''''''''''
-
-The purpose of the status bar is to show the status of the current record and
-the action buttons.
-
-.. image:: forms/status.png
- :class: img-responsive
-
-The Buttons
-...........
-
-The order of buttons follows the business flow. For instance, in a sale order,
-the logical steps are:
-
-1. Send the quotation
-2. Confirm the quotation
-3. Create the final invoice
-4. Send the goods
-
-Highlighted buttons (in red by default) emphasize the logical next step, to
-help the user. It is usually the first active button. On the other hand,
-:guilabel:`cancel` buttons *must* remain grey (normal). For instance, in
-Invoice the button :guilabel:`Refund` must never be red.
-
-Technically, buttons are highlighted by adding the class "oe_highlight"::
-
- <button class="oe_highlight" name="..." type="..." states="..."/>
-
-The Status
-..........
-
-Uses the ``statusbar`` widget, and shows the current state in red. States
-common to all flows (for instance, a sale order begins as a quotation, then we
-send it, then it becomes a full sale order, and finally it is done) should be
-visible at all times but exceptions or states depending on particular sub-flow
-should only be visible when current.
-
-.. image:: forms/status1.png
- :class: img-responsive
-
-.. image:: forms/status2.png
- :class: img-responsive
-
-The states are shown following the order used in the field (the list in a
-selection field, etc). States that are always visible are specified with the
-attribute ``statusbar_visible``.
-
-``statusbar_colors`` can be used to give a custom color to specific states.
-
-::
-
- <field name="state" widget="statusbar"
- statusbar_visible="draft,sent,progress,invoiced,done"
- statusbar_colors="{'shipping_except':'red','waiting_date':'blue'}"/>
-
-The Sheet
-'''''''''
-
-All business views should look like a printed sheet:
-
-.. image:: forms/sheet.png
- :class: img-responsive
-
-1. Elements inside a ``<form>`` or ``<page>`` do not define groups, elements
- inside them are laid out according to normal HTML rules. They content can
- be explicitly grouped using ``<group>`` or regular ``<div>`` elements.
-2. By default, the element ``<group>`` defines two columns inside, unless an
- attribute ``col="n"`` is used. The columns have the same width (1/n th of
- the group's width). Use a ``<group>`` element to produce a column of fields.
-3. To give a title to a section, add a ``string`` attribute to a ``<group>`` element::
-
- <group string="Time-sensitive operations">
-
- this replaces the former use of ``<separator string="XXX"/>``.
-4. The ``<field>`` element does not produce a label, except as direct children
- of a ``<group>`` element\ [#backwards-compatibility]_. Use :samp:`<label
- for="{field_name}>` to produce a label of a field.
-
-Sheet Headers
-.............
-
-Some sheets have headers with one or more fields, and the labels of those
-fields are only shown in edit mode.
-
-.. list-table::
- :header-rows: 1
-
- * - View mode
- - Edit mode
- * - .. image:: forms/header.png
- :class: img-responsive
- - .. image:: forms/header2.png
- :class: img-responsive
-
-Use HTML text, ``<div>``, ``<h1>``, ``<h2>``… to produce nice headers, and
-``<label>`` with the class ``oe_edit_only`` to only display the field's label
-in edit mode. The class ``oe_inline`` will make fields inline (instead of
-blocks): content following the field will be displayed on the same line rather
-than on the line below it. The form above is produced by the following XML::
-
- <label for="name" class="oe_edit_only"/>
- <h1><field name="name"/></h1>
-
- <label for="planned_revenue" class="oe_edit_only"/>
- <h2>
- <field name="planned_revenue" class="oe_inline"/>
- <field name="company_currency" class="oe_inline oe_edit_only"/> at
- <field name="probability" class="oe_inline"/> % success rate
- </h2>
-
-Button Box
-..........
-
-Many relevant actions or links can be displayed in the form. For example, in
-Opportunity form, the actions "Schedule a Call" and "Schedule a Meeting" take
-an important place in the use of the CRM. Instead of placing them in the
-"More" menu, put them directly in the sheet as buttons (on the top right) to
-make them more visible and more easily accessible.
-
-.. image:: forms/header3.png
- :class: img-responsive
-
-Technically, the buttons are placed inside a <div> to group them as a block on
-the right-hand side of the sheet.
-
-::
-
- <div class="oe_button_box oe_right">
- <button string="Schedule/Log Call" name="..." type="action"/>
- <button string="Schedule Meeting" name="action_makeMeeting" type="object"/>
- </div>
-
-Groups and Titles
-.................
-
-A column of fields is now produced with a ``<group>`` element, with an
-optional title.
-
-.. image:: forms/screenshot-03.png
- :class: img-responsive
-
-::
-
- <group string="Payment Options">
- <field name="writeoff_amount"/>
- <field name="payment_option"/>
- </group>
-
-It is recommended to have two columns of fields on the form. For this, simply
-put the ``<group>`` elements that contain the fields inside a top-level
-``<group>`` element.
-
-To make :ref:`view extension <reference/views/inheritance>` simpler, it is
-recommended to put a ``name`` attribute on ``<group>`` elements, so new fields
-can easily be added at the right place.
-
-Special Case: Subtotals
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Some classes are defined to render subtotals like in invoice forms:
-
-.. image:: forms/screenshot-00.png
- :class: img-responsive
-
-::
-
- <group class="oe_subtotal_footer">
- <field name="amount_untaxed"/>
- <field name="amount_tax"/>
- <field name="amount_total" class="oe_subtotal_footer_separator"/>
- <field name="residual" style="margin-top: 10px"/>
- </group>
-
-Placeholders and Inline Fields
-..............................
-
-Sometimes field labels make the form too complex. One can omit field labels,
-and instead put a placeholder inside the field. The placeholder text is
-visible only when the field is empty. The placeholder should tell what to
-place inside the field, it *must not* be an example as they are often confused
-with filled data.
-
-One can also group fields together by rendering them "inline" inside an
-explicit block element like `<div>``. This allows grouping semantically
-related fields as if they were a single (composite) fields.
-
-The following example, taken from the *Leads* form, shows both placeholders and
-inline fields (zip and city).
-
-.. list-table::
- :header-rows: 1
-
- * - Edit mode
- - View mode
- * - .. image:: forms/placeholder.png
- :class: img-responsive
- - .. image:: forms/screenshot-01.png
- :class: img-responsive
-
-::
-
- <group>
- <label for="street" string="Address"/>
- <div>
- <field name="street" placeholder="Street..."/>
- <field name="street2"/>
- <div>
- <field name="zip" class="oe_inline" placeholder="ZIP"/>
- <field name="city" class="oe_inline" placeholder="City"/>
- </div>
- <field name="state_id" placeholder="State"/>
- <field name="country_id" placeholder="Country"/>
- </div>
- </group>
-
-Images
-......
-
-Images, like avatars, should be displayed on the right of the sheet. The
-product form looks like:
-
-.. image:: forms/screenshot-02.png
- :class: img-responsive
-
-The form above contains a <sheet> element that starts with::
-
- <field name="product_image" widget="image" class="oe_avatar oe_right"/>
-
-Tags
-....
-
-Most :class:`~openerp.fields.Many2many` fields, like categories, are better
-rendered as a list of tags. Use the widget ``many2many_tags`` for this:
-
-.. image:: forms/screenshot-04.png
- :class: img-responsive
-
-::
-
- <field name="category_id"
- widget="many2many_tags"/>
-
-Task-based forms
-----------------
-
-Configuration Forms
-'''''''''''''''''''
-
-Examples of configuration forms: Stages, Leave Type, etc. This concerns all
-menu items under Configuration of each application (like Sales/Configuration).
-
-.. image:: forms/nosheet.png
- :class: img-responsive
-
-For those views, the guidelines are:
-
-1. no header (because no state, no workflow, no button)
-2. no sheet
-
-Regular Wizards (dialog)
-''''''''''''''''''''''''
-
-Example: "Schedule a Call" from an opportunity.
-
-.. image:: forms/wizard-popup.png
- :class: img-responsive
-
-The guidelines are:
-
-1. avoid separators (the title is already in the popup title bar, so another
- separator is not relevant)
-2. avoid cancel buttons (user generally close the popup window to get the same
- effect)
-3. action buttons must be highlighted (red)
-4. when there is a text area, use a placeholder instead of a label or a
- separator
-5. like in regular form views, put buttons in the <header> element
-
-Configuration Wizard
-''''''''''''''''''''
-
-Example: Settings / Configuration / Sales. The guidelines are:
-
-1. always in line (no popup)
-2. no sheet
-3. keep the cancel button (users cannot close the window)
-4. the button "Apply" must be red
-
-.. [#backwards-compatibility] for backwards compatibility reasons
+++ /dev/null
-========
-Snippets
-========
+++ /dev/null
-.. highlight:: xml
-
-===============
-Creating themes
-===============
-
-Basic set up
-============
-
-Create a basic theme module with :command:`odoo.py scaffold` and the ``theme``
-template: from the root odoo folder, use
-
-.. code-block:: console
-
- $ ./odoo.py scaffold -t theme "Dummy Theme" addons
-
-this should create a new folder ``dummy_theme`` in the ``addons`` directory
-with the structure:
-
-.. code-block:: text
-
- addons/dummy_theme
- |-- __init__.py
- |-- __openerp__.py
- |-- static
- | `-- style
- | `-- custom.less
- `-- views
- |-- options.xml
- |-- pages.xml
- `-- snippets.xml
-
-``static/styles`` contains your stylesheet(s), ``views`` contains the various
-XML files describing the theme and theme features to Odoo.
-
-Static Page
------------
-
-Creating a new template
-'''''''''''''''''''''''
-
-Create a new file :file:`odoo/addons/theme_dummy/views/pages.xml` and open it.
-
-In odoo, a page means a new template. You don't need special skills, simply
-copy paste the lines::
-
- <template id="website.hello" name="Homepage" page="True">
- <t t-call="website.layout">
- <div id="wrap" class="oe_structure oe_empty">
- </div>
- </t>
- </template>
-
-Refresh the page and feel the hit.
-
-Editing content on a page
-'''''''''''''''''''''''''
-
-You can now add you content! You should always use the Bootstrap structure as
-below::
-
- <template id="website.hello" name="Homepage" page="True">
- <t t-call="website.layout">
- <div id="wrap" class="oe_structure oe_empty">
- <section>
- <div class="container">
- <div class="row">
- <h1>This is Your Content</h1>
- <p>Isn't amazing to edit everything inline?</p>
- <hr/>
- </div>
- </div>
- </section>
- </div>
- </t>
- </template>
-
-Adding new item in the menu
-'''''''''''''''''''''''''''
-
-Adding these few more lines will put the new page in your menu::
-
- <record id="hello_menu" model="website.menu">
- <field name="name">Hello</field>
- <field name="url">/page/hello</field>
- <field name="parent_id" ref="website.main_menu"/>
- <field name="sequence" type="int">20</field>
- </record>
-
-Congrats! It's online! Now drag and drop some snippets on the page and let's
-style!
-
-Pimp Your Theme
----------------
-
-Easy styling with less
-''''''''''''''''''''''
-
-In ``odoo/addons/theme_dummy/static`` create a new folder and name it
-``style``. In the new folder ``odoo/addons/theme_dummy/static/style`` create a
-file and name it ``custom.less``. Open ``custom.less`` in the text editor and
-modify these lines as below:
-
-
-.. code-block:: css
-
- .h1 {
- color: #215487;
- }
- .span {
- border: 2px solid black;
- background-color: #eee;
- }
-
-Refresh the page and feel the hit.
-
-Get the most of the dom
-'''''''''''''''''''''''
-
-Right-Click, inspect element. You can go deeper by styling the main layout
-container. Here we try with the 'wrapwrap' id.
-
-.. code-block:: css
-
- #wrapwrap {
- background-color: #222;
- width: 80%;
- margin: 0 auto;
- }
-
-Easy layout with bootstrap
-''''''''''''''''''''''''''
-
-Open :file:`odoo/addons/theme_dummy/views/pages.xml` and add a new section::
-
- <section>
- <div class="container">
- <div class="row">
- <div class="alert alert-primary" role="alert">
- <a href="#" class="alert-link">...</a>
- </div>
- <div class="col-md-6 bg-blue">
- <h2>BLUE it!</h2>
- </div>
- <div class="col-md-6 bg-green">
- <h2>GREEN THAT!</h2>
- </div>
- </div>
- </div>
- </section>
-
-Refresh the page and check how it looks.
-
-The background of the alert component is the default Bootstrap primary color.
-The two other div your created have no custom styles applied yet. Open
-:file:`odoo/addons/theme_dummy/static/style/custom.less` and add these lines:
-
-.. code-block:: css
-
- @brand-primary: #1abc9c;
- @color-blue: #3498db;
- @color-green: #2ecc71;
-
- .bg-blue { background: @color-blue; }
- .bg-green { background: @color-green; }
-
- .h2 { color: white; }
-
-As you see, the default primary has changed and your new colors are shining!
-
-Build Your First Snippet
-------------------------
-
-Setting up __openerp__.py
-'''''''''''''''''''''''''
-
-Open ``__openerp__.py`` and add a new line as below:
-
-.. code-block:: python
-
- {
- 'name': 'Dummy Theme',
- 'description': 'Dummy Theme',
- 'category': 'Website',
- 'version': '1.0',
- 'author': 'OpenERP SA',
- 'depends': ['website'],
- 'data': [
- 'views/snippets.xml',
- ],
- 'application': True,
- }
-
-In ``odoo/addons/theme_learn/views`` create a new xml file, name it
-``snippets.xml`` and open it in a text editor
-
-Add your snippet in the menu
-''''''''''''''''''''''''''''
-
-Before typing your html code, you need to locate it in the WEBb. drop-down
-menu. In this case, we will add it at the end of the Structure section::
-
- <template id="snippets" inherit_id="website.snippets" name="Clean Theme snippets">
- <xpath expr="//div[@id='snippet_structure']" position="inside">
- </xpath>
- </template>
-
-Now open a new div, do not give it any id or classes. It will contain your
-snippet::
-
- <xpath expr="//div[@id='snippet_structure']" position="inside">
- <div>
- </div>
- </xpath>
-
-A thumbnail is also needed to create a more attractive link in the menu. You
-can use labels to focus on your themes snippets. Simply add a new div with
-the class ``oe_snippet_thumbnail`` and add your thumbnail image (100x79px)::
-
- <xpath expr="//div[@id='snippet_structure']" position="inside">
- <div>
- <div class="oe_snippet_thumbnail">
- <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
- <span class="oe_snippet_thumbnail_title">SNIP IT!</span>
- </div>
- </div>
- </xpath>
-
-And voila! Your new snippet is now ready to use. Just drag and drop it on your
-page to see it in action.
-
-The snippet body
-''''''''''''''''
-
-A snippet has to be in a section with the class ``oe_snippet_body`` to work
-correctly. As Odoo use the Bootstrap framework, you have use containers and
-rows to hold your content. Please refer the the Bootstrap documentation::
-
- <xpath expr="//div[@id='snippet_structure']" position="inside">
- <div>
- <div class="oe_snippet_thumbnail">
- <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
- <span class="oe_snippet_thumbnail_title">SNIP IT!</span>
- </div>
-
- <section class="oe_snippet_body fw_categories">
- <div class="container">
- <div class="row">
- </div>
- </div>
- </section>
- </div>
- </xpath>
-
-Inside your fresh new row, add some bootstraped contents::
-
- <div class="col-md-12 text-center mt32 mb32">
- <h2>A great Title</h2>
- <h3 class="text-muted ">And a great subtitle too</h3>
- <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </p>
- </div>
-
-
-Adding images to your snippet
-'''''''''''''''''''''''''''''
-
-You can easely add images in your snippets simply by setting up css
-backgrounds images.
-
-In ``odoo/addons/theme_dummy/static/`` create a new folder and name it
-``img``. Put your images there, in sub-folders if needed. Open
-:file:`odoo/addons/theme_dummy/static/style/custom.less`, add these lines
-
-.. code-block:: css
-
- @img-01: url("../img/img-boy.png");
- .dummy-boy { background-image: @img-01; }
-
- @img-02: url("../img/img-girl.png");
- .dummy-girl { background-image: @img-02; }
-
-In :file:`odoo/addons/theme_dummy/views/pages.xml` change the correspondant
-lines as below::
-
- <section>
- <div class="container">
- <div class="row dummy-bg">
- <div class="alert alert-primary" role="alert">
- <a href="#" class="alert-link">...</a>
- </div>
- <div class="col-md-6">
- <h2>BLUE it!</h2>
- <div class="dummy-boy">
- </div>
- </div>
- <div class="col-md-6">
- <h2>GREEN THAT!</h2>
- <div class="dummy-girl">
- </div>
- </div>
- </div>
- </div>
- </section>
-
-Your new snippet is now ready to use. Just drag and drop it on your page to
-see it in action.
-
-Advanced Customization
-======================
-
-Defining Your Theme Options
----------------------------
-
-Understanding XPath
-'''''''''''''''''''
-
-As your stylesheets are running on the whole website, giving more option to
-your snippets and applying them independently will push your design
-forward. In ``odoo/addons/theme_dummy/views/`` create a new file, name it
-``options.xml`` and add these lines::
-
- <template id="gourman_website_options_pattern" inherit_id="website.snippet_options">
- <xpath expr="//div[@data-option='dummy_options']//ul" position="after">
- </xpath>
- </template>
-
-Explain xpath
-"""""""""""""
-
-.. TODO:: syntax not correct (see website examples)
-
-Your option menu is now correctly set in the database, you can create an new dropdown menu.
-
-Let's say yout want three options which will change the text color and the background.
-In option.xml, add these lines inside the xpath::
-
- <li data-check_class="text-purple"><a>YOUR OPTION 1</a></li>
- <li class="dropdown-submenu">
- <a tabindex="-1" href="#">Your sub option</a>
- <ul class="dropdown-menu">
- <li data-select_class="bg-yellow"><a>YOUR OPTION 2</a></li>
- <li data-select_class="text-light-bg-dark"><a>YOUR OPTION 3</a></li>
- <li data-select_class=""><a>None</a></li>
- </ul>
- <li>
-
-Simple less css options
-'''''''''''''''''''''''
-
-In order to see these options in action, you have to write some new css
-classes. Open custom.css and add this new lines
-
-.. code-block:: css
-
- @color-purple: #2ecc71;
- @color-yellow: #2ecc71;
-
- .text-purple { color: @color-purple; }
- .bg-yellow { background-color: @color-yellow;}
- .text-light-bg-dark { color: #eee; background-color: #222;}
-
-Refresh the page. Select a snippet and click Customize. Choose one of your new
-options apply it.
-
-XPath & inherits
-''''''''''''''''
-
-You can also add images in your variables and use them on certain part of your
-pages, snippets or any html element.
-
-In :file:`odoo/addons/theme_dummy/static/style/custom.css` add these new lines
-
-.. code:: css
-
- @bg-01: url("../img/background/bg-blur.jpg");
-
- .bg-01 {
- background-image: @bg-01;
- }
-
-Now that you have set the background image, you can decide how and where the
-user can use it, for example, on a simple div.
-
-Open :file:`odoo/addons/theme_dummy/views/options.xml` and add this new xpath::
-
- <xpath expr="//div[@data-option='background-dummy']//ul" position="after">
- <ul class="dropdown-menu">
- <li data-value="bg-01">
- <a>Image 1</a>
- </li>
- </ul>
- </xpath>
-
-Your option is ready to be applied but you want it to be shown only a certain
-part of a snippet.
-
-Open :file:`odoo/addons/theme_dummy/views/snippets.xml` and add a new snippet
-with the method we learned previously::
-
- <xpath expr="//div[@id='snippet_structure']" position="inside">
- <div>
- <!-- Add a Thumbnail in the Website Builder drop-down menu -->
- <div class="oe_snippet_thumbnail">
- <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
- <span class="oe_snippet_thumbnail_title">Test OPTION</span>
- </div>
- <!-- Your Snippet content -->
- <section class="oe_snippet_body fw_categories">
- <div class="container">
- <div class="row">
- <div class="col-md-6 text-center mt32 mb32">
- <h2>NO OPTION</h2>
- <p>OFF</p>
- </div>
- <div class="col-md-6 text-center mt32 mb32 test-option">
- <h2>OPTION</h2>
- <p>This div has the 'test-option' class</p>
- </div>
- </div>
- </div>
- </section>
- </div>
- </xpath>
-
-As you see, the second ``col-md`` has a class named ``test-option``. We are
-going to specify where this option can be turned on by adding the
-``data-selector`` attribute.
-
-Go back to your ``options.xml`` files, add these new lines::
-
- <xpath expr="//div[@data-option='background-dummy']" position="attributes">
- <attribute name="data-selector">test-option</attribute>
- </xpath>
-
-Refresh your browser. You should now be able to add your image background on
-the left div only. The option is now available on each section but also on
-the left div with the custom class.
-
-The Image Database
-------------------
-
-Modifying the image database
-''''''''''''''''''''''''''''
-
-Odoo provides its own image library but you certainly want to adapt it to your
-design. Do not use the Media Manager uploading Tool to add image in your
-theme. The images url's will be lost on reload! Instead of uploading your
-images, you can create your own library and disable the old ones.
-
-In ``odoo/addons/theme_dummy/views/`` create a new file, name it
-``images.xml`` and add these lines::
-
- <record id="image_bg_blue" model="ir.attachment">
- <field name="name">bg_blue.jpg</field>
- <field name="datas_fname">bg_blue.jpg</field>
- <field name="res_model">ir.ui.view</field>
- <field name="type">url</field>
- <field name="url">/theme_clean/static/img/library/bg/bg_blue.jpg</field>
- </record>
-
-Your images is now available in your Media Manager. And your Theme has a
-total new look.
-
-Theme Selector
-==============
-
-Set Up
-------
-
-Understanding theme variants
-''''''''''''''''''''''''''''
-
-Combining theme variants
-''''''''''''''''''''''''
+++ /dev/null
-DOTFILES:=$(wildcard *.dot)
-SVGFILES:=$(patsubst %.dot,%.svg,$(DOTFILES))
-PNGFILES:=$(patsubst %.dot,%.png,$(DOTFILES))
-
-# try to disable implicit rules
-.SUFFIXES:
-
-.PHONY: all clean
-
-all: $(SVGFILES) $(PNGFILES)
-
-# must -f to ignore errors when running clean multiple times in a row
-clean:
- rm -f *.png *.svg
-
-%.svg: %.dot
- dot -Tsvg $< > $@
-
-%.png: %.dot
- dot -Tpng $< > $@
+++ /dev/null
-digraph join {
- // dummy sources as support for edges, make invisible and height 0
- a [style=invis height=0 fontsize=0]
- b [style=invis height=0 fontsize=0]
- c [style=invis height=0 fontsize=0]
-
- a -> Activity
- b -> Activity
- c -> Activity
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.38.0 (20140413.2041)
- -->
-<!-- Title: join Pages: 1 -->
-<svg width="206pt" height="93pt"
- viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
-<title>join</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
-<!-- a -->
-<!-- Activity -->
-<g id="node4" class="node"><title>Activity</title>
-<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="40.0939" ry="18"/>
-<text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00">Activity</text>
-</g>
-<!-- a->Activity -->
-<g id="edge1" class="edge"><title>a->Activity</title>
-<path fill="none" stroke="black" d="M33.6445,-71.9778C42.4332,-64.8537 58.4442,-51.875 72.4186,-40.5472"/>
-<polygon fill="black" stroke="black" points="74.7768,-43.1411 80.3411,-34.1251 70.3688,-37.7033 74.7768,-43.1411"/>
-</g>
-<!-- b -->
-<!-- b->Activity -->
-<g id="edge2" class="edge"><title>b->Activity</title>
-<path fill="none" stroke="black" d="M99,-71.9778C99,-66.0508 99,-56.0715 99,-46.3619"/>
-<polygon fill="black" stroke="black" points="102.5,-46.1364 99,-36.1364 95.5001,-46.1365 102.5,-46.1364"/>
-</g>
-<!-- c -->
-<!-- c->Activity -->
-<g id="edge3" class="edge"><title>c->Activity</title>
-<path fill="none" stroke="black" d="M164.355,-71.9778C155.567,-64.8537 139.556,-51.875 125.581,-40.5472"/>
-<polygon fill="black" stroke="black" points="127.631,-37.7033 117.659,-34.1251 123.223,-43.1411 127.631,-37.7033"/>
-</g>
-</g>
-</svg>
+++ /dev/null
-digraph order {
- Draft [style=filled fillcolor="#73fa79"]
- Closed [style=filled fillcolor="#98c7df"]
- Canceled [style=filled fillcolor="#98c7df"]
-
- Draft -> Confirmed
- Confirmed -> Closed
- Confirmed -> Canceled
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.38.0 (20140413.2041)
- -->
-<!-- Title: order Pages: 1 -->
-<svg width="188pt" height="188pt"
- viewBox="0.00 0.00 188.24 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
-<title>order</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-184 184.243,-184 184.243,4 -4,4"/>
-<!-- Draft -->
-<g id="node1" class="node"><title>Draft</title>
-<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-162" rx="30.5947" ry="18"/>
-<text text-anchor="middle" x="85.3968" y="-158.3" font-family="Times,serif" font-size="14.00">Draft</text>
-</g>
-<!-- Confirmed -->
-<g id="node4" class="node"><title>Confirmed</title>
-<ellipse fill="none" stroke="black" cx="85.3968" cy="-90" rx="51.9908" ry="18"/>
-<text text-anchor="middle" x="85.3968" y="-86.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
-</g>
-<!-- Draft->Confirmed -->
-<g id="edge1" class="edge"><title>Draft->Confirmed</title>
-<path fill="none" stroke="black" d="M85.3968,-143.697C85.3968,-135.983 85.3968,-126.712 85.3968,-118.112"/>
-<polygon fill="black" stroke="black" points="88.8969,-118.104 85.3968,-108.104 81.8969,-118.104 88.8969,-118.104"/>
-</g>
-<!-- Closed -->
-<g id="node2" class="node"><title>Closed</title>
-<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
-<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
-</g>
-<!-- Canceled -->
-<g id="node3" class="node"><title>Canceled</title>
-<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
-<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
-</g>
-<!-- Confirmed->Closed -->
-<g id="edge2" class="edge"><title>Confirmed->Closed</title>
-<path fill="none" stroke="black" d="M73.7845,-72.411C67.8042,-63.8677 60.3917,-53.2785 53.7479,-43.7874"/>
-<polygon fill="black" stroke="black" points="56.5277,-41.6552 47.9257,-35.4699 50.7931,-45.6694 56.5277,-41.6552"/>
-</g>
-<!-- Confirmed->Canceled -->
-<g id="edge3" class="edge"><title>Confirmed->Canceled</title>
-<path fill="none" stroke="black" d="M97.2461,-72.411C103.348,-63.8677 110.912,-53.2785 117.692,-43.7874"/>
-<polygon fill="black" stroke="black" points="120.668,-45.6416 123.633,-35.4699 114.972,-41.573 120.668,-45.6416"/>
-</g>
-</g>
-</svg>
+++ /dev/null
-digraph order {
- Draft [style=filled fillcolor="#73fa79"]
- Closed [style=filled fillcolor="#98c7df"]
- Canceled [style=filled fillcolor="#98c7df"]
-
- Draft -> Confirmed [label="discount <= 15%"]
- Draft -> Validation [label="discount > 15%"]
- Validation -> Confirmed [label="Accept"]
- Confirmed -> Closed
- Confirmed -> Canceled
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.38.0 (20140413.2041)
- -->
-<!-- Title: order Pages: 1 -->
-<svg width="260pt" height="291pt"
- viewBox="0.00 0.00 259.79 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
-<title>order</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-287 255.792,-287 255.792,4 -4,4"/>
-<!-- Draft -->
-<g id="node1" class="node"><title>Draft</title>
-<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-265" rx="30.5947" ry="18"/>
-<text text-anchor="middle" x="85.3968" y="-261.3" font-family="Times,serif" font-size="14.00">Draft</text>
-</g>
-<!-- Confirmed -->
-<g id="node4" class="node"><title>Confirmed</title>
-<ellipse fill="none" stroke="black" cx="85.3968" cy="-91" rx="51.9908" ry="18"/>
-<text text-anchor="middle" x="85.3968" y="-87.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
-</g>
-<!-- Draft->Confirmed -->
-<g id="edge1" class="edge"><title>Draft->Confirmed</title>
-<path fill="none" stroke="black" d="M72.5816,-248.399C62.7132,-235.312 49.8641,-215.656 44.3968,-196 40.1092,-180.585 40.1092,-175.415 44.3968,-160 48.7071,-144.503 57.6054,-129.007 66.0142,-116.73"/>
-<polygon fill="black" stroke="black" points="68.9995,-118.572 71.9779,-108.405 63.3089,-114.496 68.9995,-118.572"/>
-<text text-anchor="middle" x="94.3968" y="-174.3" font-family="Times,serif" font-size="14.00">discount <= 15%</text>
-</g>
-<!-- Validation -->
-<g id="node5" class="node"><title>Validation</title>
-<ellipse fill="none" stroke="black" cx="202.397" cy="-178" rx="49.2915" ry="18"/>
-<text text-anchor="middle" x="202.397" y="-174.3" font-family="Times,serif" font-size="14.00">Validation</text>
-</g>
-<!-- Draft->Validation -->
-<g id="edge2" class="edge"><title>Draft->Validation</title>
-<path fill="none" stroke="black" d="M103.936,-250.531C122.48,-237.059 151.286,-216.131 172.959,-200.386"/>
-<polygon fill="black" stroke="black" points="175.139,-203.129 181.172,-194.42 171.024,-197.466 175.139,-203.129"/>
-<text text-anchor="middle" x="195.897" y="-217.8" font-family="Times,serif" font-size="14.00">discount > 15%</text>
-</g>
-<!-- Closed -->
-<g id="node2" class="node"><title>Closed</title>
-<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
-<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
-</g>
-<!-- Canceled -->
-<g id="node3" class="node"><title>Canceled</title>
-<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
-<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
-</g>
-<!-- Confirmed->Closed -->
-<g id="edge4" class="edge"><title>Confirmed->Closed</title>
-<path fill="none" stroke="black" d="M73.7845,-73.174C67.7175,-64.3831 60.1766,-53.4564 53.4596,-43.7236"/>
-<polygon fill="black" stroke="black" points="56.1491,-41.4588 47.5884,-35.2165 50.3879,-45.4348 56.1491,-41.4588"/>
-</g>
-<!-- Confirmed->Canceled -->
-<g id="edge5" class="edge"><title>Confirmed->Canceled</title>
-<path fill="none" stroke="black" d="M97.2461,-73.174C103.348,-64.5087 110.912,-53.7682 117.692,-44.1415"/>
-<polygon fill="black" stroke="black" points="120.736,-45.8965 123.633,-35.7052 115.013,-41.8661 120.736,-45.8965"/>
-</g>
-<!-- Validation->Confirmed -->
-<g id="edge3" class="edge"><title>Validation->Confirmed</title>
-<path fill="none" stroke="black" d="M181.209,-161.607C162.688,-148.152 135.604,-128.475 114.953,-113.472"/>
-<polygon fill="black" stroke="black" points="116.97,-110.612 106.822,-107.566 112.856,-116.275 116.97,-110.612"/>
-<text text-anchor="middle" x="170.397" y="-130.8" font-family="Times,serif" font-size="14.00">Accept</text>
-</g>
-</g>
-</svg>
+++ /dev/null
-digraph split {
- // dummy destinations as support for edges, make invisible and height 0
- a [style=invis height=0 fontsize=0]
- b [style=invis height=0 fontsize=0]
- c [style=invis height=0 fontsize=0]
-
- Activity -> a
- Activity -> b
- Activity -> c
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 2.38.0 (20140413.2041)
- -->
-<!-- Title: split Pages: 1 -->
-<svg width="206pt" height="93pt"
- viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
-<title>split</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
-<!-- a -->
-<!-- b -->
-<!-- c -->
-<!-- Activity -->
-<g id="node4" class="node"><title>Activity</title>
-<ellipse fill="none" stroke="black" cx="99" cy="-66.7279" rx="40.0939" ry="18"/>
-<text text-anchor="middle" x="99" y="-63.0279" font-family="Times,serif" font-size="14.00">Activity</text>
-</g>
-<!-- Activity->a -->
-<g id="edge1" class="edge"><title>Activity->a</title>
-<path fill="none" stroke="black" d="M80.4582,-50.6978C68.3594,-40.8903 52.7894,-28.2691 41.577,-19.1802"/>
-<polygon fill="black" stroke="black" points="43.641,-16.3478 33.6687,-12.7696 39.233,-21.7857 43.641,-16.3478"/>
-</g>
-<!-- Activity->b -->
-<g id="edge2" class="edge"><title>Activity->b</title>
-<path fill="none" stroke="black" d="M99,-48.5325C99,-40.494 99,-30.9869 99,-23.1351"/>
-<polygon fill="black" stroke="black" points="102.5,-22.8941 99,-12.8941 95.5001,-22.8942 102.5,-22.8941"/>
-</g>
-<!-- Activity->c -->
-<g id="edge3" class="edge"><title>Activity->c</title>
-<path fill="none" stroke="black" d="M117.542,-50.6978C129.641,-40.8903 145.211,-28.2691 156.423,-19.1802"/>
-<polygon fill="black" stroke="black" points="158.767,-21.7857 164.331,-12.7696 154.359,-16.3478 158.767,-21.7857"/>
-</g>
-</g>
-</svg>
+++ /dev/null
-.. _guides/workflows:
-
-Workflows
-=========
-
-In Odoo, a workflow is a technical artefact to manage a set of "things to
-do" associated to the records of a model. The workflow provides a higher-level
-way to organize tasks to perform with or on a record.
-
-More specifically, a workflow is a directed graph where the nodes are called
-"activities" and the arcs are called "transitions".
-
-- Activities define work that should be done within the Odoo server, such
- as changing the state of some records, or sending emails.
-- Transitions control how the workflow progresses from activity to activity.
-
-In the definition of a workflow, one can attach conditions, signals, and
-triggers to transitions, so that the behavior of the workflow depends on user
-actions (such as clicking on a button), changes to records, or arbitrary
-Python code.
-
-All in all, Odoo's workflow system provides:
-
-* a description of the evolution of a record (document) over time
-* automatic actions based on various and flexible conditions
-* management of company roles and validation steps
-* management of interactions between objects
-* a visual representation of document flows through their lifecycle
-
-For instance, a basic order could have the following flow:
-
-.. sphinx.ext.graphviz would be nice, but it requires ``dot`` on any machine
-.. where the doc is compiled... otoh this is a pain in the ass because you
-.. need 2 compilation steps (dot -> image and rst -> html) every time
-
-.. image:: workflow/order_0.*
- :align: center
-
-Orders start in the *Draft* state, can be *Confirmed* by a user, and then
-either shipped (*Closed*) or *Canceled*.
-
-A company using Odoo may want to add discount support to orders, where sales
-staff has discretionary discounting powers up to 15%, but manager validation
-is required for discounts beyond 15%. The workflow can be altered online to
-add the relevant steps without editing Python or XML files:
-
-.. image:: workflow/order_1.*
- :align: center
-
-Because Activities can perform arbitrary actions, the *Validation* can
-automatically send a validation request to the relevant employee.
-
-.. note:: the order view needs to be modified to add an *Accept Discount*
- button for managers
-
-Basics
-------
-
-Defining a workflow with data files is straightforward: a record "workflow" is
-given together with records for the activities and the transitions. For
-instance, here is a simple sequence of two activities defined in XML
-
-.. code-block:: xml
-
- <record id="test_workflow" model="workflow">
- <field name="name">test.workflow</field>
- <field name="osv">test.workflow.model</field>
- <field name="on_create">True</field>
- </record>
-
- <record id="activity_a" model="workflow.activity">
- <field name="wkf_id" ref="test_workflow"/>
- <field name="flow_start">True</field>
- <field name="name">a</field>
- <field name="kind">function</field>
- <field name="action">print_a()</field>
- </record>
- <record id="activity_b" model="workflow.activity">
- <field name="wkf_id" ref="test_workflow"/>
- <field name="flow_stop">True</field>
- <field name="name">b</field>
- <field name="kind">function</field>
- <field name="action">print_b()</field>
- </record>
-
- <record id="trans_a_b" model="workflow.transition">
- <field name="act_from" ref="activity_a"/>
- <field name="act_to" ref="activity_b"/>
- </record>
-
-A worfklow is always defined with respect to a particular model (the model is
-given by the attribute ``osv`` on the model ``workflow``). Methods specified
-in the activities or transitions will be called on that model.
-
-In the example code above, a workflow called "test_workflow" is created. It is
-made up of two activies, named "a" and "b", and one transition, going from "a"
-to "b".
-
-The first activity has its attribute ``flow_start`` set to ``True`` so that
-Odoo knows where to start the workflow traversal after it is instanciated.
-Because ``on_create`` is set to True on the workflow record, the workflow is
-instanciated for each newly created record. (Otherwise, the workflow should be
-instanciated by other means, such as from some module Python code.)
-
-When the workflow is instanciated, it begins with activity "a". That activity
-is of kind ``function``, which means that the action ``print_a()`` is a method
-call on the model ``test.workflow`` (the usual ``cr, uid, ids, context``
-arguments are passed for you).
-
-The transition between "a" and "b" does not specify any condition. This means
-that the workflow instance immediately goes from "a" to "b" after "a" has been
-processed, and thus also processes activity "b".
-
-Activities
-----------
-
-While the transitions can be seen as the control structures of the workflows,
-activities are the places where everything happens, from changing record
-states to sending email.
-
-Different kinds of activities exist: ``Dummy``, ``Function``, ``Subflow``, and
-``Stop all``, each doing different things when the activity is processed. In
-addition to their kind, activies have other properties, detailed in the next
-sections.
-
-Flow start and flow stop
-''''''''''''''''''''''''
-
-The attribute ``flow_start`` is a boolean value specifying whether the activity
-is processed when the workflow is instanciated. Multiple activities can have
-their attribute ``flow_start`` set to ``True``. When instanciating a workflow
-for a record, Odoo simply processes all of them, and evaluate all their
-outgoing transitions afterwards.
-
-The attribute ``flow_stop`` is a boolean value specifying whether the activity
-stops the workflow instance. A workflow instance is considered completed when
-all its activities with the attribute ``flow_stop`` set to ``True`` are
-completed.
-
-It is important for Odoo to know when a workflow instance is completed. A
-workflow can have an activity that is actually another workflow (called a
-subflow); that activity is completed when the subflow is completed.
-
-Subflow
-'''''''
-
-An activity can embed a complete workflow, called a subflow (the embedding
-workflow is called the parent workflow). The workflow to instanciate is
-specified by attribute ``subflow_id``.
-
-.. note:: In the GUI, that attribute can not be set unless the kind of the
- activity is ``Subflow``.
-
-The activity is considered completed (and its outgoing transitions ready to be
-evaluated) when the subflow is completed (see attribute ``flow_stop`` above).
-
-Sending a signal from a subflow
-'''''''''''''''''''''''''''''''
-
-When a workflow is embedded in an activity (as a subflow) of a workflow, the
-sublow can send a signal from its own activities to the parent workflow by
-giving a signal name in the attribute ``signal_send``. Odoo processes those
-activities by sending the value of ``signal_send`` prefixed by "subflow." to
-the parent workflow instance.
-
-In other words, it is possible to react and get transitions in the parent
-workflow as activities are executed in the sublow.
-
-Server actions
-''''''''''''''
-
-An activity can run a "Server Action" by specifying its ID in the attribute
-``action_id``.
-
-Python action
-'''''''''''''
-
-An activity can execute some Python code, given by the attribute ``action``.
-The evaluation environment is the same as the one explained in the section
-`Conditions`_.
-
-Split mode
-''''''''''
-
-After an activity has been processed, Odoo evaluates its transition to reach
-the next activity in the flow.
-
-However if an activity has more than one transition, Odoo must decide which
-activity or activities to follow.
-
-.. image:: workflow/split.*
- :align: center
-
-This choice is controlled by the ``split_mode`` attribute:
-
-``XOR`` (default)
- By default, Odoo will use the first transition (in ``sequence`` order)
- whose condition is satisfied. All other transitions are ignored.
-``OR``
- In ``OR`` mode, all transitions with a satisfied condition are traversed
- simultanously. Transitions not yet valid will be ignored, even if they
- become valid later.
-``AND``
- In ``AND`` mode, Odoo will wait until *all* transitions are satisfied, and
- will traverse all of them (much like the ``OR`` mode).
-
-Both ``OR`` and ``AND`` mode will lead to activities being active in the same
-workflow.
-
-Join mode
-'''''''''
-
-Just like outgoing transition conditions can be combined together to decide
-whether they can be traversed or not, incoming transitions can be combined
-together to decide if and when an activity may be processed.
-
-.. image:: workflow/join.*
- :align: center
-
-The ``join_mode`` attribute controls that behavior:
-
-``XOR`` (default)
- Any incoming transition enables the activity and starts its processing.
-``AND``
- The activity is enabled and processed only once *all* incoming transitions
- have been traversed.
-
-Kinds
-'''''
-
-An activity's kind defines the type of work an activity can perform.
-
-Dummy (``dummy``, default)
- Do nothing at all, or call a server action. Often used as dispatch or
- gather "hubs" for transitions.
-Function (``function``)
- Run some python code, execute a server action.
-Stop all (``stopall``)
- Completely stops the workflow instance and marks it as completed.
-Subflow (``subflow``)
- Starts executing an other workflow, once that workflow is completed the
- activity is done processing.
-
- By default, the subflow is instanciated for the same record as the parent
- workflow. It is possible to change that behavior by providing Python code
- that returns a record ID (of the same data model as the subflow). The
- embedded subflow instance is then the one of the given record.
-
-
-Transitions
------------
-
-Transitions provide the control structures to orchestrate a workflow. When an
-activity is completed, the workflow engine tries to get across transitions
-departing from the completed activity, towards the next activities. In their
-simplest form (as in the example above), they link activities sequentially:
-activities are processed as soon as the activities preceding them are
-completed.
-
-Instead of running all activities in one fell swoop, it is also possible to
-wait on transitions, going through them only when some criteria are met. The
-criteria are the conditions, the signals, and the triggers. They are detailed
-in the following sections.
-
-Conditions
-''''''''''
-
-When an activity has been completed, its outgoing transitions are inspected to
-determine whether it is possible for the workflow instance to proceed through
-them and reach the next activities. When only a condition is defined (i.e., no
-signal or trigger is defined), the condition is evaluated by Odoo, and if
-it evaluates to ``True``, the worklfow instance progresses through the
-transition. If the condition is not met, it will be reevaluated every time
-the associated record is modified, or by an explicit method call to do it.
-
-By default, the attribute ``condition`` (i.e., the expression to be evaluated)
-is just "True", which trivially evaluates to ``True``. Note that the condition
-may be several lines long; in that case, the value of the last one determines
-whether the transition can be taken.
-
-In the condition evaluation environment, several symbols are conveniently
-defined (in addition to the Odoo ``safe_eval`` environment):
-
-- all the model column names, and
-- all the browse record's attributes.
-
-Signals
-'''''''
-
-In addition to a condition, a transition can specify a signal name. When such
-a signal name is present, the transition is not taken directly, even if the
-condition evaluates to ``True``. Instead the transition blocks, waiting to be
-woken up.
-
-In order to wake up a transition with a defined signal name, the signal must
-be sent to the workflow instance. A common way to send a signal is to use a
-button in the user interface, using the element ``<button/>`` with the signal
-name as the attribute ``name`` of the button. Once the button is clicked, the
-signal is sent to the workflow instance of the current record.
-
-.. note:: The condition is still evaluated when the signal is sent to the
- workflow instance.
-
-Triggers
-''''''''
-
-With conditions that evaluate to ``False``, transitions are not taken (and
-thus the activity it leads to is not processed immediately). Still, the
-workflow instance can get new chances to progress across that transition by
-providing so-called triggers. The idea is that when the condition is not
-satisfied, triggers are recorded in database. Later, it is possible to wake up
-specifically the workflow instances that installed those triggers, offering
-them to reevaluate their transition conditions. This mechanism makes it
-cheaper to wake up workflow instances by targetting just a few of them (those
-that have installed the triggers) instead of all of them.
-
-Triggers are recorded in database as record IDs (together with the model name)
-and refer to the workflow instance waiting for those records. The transition
-definition provides a model name (attribute ``trigger_model``) and a Python
-expression (attribute ``trigger_expression``) that evaluates to a list of
-record IDs in the given model. Any of those records can wake up the workflow
-instance they are associated with.
-
-.. note:: triggers are not re-installed whenever the transition is re-tried.
--- /dev/null
+.. highlight:: xml
+
+===============
+Creating themes
+===============
+
+Basic set up
+============
+
+Create a basic theme module with :command:`odoo.py scaffold` and the ``theme``
+template: from the root odoo folder, use
+
+.. code-block:: console
+
+ $ ./odoo.py scaffold -t theme "Dummy Theme" addons
+
+this should create a new folder ``dummy_theme`` in the ``addons`` directory
+with the structure:
+
+.. code-block:: text
+
+ addons/dummy_theme
+ |-- __init__.py
+ |-- __openerp__.py
+ |-- static
+ | `-- style
+ | `-- custom.less
+ `-- views
+ |-- options.xml
+ |-- pages.xml
+ `-- snippets.xml
+
+``static/styles`` contains your stylesheet(s), ``views`` contains the various
+XML files describing the theme and theme features to Odoo.
+
+Static Page
+-----------
+
+Creating a new template
+'''''''''''''''''''''''
+
+Create a new file :file:`odoo/addons/theme_dummy/views/pages.xml` and open it.
+
+In odoo, a page means a new template. You don't need special skills, simply
+copy paste the lines::
+
+ <template id="website.hello" name="Homepage" page="True">
+ <t t-call="website.layout">
+ <div id="wrap" class="oe_structure oe_empty">
+ </div>
+ </t>
+ </template>
+
+Refresh the page and feel the hit.
+
+Editing content on a page
+'''''''''''''''''''''''''
+
+You can now add you content! You should always use the Bootstrap structure as
+below::
+
+ <template id="website.hello" name="Homepage" page="True">
+ <t t-call="website.layout">
+ <div id="wrap" class="oe_structure oe_empty">
+ <section>
+ <div class="container">
+ <div class="row">
+ <h1>This is Your Content</h1>
+ <p>Isn't amazing to edit everything inline?</p>
+ <hr/>
+ </div>
+ </div>
+ </section>
+ </div>
+ </t>
+ </template>
+
+Adding new item in the menu
+'''''''''''''''''''''''''''
+
+Adding these few more lines will put the new page in your menu::
+
+ <record id="hello_menu" model="website.menu">
+ <field name="name">Hello</field>
+ <field name="url">/page/hello</field>
+ <field name="parent_id" ref="website.main_menu"/>
+ <field name="sequence" type="int">20</field>
+ </record>
+
+Congrats! It's online! Now drag and drop some snippets on the page and let's
+style!
+
+Pimp Your Theme
+---------------
+
+Easy styling with less
+''''''''''''''''''''''
+
+In ``odoo/addons/theme_dummy/static`` create a new folder and name it
+``style``. In the new folder ``odoo/addons/theme_dummy/static/style`` create a
+file and name it ``custom.less``. Open ``custom.less`` in the text editor and
+modify these lines as below:
+
+
+.. code-block:: css
+
+ .h1 {
+ color: #215487;
+ }
+ .span {
+ border: 2px solid black;
+ background-color: #eee;
+ }
+
+Refresh the page and feel the hit.
+
+Get the most of the dom
+'''''''''''''''''''''''
+
+Right-Click, inspect element. You can go deeper by styling the main layout
+container. Here we try with the 'wrapwrap' id.
+
+.. code-block:: css
+
+ #wrapwrap {
+ background-color: #222;
+ width: 80%;
+ margin: 0 auto;
+ }
+
+Easy layout with bootstrap
+''''''''''''''''''''''''''
+
+Open :file:`odoo/addons/theme_dummy/views/pages.xml` and add a new section::
+
+ <section>
+ <div class="container">
+ <div class="row">
+ <div class="alert alert-primary" role="alert">
+ <a href="#" class="alert-link">...</a>
+ </div>
+ <div class="col-md-6 bg-blue">
+ <h2>BLUE it!</h2>
+ </div>
+ <div class="col-md-6 bg-green">
+ <h2>GREEN THAT!</h2>
+ </div>
+ </div>
+ </div>
+ </section>
+
+Refresh the page and check how it looks.
+
+The background of the alert component is the default Bootstrap primary color.
+The two other div your created have no custom styles applied yet. Open
+:file:`odoo/addons/theme_dummy/static/style/custom.less` and add these lines:
+
+.. code-block:: css
+
+ @brand-primary: #1abc9c;
+ @color-blue: #3498db;
+ @color-green: #2ecc71;
+
+ .bg-blue { background: @color-blue; }
+ .bg-green { background: @color-green; }
+
+ .h2 { color: white; }
+
+As you see, the default primary has changed and your new colors are shining!
+
+Build Your First Snippet
+------------------------
+
+Setting up __openerp__.py
+'''''''''''''''''''''''''
+
+Open ``__openerp__.py`` and add a new line as below:
+
+.. code-block:: python
+
+ {
+ 'name': 'Dummy Theme',
+ 'description': 'Dummy Theme',
+ 'category': 'Website',
+ 'version': '1.0',
+ 'author': 'OpenERP SA',
+ 'depends': ['website'],
+ 'data': [
+ 'views/snippets.xml',
+ ],
+ 'application': True,
+ }
+
+In ``odoo/addons/theme_learn/views`` create a new xml file, name it
+``snippets.xml`` and open it in a text editor
+
+Add your snippet in the menu
+''''''''''''''''''''''''''''
+
+Before typing your html code, you need to locate it in the WEBb. drop-down
+menu. In this case, we will add it at the end of the Structure section::
+
+ <template id="snippets" inherit_id="website.snippets" name="Clean Theme snippets">
+ <xpath expr="//div[@id='snippet_structure']" position="inside">
+ </xpath>
+ </template>
+
+Now open a new div, do not give it any id or classes. It will contain your
+snippet::
+
+ <xpath expr="//div[@id='snippet_structure']" position="inside">
+ <div>
+ </div>
+ </xpath>
+
+A thumbnail is also needed to create a more attractive link in the menu. You
+can use labels to focus on your themes snippets. Simply add a new div with
+the class ``oe_snippet_thumbnail`` and add your thumbnail image (100x79px)::
+
+ <xpath expr="//div[@id='snippet_structure']" position="inside">
+ <div>
+ <div class="oe_snippet_thumbnail">
+ <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
+ <span class="oe_snippet_thumbnail_title">SNIP IT!</span>
+ </div>
+ </div>
+ </xpath>
+
+And voila! Your new snippet is now ready to use. Just drag and drop it on your
+page to see it in action.
+
+The snippet body
+''''''''''''''''
+
+A snippet has to be in a section with the class ``oe_snippet_body`` to work
+correctly. As Odoo use the Bootstrap framework, you have use containers and
+rows to hold your content. Please refer the the Bootstrap documentation::
+
+ <xpath expr="//div[@id='snippet_structure']" position="inside">
+ <div>
+ <div class="oe_snippet_thumbnail">
+ <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
+ <span class="oe_snippet_thumbnail_title">SNIP IT!</span>
+ </div>
+
+ <section class="oe_snippet_body fw_categories">
+ <div class="container">
+ <div class="row">
+ </div>
+ </div>
+ </section>
+ </div>
+ </xpath>
+
+Inside your fresh new row, add some bootstraped contents::
+
+ <div class="col-md-12 text-center mt32 mb32">
+ <h2>A great Title</h2>
+ <h3 class="text-muted ">And a great subtitle too</h3>
+ <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. </p>
+ </div>
+
+
+Adding images to your snippet
+'''''''''''''''''''''''''''''
+
+You can easely add images in your snippets simply by setting up css
+backgrounds images.
+
+In ``odoo/addons/theme_dummy/static/`` create a new folder and name it
+``img``. Put your images there, in sub-folders if needed. Open
+:file:`odoo/addons/theme_dummy/static/style/custom.less`, add these lines
+
+.. code-block:: css
+
+ @img-01: url("../img/img-boy.png");
+ .dummy-boy { background-image: @img-01; }
+
+ @img-02: url("../img/img-girl.png");
+ .dummy-girl { background-image: @img-02; }
+
+In :file:`odoo/addons/theme_dummy/views/pages.xml` change the correspondant
+lines as below::
+
+ <section>
+ <div class="container">
+ <div class="row dummy-bg">
+ <div class="alert alert-primary" role="alert">
+ <a href="#" class="alert-link">...</a>
+ </div>
+ <div class="col-md-6">
+ <h2>BLUE it!</h2>
+ <div class="dummy-boy">
+ </div>
+ </div>
+ <div class="col-md-6">
+ <h2>GREEN THAT!</h2>
+ <div class="dummy-girl">
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+
+Your new snippet is now ready to use. Just drag and drop it on your page to
+see it in action.
+
+Advanced Customization
+======================
+
+Defining Your Theme Options
+---------------------------
+
+Understanding XPath
+'''''''''''''''''''
+
+As your stylesheets are running on the whole website, giving more option to
+your snippets and applying them independently will push your design
+forward. In ``odoo/addons/theme_dummy/views/`` create a new file, name it
+``options.xml`` and add these lines::
+
+ <template id="gourman_website_options_pattern" inherit_id="website.snippet_options">
+ <xpath expr="//div[@data-option='dummy_options']//ul" position="after">
+ </xpath>
+ </template>
+
+Explain xpath
+"""""""""""""
+
+.. TODO:: syntax not correct (see website examples)
+
+Your option menu is now correctly set in the database, you can create an new dropdown menu.
+
+Let's say yout want three options which will change the text color and the background.
+In option.xml, add these lines inside the xpath::
+
+ <li data-check_class="text-purple"><a>YOUR OPTION 1</a></li>
+ <li class="dropdown-submenu">
+ <a tabindex="-1" href="#">Your sub option</a>
+ <ul class="dropdown-menu">
+ <li data-select_class="bg-yellow"><a>YOUR OPTION 2</a></li>
+ <li data-select_class="text-light-bg-dark"><a>YOUR OPTION 3</a></li>
+ <li data-select_class=""><a>None</a></li>
+ </ul>
+ <li>
+
+Simple less css options
+'''''''''''''''''''''''
+
+In order to see these options in action, you have to write some new css
+classes. Open custom.css and add this new lines
+
+.. code-block:: css
+
+ @color-purple: #2ecc71;
+ @color-yellow: #2ecc71;
+
+ .text-purple { color: @color-purple; }
+ .bg-yellow { background-color: @color-yellow;}
+ .text-light-bg-dark { color: #eee; background-color: #222;}
+
+Refresh the page. Select a snippet and click Customize. Choose one of your new
+options apply it.
+
+XPath & inherits
+''''''''''''''''
+
+You can also add images in your variables and use them on certain part of your
+pages, snippets or any html element.
+
+In :file:`odoo/addons/theme_dummy/static/style/custom.css` add these new lines
+
+.. code:: css
+
+ @bg-01: url("../img/background/bg-blur.jpg");
+
+ .bg-01 {
+ background-image: @bg-01;
+ }
+
+Now that you have set the background image, you can decide how and where the
+user can use it, for example, on a simple div.
+
+Open :file:`odoo/addons/theme_dummy/views/options.xml` and add this new xpath::
+
+ <xpath expr="//div[@data-option='background-dummy']//ul" position="after">
+ <ul class="dropdown-menu">
+ <li data-value="bg-01">
+ <a>Image 1</a>
+ </li>
+ </ul>
+ </xpath>
+
+Your option is ready to be applied but you want it to be shown only a certain
+part of a snippet.
+
+Open :file:`odoo/addons/theme_dummy/views/snippets.xml` and add a new snippet
+with the method we learned previously::
+
+ <xpath expr="//div[@id='snippet_structure']" position="inside">
+ <div>
+ <!-- Add a Thumbnail in the Website Builder drop-down menu -->
+ <div class="oe_snippet_thumbnail">
+ <img class="oe_snippet_thumbnail_img" src="/theme_Dummy/static/img/blocks/block_title.png"/>
+ <span class="oe_snippet_thumbnail_title">Test OPTION</span>
+ </div>
+ <!-- Your Snippet content -->
+ <section class="oe_snippet_body fw_categories">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-6 text-center mt32 mb32">
+ <h2>NO OPTION</h2>
+ <p>OFF</p>
+ </div>
+ <div class="col-md-6 text-center mt32 mb32 test-option">
+ <h2>OPTION</h2>
+ <p>This div has the 'test-option' class</p>
+ </div>
+ </div>
+ </div>
+ </section>
+ </div>
+ </xpath>
+
+As you see, the second ``col-md`` has a class named ``test-option``. We are
+going to specify where this option can be turned on by adding the
+``data-selector`` attribute.
+
+Go back to your ``options.xml`` files, add these new lines::
+
+ <xpath expr="//div[@data-option='background-dummy']" position="attributes">
+ <attribute name="data-selector">test-option</attribute>
+ </xpath>
+
+Refresh your browser. You should now be able to add your image background on
+the left div only. The option is now available on each section but also on
+the left div with the custom class.
+
+The Image Database
+------------------
+
+Modifying the image database
+''''''''''''''''''''''''''''
+
+Odoo provides its own image library but you certainly want to adapt it to your
+design. Do not use the Media Manager uploading Tool to add image in your
+theme. The images url's will be lost on reload! Instead of uploading your
+images, you can create your own library and disable the old ones.
+
+In ``odoo/addons/theme_dummy/views/`` create a new file, name it
+``images.xml`` and add these lines::
+
+ <record id="image_bg_blue" model="ir.attachment">
+ <field name="name">bg_blue.jpg</field>
+ <field name="datas_fname">bg_blue.jpg</field>
+ <field name="res_model">ir.ui.view</field>
+ <field name="type">url</field>
+ <field name="url">/theme_clean/static/img/library/bg/bg_blue.jpg</field>
+ </record>
+
+Your images is now available in your Media Manager. And your Theme has a
+total new look.
+
+Theme Selector
+==============
+
+Set Up
+------
+
+Understanding theme variants
+''''''''''''''''''''''''''''
+
+Combining theme variants
+''''''''''''''''''''''''
* This guide assumes `basic knowledge of Python
<http://docs.python.org/2/tutorial/>`_
* This guide assumes an installed Odoo
- * For production deployment, see the :ref:`dedicated deployment guides
- <guides/deployment>`
Creating a basic module
=======================
* :doc:`tutorials`, aimed at introducing the primary areas of developing Odoo
modules
-* :doc:`guides`, didactic documents covering more specific and specialized
- areas of Odoo, trying to solve more specific problems
* :doc:`reference`, which ought be the complete and canonical documentation
for Odoo subsystems
* :doc:`modules`, documenting useful specialized modules and integration
:hidden:
tutorials
- guides
reference
modules
reference/javascript
reference/reports
+ reference/workflows
+.. highlight:: xml
+
.. _reference/views:
=====
.. _reference/views/structure:
-Structure
-=========
+Common Structure
+================
View objects expose a number of fields, they are optional unless specified
otherwise)
.. todo:: widgets?
+Business Views guidelines
+-------------------------
+
+.. sectionauthor:: Aline Preillon, Raphael Collet
+
+Business views are targeted at regular users, not advanced users. Examples
+are: Opportunities, Products, Partners, Tasks, Projects, etc.
+
+.. image:: forms/oppreadonly.png
+ :class: img-responsive
+
+In general, a business view is composed of
+
+1. a status bar on top (with technical or business flow),
+2. a sheet in the middle (the form itself),
+3. a bottom part with History and Comments.
+
+Technically, the new form views are structured as follows in XML::
+
+ <form>
+ <header> ... content of the status bar ... </header>
+ <sheet> ... content of the sheet ... </sheet>
+ <div class="oe_chatter"> ... content of the bottom part ... </div>
+ </form>
+
+The Status Bar
+''''''''''''''
+
+The purpose of the status bar is to show the status of the current record and
+the action buttons.
+
+.. image:: forms/status.png
+ :class: img-responsive
+
+The Buttons
+...........
+
+The order of buttons follows the business flow. For instance, in a sale order,
+the logical steps are:
+
+1. Send the quotation
+2. Confirm the quotation
+3. Create the final invoice
+4. Send the goods
+
+Highlighted buttons (in red by default) emphasize the logical next step, to
+help the user. It is usually the first active button. On the other hand,
+:guilabel:`cancel` buttons *must* remain grey (normal). For instance, in
+Invoice the button :guilabel:`Refund` must never be red.
+
+Technically, buttons are highlighted by adding the class "oe_highlight"::
+
+ <button class="oe_highlight" name="..." type="..." states="..."/>
+
+The Status
+..........
+
+Uses the ``statusbar`` widget, and shows the current state in red. States
+common to all flows (for instance, a sale order begins as a quotation, then we
+send it, then it becomes a full sale order, and finally it is done) should be
+visible at all times but exceptions or states depending on particular sub-flow
+should only be visible when current.
+
+.. image:: forms/status1.png
+ :class: img-responsive
+
+.. image:: forms/status2.png
+ :class: img-responsive
+
+The states are shown following the order used in the field (the list in a
+selection field, etc). States that are always visible are specified with the
+attribute ``statusbar_visible``.
+
+``statusbar_colors`` can be used to give a custom color to specific states.
+
+::
+
+ <field name="state" widget="statusbar"
+ statusbar_visible="draft,sent,progress,invoiced,done"
+ statusbar_colors="{'shipping_except':'red','waiting_date':'blue'}"/>
+
+The Sheet
+'''''''''
+
+All business views should look like a printed sheet:
+
+.. image:: forms/sheet.png
+ :class: img-responsive
+
+1. Elements inside a ``<form>`` or ``<page>`` do not define groups, elements
+ inside them are laid out according to normal HTML rules. They content can
+ be explicitly grouped using ``<group>`` or regular ``<div>`` elements.
+2. By default, the element ``<group>`` defines two columns inside, unless an
+ attribute ``col="n"`` is used. The columns have the same width (1/n th of
+ the group's width). Use a ``<group>`` element to produce a column of fields.
+3. To give a title to a section, add a ``string`` attribute to a ``<group>`` element::
+
+ <group string="Time-sensitive operations">
+
+ this replaces the former use of ``<separator string="XXX"/>``.
+4. The ``<field>`` element does not produce a label, except as direct children
+ of a ``<group>`` element\ [#backwards-compatibility]_. Use :samp:`<label
+ for="{field_name}>` to produce a label of a field.
+
+Sheet Headers
+.............
+
+Some sheets have headers with one or more fields, and the labels of those
+fields are only shown in edit mode.
+
+.. list-table::
+ :header-rows: 1
+
+ * - View mode
+ - Edit mode
+ * - .. image:: forms/header.png
+ :class: img-responsive
+ - .. image:: forms/header2.png
+ :class: img-responsive
+
+Use HTML text, ``<div>``, ``<h1>``, ``<h2>``… to produce nice headers, and
+``<label>`` with the class ``oe_edit_only`` to only display the field's label
+in edit mode. The class ``oe_inline`` will make fields inline (instead of
+blocks): content following the field will be displayed on the same line rather
+than on the line below it. The form above is produced by the following XML::
+
+ <label for="name" class="oe_edit_only"/>
+ <h1><field name="name"/></h1>
+
+ <label for="planned_revenue" class="oe_edit_only"/>
+ <h2>
+ <field name="planned_revenue" class="oe_inline"/>
+ <field name="company_currency" class="oe_inline oe_edit_only"/> at
+ <field name="probability" class="oe_inline"/> % success rate
+ </h2>
+
+Button Box
+..........
+
+Many relevant actions or links can be displayed in the form. For example, in
+Opportunity form, the actions "Schedule a Call" and "Schedule a Meeting" take
+an important place in the use of the CRM. Instead of placing them in the
+"More" menu, put them directly in the sheet as buttons (on the top right) to
+make them more visible and more easily accessible.
+
+.. image:: forms/header3.png
+ :class: img-responsive
+
+Technically, the buttons are placed inside a <div> to group them as a block on
+the right-hand side of the sheet.
+
+::
+
+ <div class="oe_button_box oe_right">
+ <button string="Schedule/Log Call" name="..." type="action"/>
+ <button string="Schedule Meeting" name="action_makeMeeting" type="object"/>
+ </div>
+
+Groups and Titles
+.................
+
+A column of fields is now produced with a ``<group>`` element, with an
+optional title.
+
+.. image:: forms/screenshot-03.png
+ :class: img-responsive
+
+::
+
+ <group string="Payment Options">
+ <field name="writeoff_amount"/>
+ <field name="payment_option"/>
+ </group>
+
+It is recommended to have two columns of fields on the form. For this, simply
+put the ``<group>`` elements that contain the fields inside a top-level
+``<group>`` element.
+
+To make :ref:`view extension <reference/views/inheritance>` simpler, it is
+recommended to put a ``name`` attribute on ``<group>`` elements, so new fields
+can easily be added at the right place.
+
+Special Case: Subtotals
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Some classes are defined to render subtotals like in invoice forms:
+
+.. image:: forms/screenshot-00.png
+ :class: img-responsive
+
+::
+
+ <group class="oe_subtotal_footer">
+ <field name="amount_untaxed"/>
+ <field name="amount_tax"/>
+ <field name="amount_total" class="oe_subtotal_footer_separator"/>
+ <field name="residual" style="margin-top: 10px"/>
+ </group>
+
+Placeholders and Inline Fields
+..............................
+
+Sometimes field labels make the form too complex. One can omit field labels,
+and instead put a placeholder inside the field. The placeholder text is
+visible only when the field is empty. The placeholder should tell what to
+place inside the field, it *must not* be an example as they are often confused
+with filled data.
+
+One can also group fields together by rendering them "inline" inside an
+explicit block element like `<div>``. This allows grouping semantically
+related fields as if they were a single (composite) fields.
+
+The following example, taken from the *Leads* form, shows both placeholders and
+inline fields (zip and city).
+
+.. list-table::
+ :header-rows: 1
+
+ * - Edit mode
+ - View mode
+ * - .. image:: forms/placeholder.png
+ :class: img-responsive
+ - .. image:: forms/screenshot-01.png
+ :class: img-responsive
+
+::
+
+ <group>
+ <label for="street" string="Address"/>
+ <div>
+ <field name="street" placeholder="Street..."/>
+ <field name="street2"/>
+ <div>
+ <field name="zip" class="oe_inline" placeholder="ZIP"/>
+ <field name="city" class="oe_inline" placeholder="City"/>
+ </div>
+ <field name="state_id" placeholder="State"/>
+ <field name="country_id" placeholder="Country"/>
+ </div>
+ </group>
+
+Images
+......
+
+Images, like avatars, should be displayed on the right of the sheet. The
+product form looks like:
+
+.. image:: forms/screenshot-02.png
+ :class: img-responsive
+
+The form above contains a <sheet> element that starts with:
+
+::
+
+ <field name="product_image" widget="image" class="oe_avatar oe_right"/>
+
+Tags
+....
+
+Most :class:`~openerp.fields.Many2many` fields, like categories, are better
+rendered as a list of tags. Use the widget ``many2many_tags`` for this:
+
+.. image:: forms/screenshot-04.png
+ :class: img-responsive
+
+::
+
+ <field name="category_id" widget="many2many_tags"/>
+
+Configuration forms guidelines
+------------------------------
+
+Examples of configuration forms: Stages, Leave Type, etc. This concerns all
+menu items under Configuration of each application (like Sales/Configuration).
+
+.. image:: forms/nosheet.png
+ :class: img-responsive
+
+1. no header (because no state, no workflow, no button)
+2. no sheet
+
+Dialog forms guidelines
+-----------------------
+
+Example: "Schedule a Call" from an opportunity.
+
+.. image:: forms/wizard-popup.png
+ :class: img-responsive
+
+1. avoid separators (the title is already in the popup title bar, so another
+ separator is not relevant)
+2. avoid cancel buttons (user generally close the popup window to get the same
+ effect)
+3. action buttons must be highlighted (red)
+4. when there is a text area, use a placeholder instead of a label or a
+ separator
+5. like in regular form views, put buttons in the <header> element
+
+Configuration Wizards guidelines
+--------------------------------
+
+Example: Settings / Configuration / Sales.
+
+1. always in line (no popup)
+2. no sheet
+3. keep the cancel button (users cannot close the window)
+4. the button "Apply" must be red
+
+
.. _reference/views/graph:
Graphs
as inclusively composited: they will be composed with ``OR`` rather
than the usual ``AND``, e.g.
- .. code-block:: xml
+ ::
<filter domain="[('state', '=', 'draft')]"/>
<filter domain="[('state', '=', 'done')]"/>
if both filters are selected, will select the records whose ``state``
is ``draft`` or ``done``, but
- .. code-block:: xml
+ ::
<filter domain="[('state', '=', 'draft')]"/>
<separator/>
Search fields and filters can be configured through the action's ``context``
using :samp:`search_default_{name}` keys. For fields, the value should be the
value to set in the field, for filters it's a boolean value. For instance,
-assuming ``foo`` is a field and ``bar`` is a filter an action context of::
+assuming ``foo`` is a field and ``bar`` is a filter an action context of:
+
+.. code-block:: python
{
'search_default_foo': 'acro',
:ref:`reference/data/template` should be used as a shortcut to define QWeb
views.
+.. [#backwards-compatibility] for backwards compatibility reasons
.. [#hasclass] an extension function is added for simpler matching in QWeb
views: ``hasclass(*classes)`` matches if the context node has
all the specified classes
--- /dev/null
+DOTFILES:=$(wildcard *.dot)
+SVGFILES:=$(patsubst %.dot,%.svg,$(DOTFILES))
+PNGFILES:=$(patsubst %.dot,%.png,$(DOTFILES))
+
+# try to disable implicit rules
+.SUFFIXES:
+
+.PHONY: all clean
+
+all: $(SVGFILES) $(PNGFILES)
+
+# must -f to ignore errors when running clean multiple times in a row
+clean:
+ rm -f *.png *.svg
+
+%.svg: %.dot
+ dot -Tsvg $< > $@
+
+%.png: %.dot
+ dot -Tpng $< > $@
--- /dev/null
+digraph join {
+ // dummy sources as support for edges, make invisible and height 0
+ a [style=invis height=0 fontsize=0]
+ b [style=invis height=0 fontsize=0]
+ c [style=invis height=0 fontsize=0]
+
+ a -> Activity
+ b -> Activity
+ c -> Activity
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: join Pages: 1 -->
+<svg width="206pt" height="93pt"
+ viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
+<title>join</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
+<!-- a -->
+<!-- Activity -->
+<g id="node4" class="node"><title>Activity</title>
+<ellipse fill="none" stroke="black" cx="99" cy="-18" rx="40.0939" ry="18"/>
+<text text-anchor="middle" x="99" y="-14.3" font-family="Times,serif" font-size="14.00">Activity</text>
+</g>
+<!-- a->Activity -->
+<g id="edge1" class="edge"><title>a->Activity</title>
+<path fill="none" stroke="black" d="M33.6445,-71.9778C42.4332,-64.8537 58.4442,-51.875 72.4186,-40.5472"/>
+<polygon fill="black" stroke="black" points="74.7768,-43.1411 80.3411,-34.1251 70.3688,-37.7033 74.7768,-43.1411"/>
+</g>
+<!-- b -->
+<!-- b->Activity -->
+<g id="edge2" class="edge"><title>b->Activity</title>
+<path fill="none" stroke="black" d="M99,-71.9778C99,-66.0508 99,-56.0715 99,-46.3619"/>
+<polygon fill="black" stroke="black" points="102.5,-46.1364 99,-36.1364 95.5001,-46.1365 102.5,-46.1364"/>
+</g>
+<!-- c -->
+<!-- c->Activity -->
+<g id="edge3" class="edge"><title>c->Activity</title>
+<path fill="none" stroke="black" d="M164.355,-71.9778C155.567,-64.8537 139.556,-51.875 125.581,-40.5472"/>
+<polygon fill="black" stroke="black" points="127.631,-37.7033 117.659,-34.1251 123.223,-43.1411 127.631,-37.7033"/>
+</g>
+</g>
+</svg>
--- /dev/null
+digraph order {
+ Draft [style=filled fillcolor="#73fa79"]
+ Closed [style=filled fillcolor="#98c7df"]
+ Canceled [style=filled fillcolor="#98c7df"]
+
+ Draft -> Confirmed
+ Confirmed -> Closed
+ Confirmed -> Canceled
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: order Pages: 1 -->
+<svg width="188pt" height="188pt"
+ viewBox="0.00 0.00 188.24 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
+<title>order</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-184 184.243,-184 184.243,4 -4,4"/>
+<!-- Draft -->
+<g id="node1" class="node"><title>Draft</title>
+<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-162" rx="30.5947" ry="18"/>
+<text text-anchor="middle" x="85.3968" y="-158.3" font-family="Times,serif" font-size="14.00">Draft</text>
+</g>
+<!-- Confirmed -->
+<g id="node4" class="node"><title>Confirmed</title>
+<ellipse fill="none" stroke="black" cx="85.3968" cy="-90" rx="51.9908" ry="18"/>
+<text text-anchor="middle" x="85.3968" y="-86.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
+</g>
+<!-- Draft->Confirmed -->
+<g id="edge1" class="edge"><title>Draft->Confirmed</title>
+<path fill="none" stroke="black" d="M85.3968,-143.697C85.3968,-135.983 85.3968,-126.712 85.3968,-118.112"/>
+<polygon fill="black" stroke="black" points="88.8969,-118.104 85.3968,-108.104 81.8969,-118.104 88.8969,-118.104"/>
+</g>
+<!-- Closed -->
+<g id="node2" class="node"><title>Closed</title>
+<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
+<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
+</g>
+<!-- Canceled -->
+<g id="node3" class="node"><title>Canceled</title>
+<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
+<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
+</g>
+<!-- Confirmed->Closed -->
+<g id="edge2" class="edge"><title>Confirmed->Closed</title>
+<path fill="none" stroke="black" d="M73.7845,-72.411C67.8042,-63.8677 60.3917,-53.2785 53.7479,-43.7874"/>
+<polygon fill="black" stroke="black" points="56.5277,-41.6552 47.9257,-35.4699 50.7931,-45.6694 56.5277,-41.6552"/>
+</g>
+<!-- Confirmed->Canceled -->
+<g id="edge3" class="edge"><title>Confirmed->Canceled</title>
+<path fill="none" stroke="black" d="M97.2461,-72.411C103.348,-63.8677 110.912,-53.2785 117.692,-43.7874"/>
+<polygon fill="black" stroke="black" points="120.668,-45.6416 123.633,-35.4699 114.972,-41.573 120.668,-45.6416"/>
+</g>
+</g>
+</svg>
--- /dev/null
+digraph order {
+ Draft [style=filled fillcolor="#73fa79"]
+ Closed [style=filled fillcolor="#98c7df"]
+ Canceled [style=filled fillcolor="#98c7df"]
+
+ Draft -> Confirmed [label="discount <= 15%"]
+ Draft -> Validation [label="discount > 15%"]
+ Validation -> Confirmed [label="Accept"]
+ Confirmed -> Closed
+ Confirmed -> Canceled
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: order Pages: 1 -->
+<svg width="260pt" height="291pt"
+ viewBox="0.00 0.00 259.79 291.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 287)">
+<title>order</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-287 255.792,-287 255.792,4 -4,4"/>
+<!-- Draft -->
+<g id="node1" class="node"><title>Draft</title>
+<ellipse fill="#73fa79" stroke="black" cx="85.3968" cy="-265" rx="30.5947" ry="18"/>
+<text text-anchor="middle" x="85.3968" y="-261.3" font-family="Times,serif" font-size="14.00">Draft</text>
+</g>
+<!-- Confirmed -->
+<g id="node4" class="node"><title>Confirmed</title>
+<ellipse fill="none" stroke="black" cx="85.3968" cy="-91" rx="51.9908" ry="18"/>
+<text text-anchor="middle" x="85.3968" y="-87.3" font-family="Times,serif" font-size="14.00">Confirmed</text>
+</g>
+<!-- Draft->Confirmed -->
+<g id="edge1" class="edge"><title>Draft->Confirmed</title>
+<path fill="none" stroke="black" d="M72.5816,-248.399C62.7132,-235.312 49.8641,-215.656 44.3968,-196 40.1092,-180.585 40.1092,-175.415 44.3968,-160 48.7071,-144.503 57.6054,-129.007 66.0142,-116.73"/>
+<polygon fill="black" stroke="black" points="68.9995,-118.572 71.9779,-108.405 63.3089,-114.496 68.9995,-118.572"/>
+<text text-anchor="middle" x="94.3968" y="-174.3" font-family="Times,serif" font-size="14.00">discount <= 15%</text>
+</g>
+<!-- Validation -->
+<g id="node5" class="node"><title>Validation</title>
+<ellipse fill="none" stroke="black" cx="202.397" cy="-178" rx="49.2915" ry="18"/>
+<text text-anchor="middle" x="202.397" y="-174.3" font-family="Times,serif" font-size="14.00">Validation</text>
+</g>
+<!-- Draft->Validation -->
+<g id="edge2" class="edge"><title>Draft->Validation</title>
+<path fill="none" stroke="black" d="M103.936,-250.531C122.48,-237.059 151.286,-216.131 172.959,-200.386"/>
+<polygon fill="black" stroke="black" points="175.139,-203.129 181.172,-194.42 171.024,-197.466 175.139,-203.129"/>
+<text text-anchor="middle" x="195.897" y="-217.8" font-family="Times,serif" font-size="14.00">discount > 15%</text>
+</g>
+<!-- Closed -->
+<g id="node2" class="node"><title>Closed</title>
+<ellipse fill="#98c7df" stroke="black" cx="36.3968" cy="-18" rx="36.2938" ry="18"/>
+<text text-anchor="middle" x="36.3968" y="-14.3" font-family="Times,serif" font-size="14.00">Closed</text>
+</g>
+<!-- Canceled -->
+<g id="node3" class="node"><title>Canceled</title>
+<ellipse fill="#98c7df" stroke="black" cx="135.397" cy="-18" rx="44.6926" ry="18"/>
+<text text-anchor="middle" x="135.397" y="-14.3" font-family="Times,serif" font-size="14.00">Canceled</text>
+</g>
+<!-- Confirmed->Closed -->
+<g id="edge4" class="edge"><title>Confirmed->Closed</title>
+<path fill="none" stroke="black" d="M73.7845,-73.174C67.7175,-64.3831 60.1766,-53.4564 53.4596,-43.7236"/>
+<polygon fill="black" stroke="black" points="56.1491,-41.4588 47.5884,-35.2165 50.3879,-45.4348 56.1491,-41.4588"/>
+</g>
+<!-- Confirmed->Canceled -->
+<g id="edge5" class="edge"><title>Confirmed->Canceled</title>
+<path fill="none" stroke="black" d="M97.2461,-73.174C103.348,-64.5087 110.912,-53.7682 117.692,-44.1415"/>
+<polygon fill="black" stroke="black" points="120.736,-45.8965 123.633,-35.7052 115.013,-41.8661 120.736,-45.8965"/>
+</g>
+<!-- Validation->Confirmed -->
+<g id="edge3" class="edge"><title>Validation->Confirmed</title>
+<path fill="none" stroke="black" d="M181.209,-161.607C162.688,-148.152 135.604,-128.475 114.953,-113.472"/>
+<polygon fill="black" stroke="black" points="116.97,-110.612 106.822,-107.566 112.856,-116.275 116.97,-110.612"/>
+<text text-anchor="middle" x="170.397" y="-130.8" font-family="Times,serif" font-size="14.00">Accept</text>
+</g>
+</g>
+</svg>
--- /dev/null
+digraph split {
+ // dummy destinations as support for edges, make invisible and height 0
+ a [style=invis height=0 fontsize=0]
+ b [style=invis height=0 fontsize=0]
+ c [style=invis height=0 fontsize=0]
+
+ Activity -> a
+ Activity -> b
+ Activity -> c
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: split Pages: 1 -->
+<svg width="206pt" height="93pt"
+ viewBox="0.00 0.00 206.00 92.73" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 88.7279)">
+<title>split</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-88.7279 202,-88.7279 202,4 -4,4"/>
+<!-- a -->
+<!-- b -->
+<!-- c -->
+<!-- Activity -->
+<g id="node4" class="node"><title>Activity</title>
+<ellipse fill="none" stroke="black" cx="99" cy="-66.7279" rx="40.0939" ry="18"/>
+<text text-anchor="middle" x="99" y="-63.0279" font-family="Times,serif" font-size="14.00">Activity</text>
+</g>
+<!-- Activity->a -->
+<g id="edge1" class="edge"><title>Activity->a</title>
+<path fill="none" stroke="black" d="M80.4582,-50.6978C68.3594,-40.8903 52.7894,-28.2691 41.577,-19.1802"/>
+<polygon fill="black" stroke="black" points="43.641,-16.3478 33.6687,-12.7696 39.233,-21.7857 43.641,-16.3478"/>
+</g>
+<!-- Activity->b -->
+<g id="edge2" class="edge"><title>Activity->b</title>
+<path fill="none" stroke="black" d="M99,-48.5325C99,-40.494 99,-30.9869 99,-23.1351"/>
+<polygon fill="black" stroke="black" points="102.5,-22.8941 99,-12.8941 95.5001,-22.8942 102.5,-22.8941"/>
+</g>
+<!-- Activity->c -->
+<g id="edge3" class="edge"><title>Activity->c</title>
+<path fill="none" stroke="black" d="M117.542,-50.6978C129.641,-40.8903 145.211,-28.2691 156.423,-19.1802"/>
+<polygon fill="black" stroke="black" points="158.767,-21.7857 164.331,-12.7696 154.359,-16.3478 158.767,-21.7857"/>
+</g>
+</g>
+</svg>
--- /dev/null
+.. _reference/workflows:
+
+Workflows
+=========
+
+In Odoo, a workflow is a technical artefact to manage a set of "things to
+do" associated to the records of a model. The workflow provides a higher-level
+way to organize tasks to perform with or on a record.
+
+More specifically, a workflow is a directed graph where the nodes are called
+"activities" and the arcs are called "transitions".
+
+- Activities define work that should be done within the Odoo server, such
+ as changing the state of some records, or sending emails.
+- Transitions control how the workflow progresses from activity to activity.
+
+In the definition of a workflow, one can attach conditions, signals, and
+triggers to transitions, so that the behavior of the workflow depends on user
+actions (such as clicking on a button), changes to records, or arbitrary
+Python code.
+
+All in all, Odoo's workflow system provides:
+
+* a description of the evolution of a record (document) over time
+* automatic actions based on various and flexible conditions
+* management of company roles and validation steps
+* management of interactions between objects
+* a visual representation of document flows through their lifecycle
+
+For instance, a basic order could have the following flow:
+
+.. sphinx.ext.graphviz would be nice, but it requires ``dot`` on any machine
+.. where the doc is compiled... otoh this is a pain in the ass because you
+.. need 2 compilation steps (dot -> image and rst -> html) every time
+
+.. image:: workflow/order_0.*
+ :align: center
+
+Orders start in the *Draft* state, can be *Confirmed* by a user, and then
+either shipped (*Closed*) or *Canceled*.
+
+A company using Odoo may want to add discount support to orders, where sales
+staff has discretionary discounting powers up to 15%, but manager validation
+is required for discounts beyond 15%. The workflow can be altered online to
+add the relevant steps without editing Python or XML files:
+
+.. image:: workflow/order_1.*
+ :align: center
+
+Because Activities can perform arbitrary actions, the *Validation* can
+automatically send a validation request to the relevant employee.
+
+.. note:: the order view needs to be modified to add an *Accept Discount*
+ button for managers
+
+Basics
+------
+
+Defining a workflow with data files is straightforward: a record "workflow" is
+given together with records for the activities and the transitions. For
+instance, here is a simple sequence of two activities defined in XML
+
+.. code-block:: xml
+
+ <record id="test_workflow" model="workflow">
+ <field name="name">test.workflow</field>
+ <field name="osv">test.workflow.model</field>
+ <field name="on_create">True</field>
+ </record>
+
+ <record id="activity_a" model="workflow.activity">
+ <field name="wkf_id" ref="test_workflow"/>
+ <field name="flow_start">True</field>
+ <field name="name">a</field>
+ <field name="kind">function</field>
+ <field name="action">print_a()</field>
+ </record>
+ <record id="activity_b" model="workflow.activity">
+ <field name="wkf_id" ref="test_workflow"/>
+ <field name="flow_stop">True</field>
+ <field name="name">b</field>
+ <field name="kind">function</field>
+ <field name="action">print_b()</field>
+ </record>
+
+ <record id="trans_a_b" model="workflow.transition">
+ <field name="act_from" ref="activity_a"/>
+ <field name="act_to" ref="activity_b"/>
+ </record>
+
+A worfklow is always defined with respect to a particular model (the model is
+given by the attribute ``osv`` on the model ``workflow``). Methods specified
+in the activities or transitions will be called on that model.
+
+In the example code above, a workflow called "test_workflow" is created. It is
+made up of two activies, named "a" and "b", and one transition, going from "a"
+to "b".
+
+The first activity has its attribute ``flow_start`` set to ``True`` so that
+Odoo knows where to start the workflow traversal after it is instanciated.
+Because ``on_create`` is set to True on the workflow record, the workflow is
+instanciated for each newly created record. (Otherwise, the workflow should be
+instanciated by other means, such as from some module Python code.)
+
+When the workflow is instanciated, it begins with activity "a". That activity
+is of kind ``function``, which means that the action ``print_a()`` is a method
+call on the model ``test.workflow`` (the usual ``cr, uid, ids, context``
+arguments are passed for you).
+
+The transition between "a" and "b" does not specify any condition. This means
+that the workflow instance immediately goes from "a" to "b" after "a" has been
+processed, and thus also processes activity "b".
+
+Activities
+----------
+
+While the transitions can be seen as the control structures of the workflows,
+activities are the places where everything happens, from changing record
+states to sending email.
+
+Different kinds of activities exist: ``Dummy``, ``Function``, ``Subflow``, and
+``Stop all``, each doing different things when the activity is processed. In
+addition to their kind, activies have other properties, detailed in the next
+sections.
+
+Flow start and flow stop
+''''''''''''''''''''''''
+
+The attribute ``flow_start`` is a boolean value specifying whether the activity
+is processed when the workflow is instanciated. Multiple activities can have
+their attribute ``flow_start`` set to ``True``. When instanciating a workflow
+for a record, Odoo simply processes all of them, and evaluate all their
+outgoing transitions afterwards.
+
+The attribute ``flow_stop`` is a boolean value specifying whether the activity
+stops the workflow instance. A workflow instance is considered completed when
+all its activities with the attribute ``flow_stop`` set to ``True`` are
+completed.
+
+It is important for Odoo to know when a workflow instance is completed. A
+workflow can have an activity that is actually another workflow (called a
+subflow); that activity is completed when the subflow is completed.
+
+Subflow
+'''''''
+
+An activity can embed a complete workflow, called a subflow (the embedding
+workflow is called the parent workflow). The workflow to instanciate is
+specified by attribute ``subflow_id``.
+
+.. note:: In the GUI, that attribute can not be set unless the kind of the
+ activity is ``Subflow``.
+
+The activity is considered completed (and its outgoing transitions ready to be
+evaluated) when the subflow is completed (see attribute ``flow_stop`` above).
+
+Sending a signal from a subflow
+'''''''''''''''''''''''''''''''
+
+When a workflow is embedded in an activity (as a subflow) of a workflow, the
+sublow can send a signal from its own activities to the parent workflow by
+giving a signal name in the attribute ``signal_send``. Odoo processes those
+activities by sending the value of ``signal_send`` prefixed by "subflow." to
+the parent workflow instance.
+
+In other words, it is possible to react and get transitions in the parent
+workflow as activities are executed in the sublow.
+
+Server actions
+''''''''''''''
+
+An activity can run a "Server Action" by specifying its ID in the attribute
+``action_id``.
+
+Python action
+'''''''''''''
+
+An activity can execute some Python code, given by the attribute ``action``.
+The evaluation environment is the same as the one explained in the section
+`Conditions`_.
+
+Split mode
+''''''''''
+
+After an activity has been processed, Odoo evaluates its transition to reach
+the next activity in the flow.
+
+However if an activity has more than one transition, Odoo must decide which
+activity or activities to follow.
+
+.. image:: workflow/split.*
+ :align: center
+
+This choice is controlled by the ``split_mode`` attribute:
+
+``XOR`` (default)
+ By default, Odoo will use the first transition (in ``sequence`` order)
+ whose condition is satisfied. All other transitions are ignored.
+``OR``
+ In ``OR`` mode, all transitions with a satisfied condition are traversed
+ simultanously. Transitions not yet valid will be ignored, even if they
+ become valid later.
+``AND``
+ In ``AND`` mode, Odoo will wait until *all* transitions are satisfied, and
+ will traverse all of them (much like the ``OR`` mode).
+
+Both ``OR`` and ``AND`` mode will lead to activities being active in the same
+workflow.
+
+Join mode
+'''''''''
+
+Just like outgoing transition conditions can be combined together to decide
+whether they can be traversed or not, incoming transitions can be combined
+together to decide if and when an activity may be processed.
+
+.. image:: workflow/join.*
+ :align: center
+
+The ``join_mode`` attribute controls that behavior:
+
+``XOR`` (default)
+ Any incoming transition enables the activity and starts its processing.
+``AND``
+ The activity is enabled and processed only once *all* incoming transitions
+ have been traversed.
+
+Kinds
+'''''
+
+An activity's kind defines the type of work an activity can perform.
+
+Dummy (``dummy``, default)
+ Do nothing at all, or call a server action. Often used as dispatch or
+ gather "hubs" for transitions.
+Function (``function``)
+ Run some python code, execute a server action.
+Stop all (``stopall``)
+ Completely stops the workflow instance and marks it as completed.
+Subflow (``subflow``)
+ Starts executing an other workflow, once that workflow is completed the
+ activity is done processing.
+
+ By default, the subflow is instanciated for the same record as the parent
+ workflow. It is possible to change that behavior by providing Python code
+ that returns a record ID (of the same data model as the subflow). The
+ embedded subflow instance is then the one of the given record.
+
+
+Transitions
+-----------
+
+Transitions provide the control structures to orchestrate a workflow. When an
+activity is completed, the workflow engine tries to get across transitions
+departing from the completed activity, towards the next activities. In their
+simplest form (as in the example above), they link activities sequentially:
+activities are processed as soon as the activities preceding them are
+completed.
+
+Instead of running all activities in one fell swoop, it is also possible to
+wait on transitions, going through them only when some criteria are met. The
+criteria are the conditions, the signals, and the triggers. They are detailed
+in the following sections.
+
+Conditions
+''''''''''
+
+When an activity has been completed, its outgoing transitions are inspected to
+determine whether it is possible for the workflow instance to proceed through
+them and reach the next activities. When only a condition is defined (i.e., no
+signal or trigger is defined), the condition is evaluated by Odoo, and if
+it evaluates to ``True``, the worklfow instance progresses through the
+transition. If the condition is not met, it will be reevaluated every time
+the associated record is modified, or by an explicit method call to do it.
+
+By default, the attribute ``condition`` (i.e., the expression to be evaluated)
+is just "True", which trivially evaluates to ``True``. Note that the condition
+may be several lines long; in that case, the value of the last one determines
+whether the transition can be taken.
+
+In the condition evaluation environment, several symbols are conveniently
+defined (in addition to the Odoo ``safe_eval`` environment):
+
+- all the model column names, and
+- all the browse record's attributes.
+
+Signals
+'''''''
+
+In addition to a condition, a transition can specify a signal name. When such
+a signal name is present, the transition is not taken directly, even if the
+condition evaluates to ``True``. Instead the transition blocks, waiting to be
+woken up.
+
+In order to wake up a transition with a defined signal name, the signal must
+be sent to the workflow instance. A common way to send a signal is to use a
+button in the user interface, using the element ``<button/>`` with the signal
+name as the attribute ``name`` of the button. Once the button is clicked, the
+signal is sent to the workflow instance of the current record.
+
+.. note:: The condition is still evaluated when the signal is sent to the
+ workflow instance.
+
+Triggers
+''''''''
+
+With conditions that evaluate to ``False``, transitions are not taken (and
+thus the activity it leads to is not processed immediately). Still, the
+workflow instance can get new chances to progress across that transition by
+providing so-called triggers. The idea is that when the condition is not
+satisfied, triggers are recorded in database. Later, it is possible to wake up
+specifically the workflow instances that installed those triggers, offering
+them to reevaluate their transition conditions. This mechanism makes it
+cheaper to wake up workflow instances by targetting just a few of them (those
+that have installed the triggers) instead of all of them.
+
+Triggers are recorded in database as record IDs (together with the model name)
+and refer to the workflow instance waiting for those records. The transition
+definition provides a model name (attribute ``trigger_model``) and a Python
+expression (attribute ``trigger_expression``) that evaluates to a list of
+record IDs in the given model. Any of those records can wake up the workflow
+instance they are associated with.
+
+.. note:: triggers are not re-installed whenever the transition is re-tried.
howtos/website
howtos/backend
howtos/web
+ howtos/themes