[MOV] Odoo Tech doc

This commit is contained in:
Victor Feyens 2020-09-24 17:45:55 +02:00
parent 3509521c76
commit 672b487aca
255 changed files with 27746 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,19 @@
Short description of the issue
***Impacted versions:***
-
***Steps to reproduce:***
1.
2.
3.
***Current behavior:***
-
***Expected behavior:***
-

View File

@ -0,0 +1,26 @@
@import "style.css";
p.rubric {
font-family: Lato, Arial, sans-serif;
font-weight: 500;
line-height: 1.1;
color: inherit;
margin-top: 10px;
margin-bottom: 8px;
}
.section p.rubric {
font-size: 30px;
}
.section .section p.rubric {
font-size: 24px;
}
.section .section .section p.rubric {
font-size: 18px;
}
.section .section .section .section p.rubric {
font-size: 14px;
}
.section .section .section .section .section p.rubric {
font-size: 12px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

241
developer/conf.py Normal file
View File

@ -0,0 +1,241 @@
# -*- coding: utf-8 -*-
import sys, os
import sphinx
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
DIR = os.path.dirname(__file__)
sys.path.insert(0,
os.path.abspath(
os.path.join(DIR, '_extensions')))
# put current odoo's source on PYTHONPATH for autodoc
sys.path.insert(0, os.path.abspath(os.path.join(DIR, '../../odoo')))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = '1.2'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.ifconfig',
'sphinx.ext.todo',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.linkcode',
# 'autojsdoc.ext',
'github_link',
'odoo_ext',
'html_domain',
'exercise_admonition',
'patchqueue'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'odoo'
copyright = u'Odoo S.A.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '13.0'
# The full version, including alpha/beta/rc tags.
release = '13.0'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# markdown compatibility: make `foo` behave like ``foo``, the rst default is
# title-reference which is never what people are looking for
default_role = 'literal'
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'odoo'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'odoo_ext'
odoo_cover_default = 'banners/installing_odoo.jpg'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['_extensions']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_add_permalinks = u''
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# FIXME: no sidebar on index?
html_sidebars = {
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
latex_elements = {
'papersize': r'a4paper',
'preamble': u'''\\setcounter{tocdepth}{2}
''',
}
# default must be set otherwise ifconfig blows up
todo_include_todos = False
intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None),
'werkzeug': ('http://werkzeug.pocoo.org/docs/', None),
}
github_user = 'odoo'
github_project = 'odoo'
# monkeypatch PHP lexer to not require <?php
from sphinx.highlighting import lexers
from pygments.lexers.web import PhpLexer
lexers['php'] = PhpLexer(startinline=True)
def setup(app):
app.connect('html-page-context', canonicalize)
app.add_config_value('canonical_root', None, 'env')
app.add_config_value('canonical_branch', 'master', 'env')
app.connect('html-page-context', versionize)
app.add_config_value('versions', '', 'env')
app.connect('html-page-context', analytics)
app.add_config_value('google_analytics_key', '', 'env')
def canonicalize(app, pagename, templatename, context, doctree):
""" Adds a 'canonical' URL for the current document in the rendering
context. Requires the ``canonical_root`` setting being set. The canonical
branch is ``master`` but can be overridden using ``canonical_branch``.
"""
if not app.config.canonical_root:
return
context['canonical'] = _build_url(
app.config.canonical_root, app.config.canonical_branch, pagename)
def versionize(app, pagename, templatename, context, doctree):
""" Adds a version switcher below the menu, requires ``canonical_root``
and ``versions`` (an ordered, space-separated lists of all possible
versions).
"""
if not (app.config.canonical_root and app.config.versions):
return
context['versions'] = [
(vs, _build_url(app.config.canonical_root, vs, pagename))
for vs in app.config.versions.split(',')
if vs != app.config.version
]
def analytics(app, pagename, templatename, context, doctree):
if not app.config.google_analytics_key:
return
context['google_analytics_key'] = app.config.google_analytics_key
def _build_url(root, branch, pagename):
return "{canonical_url}{canonical_branch}/{canonical_page}".format(
canonical_url=root,
canonical_branch=branch,
canonical_page=(pagename + '.html').replace('index.html', '')
.replace('index/', ''),
)

43
developer/glossary.rst Normal file
View File

