niv-openerp
2012-11-26 10:37:47 +01:00
99 changed files with 500432 additions and 416375 deletions
+59 -35
View File
@@ -10,13 +10,25 @@ Installation from sources
.. _getting_started_installation_source-link:
Source code is hosted on Launchpad_. In order to get the sources, you will need Bazaar_ to pull the source from Launchpad. Bazaar is a version control system that helps you track project history over time and collaborate efficiently. You may have to create an account on Launchpad to be able to collaborate on OpenERP development. Please refer to the Launchpad and Bazaar documentation to install and setup your development environment.
Source code is hosted on Launchpad_. In order to get the sources, you
will need Bazaar_ to pull the source from Launchpad. Bazaar is a
version control system that helps you track project history over time
and collaborate efficiently. You may have to create an account on
Launchpad to be able to collaborate on OpenERP development. Please
refer to the Launchpad and Bazaar documentation to install and setup
your development environment.
The running example of this section is based on an Ubuntu environment. You may have to adapt the steps according to your system. Once your working environment is ready, prepare a working directory that will contain the sources. For a ``source`` base directory, type::
The running example of this section is based on an Ubuntu
environment. You may have to adapt the steps according to your
system. Once your working environment is ready, prepare a working
directory that will contain the sources. For a ``source`` base
directory, type::
mkdir source;cd source
OpenERP provides a setup script that automatizes the tasks of creating a shared repository and getting the source code. Get the setup script of OpenERP by typing::
OpenERP provides a setup script that automatizes the tasks of creating
a shared repository and getting the source code. Get the setup script
of OpenERP by typing::
bzr cat -d lp:~openerp-dev/openerp-tools/trunk setup.sh | sh
@@ -29,27 +41,30 @@ If you want some help about the available options, please type::
make help
Next step is to initialize the shared repository and download the sources. Get the current trunk version of OpenERP by typing::
Next step is to initialize the shared repository and download the
sources. Get the current trunk version of OpenERP by typing::
make init-trunk
This will create the following structure inside your ``source`` directory, and fetch the latest source code from ``trunk``::
This will create the following structure inside your ``source``
directory, and fetch the latest source code from ``trunk``::
drwxrwxr-x 3 openerp openerp 4096 2012-04-17 11:10 addons
drwxrwxr-x 3 openerp openerp 4096 2012-04-17 11:10 misc
drwxrwxr-x 3 openerp openerp 4096 2012-04-17 11:10 server
drwxrwxr-x 3 openerp openerp 4096 2012-04-17 11:10 web
Some dependencies are necessary to use OpenERP. Depending on your environment, you might have to install the following packages::
Some dependencies are necessary to use OpenERP. Depending on your
environment, you might have to install the following packages::
sudo apt-get install graphviz ghostscript postgresql-client
sudo apt-get install python-dateutil python-feedparser python-gdata
python-ldap python-libxslt1 python-lxml python-mako, python-openid
python-psycopg2 python-pybabel python-pychart python-pydot
python-pyparsing python-reportlab python-simplejson python-tz
python-vatnumber python-vobject python-webdav python-werkzeug python-xlwt
python-yaml python-imaging python-matplotlib
sudo apt-get install graphviz ghostscript postgresql-client \
python-dateutil python-feedparser python-gdata \
python-ldap python-libxslt1 python-lxml python-mako \
python-openid python-psycopg2 python-pybabel python-pychart \
python-pydot python-pyparsing python-reportlab python-simplejson \
python-tz python-vatnumber python-vobject python-webdav \
python-werkzeug python-xlwt python-yaml python-imaging \
python-matplotlib
Next step is to initialize the database. This will create a new openerp role::
@@ -59,7 +74,8 @@ Finally, launch the OpenERP server::
make server
Testing your installation can be done on http://localhost:8069/ . You should see the OpenERP main login page.
Testing your installation can be done on http://localhost:8069/. You
should see the OpenERP main login page.
.. _Launchpad: https://launchpad.net/
.. _Bazaar: http://bazaar.canonical.com/en/
@@ -67,12 +83,12 @@ Testing your installation can be done on http://localhost:8069/ . You should see
Command line options
====================
.. program:: openerp-server
Using the command ::
./openerp-server --help
gives you the available command line options. For OpenERP server at revision 4133, an output example is given in the `Command line options example`_. Here are a few interesting command line options.
General Options
+++++++++++++++
@@ -117,7 +133,8 @@ Database related options
Internationalization options
++++++++++++++++++++++++++++
Use these options to translate OpenERP to another language.See i18n section of the user manual. Option '-l' is mandatory.::
Use these options to translate OpenERP to another language.See i18n
section of the user manual. Option '-l' is mandatory.::
-l LANGUAGE, --language=LANGUAGE
specify the language of the translation file. Use it
@@ -134,8 +151,9 @@ Use these options to translate OpenERP to another language.See i18n section of t
Options from previous versions
++++++++++++++++++++++++++++++
Some options were removed in OpenERP version 6. For example, ``price_accuracy`` is now
configured through the :ref:`decimal_accuracy` screen.
Some options were removed in OpenERP version 6. For example,
``price_accuracy`` is now configured through the
:ref:`decimal_accuracy` screen.
Configuration
==============
@@ -147,7 +165,12 @@ Two configuration files are available:
* one for the client: ``~/.openerprc``
* one for the server: ``~/.openerp_serverrc``
If they are not found, the server and the client will start with a default configuration. Those files follow the convention used by python's ConfigParser module. Please note that lines beginning with "#" or ";" are comments. The client configuration file is automatically generated upon the first start. The sezrver configuration file can automatically be created using the command ::
If they are not found, the server and the client will start with a
default configuration. Those files follow the convention used by
python's ConfigParser module. Please note that lines beginning with
"#" or ";" are comments. The client configuration file is
automatically generated upon the first start. The sezrver
configuration file can automatically be created using the command ::
./openerp-server -s or ./openerp-server --save
@@ -156,19 +179,20 @@ You can specify alternate configuration files with ::
-c CONFIG, --config=CONFIG specify alternate config file
Configure addons locations
--------------------------
++++++++++++++++++++++++++
By default, the only directory of addons known by the server is server/bin/addons.
It is possible to add new addons by
By default, the only directory of addons known by the server is
server/bin/addons. It is possible to add new addons by
- copying them in server/bin/addons, or creating a symbolic link to each
of them in this directory, or
- specifying another directory containing addons to the server. The later
can be accomplished either by running the server with the ``--addons-path=``
option, or by configuring this option in the openerp_serverrc file,
automatically generated under Linux in your home directory by the
server when executed with the ``--save`` option. You can provide several
addons to the ``addons_path`` = option, separating them using commas.
- copying them in server/bin/addons, or creating a symbolic link to
each of them in this directory, or
- specifying another directory containing addons to the server. The
later can be accomplished either by running the server with the
``--addons-path=`` option, or by configuring this option in the
openerp_serverrc file, automatically generated under Linux in your
home directory by the server when executed with the ``--save``
option. You can provide several addons to the ``addons_path`` =
option, separating them using commas.
Start-up script
===============
@@ -176,9 +200,9 @@ Start-up script
.. versionadded:: 6.1
To run the OpenERP server, the conventional approach is to use the
`openerp-server` script. It loads the :ref:`openerp library`, sets a few
configuration variables corresponding to command-line arguments, and starts to
listen to incoming connections from clients.
`openerp-server` script. It loads the :ref:`openerp library`, sets a
few configuration variables corresponding to command-line arguments,
and starts to listen to incoming connections from clients.
Depending on your deployment needs, you can write such a start-up script very
easily. We also recommend you take a look at an alternative tool called
+2
View File
@@ -1,3 +1,5 @@
.. _module-dev:
=======
Modules
=======
+12 -10
View File
@@ -1,3 +1,5 @@
.. _module-dev-structure:
Module structure
================
@@ -124,11 +126,11 @@ But it is dangerous to write or read directly in the PostgreSQL database, as
you will shortcut important steps like constraints checking or workflow
modification.
.. figure:: images/pom_3_0_3.png
:scale: 50
:align: center
.. .. figure:: images/pom_3_0_3.png
.. :scale: 50
.. :align: center
*The Physical Objects Model of [OpenERP version 3.0.3]*
.. *The Physical Objects Model of [OpenERP version 3.0.3]*
XML Files
@@ -311,9 +313,9 @@ When you open an invoice, here is the chain of operations followed by the client
* The client asks (with XML-RPC) to the server what views are defined for the invoice object and what are the data it must show.
* The client displays the form according to the view
.. figure:: images/arch_view_use.png
:scale: 50
:align: center
.. .. figure:: images/arch_view_use.png
.. :scale: 50
.. :align: center
To develop new objects
//////////////////////
@@ -342,9 +344,9 @@ The workflows describe these interactions with graphs. One or several workflows
Below is an example workflow used for sale orders. It must generate invoices and shipments according to certain conditions.
.. figure:: images/arch_workflow_sale.png
:scale: 85
:align: center
.. .. figure:: images/arch_workflow_sale.png
.. :scale: 85
.. :align: center
In this graph, the nodes represent the actions to be done:
+2
View File
@@ -1,3 +1,5 @@
.. _module-dev-api:
Objects, Fields and Methods
===========================
+32 -30
View File
@@ -1,3 +1,5 @@
.. _module-dev-views:
Views and Events
================
@@ -45,26 +47,26 @@ The field disposition in a form view always follows the same principle. Fields a
* Fields are placed on the screen from left to right, and from top to bottom, according to the order in which they are declared in the view.
* Every screen is divided into 4 columns, each column being able to contain either a label, or an "edition" field. As every edition field is preceded (by default) by a label with its name, there will be two fields (and their respective labels) on each line of the screen. The green and red zones on the screen-shot below, illustrate those 4 columns. They designate respectively the labels and their corresponding fields.
.. figure:: images/sale_order.png
:scale: 50
:align: center
.. .. figure:: images/sale_order.png
.. :scale: 50
.. :align: center
Views also support more advanced placement options:
* A view field can use several columns. For example, on the screen-shot below, the zone in the blue frame is, in fact, the only field of a "one to many". We will come back later on this note, but let's note that it uses the whole width of the screen and not only one column.
.. figure:: images/sale_order_sale_order_lines.png
:scale: 50
:align: center
.. .. figure:: images/sale_order_sale_order_lines.png
.. :scale: 50
.. :align: center
* We can also make the opposite operation: take a columns group and divide it in as many columns as desired. The surrounded green zones of the screen above are good examples. Precisely, the green framework up and on the right side takes the place of two columns, but contains 4 columns.
As we can see below in the purple zone of the screen, there is also a way to distribute the fields of an object on different tabs.
.. figure:: images/sale_order_notebook.png
:scale: 50
:align: center
.. .. figure:: images/sale_order_notebook.png
.. :scale: 50
.. :align: center
On Change
+++++++++
@@ -129,9 +131,9 @@ Tree views
These views are used when we work in list mode (in order to visualize several resources at once) and in the search screen. These views are simpler than the form views and thus have less options.
.. figure:: images/tree_view.png
:scale: 50
:align: center
.. .. figure:: images/tree_view.png
.. :scale: 50
.. :align: center
Search views
--------------
@@ -140,9 +142,9 @@ Search views are a new feature of OpenERP supported as of version 6.0
It creates a customized search panel, and is declared quite similarly to a form view,
except that the view type and root element change to ``search`` instead of ``form``.
.. image:: images/search.png
:scale: 50
:align: center
.. .. image:: images/search.png
.. :scale: 50
.. :align: center
Following is the list of new elements and features supported in search views.
@@ -300,9 +302,9 @@ combining them with AND/OR operators. It is also possible to save any search con
of all currently applied domain and context values) as a personal filter, which can be recalled
at any time. Filters can also be turned into Shortcuts directly available in the User's homepage.
.. image:: images/filter.png
:scale: 50
:align: center
.. .. image:: images/filter.png
.. :scale: 50
.. :align: center
In above screenshot we filter Partner where Salesman = Demo user and Country = Belgium,
@@ -440,15 +442,15 @@ Screenshots
Month Calendar:
.. figure:: images/calendar_month.png
:scale: 50%
:align: center
.. .. figure:: images/calendar_month.png
.. :scale: 50%
.. :align: center
Week Calendar:
.. figure:: images/calendar_week.png
:scale: 50%
:align: center
.. .. figure:: images/calendar_week.png
.. :scale: 50%
.. :align: center
Gantt Views
@@ -556,9 +558,9 @@ end time can be changed by dragging right end of a bar.
Screenshots
+++++++++++
.. figure:: images/gantt.png
:scale: 50%
:align: center
.. .. figure:: images/gantt.png
.. :scale: 50%
.. :align: center
Design Elements
@@ -1337,9 +1339,9 @@ The *view_id* method works very well for menus/actions, but how can you specify
field, for example? When you have a one2many field, two views are used, a tree view (**in blue**), and a form view when
you click on the add button (**in red**).
.. figure:: images/one2many_views.png
:scale: 70%
:align: center
.. .. figure:: images/one2many_views.png
.. :scale: 70%
.. :align: center
When you add a one2many field in a form view, you do something like this :
+5 -3
View File
@@ -1,3 +1,5 @@
.. _module-dev-actions:
=================
Menus and Actions
=================
@@ -207,9 +209,9 @@ They indicate at the user that he has to open a new window in a new 'tab'.
Administration > Custom > Low Level > Base > Action > Window Actions
.. figure:: images/module_base_action_window.png
:scale: 85
:align: center
.. .. figure:: images/module_base_action_window.png
.. :scale: 85
.. :align: center
Examples of actions
+++++++++++++++++++
+1
View File
@@ -1,3 +1,4 @@
.. _module-dev-example:
==========================
Example of module creation
+1
View File
@@ -1,3 +1,4 @@
.. _module-dev-versioning:
.. _module_versioning:
=================
+2
View File
@@ -1,3 +1,5 @@
.. _security:
==================================
Security in OpenERP: users, groups
==================================
+150
View File
@@ -15,10 +15,159 @@
Mr Demo</field>
<field name="company_id" ref="main_company"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/>
<field name="image">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
gk//2Q==</field>
</record>
<record model="res.partner" id="base.partner_root">
<field name="email">admin@example.com</field>
<field name="image">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
kALR5oiAU7jnCuj0RFIHQbIiKAf/2Q==</field>
</record>
<!-- new rate for demo transactions in multi currency -->
@@ -27,5 +176,6 @@ Mr Demo</field>
<field name="currency_id" ref="USD"/>
<field eval="time.strftime('%Y-06-06')" name="name"/>
</record>
</data>
</openerp>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12242 -8491
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+10851 -7653
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+11036 -7945
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13000 -8478
View File
File diff suppressed because it is too large Load Diff
+10349 -7629
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12407 -8439
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13878 -9292
View File
File diff suppressed because it is too large Load Diff
+13095 -8883
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -51,12 +51,14 @@ class ir_config_parameter(osv.osv):
('key_uniq', 'unique (key)', 'Key must be unique.')
]
def init(self, cr):
def init(self, cr, force=False):
"""
Initializes the parameters listed in _default_parameters.
It overrides existing parameters if force is ``True``.
"""
for key, func in _default_parameters.iteritems():
ids = self.search(cr, SUPERUSER_ID, [('key','=',key)])
# force=True skips search and always performs the 'if' body (because ids=False)
ids = not force and self.search(cr, SUPERUSER_ID, [('key','=',key)])
if not ids:
self.set_param(cr, SUPERUSER_ID, key, func())
@@ -73,7 +73,15 @@ class base_language_export(osv.osv_memory):
self.write(cr, uid, ids, {'state': 'get',
'data': out,
'name':this.name}, context=context)
return True
return {
'type': 'ir.actions.act_window',
'res_model': 'base.language.export',
'view_mode': 'form',
'view_type': 'form',
'res_id': this.id,
'views': [(False, 'form')],
'target': 'new',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1 -1
View File
@@ -127,7 +127,7 @@ class res_currency(osv.osv):
if isinstance(ids, (int, long)):
ids = [ids]
reads = self.read(cr, uid, ids, ['name','symbol'], context=context, load='_classic_write')
return [(x['id'], tools.ustr(x['name']) + (x['symbol'] and (' (' + tools.ustr(x['symbol']) + ')') or '')) for x in reads]
return [(x['id'], tools.ustr(x['name'])) for x in reads]
def round(self, cr, uid, currency, amount):
"""Return ``amount`` rounded according to ``currency``'s
+1 -1
View File
@@ -6,7 +6,7 @@
<menuitem name="Sales"
id="menu_base_partner"
groups="base.group_sale_salesman"
sequence="30"/>
sequence="20"/>
<menuitem id="base.menu_sales" parent="base.menu_base_partner" name="Sales" sequence="1" />
<menuitem id="menu_base_config" parent="menu_base_partner" name="Configuration" sequence="30" groups="group_system"/>
+3 -3
View File
@@ -398,10 +398,10 @@ class res_users(osv.osv):
# prevent/delay login in that case. It will also have been logged
# as a SQL error, if anyone cares.
try:
cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", (user_id,))
cr.execute("SELECT id FROM res_users WHERE id=%s FOR UPDATE NOWAIT", (user_id,), log_exceptions=False)
cr.execute("UPDATE res_users SET login_date = now() AT TIME ZONE 'UTC' WHERE id=%s", (user_id,))
except Exception, e:
_logger.exception("Failed to update last_login for db:%s login:%s", db, login)
except Exception:
_logger.debug("Failed to update last_login for db:%s login:%s", db, login, exc_info=True)
except openerp.exceptions.AccessDenied:
_logger.info("Login failed for db:%s login:%s", db, login)
user_id = False
+2 -1
View File
@@ -1,7 +1,8 @@
import test_base, test_expression, test_ir_values
import test_base, test_expression, test_search, test_ir_values
checks = [
test_base,
test_expression,
test_search,
test_ir_values,
]
+60
View File
@@ -0,0 +1,60 @@
import unittest2
import openerp.tests.common as common
class test_expression(common.TransactionCase):
def test_search_order(self):
registry, cr, uid = self.registry, self.cr, self.uid
# Create 6 partners with a given name, and a given creation order to
# ensure the order of their ID. Some are set as unactive to verify they
# are by default excluded from the searches and to provide a second
# `order` argument.
partners = registry('res.partner')
c = partners.create(cr, uid, {'name': 'test_search_order_C'})
d = partners.create(cr, uid, {'name': 'test_search_order_D', 'active': False})
a = partners.create(cr, uid, {'name': 'test_search_order_A'})
b = partners.create(cr, uid, {'name': 'test_search_order_B'})
ab = partners.create(cr, uid, {'name': 'test_search_order_AB'})
e = partners.create(cr, uid, {'name': 'test_search_order_E', 'active': False})
# The tests.
# The basic searches should exclude records that have active = False.
# The order of the returned ids should be given by the `order`
# parameter of search().
name_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name asc")
self.assertEqual([a, ab, b, c], name_asc, "Search with 'NAME ASC' order failed.")
name_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="name desc")
self.assertEqual([c, b, ab, a], name_desc, "Search with 'NAME DESC' order failed.")
id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id asc")
self.assertEqual([c, a, b, ab], id_asc, "Search with 'ID ASC' order failed.")
id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%')], order="id desc")
self.assertEqual([ab, b, a, c], id_desc, "Search with 'ID DESC' order failed.")
# The inactive records shouldn't be excluded as soon as a condition on
# that field is present in the domain. The `order` parameter of
# search() should support any legal coma-separated values.
active_asc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id asc")
self.assertEqual([d, e, c, a, b, ab], active_asc_id_asc, "Search with 'ACTIVE ASC, ID ASC' order failed.")
active_desc_id_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id asc")
self.assertEqual([c, a, b, ab, d, e], active_desc_id_asc, "Search with 'ACTIVE DESC, ID ASC' order failed.")
active_asc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active asc, id desc")
self.assertEqual([e, d, ab, b, a, c], active_asc_id_desc, "Search with 'ACTIVE ASC, ID DESC' order failed.")
active_desc_id_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="active desc, id desc")
self.assertEqual([ab, b, a, c, e, d], active_desc_id_desc, "Search with 'ACTIVE DESC, ID DESC' order failed.")
id_asc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active asc")
self.assertEqual([c, d, a, b, ab, e], id_asc_active_asc, "Search with 'ID ASC, ACTIVE ASC' order failed.")
id_asc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id asc, active desc")
self.assertEqual([c, d, a, b, ab, e], id_asc_active_desc, "Search with 'ID ASC, ACTIVE DESC' order failed.")
id_desc_active_asc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active asc")
self.assertEqual([e, ab, b, a, d, c], id_desc_active_asc, "Search with 'ID DESC, ACTIVE ASC' order failed.")
id_desc_active_desc = partners.search(cr, uid, [('name', 'like', 'test_search_order%'), '|', ('active', '=', True), ('active', '=', False)], order="id desc, active desc")
self.assertEqual([e, ab, b, a, d, c], id_desc_active_desc, "Search with 'ID DESC, ACTIVE DESC' order failed.")
+2 -1
View File
@@ -348,7 +348,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
for (model, name) in cr.fetchall():
model_obj = pool.get(model)
if model_obj and not model_obj.is_transient():
_logger.warning('Model %s (%s) has no access rules!', model, name)
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))
# Temporary warning while we remove access rights on osv_memory objects, as they have
# been replaced by owner-only access rights
+2
View File
@@ -234,6 +234,8 @@ class html(text):
_type = 'html'
_symbol_c = '%s'
def _symbol_f(x):
if x is None or x == False:
return None
return html_sanitize(x)
_symbol_set = (_symbol_c, _symbol_f)
+4 -4
View File
@@ -1603,7 +1603,7 @@ class BaseModel(object):
if fld_def._type == 'many2many':
obj = self.pool.get(fld_def._obj)
field_value2 = []
for i in range(len(field_value)):
for i in range(len(field_value or [])):
if not obj.search(cr, uid, [('id', '=',
field_value[i])]):
continue
@@ -1612,7 +1612,7 @@ class BaseModel(object):
if fld_def._type == 'one2many':
obj = self.pool.get(fld_def._obj)
field_value2 = []
for i in range(len(field_value)):
for i in range(len(field_value or [])):
field_value2.append({})
for field2 in field_value[i]:
if field2 in obj._columns.keys() and obj._columns[field2]._type == 'many2one':
@@ -1782,7 +1782,7 @@ class BaseModel(object):
# TODO: find a way to remove this hack, by allow dynamic domains
dom = []
if column._domain and not isinstance(column._domain, basestring):
dom = column._domain
dom = list(column._domain)
dom += eval(node.get('domain', '[]'), {'uid': user, 'time': time})
search_context = dict(context)
if column._context and not isinstance(column._context, basestring):
@@ -4722,7 +4722,7 @@ class BaseModel(object):
order_direction = order_split[1].strip() if len(order_split) == 2 else ''
inner_clause = None
if order_field == 'id':
order_by_clause = '"%s"."%s"' % (self._table, order_field)
order_by_elements.append('"%s"."id" %s' % (self._table, order_direction))
elif order_field in self._columns:
order_column = self._columns[order_field]
if order_column._classic_read:
@@ -8,7 +8,7 @@
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'data': ['view.xml'],
'data': ['view.xml', 'ir.model.access.csv'],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_test_exceptions_model,access_test_exceptions_model,model_test_exceptions_model,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_exceptions_model access_test_exceptions_model model_test_exceptions_model 1 1 1 1
@@ -8,7 +8,7 @@
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'data': [],
'data': ['ir.model.access.csv'],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,25 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_export_boolean,access_export_boolean,model_export_boolean,,1,1,1,1
access_export_integer,access_export_integer,model_export_integer,,1,1,1,1
access_export_float,access_export_float,model_export_float,,1,1,1,1
access_export_decimal,access_export_decimal,model_export_decimal,,1,1,1,1
access_export_string_bounded,access_export_string_bounded,model_export_string_bounded,,1,1,1,1
access_export_string_required,access_export_string_required,model_export_string_required,,1,1,1,1
access_export_string,access_export_string,model_export_string,,1,1,1,1
access_export_date,access_export_date,model_export_date,,1,1,1,1
access_export_datetime,access_export_datetime,model_export_datetime,,1,1,1,1
access_export_text,access_export_text,model_export_text,,1,1,1,1
access_export_selection,access_export_selection,model_export_selection,,1,1,1,1
access_export_selection_function,access_export_selection_function,model_export_selection_function,,1,1,1,1
access_export_many2one,access_export_many2one,model_export_many2one,,1,1,1,1
access_export_one2many,access_export_one2many,model_export_one2many,,1,1,1,1
access_export_many2many,access_export_many2many,model_export_many2many,,1,1,1,1
access_export_function,access_export_function,model_export_function,,1,1,1,1
access_export_one2many_child,access_export_one2many_child,model_export_one2many_child,,1,1,1,1
access_export_one2many_multiple,access_export_one2many_multiple,model_export_one2many_multiple,,1,1,1,1
access_export_one2many_multiple_child,access_export_one2many_multiple_child,model_export_one2many_multiple_child,,1,1,1,1
access_export_one2many_child_1,access_export_one2many_child_1,model_export_one2many_child_1,,1,1,1,1
access_export_one2many_child_2,access_export_one2many_child_2,model_export_one2many_child_2,,1,1,1,1
access_export_many2many_other,access_export_many2many_other,model_export_many2many_other,,1,1,1,1
access_export_selection_withdefault,access_export_selection_withdefault,model_export_selection_withdefault,,1,1,1,1
access_export_one2many_recursive,access_export_one2many_recursive,model_export_one2many_recursive,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_export_boolean access_export_boolean model_export_boolean 1 1 1 1
3 access_export_integer access_export_integer model_export_integer 1 1 1 1
4 access_export_float access_export_float model_export_float 1 1 1 1
5 access_export_decimal access_export_decimal model_export_decimal 1 1 1 1
6 access_export_string_bounded access_export_string_bounded model_export_string_bounded 1 1 1 1
7 access_export_string_required access_export_string_required model_export_string_required 1 1 1 1
8 access_export_string access_export_string model_export_string 1 1 1 1
9 access_export_date access_export_date model_export_date 1 1 1 1
10 access_export_datetime access_export_datetime model_export_datetime 1 1 1 1
11 access_export_text access_export_text model_export_text 1 1 1 1
12 access_export_selection access_export_selection model_export_selection 1 1 1 1
13 access_export_selection_function access_export_selection_function model_export_selection_function 1 1 1 1
14 access_export_many2one access_export_many2one model_export_many2one 1 1 1 1
15 access_export_one2many access_export_one2many model_export_one2many 1 1 1 1
16 access_export_many2many access_export_many2many model_export_many2many 1 1 1 1
17 access_export_function access_export_function model_export_function 1 1 1 1
18 access_export_one2many_child access_export_one2many_child model_export_one2many_child 1 1 1 1
19 access_export_one2many_multiple access_export_one2many_multiple model_export_one2many_multiple 1 1 1 1
20 access_export_one2many_multiple_child access_export_one2many_multiple_child model_export_one2many_multiple_child 1 1 1 1
21 access_export_one2many_child_1 access_export_one2many_child_1 model_export_one2many_child_1 1 1 1 1
22 access_export_one2many_child_2 access_export_one2many_child_2 model_export_one2many_child_2 1 1 1 1
23 access_export_many2many_other access_export_many2many_other model_export_many2many_other 1 1 1 1
24 access_export_selection_withdefault access_export_selection_withdefault model_export_selection_withdefault 1 1 1 1
25 access_export_one2many_recursive access_export_one2many_recursive model_export_one2many_recursive 1 1 1 1
@@ -8,7 +8,7 @@
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'data': [],
'data': ['ir.model.access.csv'],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_test_limits_model,access_test_limits_model,model_test_limits_model,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_limits_model access_test_limits_model model_test_limits_model 1 1 1 1
@@ -8,7 +8,7 @@
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'data': [],
'data': ['ir.model.access.csv'],
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_test_uninstall_model,access_test_uninstall_model,model_test_uninstall_model,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_uninstall_model access_test_uninstall_model model_test_uninstall_model 1 1 1 1
+9 -9
View File
@@ -9,8 +9,8 @@ import common
DB = common.DB
ADMIN_USER_ID = common.ADMIN_USER_ID
def cursor():
return openerp.modules.registry.RegistryManager.get(DB).db.cursor()
def registry():
return openerp.modules.registry.RegistryManager.get(DB)
class test_cr_execute(unittest2.TestCase):
@@ -21,12 +21,12 @@ class test_cr_execute(unittest2.TestCase):
"""
Try to use iterable but non-list or int params in query parameters.
"""
cr = cursor()
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE login=%s", 'admin')
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE id=%s", 1)
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE id=%s", '1')
with registry().cursor(auto_commit=False) as cr:
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE login=%s", 'admin')
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE id=%s", 1)
with self.assertRaises(ValueError):
cr.execute("SELECT id FROM res_users WHERE id=%s", '1')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+3
View File
@@ -173,6 +173,9 @@ class TestCleaner(unittest2.TestCase):
new_html = html_email_clean(TEXT_TPL)
self.assertNotIn('quote', new_html, 'html_email_cleaner did not remove correctly plaintext quotes')
# Test5: False boolean for text must return empty string
new_html = html_email_clean(False)
self.assertEqual(new_html, False, 'html_email_cleaner did change a False in an other value.')
class TestHtmlTools(unittest2.TestCase):
""" Test some of our generic utility functions about html """
+3
View File
@@ -109,6 +109,7 @@ class TestInherits(common.TransactionCase):
self.assertEqual(foo.name, 'Foo')
self.assertEqual(foo.partner_id.id, par_id)
@mute_logger('openerp.osv.orm')
def test_read(self):
""" inherited fields should be read without any indirection """
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
@@ -120,6 +121,7 @@ class TestInherits(common.TransactionCase):
foo = self.user.browse(self.cr, UID, foo_id)
self.assertEqual(foo.name, foo.partner_id.name)
@mute_logger('openerp.osv.orm')
def test_copy(self):
""" copying a user should automatically copy its partner, too """
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
@@ -134,6 +136,7 @@ class TestInherits(common.TransactionCase):
self.assertNotEqual(foo.id, bar.id)
self.assertNotEqual(foo.partner_id.id, bar.partner_id.id)
@mute_logger('openerp.osv.orm')
def test_copy_with_ancestor(self):
""" copying a user with 'parent_id' in defaults should not duplicate the partner """
foo_id = self.user.create(self.cr, UID, {'name': 'Foo', 'login': 'foo', 'password': 'foo'})
+3
View File
@@ -130,6 +130,9 @@ def html_email_clean(html):
dest += source[idx:]
return dest
if not html:
return html
html = ustr(html)
# 1. <br[ /]> -> \n, because otherwise the tree is obfuscated
+10 -4
View File
@@ -23,7 +23,6 @@ import codecs
import csv
import fnmatch
import inspect
import itertools
import locale
import os
import openerp.pooler as pooler
@@ -512,7 +511,7 @@ def trans_parse_rml(de):
def trans_parse_view(de):
res = []
if de.text and de.text.strip():
if not isinstance(de, SKIPPED_ELEMENT_TYPES) and de.text and de.text.strip():
res.append(de.text.strip().encode("utf8"))
if de.tail and de.tail.strip():
res.append(de.tail.strip().encode("utf8"))
@@ -618,7 +617,12 @@ def trans_generate(lang, modules, cr):
_to_translate = []
def push_translation(module, type, name, id, source, comments=None):
tuple = (module, source, name, id, type, comments or [])
if source and tuple not in _to_translate:
# empty and one-letter terms are ignored, they probably are not meant to be
# translated, and would be very hard to translate anyway.
if not source or len(source.strip()) <= 1:
_logger.debug("Ignoring empty or 1-letter source term: %r", tuple)
return
if tuple not in _to_translate:
_to_translate.append(tuple)
def encode(s):
@@ -841,6 +845,8 @@ def trans_generate(lang, modules, cr):
keywords=extract_keywords):
push_translation(module, trans_type, display_path, lineno,
encode(message), comments + extra_comments)
except Exception:
_logger.exception("Failed to extract terms from %s", fabsolutepath)
finally:
src_file.close()
@@ -856,7 +862,7 @@ def trans_generate(lang, modules, cr):
for fname in fnmatch.filter(files, '*.js'):
babel_extract_terms(fname, path, root, 'javascript',
extra_comments=[WEB_TRANSLATION_COMMENT],
extract_keywords={'_t': None})
extract_keywords={'_t': None, '_lt': None})
# QWeb template files
if fnmatch.fnmatch(root, '*/static/src/xml*'):
for fname in fnmatch.filter(files, '*.xml'):