From c946b35f71d68916aca521dacfe3a15154731416 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Thu, 6 May 2021 13:42:08 +0200 Subject: [PATCH 1/5] [FIX] conf: specify which value is actually needed --- conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.py b/conf.py index c44925f63..a92ac09d4 100644 --- a/conf.py +++ b/conf.py @@ -308,7 +308,7 @@ def _generate_alternate_urls(app, pagename, templatename, context, doctree): def _build_url(_version=None, _lang=None): if app.config.is_remote_build: - # Project root like https://odoo.com/documentation/14.0/fr + # Project root like https://www.odoo.com/documentation _root = app.config.project_root else: # Project root like .../documentation/_build/html/14.0/fr From 73806971a295cf57a7dbe86314005431074f9b6a Mon Sep 17 00:00:00 2001 From: Ludvig Auvens Date: Fri, 7 May 2021 10:48:38 +0200 Subject: [PATCH 2/5] [ADD] IoT: New doc about how to connect a scale using the IoT box. --- .../applications/productivity/iot/devices.rst | 3 +- .../productivity/iot/devices/scale.rst | 55 ++++++++++++++++++ .../iot/devices/scale/driver-list.png | Bin 0 -> 22773 bytes .../scale/electronic-scale-feature.png | Bin 0 -> 11705 bytes .../iot/devices/scale/iot-box-pos.png | Bin 0 -> 5666 bytes .../iot/devices/scale/iot-choice.png | Bin 0 -> 4628 bytes .../iot/devices/scale/scale-view.png | Bin 0 -> 5856 bytes 7 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 content/applications/productivity/iot/devices/scale.rst create mode 100644 content/applications/productivity/iot/devices/scale/driver-list.png create mode 100644 content/applications/productivity/iot/devices/scale/electronic-scale-feature.png create mode 100644 content/applications/productivity/iot/devices/scale/iot-box-pos.png create mode 100644 content/applications/productivity/iot/devices/scale/iot-choice.png create mode 100644 content/applications/productivity/iot/devices/scale/scale-view.png diff --git a/content/applications/productivity/iot/devices.rst b/content/applications/productivity/iot/devices.rst index c834c9a61..5be79fa62 100644 --- a/content/applications/productivity/iot/devices.rst +++ b/content/applications/productivity/iot/devices.rst @@ -9,4 +9,5 @@ Devices devices/measurement_tool devices/camera devices/footswitch - devices/printer \ No newline at end of file + devices/printer + devices/scale \ No newline at end of file diff --git a/content/applications/productivity/iot/devices/scale.rst b/content/applications/productivity/iot/devices/scale.rst new file mode 100644 index 000000000..38e01bb56 --- /dev/null +++ b/content/applications/productivity/iot/devices/scale.rst @@ -0,0 +1,55 @@ +=============== +Connect a Scale +=============== + +When using your **IoT Box** in Odoo, you could need to use a scale. Doing so is easy and convenient +as it can be done in a few steps. Then, you can use it in your **Point of Sale app** to weigh your +products, which is helpful if their price are based on it. + +Connection +========== + +To link the scale to the **IoT Box**, connect them with a cable. + +.. note:: + In some cases, a serial to USB adapter may be needed. + +If your scale is `compatibale with Odoo IoT Box `_, there +is no need to set up anything because it will be automatically detected as soon as it is connected. + +.. image:: scale/iot-choice.png + :align: center + :alt: IOT box auto detection. + +You may need to restart the box and download your scales’ drivers from the box in some cases. To do +so, go to the *IoT Box Home Page* and click on *drivers list*. Then, click on load drivers. + +.. image:: scale/driver-list.png + :align: center + :alt: View of the IoT box settings and driver list. + +Use a Scale in Point of Sale +============================ + +To use the scale in your *Point of Sale* app, go to :menuselection:`Point of Sale --> Configuration +--> Point of Sale`, open the one you want to configure, then click on *Edit* and enable the *IoT +Box* feature. + +.. image:: scale/iot-box-pos.png + :align: center + :alt: View of the IoT box feature inside of the PoS settings. + +Now, choose the *IoT Box* in the dropdown menu and check the *Electronic Scale* option. Then, you +hit save. + +.. image:: scale/electronic-scale-feature.png + :align: center + :alt: List of the external tools that can be used with PoS and the IoT box. + +The scale is now available in all your *PoS* sessions. Then, if a product has a price per weight +set, clicking on it on the *PoS* screen opens the scale screen, where the cashier can weigh the +product and add the correct price to the cart. + +.. image:: scale/scale-view.png + :align: center + :alt: Electronic Scale dashboard view when no items are being weighed. \ No newline at end of file diff --git a/content/applications/productivity/iot/devices/scale/driver-list.png b/content/applications/productivity/iot/devices/scale/driver-list.png new file mode 100644 index 0000000000000000000000000000000000000000..d87a4cca9fd456cd9dea2b020cca507316adc471 GIT binary patch literal 22773 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 CU|E^~ literal 0 HcmV?d00001 diff --git a/content/applications/productivity/iot/devices/scale/electronic-scale-feature.png b/content/applications/productivity/iot/devices/scale/electronic-scale-feature.png new file mode 100644 index 0000000000000000000000000000000000000000..6bd38692b6686feb42118a293c21b5fae9acae3d GIT binary patch literal 11705 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 literal 0 HcmV?d00001 diff --git a/content/applications/productivity/iot/devices/scale/iot-choice.png b/content/applications/productivity/iot/devices/scale/iot-choice.png new file mode 100644 index 0000000000000000000000000000000000000000..8021bcfaa0db8fbcd8d240f57c480874b1d04e7d GIT binary patch literal 4628 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 literal 0 HcmV?d00001 diff --git a/content/applications/productivity/iot/devices/scale/scale-view.png b/content/applications/productivity/iot/devices/scale/scale-view.png new file mode 100644 index 0000000000000000000000000000000000000000..49437b31a426287fcf404f98fbf4c7ae24369ded GIT binary patch literal 5856 zcmaJ_2Q-}Bx|TvDLaLI8NP-~RpJ>sgh#*KX7(Ed+N*G2bqW6ey^k5>&j9y3YgTaIu zqjzJ9no$OG{pXy!*1c!lbHDX`-`eZl&wk&%-*-QIuk}T|)ly}?bo&w=9UZgU>z6uo zbZ021F9+kfQ%jl;uP+_lIl8xR^i(#<93RtYG^bt&001~V zH~<2HUS3}N`}<2vOF#gitE-Dbp}4!d6V}&*gMutAEhi?h7z`#mJ3A~aY;bTeARu6D zY|Nt<;^gE=qa8W*<^TXdJRWasVq#@wm6(_~H#avkGn1BUe(|=rkmC zrn9qicXu~n4!^U#1F%i(@9(#;u%OWns8niQeLbNem~=ubDk=i#+nbr0$HvC4uC78H z4FLLPsNvz<+}!;9d>0p&@A2_lTU%>1T2xeYds`c7V`GzyudJ+e>aV4ouB#9Fr4KSc zUo<&62{4cBJD@EQ)-p0O$bAVk+U^%q0N4;vTT`<|{_XS|J&F#h@z1!I{<*R zzg1FFLOWdEB_YxXf3}Wkwuwj>4ECjFv8T5;b*#?73%=3y<+&4bQx)79Oh=CK^7 z!MetVM%>yT05G8I&vDELz~*cv3Qx|c=nk5iaT~`#`XF#`!zmIus%j9vebkC4N2bH^ z1cXQFY$tjB^Kcg$yYQ_af`$1mRromd!DxG!6Uv}fFw6|7Us_t)+}w=VrGYZrR#(a} zB=S#JeJ|*6W$?$)KFH?Q6nP7Y$96n5B>@`eP z$Ii_h<2zk#Epi4R)*wH4Vo-=Zu%#&WcYT)czz_HSZ0vk#!Z>Ycwy_VEVDA~xKCwR9 z0h@14NaT^ ziEjJ$#jz~LxvQz>3wCI9psKySKWB!99v!Ogh>Peu0D)XX5`t|b;=eZ+2sqj*Go;vy$o1z}>Qw@j=A@SD0HZ&i+ zr_ru=V&b^@WmQ!1^&yXp{YWG%8y=?~X03jW#}D9qNMjP8eG`9)e4Ax~;=NBlIR zIULwk^R+e8@l8AQ>%6`>(Nwtz9b+Kwun`>HUdJpK6f6rfFcGXfw2PUstC|FSI9v6m zo`}lsd%VNGUG*7i69A;Io*OUik`Zx58vRrPzlXLzNAc2?<~o?Ue!*u=;C;Md;p{&~ zYcNe5u79t2RWHhk*j@Yc4<4EzvEQyPwVTlQ8q{Qy<**|H|&HR zw7tf;#^nbP(UA{--E^ck?0`fDUx;bVdfVaV>v_4IQd3Lrw#GaT-AMO1EdA~;yi628{$_E%3 zO1@UHdD;s)bu96Q?X?W1ouP6}g?(1k&)>+=z8qv4O)R`_Rcc$%=J;bc%2XaT9^*aE zv~aF93;sm>)!v|_TPx0lrJ=x;u#L9YjhY^Ma+nV@%+1mO`BcK{`Z6qsB)1%roabHf z^l<*~L9y>*_BZJ`u@(Z*XnzU9*6Emt>5fZM5b=e$%0D8BGeO8W|4SCyIcEz5$?p}= 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 R4E(!SO-1Wv*>j7p{{^b$TZ8}r literal 0 HcmV?d00001 From ac99ad7abd49acb7ceaa7935fe93bea88fddc3bb Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Mon, 10 May 2021 13:42:17 +0200 Subject: [PATCH 3/5] [REM] *: patchqueue extension Remove the patchqueue extension from the doc requirements since it isn't maintained anymore (raising warnings for recent sphinx versions) and the patches to specify code blocks aren't easy to maintain. Remove hidden code patches, and replaces shown patches by code block / literalincludes to keep the useful content. --- conf.py | 3 - content/developer/howtos/backend.rst | 286 --------- .../howtos/backend/exercise-access-rights | 40 -- .../howtos/backend/exercise-access-rules | 27 - .../howtos/backend/exercise-advanced-treeview | 19 - .../howtos/backend/exercise-basic-action | 54 -- .../howtos/backend/exercise-calendar | 78 --- .../howtos/backend/exercise-computed | 40 -- .../howtos/backend/exercise-constraint-python | 25 - .../howtos/backend/exercise-constraint-sql | 24 - .../howtos/backend/exercise-copy-override | 28 - .../howtos/backend/exercise-creation | 152 ----- .../howtos/backend/exercise-dashboard | 95 --- .../howtos/backend/exercise-defaults | 28 - .../developer/howtos/backend/exercise-demo | 48 -- .../howtos/backend/exercise-domain-advanced | 42 -- .../howtos/backend/exercise-domain-basic | 17 - .../howtos/backend/exercise-formview | 29 - .../backend/exercise-formview-notebooks | 24 - .../developer/howtos/backend/exercise-gantt | 61 -- .../developer/howtos/backend/exercise-graph | 56 -- .../developer/howtos/backend/exercise-kanban | 78 --- .../howtos/backend/exercise-many2many | 22 - .../howtos/backend/exercise-many2one | 95 --- .../developer/howtos/backend/exercise-model | 19 - .../howtos/backend/exercise-model-inheritance | 78 --- .../howtos/backend/exercise-onchange | 28 - .../howtos/backend/exercise-one2many | 36 -- .../developer/howtos/backend/exercise-report | 50 -- .../howtos/backend/exercise-searchview | 28 - .../howtos/backend/exercise-searchview-basic | 24 - .../developer/howtos/backend/exercise-session | 58 -- .../howtos/backend/exercise-translations | 56 -- .../developer/howtos/backend/exercise-wizard | 25 - .../howtos/backend/exercise-wizard-action | 30 - .../howtos/backend/exercise-wizard-launch | 45 -- .../howtos/backend/exercise-wizard-multi | 38 -- content/developer/howtos/backend/series | 35 -- content/developer/howtos/website.rst | 560 +++++++++++++++++- content/developer/howtos/website/basic-acl | 23 - .../developer/howtos/website/basic-controller | 22 - content/developer/howtos/website/basic-model | 18 - .../developer/howtos/website/biography-esc | 23 - .../developer/howtos/website/biography-field | 18 - .../developer/howtos/website/chatter-backend | 29 - .../developer/howtos/website/converter-model | 44 -- content/developer/howtos/website/course-m2o | 24 - .../developer/howtos/website/course-no-price | 21 - content/developer/howtos/website/course-o2m | 33 -- .../developer/howtos/website/course-product | 142 ----- .../howtos/website/course-products-sidebar | 18 - content/developer/howtos/website/course-views | 57 -- .../howtos/website/data-retrieval-orm | 30 - content/developer/howtos/website/demo-data | 42 -- content/developer/howtos/website/field-format | 16 - content/developer/howtos/website/field-raw | 15 - content/developer/howtos/website/field-widget | 16 - content/developer/howtos/website/module-empty | 153 ----- .../howtos/website/product-dependency | 16 - .../developer/howtos/website/routing-basic | 19 - .../howtos/website/routing-converter | 20 - content/developer/howtos/website/series | 27 - .../developer/howtos/website/teacher-links | 27 - .../howtos/website/teachers-formview | 26 - .../developer/howtos/website/teachers-menu | 35 -- content/developer/howtos/website/template | 42 -- .../developer/howtos/website/website-support | 50 -- content/developer/webservices/iap.rst | 214 +++++-- content/developer/webservices/iap/01-init | 16 - content/developer/webservices/iap/02-button | 34 -- content/developer/webservices/iap/03-callback | 40 -- content/developer/webservices/iap/series | 3 - .../developer/webservices/iap_service/01-init | 16 - .../developer/webservices/iap_service/02-tnx | 48 -- .../webservices/iap_service/03-template | 56 -- .../developer/webservices/iap_service/series | 3 - requirements.txt | 1 - 77 files changed, 696 insertions(+), 3222 deletions(-) delete mode 100644 content/developer/howtos/backend/exercise-access-rights delete mode 100644 content/developer/howtos/backend/exercise-access-rules delete mode 100644 content/developer/howtos/backend/exercise-advanced-treeview delete mode 100644 content/developer/howtos/backend/exercise-basic-action delete mode 100644 content/developer/howtos/backend/exercise-calendar delete mode 100644 content/developer/howtos/backend/exercise-computed delete mode 100644 content/developer/howtos/backend/exercise-constraint-python delete mode 100644 content/developer/howtos/backend/exercise-constraint-sql delete mode 100644 content/developer/howtos/backend/exercise-copy-override delete mode 100644 content/developer/howtos/backend/exercise-creation delete mode 100644 content/developer/howtos/backend/exercise-dashboard delete mode 100644 content/developer/howtos/backend/exercise-defaults delete mode 100644 content/developer/howtos/backend/exercise-demo delete mode 100644 content/developer/howtos/backend/exercise-domain-advanced delete mode 100644 content/developer/howtos/backend/exercise-domain-basic delete mode 100644 content/developer/howtos/backend/exercise-formview delete mode 100644 content/developer/howtos/backend/exercise-formview-notebooks delete mode 100644 content/developer/howtos/backend/exercise-gantt delete mode 100644 content/developer/howtos/backend/exercise-graph delete mode 100644 content/developer/howtos/backend/exercise-kanban delete mode 100644 content/developer/howtos/backend/exercise-many2many delete mode 100644 content/developer/howtos/backend/exercise-many2one delete mode 100644 content/developer/howtos/backend/exercise-model delete mode 100644 content/developer/howtos/backend/exercise-model-inheritance delete mode 100644 content/developer/howtos/backend/exercise-onchange delete mode 100644 content/developer/howtos/backend/exercise-one2many delete mode 100644 content/developer/howtos/backend/exercise-report delete mode 100644 content/developer/howtos/backend/exercise-searchview delete mode 100644 content/developer/howtos/backend/exercise-searchview-basic delete mode 100644 content/developer/howtos/backend/exercise-session delete mode 100644 content/developer/howtos/backend/exercise-translations delete mode 100644 content/developer/howtos/backend/exercise-wizard delete mode 100644 content/developer/howtos/backend/exercise-wizard-action delete mode 100644 content/developer/howtos/backend/exercise-wizard-launch delete mode 100644 content/developer/howtos/backend/exercise-wizard-multi delete mode 100644 content/developer/howtos/backend/series delete mode 100644 content/developer/howtos/website/basic-acl delete mode 100644 content/developer/howtos/website/basic-controller delete mode 100644 content/developer/howtos/website/basic-model delete mode 100644 content/developer/howtos/website/biography-esc delete mode 100644 content/developer/howtos/website/biography-field delete mode 100644 content/developer/howtos/website/chatter-backend delete mode 100644 content/developer/howtos/website/converter-model delete mode 100644 content/developer/howtos/website/course-m2o delete mode 100644 content/developer/howtos/website/course-no-price delete mode 100644 content/developer/howtos/website/course-o2m delete mode 100644 content/developer/howtos/website/course-product delete mode 100644 content/developer/howtos/website/course-products-sidebar delete mode 100644 content/developer/howtos/website/course-views delete mode 100644 content/developer/howtos/website/data-retrieval-orm delete mode 100644 content/developer/howtos/website/demo-data delete mode 100644 content/developer/howtos/website/field-format delete mode 100644 content/developer/howtos/website/field-raw delete mode 100644 content/developer/howtos/website/field-widget delete mode 100644 content/developer/howtos/website/module-empty delete mode 100644 content/developer/howtos/website/product-dependency delete mode 100644 content/developer/howtos/website/routing-basic delete mode 100644 content/developer/howtos/website/routing-converter delete mode 100644 content/developer/howtos/website/series delete mode 100644 content/developer/howtos/website/teacher-links delete mode 100644 content/developer/howtos/website/teachers-formview delete mode 100644 content/developer/howtos/website/teachers-menu delete mode 100644 content/developer/howtos/website/template delete mode 100644 content/developer/howtos/website/website-support delete mode 100644 content/developer/webservices/iap/01-init delete mode 100644 content/developer/webservices/iap/02-button delete mode 100644 content/developer/webservices/iap/03-callback delete mode 100644 content/developer/webservices/iap/series delete mode 100644 content/developer/webservices/iap_service/01-init delete mode 100644 content/developer/webservices/iap_service/02-tnx delete mode 100644 content/developer/webservices/iap_service/03-template delete mode 100644 content/developer/webservices/iap_service/series diff --git a/conf.py b/conf.py index a92ac09d4..922709e57 100644 --- a/conf.py +++ b/conf.py @@ -102,9 +102,6 @@ extensions = [ 'exercise_admonition', - # Build code from git patches - 'patchqueue', - # Redirection generator 'redirects', diff --git a/content/developer/howtos/backend.rst b/content/developer/howtos/backend.rst index 14d6842f3..4fd02f7ed 100644 --- a/content/developer/howtos/backend.rst +++ b/content/developer/howtos/backend.rst @@ -1,6 +1,4 @@ -.. queue:: backend/series - ================= Building a Module ================= @@ -111,14 +109,6 @@ or XML. The usage of most of those files will be explained along this tutorial. Use the command line above to create an empty module Open Academy, and install it in Odoo. - .. only:: solutions - - #. Invoke the command ``odoo-bin scaffold openacademy addons``. - #. Adapt the manifest file to your module. - #. Don't bother about the other files. - - .. patch:: - Object-Relational Mapping ------------------------- @@ -213,12 +203,6 @@ overridden by setting :attr:`~odoo.models.Model._rec_name`. Define a new data model *Course* in the *openacademy* module. A course has a title and a description. Courses must have a title. - .. only:: solutions - - Edit the file ``openacademy/models/models.py`` to include a *Course* class. - - .. patch:: - Data files ---------- @@ -257,12 +241,6 @@ be declared in the ``'data'`` list (always loaded) or in the ``'demo'`` list Create demonstration data filling the *Courses* model with a few demonstration courses. - .. only:: solutions - - Edit the file ``openacademy/demo/demo.xml`` to include some data. - - .. patch:: - .. tip:: The content of the data files is only loaded when a module is installed or updated. @@ -310,14 +288,6 @@ action more easily. - display a list of all the courses - create/modify courses - .. only:: solutions - - #. Create ``openacademy/views/openacademy.xml`` with an action and - the menus triggering the action - #. Add it to the ``data`` list of ``openacademy/__manifest__.py`` - - .. patch:: - Basic views =========== @@ -410,22 +380,12 @@ elements (groups, notebooks) and interactive elements (buttons and fields): Create your own form view for the Course object. Data displayed should be: the name and the description of the course. - .. only:: solutions - - .. patch:: - .. exercise:: Notebooks In the Course form view, put the description field under a tab, such that it will be easier to add other tabs later, containing additional information. - .. only:: solutions - - Modify the Course form view as follows: - - .. patch:: - Form views can also use plain HTML for more flexible layouts: .. code-block:: xml @@ -473,10 +433,6 @@ searching on the ``name`` field. Allow searching for courses based on their title or their description. - .. only:: solutions - - .. patch:: - Relations between models ======================== @@ -493,18 +449,6 @@ client data; it is also related to its sale order line records. duration and a number of seats. Add an action and a menu item to display them. Make the new model visible via a menu item. - .. only:: solutions - - #. Create the class *Session* in ``openacademy/models/models.py``. - #. Add access to the session object in ``openacademy/view/openacademy.xml``. - - .. patch:: - - .. note:: ``digits=(6, 2)`` specifies the precision of a float number: - 6 is the total number of digits, while 2 is the number of - digits after the comma. Note that it results in the number - digits before the comma is a maximum 4 - Relational fields ----------------- @@ -555,25 +499,11 @@ Relational field types are: of the model ``openacademy.course`` and is required. - Adapt the views. - .. only:: solutions - - #. Add the relevant ``Many2one`` fields to the models, and - #. add them in the views. - - .. patch:: - .. exercise:: Inverse one2many relations Using the inverse relational field one2many, modify the models to reflect the relation between courses and sessions. - .. only:: solutions - - #. Modify the ``Course`` class, and - #. add the field in the course form view. - - .. patch:: - .. exercise:: Multiple many2many relations Using the relational field many2many, modify the *Session* model to relate @@ -581,13 +511,6 @@ Relational field types are: partner records, so we will relate to the built-in model ``res.partner``. Adapt the views accordingly. - .. only:: solutions - - #. Modify the ``Session`` class, and - #. add the field in the form view. - - .. patch:: - Inheritance =========== @@ -687,21 +610,6 @@ instead of a single view its ``arch`` field is composed of any number of the session-partner relation * Using view inheritance, display this fields in the partner form view - .. only:: solutions - - .. note:: - - This is the opportunity to introduce the developer mode to - inspect the view, find its external ID and the place to put the - new field. - - #. Create a file ``openacademy/models/partner.py`` and import it in - ``__init__.py`` - #. Create a file ``openacademy/views/partner.xml`` and add it to - ``__manifest__.py`` - - .. patch:: - Domains ####### @@ -734,31 +642,12 @@ records for the relation when trying to select records in the client interface. When selecting the instructor for a *Session*, only instructors (partners with ``instructor`` set to ``True``) should be visible. - .. only:: solutions - - .. patch:: - - .. note:: - - A domain declared as a literal list is evaluated server-side and - can't refer to dynamic values on the right-hand side, a domain - declared as a string is evaluated client-side and allows - field names on the right-hand side - .. exercise:: More complex domains Create new partner categories *Teacher / Level 1* and *Teacher / Level 2*. The instructor for a session can be either an instructor or a teacher (of any level). - .. only:: solutions - - #. Modify the *Session* model's domain - #. Modify ``openacademy/view/partner.xml`` to get access to - *Partner categories*: - - .. patch:: - Computed fields and default values ================================== @@ -828,13 +717,6 @@ field whenever some of its dependencies have been modified:: * Display that field in the tree and form views * Display the field as a progress bar - .. only:: solutions - - #. Add a computed field to *Session* - #. Show the field in the *Session* view: - - .. patch:: - Default values -------------- @@ -865,15 +747,6 @@ float, string), or a function taking a recordset and returning a value:: * Add a field ``active`` in the class Session, and set sessions as active by default. - .. only:: solutions - - .. patch:: - - .. note:: - - Odoo has built-in rules making fields with an ``active`` field set - to ``False`` invisible. - Onchange ======== @@ -919,10 +792,6 @@ the ``taken_seats`` progressbar is automatically updated. Add an explicit onchange to warn about invalid values, like a negative number of seats, or more participants than seats. - .. only:: solutions - - .. patch:: - Model constraints ================= @@ -950,10 +819,6 @@ raise an exception if its invariant is not satisfied:: Add a constraint that checks that the instructor is not present in the attendees of his/her own session. - .. only:: solutions - - .. patch:: - SQL constraints are defined through the model attribute :attr:`~odoo.models.Model._sql_constraints`. The latter is assigned to a list of triples of strings ``(name, sql_definition, message)``, where ``name`` is a @@ -968,10 +833,6 @@ and ``message`` is the error message. #. CHECK that the course description and the course title are different #. Make the Course's name UNIQUE - .. only:: solutions - - .. patch:: - .. exercise:: Exercise 6 - Add a duplicate option Since we added a constraint for the Course name uniqueness, it is not @@ -981,10 +842,6 @@ and ``message`` is the error message. Re-implement your own "copy" method which allows to duplicate the Course object, changing the original name into "Copy of [original name]". - .. only:: solutions - - .. patch:: - Advanced Views ============== @@ -1028,12 +885,6 @@ behavior: 5 days are colored blue, and the ones lasting more than 15 days are colored red. - .. only:: solutions - - Modify the session tree view: - - .. patch:: - Calendars --------- @@ -1063,19 +914,6 @@ their most common attributes are: Add a Calendar view to the *Session* model enabling the user to view the events associated to the Open Academy. - .. only:: solutions - - #. Add an ``end_date`` field computed from ``start_date`` and - ``duration`` - - .. tip:: the inverse function makes the field writable, and allows - moving the sessions (via drag and drop) in the calendar view - - #. Add a calendar view to the *Session* model - #. And add the calendar view to the *Session* model's actions - - .. patch:: - Search views ------------ @@ -1125,10 +963,6 @@ default and behave as booleans (they can only be enabled by default). responsible in the course search view. Make it selected by default. #. Add a button to group courses by responsible user. - .. only:: solutions - - .. patch:: - Gantt ----- @@ -1153,14 +987,6 @@ their root element is ````. Add a Gantt Chart enabling the user to view the sessions scheduling linked to the Open Academy module. The sessions should be grouped by instructor. - .. only:: solutions - - #. Create a computed field expressing the session's duration in hours - #. Add the gantt view's definition, and add the gantt view to the - *Session* model's action - - .. patch:: - Graph views ----------- @@ -1212,13 +1038,6 @@ the values: Add a Graph view in the Session object that displays, for each course, the number of attendees under the form of a bar chart. - .. only:: solutions - - #. Add the number of attendees as a stored computed field - #. Then add the relevant view - - .. patch:: - Kanban ------ @@ -1239,13 +1058,6 @@ Kanban views define the structure of each card as a mix of form elements Add a Kanban view that displays sessions grouped by course (columns are thus courses). - .. only:: solutions - - #. Add an integer ``color`` field to the *Session* model - #. Add the kanban view and update the action - - .. patch:: - Security ======== @@ -1282,16 +1094,6 @@ rights are usually created by a CSV file named after its model: Create a new user "John Smith". Then create a group "OpenAcademy / Session Read" with read access to the *Session* model. - .. only:: solutions - - #. Create a new user *John Smith* through - :menuselection:`Settings --> Users --> Users` - #. Create a new group ``session_read`` through - :menuselection:`Settings --> Users --> Groups`, it should have - read access on the *Session* model - #. Edit *John Smith* to make them a member of ``session_read`` - #. Log in as *John Smith* to check the access rights are correct - .. exercise:: Add access control through data files in your module Using data files, @@ -1300,17 +1102,6 @@ rights are usually created by a CSV file named after its model: OpenAcademy models * Make *Session* and *Course* readable by all users - .. only:: solutions - - #. Create a new file ``openacademy/security/security.xml`` to - hold the OpenAcademy Manager group - #. Edit the file ``openacademy/security/ir.model.access.csv`` with - the access rights to the models - #. Finally update ``openacademy/__manifest__.py`` to add the new data - files to it - - .. patch:: - Record rules ------------ @@ -1344,12 +1135,6 @@ the same convention as the method :meth:`~odoo.models.Model.write` of the ORM. to the responsible of a course. If a course has no responsible, all users of the group must be able to modify it. - .. only:: solutions - - Create a new rule in ``openacademy/security/security.xml``: - - .. patch:: - Wizards ======= @@ -1377,12 +1162,6 @@ session, or for a list of sessions at once. Create a wizard model with a many2one relationship with the *Session* model and a many2many relationship with the *Partner* model. - .. only:: solutions - - Add a new file ``openacademy/wizard.py``: - - .. patch:: - Launching wizards ----------------- @@ -1416,28 +1195,16 @@ Wizards use regular views and their buttons may use the attribute #. Define a default value for the session field in the wizard; use the context parameter ``self._context`` to retrieve the current session. - .. only:: solutions - - .. patch:: - .. exercise:: Register attendees Add buttons to the wizard, and implement the corresponding method for adding the attendees to the given session. - .. only:: solutions - - .. patch:: - .. exercise:: Register attendees to multiple sessions Modify the wizard model so that attendees can be registered to multiple sessions. - .. only:: solutions - - .. patch:: - Internationalization ==================== @@ -1477,40 +1244,6 @@ for editing and merging PO/POT files. Choose a second language for your Odoo installation. Translate your module using the facilities provided by Odoo. - .. only:: solutions - - #. Create a directory ``openacademy/i18n/`` - #. You will need to activate the developer mode - to access the menus mentioned below ( - :menuselection:`Settings --> Activate the developer mode` - ) - #. Install whichever language you want ( - :menuselection:`Settings --> Translations --> Load a - Translation`) - #. Generate the missing terms (:menuselection:`Settings --> - Translations --> Application Terms --> Generate Missing Terms`) - #. Create a template translation file by exporting ( - :menuselection:`Settings --> Translations -> Import/Export - --> Export Translation`) without specifying a language, save in - ``openacademy/i18n/`` - #. Create a translation file by exporting ( - :menuselection:`Settings --> Translations --> Import/Export - --> Export Translation`) and specifying a language. Save it in - ``openacademy/i18n/`` - #. Open the exported translation file (with a basic text editor or a - dedicated PO-file editor e.g. POEdit_ and translate the missing - terms - - #. In ``models.py``, add an import statement for the function - ``odoo._`` and mark missing strings as translatable - - #. Repeat steps 3-6 - - .. patch:: - - .. todo:: do we never reload translations? - - Reporting ========= @@ -1599,10 +1332,6 @@ http://localhost:8069/report/pdf/account.report_invoice/1. For each session, it should display session's name, its start and end, and list the session's attendees. - .. only:: solutions - - .. patch:: - Dashboards ---------- @@ -1614,21 +1343,6 @@ Dashboards and automatically displayed in the web client when the OpenAcademy main menu is selected. - .. only:: solutions - - #. Create a file ``openacademy/views/session_board.xml``. It should contain - the board view, the actions referenced in that view, an action to - open the dashboard and a re-definition of the main menu item to add - the dashboard action - - .. note:: Available dashboard styles are ``1``, ``1-1``, ``1-2``, - ``2-1`` and ``1-1-1`` - - #. Update ``openacademy/__manifest__.py`` to reference the new data - file - - .. patch:: - WebServices =========== diff --git a/content/developer/howtos/backend/exercise-access-rights b/content/developer/howtos/backend/exercise-access-rights deleted file mode 100644 index 465dffea8..000000000 --- a/content/developer/howtos/backend/exercise-access-rights +++ /dev/null @@ -1,40 +0,0 @@ -# HG changeset patch -# Parent 303a5f4f011822dcb42b5833d579eabd3f03f4bf - -Index: addons/openacademy/__manifest__.py -=================================================================== ---- addons.orig/openacademy/__manifest__.py 2014-08-26 17:26:18.143783102 +0200 -+++ addons/openacademy/__manifest__.py 2014-08-26 17:26:18.135783102 +0200 -@@ -25,7 +25,8 @@ - - # always loaded - 'data': [ -- # 'security/ir.model.access.csv', -+ 'security/security.xml', -+ 'security/ir.model.access.csv', - 'templates.xml', - 'views/openacademy.xml', - 'views/partner.xml', -Index: addons/openacademy/security/ir.model.access.csv -=================================================================== ---- addons.orig/openacademy/security/ir.model.access.csv 2014-08-26 17:26:18.143783102 +0200 -+++ addons/openacademy/security/ir.model.access.csv 2014-08-26 17:26:18.135783102 +0200 -@@ -1,2 +1,5 @@ - id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink --access_openacademy_openacademy,openacademy.openacademy,model_openacademy_openacademy,,1,0,0,0 -+course_manager,course manager,model_openacademy_course,group_manager,1,1,1,1 -+session_manager,session manager,model_openacademy_session,group_manager,1,1,1,1 -+course_read_all,course all,model_openacademy_course,,1,0,0,0 -+session_read_all,session all,model_openacademy_session,,1,0,0,0 -Index: addons/openacademy/security/security.xml -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/security/security.xml 2014-08-26 17:26:18.135783102 +0200 -@@ -0,0 +1,7 @@ -+ -+ -+ -+ OpenAcademy / Manager -+ -+ -+ diff --git a/content/developer/howtos/backend/exercise-access-rules b/content/developer/howtos/backend/exercise-access-rules deleted file mode 100644 index d6290dfdb..000000000 --- a/content/developer/howtos/backend/exercise-access-rules +++ /dev/null @@ -1,27 +0,0 @@ -# HG changeset patch -# Parent 0602022dc2a428f9995c886df33b699b6d3bcb69 - -Index: addons/openacademy/security/security.xml -=================================================================== ---- addons.orig/openacademy/security/security.xml 2014-08-26 17:26:18.971783090 +0200 -+++ addons/openacademy/security/security.xml 2014-08-26 17:26:18.967783090 +0200 -@@ -3,5 +3,19 @@ - - OpenAcademy / Manager - -+ -+ -+ Only Responsible can modify Course -+ -+ -+ -+ -+ -+ -+ -+ ['|', ('responsible_id','=',False), -+ ('responsible_id','=',user.id)] -+ -+ - - diff --git a/content/developer/howtos/backend/exercise-advanced-treeview b/content/developer/howtos/backend/exercise-advanced-treeview deleted file mode 100644 index 3d674bb25..000000000 --- a/content/developer/howtos/backend/exercise-advanced-treeview +++ /dev/null @@ -1,19 +0,0 @@ -# HG changeset patch -# Parent f8d2422e87b3ff566dc947ad582608db3b15e077 - -Index: addons/openacademy/views/openacademy.xml -=================================================================== ---- addons.orig/openacademy/views/openacademy.xml 2014-08-26 17:26:09.283783234 +0200 -+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:26:09.279783234 +0200 -@@ -116,9 +116,10 @@ - session.tree - openacademy.session - -- -+ - - -+ - - - diff --git a/content/developer/howtos/backend/exercise-basic-action b/content/developer/howtos/backend/exercise-basic-action deleted file mode 100644 index 277e88bed..000000000 --- a/content/developer/howtos/backend/exercise-basic-action +++ /dev/null @@ -1,54 +0,0 @@ -# HG changeset patch -# Parent 16e4cb131d9f7f3a72a8a1b0bc46c2ce9ac76435 -Index: addons/openacademy/__manifest__.py -=================================================================== ---- addons.orig/openacademy/__manifest__.py 2014-08-26 17:25:53.519783468 +0200 -+++ addons/openacademy/__manifest__.py 2014-08-26 17:25:53.511783468 +0200 -@@ -27,6 +27,7 @@ - 'data': [ - # 'security/ir.model.access.csv', - 'templates.xml', -+ 'views/openacademy.xml', - ], - # only loaded in demonstration mode - 'demo': [ -Index: addons/openacademy/views/openacademy.xml -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:53.511783468 +0200 -@@ -0,0 +1,35 @@ -+ -+ -+ -+ -+ -+ -+ Courses -+ openacademy.course -+ form -+ tree,form -+ -+