@ -0,0 +1,43 @@
:orphan: true
========
Glossary
========
.. glossary::
external id
external identifier
external identifiers
string identifier stored in ``ir.model.data``, can be used to refer
to a record regardless of its database identifier during data imports
or export/import roundtrips.
External identifiers are in the form :samp:`{module}.{id}` (e.g.
``account.invoice_graph``). From within a module, the
:samp:`{module}.` prefix can be left out.
Sometimes referred to as "xml id" or ``xml_id`` as XML-based
:ref:`reference/data` make extensive use of them.
format string
inspired by `jinja variables`_, format strings allow more easily
mixing literal content and computed content (expressions): content
between ``{{`` and ``}}`` is interpreted as an expression and
evaluated, other content is interpreted as literal strings and
displayed as-is
GIS
Geographic Information System
any computer system or subsystem to capture, store, manipulate,
analyze, manage or present spatial and geographical data.
minified
minification
process of removing extraneous/non-necessary sections of files
(comments, whitespace) and possibly recompiling them using equivalent
but shorter structures (`ternary operator`_ instead of ``if/else``) in
order to reduce network traffic
.. _jinja variables: http://jinja.pocoo.org/docs/dev/templates/#variables
.. _ternary operator: http://en.wikipedia.org/wiki/%3F:

1822
developer/howtos/backend.rst Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
# 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 @@
+<odoo>
+
+ <record id="group_manager" model="res.groups">
+ <field name="name">OpenAcademy / Manager</field>
+ </record>
+
+</odoo>

View File

@ -0,0 +1,27 @@
# 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 @@
<record id="group_manager" model="res.groups">
<field name="name">OpenAcademy / Manager</field>
</record>
+
+ <record id="only_responsible_can_modify" model="ir.rule">
+ <field name="name">Only Responsible can modify Course</field>
+ <field name="model_id" ref="model_openacademy_course"/>
+ <field name="groups" eval="[(4, ref('openacademy.group_manager'))]"/>
+ <field name="perm_read" eval="0"/>
+ <field name="perm_write" eval="1"/>
+ <field name="perm_create" eval="0"/>
+ <field name="perm_unlink" eval="1"/>
+ <field name="domain_force">
+ ['|', ('responsible_id','=',False),
+ ('responsible_id','=',user.id)]
+ </field>
+ </record>
</odoo>

View File

@ -0,0 +1,19 @@
# 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
@@ -115,9 +115,10 @@
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="arch" type="xml">
- <tree string="Session Tree">
+ <tree string="Session Tree" decoration-info="duration&lt;5" decoration-danger="duration&gt;15">
<field name="name"/>
<field name="course_id"/>
+ <field name="duration" invisible="1"/>
<field name="taken_seats" widget="progressbar"/>
</tree>
</field>

View File

@ -0,0 +1,53 @@
# 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,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+
+ <!-- window action -->
+ <!--
+ The following tag is an action definition for a "window action",
+ that is an action opening a view or a set of views
+ -->
+ <record model="ir.actions.act_window" id="course_list_action">
+ <field name="name">Courses</field>
+ <field name="res_model">openacademy.course</field>
+ <field name="view_mode">tree,form</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">Create the first course
+ </p>
+ </field>
+ </record>
+
+ <!-- top level menu: no parent -->
+ <menuitem id="main_openacademy_menu" name="Open Academy"/>
+ <!-- A first level in the left side menu is needed
+ before using action= attribute -->
+ <menuitem id="openacademy_menu" name="Open Academy"
+ parent="main_openacademy_menu"/>
+ <!-- the following menuitem should appear *after*
+ its parent openacademy_menu and *after* its
+ action course_list_action -->
+ <menuitem id="courses_menu" name="Courses" parent="openacademy_menu"
+ action="course_list_action"/>
+ <!-- Full id location:
+ action="openacademy.course_list_action"
+ It is not required when it is the same module -->
+
+</odoo>

View File

@ -0,0 +1,77 @@
# 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
@@ -124,10 +124,21 @@
</field>
</record>
+ <!-- calendar view -->
+ <record model="ir.ui.view" id="session_calendar_view">
+ <field name="name">session.calendar</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <calendar string="Session Calendar" date_start="start_date" date_stop="end_date" color="instructor_id">
+ <field name="name"/>
+ </calendar>
+ </field>
+ </record>
+
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
- <field name="view_mode">tree,form</field>
+ <field name="view_mode">tree,form,calendar</field>
</record>
<menuitem id="session_menu" name="Sessions"

View File

@ -0,0 +1,40 @@
# HG changeset patch
# Parent a358be0a577b0569831958a8ec1302825c645dee
# Parent 59107edbe5f81bab5e7db172bf2bffa504ce399a
diff --git a/openacademy/models.py b/openacademy/models.py
--- a/openacademy/models.py
+++ b/openacademy/models.py
@@ -30,3 +30,13 @@ class Session(models.Model):
course_id = fields.Many2one('openacademy.course',
ondelete='cascade', string="Course", required=True)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
+
+ taken_seats = fields.Float(string="Taken seats", compute='_taken_seats')
+
+ @api.depends('seats', 'attendee_ids')
+ def _taken_seats(self):
+ for r in self:
+ if not r.seats:
+ r.taken_seats = 0.0
+ else:
+ r.taken_seats = 100.0 * len(r.attendee_ids) / r.seats
diff --git a/openacademy/views/openacademy.xml b/openacademy/views/openacademy.xml
--- a/openacademy/views/openacademy.xml
+++ b/openacademy/views/openacademy.xml
@@ -99,6 +99,7 @@
<field name="start_date"/>
<field name="duration"/>
<field name="seats"/>
+ <field name="taken_seats" widget="progressbar"/>
</group>
</group>
<label for="attendee_ids"/>
@@ -116,6 +117,7 @@
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
+ <field name="taken_seats" widget="progressbar"/>
</tree>
</field>
</record>

View File

@ -0,0 +1,25 @@
# 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")

View File

@ -0,0 +1,24 @@
# 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'

View File

@ -0,0 +1,27 @@
# 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,19 @@ class Course(models.Model):
session_ids = fields.One2many(
'openacademy.session', 'course_id', string="Sessions")
+ 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)',

View File

@ -0,0 +1,152 @@
# 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/13.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/<model("openacademy.openacademy"):obj>/', 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 @@
+<odoo>
+
+ <!-- -->
+ <!-- <record id="object0" model="openacademy.openacademy"> -->
+ <!-- <field name="name">Object 0</field> -->
+ <!-- </record> -->
+ <!-- -->
+ <!-- <record id="object1" model="openacademy.openacademy"> -->
+ <!-- <field name="name">Object 1</field> -->
+ <!-- </record> -->
+ <!-- -->
+ <!-- <record id="object2" model="openacademy.openacademy"> -->
+ <!-- <field name="name">Object 2</field> -->
+ <!-- </record> -->
+ <!-- -->
+ <!-- <record id="object3" model="openacademy.openacademy"> -->
+ <!-- <field name="name">Object 3</field> -->
+ <!-- </record> -->
+ <!-- -->
+ <!-- <record id="object4" model="openacademy.openacademy"> -->
+ <!-- <field name="name">Object 4</field> -->
+ <!-- </record> -->
+ <!-- -->
+
+</odoo>
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 @@
+<odoo>
+
+ <!-- <template id="listing"> -->
+ <!-- <ul> -->
+ <!-- <li t-foreach="objects" t-as="object"> -->
+ <!-- <a t-attf-href="{{ root }}/objects/{{ object.id }}"> -->
+ <!-- <t t-esc="object.display_name"/> -->
+ <!-- </a> -->
+ <!-- </li> -->
+ <!-- </ul> -->
+ <!-- </template> -->
+ <!-- <template id="object"> -->
+ <!-- <h1><t t-esc="object.display_name"/></h1> -->
+ <!-- <dl> -->
+ <!-- <t t-foreach="object._fields" t-as="field"> -->
+ <!-- <dt><t t-esc="field"/></dt> -->
+ <!-- <dd><t t-esc="object[field]"/></dd> -->
+ <!-- </t> -->
+ <!-- </dl> -->
+ <!-- </template> -->
+
+</odoo>

View File

@ -0,0 +1,91 @@
# 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,62 @@
+<?xml version="1.0"?>
+<odoo>
+
+ <record model="ir.actions.act_window" id="act_session_graph">
+ <field name="name">Attendees by course</field>
+ <field name="res_model">openacademy.session</field>
+ <field name="view_mode">graph</field>
+ <field name="view_id"
+ ref="openacademy.openacademy_session_graph_view"/>
+ </record>
+ <record model="ir.actions.act_window" id="act_session_calendar">
+ <field name="name">Sessions</field>
+ <field name="res_model">openacademy.session</field>
+ <field name="view_mode">calendar</field>
+ <field name="view_id" ref="openacademy.session_calendar_view"/>
+ </record>
+ <record model="ir.actions.act_window" id="act_course_list">
+ <field name="name">Courses</field>
+ <field name="res_model">openacademy.course</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+ <record model="ir.ui.view" id="board_session_form">
+ <field name="name">Session Dashboard Form</field>
+ <field name="model">board.board</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="Session Dashboard">
+ <board style="2-1">
+ <column>
+ <action
+ string="Attendees by course"
+ name="%(act_session_graph)d"
+ height="150"
+ width="510"/>
+ <action
+ string="Sessions"
+ name="%(act_session_calendar)d"/>
+ </column>
+ <column>
+ <action
+ string="Courses"
+ name="%(act_course_list)d"/>
+ </column>
+ </board>
+ </form>
+ </field>
+ </record>
+ <record model="ir.actions.act_window" id="open_board_session">
+ <field name="name">Session Dashboard</field>
+ <field name="res_model">board.board</field>
+ <field name="view_mode">form</field>
+ <field name="usage">menu</field>
+ <field name="view_id" ref="board_session_form"/>
+ </record>
+
+ <menuitem
+ name="Session Dashboard" parent="base.menu_reporting_dashboard"
+ action="open_board_session"
+ sequence="1"
+ id="menu_board_session"/>
+
+</odoo>

View File

@ -0,0 +1,28 @@
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
@@ -94,6 +94,7 @@
<field name="course_id"/>
<field name="name"/>
<field name="instructor_id"/>
+ <field name="active"/>
</group>
<group string="Schedule">
<field name="start_date"/>