Create the first course -+

-+
-+
-+ -+ -+ -+ -+ -+ -+ -+ -+ -+
diff --git a/content/developer/howtos/backend/exercise-calendar b/content/developer/howtos/backend/exercise-calendar deleted file mode 100644 index 1ef0cbe2c..000000000 --- a/content/developer/howtos/backend/exercise-calendar +++ /dev/null @@ -1,78 +0,0 @@ -# HG changeset patch -# Parent 85a8d7317b9e13480f39ad739955442d15144451 -# Parent 16fcdc4c6462a7872636f3c19550c16879af5281 - -diff --git a/openacademy/models.py b/openacademy/models.py ---- a/openacademy/models.py -+++ b/openacademy/models.py -@@ -1,5 +1,6 @@ - # -*- coding: utf-8 -*- - -+from datetime import timedelta - from odoo import models, fields, api, exceptions - - class Course(models.Model): -@@ -57,6 +58,8 @@ class Session(models.Model): - attendee_ids = fields.Many2many('res.partner', string="Attendees") - - taken_seats = fields.Float(string="Taken seats", compute='_taken_seats') -+ end_date = fields.Date(string="End Date", store=True, -+ compute='_get_end_date', inverse='_set_end_date') - - @api.depends('seats', 'attendee_ids') - def _taken_seats(self): -@@ -83,6 +86,27 @@ class Session(models.Model): - }, - } - -+ @api.depends('start_date', 'duration') -+ def _get_end_date(self): -+ for r in self: -+ if not (r.start_date and r.duration): -+ r.end_date = r.start_date -+ continue -+ -+ # Add duration to start_date, but: Monday + 5 days = Saturday, so -+ # subtract one second to get on Friday instead -+ duration = timedelta(days=r.duration, seconds=-1) -+ r.end_date = r.start_date + duration -+ -+ def _set_end_date(self): -+ for r in self: -+ if not (r.start_date and r.end_date): -+ continue -+ -+ # Compute the difference between dates, but: Friday - Monday = 4 days, -+ # so add one day to get 5 days instead -+ r.duration = (r.end_date - r.start_date).days + 1 -+ - @api.constrains('instructor_id', 'attendee_ids') - def _check_instructor_not_in_attendees(self): - for r in self: -diff --git a/openacademy/views/openacademy.xml b/openacademy/views/openacademy.xml ---- a/openacademy/views/openacademy.xml -+++ b/openacademy/views/openacademy.xml -@@ -125,11 +125,22 @@ - - - -+ -+ -+ session.calendar -+ openacademy.session -+ -+ -+ -+ -+ -+ -+ - - Sessions - openacademy.session - form -- tree,form -+ tree,form,calendar - - - - - -+ - - - - diff --git a/content/developer/howtos/backend/exercise-constraint-python b/content/developer/howtos/backend/exercise-constraint-python deleted file mode 100644 index 248507a24..000000000 --- a/content/developer/howtos/backend/exercise-constraint-python +++ /dev/null @@ -1,25 +0,0 @@ -# HG changeset patch -# Parent 7a7d003fe38426a405ce0657a627a139133ec4dd -# Parent 52f54b46487c8224a5aade4b921be77360ed3eae - -diff --git a/openacademy/models.py b/openacademy/models.py ---- a/openacademy/models.py -+++ b/openacademy/models.py -@@ -1,6 +1,6 @@ - # -*- coding: utf-8 -*- - --from odoo import models, fields, api -+from odoo import models, fields, api, exceptions - - class Course(models.Model): - _name = 'openacademy.course' -@@ -58,3 +58,9 @@ class Session(models.Model): - 'message': "Increase seats or remove excess attendees", - }, - } -+ -+ @api.constrains('instructor_id', 'attendee_ids') -+ def _check_instructor_not_in_attendees(self): -+ for r in self: -+ if r.instructor_id and r.instructor_id in r.attendee_ids: -+ raise exceptions.ValidationError("A session's instructor can't be an attendee") diff --git a/content/developer/howtos/backend/exercise-constraint-sql b/content/developer/howtos/backend/exercise-constraint-sql deleted file mode 100644 index 5595a6db3..000000000 --- a/content/developer/howtos/backend/exercise-constraint-sql +++ /dev/null @@ -1,24 +0,0 @@ -# HG changeset patch -# Parent 121bbfe120be3007f5e04611dbc27038abafcce8 - -Index: addons/openacademy/models.py -=================================================================== ---- addons.orig/openacademy/models.py -+++ addons/openacademy/models.py -@@ -14,6 +14,16 @@ - session_ids = fields.One2many( - 'openacademy.session', 'course_id', string="Sessions") - -+ _sql_constraints = [ -+ ('name_description_check', -+ 'CHECK(name != description)', -+ "The title of the course should not be the description"), -+ -+ ('name_unique', -+ 'UNIQUE(name)', -+ "The course title must be unique"), -+ ] -+ - - class Session(models.Model): - _name = 'openacademy.session' diff --git a/content/developer/howtos/backend/exercise-copy-override b/content/developer/howtos/backend/exercise-copy-override deleted file mode 100644 index 3099526ad..000000000 --- a/content/developer/howtos/backend/exercise-copy-override +++ /dev/null @@ -1,28 +0,0 @@ -# HG changeset patch -# Parent 7d14b75cdfd4c7a272a13572947de5d47f3e851f -# Parent f400352a70963801f0b4732d33a0183e4f6800ff - -diff --git a/openacademy/models.py b/openacademy/models.py ---- a/openacademy/models.py -+++ b/openacademy/models.py -@@ -14,6 +14,20 @@ class Course(models.Model): - session_ids = fields.One2many( - 'openacademy.session', 'course_id', string="Sessions") - -+ @api.multi -+ def copy(self, default=None): -+ default = dict(default or {}) -+ -+ copied_count = self.search_count( -+ [('name', '=like', u"Copy of {}%".format(self.name))]) -+ if not copied_count: -+ new_name = u"Copy of {}".format(self.name) -+ else: -+ new_name = u"Copy of {} ({})".format(self.name, copied_count) -+ -+ default['name'] = new_name -+ return super(Course, self).copy(default) -+ - _sql_constraints = [ - ('name_description_check', - 'CHECK(name != description)', diff --git a/content/developer/howtos/backend/exercise-creation b/content/developer/howtos/backend/exercise-creation deleted file mode 100644 index b5cf55584..000000000 --- a/content/developer/howtos/backend/exercise-creation +++ /dev/null @@ -1,152 +0,0 @@ -# HG changeset patch -# Parent 0000000000000000000000000000000000000000 -Index: addons/openacademy/__manifest__.py -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/__manifest__.py 2014-08-26 17:25:49.787783523 +0200 -@@ -0,0 +1,35 @@ -+# -*- coding: utf-8 -*- -+{ -+ 'name': "Open Academy", -+ -+ 'summary': """Manage trainings""", -+ -+ 'description': """ -+ Open Academy module for managing trainings: -+ - training courses -+ - training sessions -+ - attendees registration -+ """, -+ -+ 'author': "My Company", -+ 'website': "http://www.yourcompany.com", -+ -+ # Categories can be used to filter modules in modules listing -+ # Check https://github.com/odoo/odoo/blob/12.0/odoo/addons/base/data/ir_module_category_data.xml -+ # for the full list -+ 'category': 'Test', -+ 'version': '0.1', -+ -+ # any module necessary for this one to work correctly -+ 'depends': ['base'], -+ -+ # always loaded -+ 'data': [ -+ # 'security/ir.model.access.csv', -+ 'templates.xml', -+ ], -+ # only loaded in demonstration mode -+ 'demo': [ -+ 'demo.xml', -+ ], -+} -Index: addons/openacademy/__init__.py -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/__init__.py 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,3 @@ -+# -*- coding: utf-8 -*- -+from . import controllers -+from . import models -Index: addons/openacademy/controllers.py -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/controllers.py 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,20 @@ -+# -*- coding: utf-8 -*- -+from odoo import http -+ -+# class Openacademy(http.Controller): -+# @http.route('/openacademy/openacademy/', auth='public') -+# def index(self, **kw): -+# return "Hello, world" -+ -+# @http.route('/openacademy/openacademy/objects/', auth='public') -+# def list(self, **kw): -+# return http.request.render('openacademy.listing', { -+# 'root': '/openacademy/openacademy', -+# 'objects': http.request.env['openacademy.openacademy'].search([]), -+# }) -+ -+# @http.route('/openacademy/openacademy/objects//', auth='public') -+# def object(self, obj, **kw): -+# return http.request.render('openacademy.object', { -+# 'object': obj -+# }) -Index: addons/openacademy/demo.xml -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/demo.xml 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,25 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -Index: addons/openacademy/models.py -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/models.py 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,8 @@ -+# -*- coding: utf-8 -*- -+ -+from odoo import models, fields, api -+ -+# class openacademy(models.Model): -+# _name = 'openacademy.openacademy' -+ -+# name = fields.Char() -Index: addons/openacademy/security/ir.model.access.csv -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/security/ir.model.access.csv 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,2 @@ -+id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink -+access_openacademy_openacademy,openacademy.openacademy,model_openacademy_openacademy,,1,0,0,0 -Index: addons/openacademy/templates.xml -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/templates.xml 2014-08-26 17:25:49.791783523 +0200 -@@ -0,0 +1,22 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ diff --git a/content/developer/howtos/backend/exercise-dashboard b/content/developer/howtos/backend/exercise-dashboard deleted file mode 100644 index 01876e651..000000000 --- a/content/developer/howtos/backend/exercise-dashboard +++ /dev/null @@ -1,95 +0,0 @@ -# HG changeset patch -# Parent 643813940cbea07bec792f9e1c60022a9292fa90 - -Index: addons/openacademy/__manifest__.py -=================================================================== ---- addons.orig/openacademy/__manifest__.py 2014-08-26 17:26:21.535783052 +0200 -+++ addons/openacademy/__manifest__.py 2014-08-26 17:26:21.531783052 +0200 -@@ -21,7 +21,7 @@ - 'version': '0.1', - - # any module necessary for this one to work correctly -- 'depends': ['base'], -+ 'depends': ['base', 'board'], - - # always loaded - 'data': [ -@@ -30,6 +30,7 @@ - 'templates.xml', - 'views/openacademy.xml', - 'views/partner.xml', -+ 'views/session_board.xml', - 'reports.xml', - ], - # only loaded in demonstration mode -Index: addons/openacademy/views/session_board.xml -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ addons/openacademy/views/session_board.xml 2014-08-26 17:26:21.531783052 +0200 -@@ -0,0 +1,66 @@ -+ -+ -+ -+ -+ Attendees by course -+ openacademy.session -+ form -+ graph -+ -+ -+ -+ Sessions -+ openacademy.session -+ form -+ calendar -+ -+ -+ -+ Courses -+ openacademy.course -+ form -+ tree,form -+ -+ -+ Session Dashboard Form -+ board.board -+ form -+ -+
-+ -+ -+ -+ -+ -+ -+ -+ -+ -+
-+
-+
-+ -+ Session Dashboard -+ board.board -+ form -+ form -+ menu -+ -+ -+ -+ -+ -+
diff --git a/content/developer/howtos/backend/exercise-defaults b/content/developer/howtos/backend/exercise-defaults deleted file mode 100644 index 6c61e9b1e..000000000 --- a/content/developer/howtos/backend/exercise-defaults +++ /dev/null @@ -1,28 +0,0 @@ -Index: addons/openacademy/models.py -=================================================================== ---- addons.orig/openacademy/models.py -+++ addons/openacademy/models.py -@@ -20,9 +20,10 @@ - _description = "OpenAcademy Sessions" - - name = fields.Char(required=True) -- start_date = fields.Date() -+ start_date = fields.Date(default=fields.Date.today) - duration = fields.Float(digits=(6, 2), help="Duration in days") - seats = fields.Integer(string="Number of seats") -+ active = fields.Boolean(default=True) - - instructor_id = fields.Many2one('res.partner', string="Instructor", - domain=['|', ('instructor', '=', True), -Index: addons/openacademy/views/openacademy.xml -=================================================================== ---- addons.orig/openacademy/views/openacademy.xml -+++ addons/openacademy/views/openacademy.xml -@@ -95,6 +95,7 @@ - - - -+ - - - diff --git a/content/developer/howtos/backend/exercise-demo b/content/developer/howtos/backend/exercise-demo deleted file mode 100644 index 50a956442..000000000 --- a/content/developer/howtos/backend/exercise-demo +++ /dev/null @@ -1,48 +0,0 @@ -# HG changeset patch -# Parent 84e2b0b43fc61fd0bcbb44c1929755d44ee58ae5 - -Index: addons/openacademy/demo.xml -=================================================================== ---- addons.orig/openacademy/demo.xml 2014-08-26 17:25:52.683783480 +0200 -+++ addons/openacademy/demo.xml 2014-08-26 17:25:52.679783480 +0200 -@@ -1,25 +1,19 @@ - - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -+ -+ Course 0 -+ Course 0's description -+ -+Can have multiple lines -+ -+ -+ -+ Course 1 -+ -+ -+ -+ Course 2 -+ Course 2's description -+ - - diff --git a/content/developer/howtos/backend/exercise-domain-advanced b/content/developer/howtos/backend/exercise-domain-advanced deleted file mode 100644 index 9b96a4459..000000000 --- a/content/developer/howtos/backend/exercise-domain-advanced +++ /dev/null @@ -1,42 +0,0 @@ -# HG changeset patch -# Parent 69d1f2d359eb8ef304a9d99f17790c78b35eda1a - -Index: addons/openacademy/models.py -=================================================================== ---- addons.orig/openacademy/models.py -+++ addons/openacademy/models.py -@@ -25,7 +25,8 @@ - seats = fields.Integer(string="Number of seats") - - instructor_id = fields.Many2one('res.partner', string="Instructor", -- domain=[('instructor', '=', True)]) -+ domain=['|', ('instructor', '=', True), -+ ('category_id.name', 'ilike', "Teacher")]) - course_id = fields.Many2one('openacademy.course', - ondelete='cascade', string="Course", required=True) - attendee_ids = fields.Many2many('res.partner', string="Attendees") -Index: addons/openacademy/views/partner.xml -=================================================================== ---- addons.orig/openacademy/views/partner.xml -+++ addons/openacademy/views/partner.xml -@@ -29,4 +29,20 @@ - parent="configuration_menu" - action="contact_list_action"/> - -+ -+ Contact Tags -+ res.partner.category -+ tree,form -+ -+ -+ -+ -+ Teacher / Level 1 -+ -+ -+ Teacher / Level 2 -+ -+ - diff --git a/content/developer/howtos/backend/exercise-domain-basic b/content/developer/howtos/backend/exercise-domain-basic deleted file mode 100644 index 71ee608cf..000000000 --- a/content/developer/howtos/backend/exercise-domain-basic +++ /dev/null @@ -1,17 +0,0 @@ -# HG changeset patch -# Parent 142c5065ff1b7266d944d4ef5239e814ae22f0df - -Index: addons/openacademy/models.py -=================================================================== ---- addons.orig/openacademy/models.py -+++ addons/openacademy/models.py -@@ -24,7 +24,8 @@ - duration = fields.Float(digits=(6, 2), help="Duration in days") - seats = fields.Integer(string="Number of seats") - -- instructor_id = fields.Many2one('res.partner', string="Instructor") -+ instructor_id = fields.Many2one('res.partner', string="Instructor", -+ domain=[('instructor', '=', True)]) - course_id = fields.Many2one('openacademy.course', - ondelete='cascade', string="Course", required=True) - attendee_ids = fields.Many2many('res.partner', string="Attendees") diff --git a/content/developer/howtos/backend/exercise-formview b/content/developer/howtos/backend/exercise-formview deleted file mode 100644 index 9f80bc2f7..000000000 --- a/content/developer/howtos/backend/exercise-formview +++ /dev/null @@ -1,29 +0,0 @@ -# HG changeset patch -# Parent 4a0db1d29257764f4df5cb1ee0be7e59e8c8d0d8 - -Index: addons/openacademy/views/openacademy.xml -=================================================================== ---- addons.orig/openacademy/views/openacademy.xml 2014-08-26 17:25:54.291783456 +0200 -+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:54.283783457 +0200 -@@ -1,6 +1,21 @@ - - - -+ -+ course.form -+ openacademy.course -+ -+
-+ -+ -+ -+ -+ -+ -+
-+
-+
-+ - - -+
-+ -+ -+ - - Sessions - openacademy.session - form -- tree,form,calendar -+ tree,form,calendar,gantt - - - - - -+ -+ openacademy.session.graph -+ openacademy.session -+ -+ -+ -+ -+ -+ -+ -+ - - Sessions - openacademy.session - form -- tree,form,calendar,gantt -+ tree,form,calendar,gantt,graph - - - -+
-+ -+
-+ -+
    -+
  • -+ Delete -+
  • -+
  • -+
      -+ -+
    -+
-+
-+
-+
-+ -+ Session name: -+ -+
-+ Start date: -+ -+
-+ duration: -+ -+
-+ -+ -+ -+ -+ -+ -+ - - Sessions - openacademy.session - form -- tree,form,calendar,gantt,graph -+ tree,form,calendar,gantt,graph,kanban - - - - - -+