View File

@ -0,0 +1,48 @@
# 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 @@
<odoo>
- <!-- -->
- <!-- <record id="object0" model="openacademy.openacademy"> -->
- <!-- <field name="name">Object 0</field> -->
- <!-- </record> -->
- <!-- -->
- <!-- <record id="object1" model="openacademy.openacademy"> -->
- <!-- <field name="name">Object 1</field> -->
- <!-- </record> -->
- <!-- -->
- <!-- <record id="object2" model="openacademy.openacademy"> -->
- <!-- <field name="name">Object 2</field> -->
- <!-- </record> -->
- <!-- -->
- <!-- <record id="object3" model="openacademy.openacademy"> -->
- <!-- <field name="name">Object 3</field> -->
- <!-- </record> -->
- <!-- -->
- <!-- <record id="object4" model="openacademy.openacademy"> -->
- <!-- <field name="name">Object 4</field> -->
- <!-- </record> -->
- <!-- -->
+ <record model="openacademy.course" id="course0">
+ <field name="name">Course 0</field>
+ <field name="description">Course 0's description
+
+Can have multiple lines
+ </field>
+ </record>
+ <record model="openacademy.course" id="course1">
+ <field name="name">Course 1</field>
+ <!-- no description for this one -->
+ </record>
+ <record model="openacademy.course" id="course2">
+ <field name="name">Course 2</field>
+ <field name="description">Course 2's description</field>
+ </record>
</odoo>

View File

@ -0,0 +1,42 @@
# 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"/>
+ <record model="ir.actions.act_window" id="contact_cat_list_action">
+ <field name="name">Contact Tags</field>
+ <field name="res_model">res.partner.category</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+ <menuitem id="contact_cat_menu" name="Contact Tags"
+ parent="configuration_menu"
+ action="contact_cat_list_action"/>
+
+ <record model="res.partner.category" id="teacher1">
+ <field name="name">Teacher / Level 1</field>
+ </record>
+ <record model="res.partner.category" id="teacher2">
+ <field name="name">Teacher / Level 2</field>
+ </record>
+
</odoo>

View File

@ -0,0 +1,17 @@
# 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")

View File

@ -0,0 +1,29 @@
# 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 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
+ <record model="ir.ui.view" id="course_form_view">
+ <field name="name">course.form</field>
+ <field name="model">openacademy.course</field>
+ <field name="arch" type="xml">
+ <form string="Course Form">
+ <sheet>
+ <group>
+ <field name="name"/>
+ <field name="description"/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
<!-- window action -->
<!--
The following tag is an action definition for a "window action",

View File

@ -0,0 +1,24 @@
# HG changeset patch
# Parent 5508a5440faa7b607d057c4e4ae70af6b6f7cac9
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml 2014-08-26 17:25:55.023783446 +0200
+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:55.015783446 +0200
@@ -9,8 +9,15 @@
<sheet>
<group>
<field name="name"/>
- <field name="description"/>
</group>
+ <notebook>
+ <page string="Description">
+ <field name="description"/>
+ </page>
+ <page string="About">
+ This is an example of notebooks
+ </page>
+ </notebook>
</sheet>
</form>
</field>

View File

@ -0,0 +1,30 @@
# HG changeset patch
# Parent dba00a105dd2a82490394b8dec5fea5f1d8847e1
# Parent f4374b6e2e661e0782e396b24c57c1eb97d13288
diff --git a/openacademy/views/openacademy.xml b/openacademy/views/openacademy.xml
--- a/openacademy/views/openacademy.xml
+++ b/openacademy/views/openacademy.xml
@@ -142,10 +142,21 @@
</field>
</record>
+ <record model="ir.ui.view" id="session_gantt_view">
+ <field name="name">session.gantt</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <gantt string="Session Gantt"
+ date_start="start_date" date_stop="end_date"
+ default_group_by='instructor_id'>
+ </gantt>
+ </field>
+ </record>
+
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
- <field name="view_mode">tree,form,calendar</field>
+ <field name="view_mode">tree,form,calendar,gantt</field>
</record>
<menuitem id="session_menu" name="Sessions"

View File

@ -0,0 +1,55 @@
# HG changeset patch
# Parent a6fe4d3923db1f8f5dff2c39a711a814b0a0f549
# Parent 0687e07f570f363bf5005c6337e0c565a63a6bac
diff --git a/openacademy/models.py b/openacademy/models.py
--- a/openacademy/models.py
+++ b/openacademy/models.py
@@ -60,6 +60,9 @@ class Session(models.Model):
end_date = fields.Date(string="End Date", store=True,
compute='_get_end_date', inverse='_set_end_date')
+ attendees_count = fields.Integer(
+ string="Attendees count", compute='_get_attendees_count', store=True)
+
@api.depends('seats', 'attendee_ids')
def _taken_seats(self):
for r in self:
@@ -106,6 +109,11 @@ class Session(models.Model):
# so add one day to get 5 days instead
r.duration = (r.end_date - r.start_date).days + 1
+ @api.depends('attendee_ids')
+ def _get_attendees_count(self):
+ for r in self:
+ r.attendees_count = len(r.attendee_ids)
+
@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
@@ -153,10 +153,21 @@
</field>
</record>
+ <record model="ir.ui.view" id="openacademy_session_graph_view">
+ <field name="name">openacademy.session.graph</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <graph string="Participations by Courses">
+ <field name="course_id"/>
+ <field name="attendees_count" type="measure"/>
+ </graph>
+ </field>
+ </record>
+
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
- <field name="view_mode">tree,form,calendar,gantt</field>
+ <field name="view_mode">tree,form,calendar,gantt,graph</field>
</record>
<menuitem id="session_menu" name="Sessions"

View File

@ -0,0 +1,77 @@
# HG changeset patch
# Parent 8d66f7620781558d4520f97e4cebc14ed180683e
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -49,6 +49,7 @@
duration = fields.Float(digits=(6, 2), help="Duration in days")
seats = fields.Integer(string="Number of seats")
active = fields.Boolean(default=True)
+ color = fields.Integer()
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
@@ -165,10 +165,56 @@
</field>
</record>
+ <record model="ir.ui.view" id="view_openacad_session_kanban">
+ <field name="name">openacademy.session.kanban</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <kanban default_group_by="course_id">
+ <field name="color"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div
+ t-attf-class="oe_kanban_color_{{kanban_getcolor(record.color.raw_value)}}
+ oe_kanban_global_click_edit oe_semantic_html_override
+ oe_kanban_card {{record.group_fancy==1 ? 'oe_kanban_card_fancy' : ''}}">
+ <div class="oe_dropdown_kanban">
+ <!-- dropdown menu -->
+ <div class="oe_dropdown_toggle">
+ <i class="fa fa-bars fa-lg" title="Manage" aria-label="Manage"/>
+ <ul class="oe_dropdown_menu">
+ <li>
+ <a type="delete">Delete</a>
+ </li>
+ <li>
+ <ul class="oe_kanban_colorpicker"
+ data-field="color"/>
+ </li>
+ </ul>
+ </div>
+ <div class="oe_clear"></div>
+ </div>
+ <div t-attf-class="oe_kanban_content">
+ <!-- title -->
+ Session name:
+ <field name="name"/>
+ <br/>
+ Start date:
+ <field name="start_date"/>
+ <br/>
+ duration:
+ <field name="duration"/>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
+
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
- <field name="view_mode">tree,form,calendar,gantt,graph</field>
+ <field name="view_mode">tree,form,calendar,gantt,graph,kanban</field>
</record>
<menuitem id="session_menu" name="Sessions"

View File

@ -0,0 +1,22 @@
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -27,3 +27,4 @@
instructor_id = fields.Many2one('res.partner', string="Instructor")
course_id = fields.Many2one('openacademy.course',
ondelete='cascade', string="Course", required=True)
+ attendee_ids = fields.Many2many('res.partner', string="Attendees")
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml
@@ -101,6 +101,8 @@
<field name="seats"/>
</group>
</group>
+ <label for="attendee_ids"/>
+ <field name="attendee_ids"/>
</sheet>
</form>
</field>

View File

@ -0,0 +1,95 @@
# HG changeset patch
# Parent a6e217b1fbbc64111581c269629b1c25c23abb99
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -9,6 +9,9 @@
name = fields.Char(string="Title", required=True)
description = fields.Text()
+ responsible_id = fields.Many2one('res.users',
+ ondelete='set null', string="Responsible", index=True)
+
class Session(models.Model):
_name = 'openacademy.session'
@@ -18,3 +21,7 @@
start_date = fields.Date()
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")
+ course_id = fields.Many2one('openacademy.course',
+ ondelete='cascade', string="Course", required=True)
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml
@@ -9,6 +9,7 @@
<sheet>
<group>
<field name="name"/>
+ <field name="responsible_id"/>
</group>
<notebook>
<page string="Description">
@@ -34,6 +35,18 @@
</field>
</record>
+ <!-- override the automatically generated list view for courses -->
+ <record model="ir.ui.view" id="course_tree_view">
+ <field name="name">course.tree</field>
+ <field name="model">openacademy.course</field>
+ <field name="arch" type="xml">
+ <tree string="Course Tree">
+ <field name="name"/>
+ <field name="responsible_id"/>
+ </tree>
+ </field>
+ </record>
+
<!-- window action -->
<!--
The following tag is an action definition for a "window action",
@@ -72,16 +85,34 @@
<form string="Session Form">
<sheet>
<group>
- <field name="name"/>
- <field name="start_date"/>
- <field name="duration"/>
- <field name="seats"/>
+ <group string="General">
+ <field name="course_id"/>
+ <field name="name"/>
+ <field name="instructor_id"/>
+ </group>
+ <group string="Schedule">
+ <field name="start_date"/>
+ <field name="duration"/>
+ <field name="seats"/>
+ </group>
</group>
</sheet>
</form>
</field>
</record>
+ <!-- session tree/list view -->
+ <record model="ir.ui.view" id="session_tree_view">
+ <field name="name">session.tree</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <tree string="Session Tree">
+ <field name="name"/>
+ <field name="course_id"/>
+ </tree>
+ </field>
+ </record>
+
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>

View File

@ -0,0 +1,19 @@
# HG changeset patch
# Parent e3bb12713a6d38c28f50d46e8c1bab74ac40c1be
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -2,7 +2,9 @@
from odoo import models, fields, api
-# class openacademy(models.Model):
-# _name = 'openacademy.openacademy'
+class Course(models.Model):
+ _name = 'openacademy.course'
+ _description = "OpenAcademy Courses"
-# name = fields.Char()
+ name = fields.Char(string="Title", required=True)
+ description = fields.Text()

View File

@ -0,0 +1,78 @@
# HG changeset patch
# Parent d903c828fb10f2b38e5f43e9ceaeae0a9db7f858
Index: addons/openacademy/__init__.py
===================================================================
--- addons.orig/openacademy/__init__.py 2014-08-26 17:26:01.227783353 +0200
+++ addons/openacademy/__init__.py 2014-08-26 17:26:01.219783354 +0200
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
+from . import partner
Index: addons/openacademy/__manifest__.py
===================================================================
--- addons.orig/openacademy/__manifest__.py 2014-08-26 17:26:01.227783353 +0200
+++ addons/openacademy/__manifest__.py 2014-08-26 17:26:01.223783354 +0200
@@ -28,6 +28,7 @@
# 'security/ir.model.access.csv',
'templates.xml',
'views/openacademy.xml',
+ 'views/partner.xml',
],
# only loaded in demonstration mode
'demo': [
Index: addons/openacademy/partner.py
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/partner.py 2014-08-26 17:26:01.223783354 +0200
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+from odoo import fields, models
+
+class Partner(models.Model):
+ _inherit = 'res.partner'
+
+ # Add a new column to the res.partner model, by default partners are not
+ # instructors
+ instructor = fields.Boolean("Instructor", default=False)
+
+ session_ids = fields.Many2many('openacademy.session',
+ string="Attended Sessions", readonly=True)
Index: addons/openacademy/views/partner.xml
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ addons/openacademy/views/partner.xml 2014-08-26 17:26:01.223783354 +0200
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+ <odoo>
+
+ <!-- Add instructor field to existing view -->
+ <record model="ir.ui.view" id="partner_instructor_form_view">
+ <field name="name">partner.instructor</field>
+ <field name="model">res.partner</field>
+ <field name="inherit_id" ref="base.view_partner_form"/>
+ <field name="arch" type="xml">
+ <notebook position="inside">
+ <page string="Sessions">
+ <group>
+ <field name="instructor"/>
+ <field name="session_ids"/>
+ </group>
+ </page>
+ </notebook>
+ </field>
+ </record>
+
+ <record model="ir.actions.act_window" id="contact_list_action">
+ <field name="name">Contacts</field>
+ <field name="res_model">res.partner</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+ <menuitem id="configuration_menu" name="Configuration"
+ parent="main_openacademy_menu"/>
+ <menuitem id="contact_menu" name="Contacts"
+ parent="configuration_menu"
+ action="contact_list_action"/>
+
+</odoo>

View File

@ -0,0 +1,28 @@
# HG changeset patch
# Parent 8d5573b704b2867788dd6895503f1871c2976a29
# Parent 9eb163e5da677a0d09e01a354ba56697b576a4bc
diff --git a/openacademy/models.py b/openacademy/models.py
--- a/openacademy/models.py
+++ b/openacademy/models.py
@@ -41,3 +41,20 @@ class Session(models.Model):
r.taken_seats = 0.0
else:
r.taken_seats = 100.0 * len(r.attendee_ids) / r.seats
+
+ @api.onchange('seats', 'attendee_ids')
+ def _verify_valid_seats(self):
+ if self.seats < 0:
+ return {
+ 'warning': {
+ 'title': "Incorrect 'seats' value",
+ 'message': "The number of available seats may not be negative",
+ },
+ }
+ if self.seats < len(self.attendee_ids):
+ return {
+ 'warning': {
+ 'title': "Too many attendees",
+ 'message': "Increase seats or remove excess attendees",
+ },
+ }

View File

@ -0,0 +1,36 @@
# HG changeset patch
# Parent cb05882d4fe73e97b9d34a69190ced14d1a50c24
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -11,6 +11,8 @@
responsible_id = fields.Many2one('res.users',
ondelete='set null', string="Responsible", index=True)
+ session_ids = fields.One2many(
+ 'openacademy.session', 'course_id', string="Sessions")
class Session(models.Model):
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml
@@ -15,8 +15,13 @@
<page string="Description">
<field name="description"/>
</page>
- <page string="About">
- This is an example of notebooks
+ <page string="Sessions">
+ <field name="session_ids">
+ <tree string="Registered sessions">
+ <field name="name"/>
+ <field name="instructor_id"/>
+ </tree>
+ </field>
</page>
</notebook>
</sheet>

View File

@ -0,0 +1,52 @@
# HG changeset patch
# Parent c140f0a861a08881d8737bca0ffb83904a2059a3
Index: addons/openacademy/__manifest__.py
===================================================================
--- addons.orig/openacademy/__manifest__.py 2014-08-29 08:39:43.975536806 +0200
+++ addons/openacademy/__manifest__.py 2014-08-29 08:39:52.000000000 +0200
@@ -30,6 +30,7 @@
'templates.xml',
'views/openacademy.xml',
'views/partner.xml',
+ 'reports.xml',
],
# only loaded in demonstration mode
'demo': [
Index: foo/openacademy/reports.xml
===================================================================
--- /dev/null
+++ foo/openacademy/reports.xml
@@ -0,0 +1,32 @@
+<odoo>
+
+ <record id="report_session" model="ir.actions.report">
+ <field name="name">Session Report</field>
+ <field name="model">openacademy.session</field>
+ <field name="report_type">qweb-pdf</field>
+ <field name="report_name">openacademy.report_session_view</field>
+ <field name="report_file">openacademy.report_session</field>
+ <field name="binding_model_id" ref="model_openacademy_session"/>
+ <field name="binding_type">report</field>
+ </record>
+
+ <template id="report_session_view">
+ <t t-call="web.html_container">
+ <t t-foreach="docs" t-as="doc">
+ <t t-call="web.external_layout">
+ <div class="page">
+ <h2 t-field="doc.name"/>
+ <p>From <span t-field="doc.start_date"/> to <span t-field="doc.end_date"/></p>
+ <h3>Attendees:</h3>
+ <ul>
+ <t t-foreach="doc.attendee_ids" t-as="attendee">
+ <li><span t-field="attendee.name"/></li>
+ </t>
+ </ul>
+ </div>
+ </t>
+ </t>
+ </t>
+ </template>
+
+</odoo>

View File

@ -0,0 +1,28 @@
# HG changeset patch
# Parent 93a45ab8dd0a76c131cb5eeca6e44b71dca9f100
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml 2014-08-28 14:01:45.299033618 +0200
+++ addons/openacademy/views/openacademy.xml 2014-08-28 14:18:58.847018275 +0200
@@ -36,6 +36,12 @@
<search>
<field name="name"/>
<field name="description"/>
+ <filter name="my_courses" string="My Courses"
+ domain="[('responsible_id', '=', uid)]"/>
+ <group string="Group By">
+ <filter name="by_responsible" string="Responsible"
+ context="{'group_by': 'responsible_id'}"/>
+ </group>
</search>
</field>
</record>
@@ -61,6 +67,7 @@
<field name="name">Courses</field>
<field name="res_model">openacademy.course</field>
<field name="view_mode">tree,form</field>
+ <field name="context" eval="{'search_default_my_courses': 1}"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">Create the first course
</p>

View File

@ -0,0 +1,24 @@
# HG changeset patch
# Parent b9bfc8929e0ffc3eb153641e14952fe5d99eb908
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml 2014-08-26 17:25:55.807783434 +0200
+++ addons/openacademy/views/openacademy.xml 2014-08-26 17:25:55.799783434 +0200
@@ -23,6 +23,17 @@
</field>
</record>
+ <record model="ir.ui.view" id="course_search_view">
+ <field name="name">course.search</field>
+ <field name="model">openacademy.course</field>
+ <field name="arch" type="xml">
+ <search>
+ <field name="name"/>
+ <field name="description"/>
+ </search>
+ </field>
+ </record>
+
<!-- window action -->
<!--
The following tag is an action definition for a "window action",

View File

@ -0,0 +1,57 @@
# HG changeset patch
# Parent 22f8d180a7f9ad209d7e98cf7d1bd0fee1f05350
Index: addons/openacademy/models.py
===================================================================
--- addons.orig/openacademy/models.py
+++ addons/openacademy/models.py
@@ -8,3 +8,13 @@
name = fields.Char(string="Title", required=True)
description = fields.Text()
+
+
+class Session(models.Model):
+ _name = 'openacademy.session'
+ _description = "OpenAcademy Sessions"
+
+ name = fields.Char(required=True)
+ start_date = fields.Date()
+ duration = fields.Float(digits=(6, 2), help="Duration in days")
+ seats = fields.Integer(string="Number of seats")
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml
@@ -64,4 +64,32 @@
action="openacademy.course_list_action"
It is not required when it is the same module -->
+ <!-- session form view -->
+ <record model="ir.ui.view" id="session_form_view">
+ <field name="name">session.form</field>
+ <field name="model">openacademy.session</field>
+ <field name="arch" type="xml">
+ <form string="Session Form">
+ <sheet>
+ <group>
+ <field name="name"/>
+ <field name="start_date"/>
+ <field name="duration"/>
+ <field name="seats"/>
+ </group>
+ </sheet>
+ </form>
+ </field>
+ </record>
+
+ <record model="ir.actions.act_window" id="session_list_action">
+ <field name="name">Sessions</field>
+ <field name="res_model">openacademy.session</field>
+ <field name="view_mode">tree,form</field>
+ </record>
+
+ <menuitem id="session_menu" name="Sessions"
+ parent="openacademy_menu"
+ action="session_list_action"/>
+
</odoo>

View File

@ -0,0 +1,56 @@
# HG changeset patch
# Parent 7c95aad3b60e4c2006c5f706bd157e8e05318bfa
diff --git a/openacademy/models.py b/openacademy/models.py
--- a/openacademy/models.py
+++ b/openacademy/models.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from datetime import timedelta
-from odoo import models, fields, api, exceptions
+from odoo import models, fields, api, exceptions, _
class Course(models.Model):
_name = 'openacademy.course'
@@ -20,11 +20,11 @@ class Course(models.Model):
default = dict(default or {})
copied_count = self.search_count(
- [('name', '=like', u"Copy of {}%".format(self.name))])
+ [('name', '=like', _(u"Copy of {}%").format(self.name))])
if not copied_count:
- new_name = u"Copy of {}".format(self.name)
+ new_name = _(u"Copy of {}").format(self.name)
else:
- new_name = u"Copy of {} ({})".format(self.name, copied_count)
+ new_name = _(u"Copy of {} ({})").format(self.name, copied_count)
default['name'] = new_name
return super(Course, self).copy(default)
@@ -81,15 +81,15 @@ class Session(models.Model):
if self.seats < 0:
return {
'warning': {
- 'title': "Incorrect 'seats' value",
- 'message': "The number of available seats may not be negative",
+ 'title': _("Incorrect 'seats' value"),
+ 'message': _("The number of available seats may not be negative"),
},
}
if self.seats < len(self.attendee_ids):
return {
'warning': {
- 'title': "Too many attendees",
- 'message': "Increase seats or remove excess attendees",
+ 'title': _("Too many attendees"),
+ 'message': _("Increase seats or remove excess attendees"),
},
}
@@ -114,4 +114,4 @@ class Session(models.Model):
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")
+ raise exceptions.ValidationError(_("A session's instructor can't be an attendee"))

View File

@ -0,0 +1,36 @@
Index: addons/openacademy/__init__.py
===================================================================
--- addons.orig/openacademy/__init__.py
+++ addons/openacademy/__init__.py
@@ -2,3 +2,4 @@
from . import controllers
from . import models
from . import partner
+from . import wizard
Index: addons/openacademy/wizard.py
===================================================================
--- /dev/null
+++ addons/openacademy/wizard.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from odoo import models, fields, api
+
+class Wizard(models.TransientModel):
+ _name = 'openacademy.wizard'
+ _description = "Wizard: Quick Registration of Attendees to Sessions"
+
+ session_id = fields.Many2one('openacademy.session',
+ string="Session", required=True)
+ attendee_ids = fields.Many2many('res.partner', string="Attendees")
Index: foo/openacademy/security/ir.model.access.csv
===================================================================
--- foo.orig/openacademy/security/ir.model.access.csv
+++ foo/openacademy/security/ir.model.access.csv
@@ -1,5 +1,6 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
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
+wizard_manager,wizard session manager,model_openacademy_wizard,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

View File

@ -0,0 +1,29 @@
Index: addons/openacademy/views/openacademy.xml
===================================================================
--- addons.orig/openacademy/views/openacademy.xml
+++ addons/openacademy/views/openacademy.xml
@@ -232,6 +232,12 @@
<field name="session_id"/>
<field name="attendee_ids"/>
</group>
+ <footer>
+ <button name="subscribe" type="object"
+ string="Subscribe" class="oe_highlight"/>
+ or
+ <button special="cancel" string="Cancel"/>
+ </footer>
</form>
</field>
</record>
Index: addons/openacademy/wizard.py
===================================================================
--- addons.orig/openacademy/wizard.py
+++ addons/openacademy/wizard.py
@@ -12,3 +12,7 @@
session_id = fields.Many2one('openacademy.session',
string="Session", required=True, default=_default_session)
attendee_ids = fields.Many2many('res.partner', string="Attendees")
+
+ def subscribe(self):
+ self.session_id.attendee_ids |= self.attendee_ids
+ return {}

Some files were not shown because too many files have changed in this diff Show More