summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntony Lesuisse <al@openerp.com>2014-02-27 17:18:19 +0100
committerAntony Lesuisse <al@openerp.com>2014-02-27 17:18:19 +0100
commit38d1ca1ff2472f4e1d3bc3d5f3454dc7603374a6 (patch)
tree1b2a223afdb1cb27b7d0a19e8bcb7a15ae11219a
parent14815d669ff5ae428a74c7b81327667cdbcf44f9 (diff)
parent6df317c54629e5c222e8db511b38ada767ec60af (diff)
[MERGE] trunk
bzr revid: al@openerp.com-20140227161819-p9chmskfifo0rygs
-rw-r--r--debian/control1
-rw-r--r--doc/03_module_dev_01.rst88
-rw-r--r--doc/06_ir_qweb.rst98
-rw-r--r--doc/06_misc.rst1
-rw-r--r--doc/conf.py1
-rw-r--r--doc/ir_actions.rst14
-rwxr-xr-xoe3
-rw-r--r--openerp/__init__.py50
-rw-r--r--openerp/addons/__init__.py3
-rw-r--r--openerp/addons/base/__init__.py1
-rw-r--r--openerp/addons/base/__openerp__.py2
-rw-r--r--openerp/addons/base/base.sql14
-rw-r--r--openerp/addons/base/base_data.xml35
-rw-r--r--openerp/addons/base/base_demo.xml21
-rw-r--r--openerp/addons/base/i18n/ab.po4
-rw-r--r--openerp/addons/base/i18n/af.po35
-rw-r--r--openerp/addons/base/i18n/am.po8
-rw-r--r--openerp/addons/base/i18n/ar.po4
-rw-r--r--openerp/addons/base/i18n/bg.po4
-rw-r--r--openerp/addons/base/i18n/bn.po4
-rw-r--r--openerp/addons/base/i18n/bs.po4
-rw-r--r--openerp/addons/base/i18n/ca.po4
-rw-r--r--openerp/addons/base/i18n/cs.po14
-rw-r--r--openerp/addons/base/i18n/da.po4
-rw-r--r--openerp/addons/base/i18n/de.po1941
-rw-r--r--openerp/addons/base/i18n/el.po4
-rw-r--r--openerp/addons/base/i18n/en_GB.po4
-rw-r--r--openerp/addons/base/i18n/es.po4
-rw-r--r--openerp/addons/base/i18n/es_AR.po4
-rw-r--r--openerp/addons/base/i18n/es_BO.po4
-rw-r--r--openerp/addons/base/i18n/es_CL.po4
-rw-r--r--openerp/addons/base/i18n/es_CR.po4
-rw-r--r--openerp/addons/base/i18n/es_DO.po4
-rw-r--r--openerp/addons/base/i18n/es_EC.po4
-rw-r--r--openerp/addons/base/i18n/es_MX.po4
-rw-r--r--openerp/addons/base/i18n/es_PE.po4
-rw-r--r--openerp/addons/base/i18n/es_VE.po4
-rw-r--r--openerp/addons/base/i18n/et.po4
-rw-r--r--openerp/addons/base/i18n/eu.po4
-rw-r--r--openerp/addons/base/i18n/fa.po4
-rw-r--r--openerp/addons/base/i18n/fa_AF.po4
-rw-r--r--openerp/addons/base/i18n/fi.po24
-rw-r--r--openerp/addons/base/i18n/fr.po6
-rw-r--r--openerp/addons/base/i18n/fr_CA.po4
-rw-r--r--openerp/addons/base/i18n/gl.po4
-rw-r--r--openerp/addons/base/i18n/gu.po4
-rw-r--r--openerp/addons/base/i18n/he.po478
-rw-r--r--openerp/addons/base/i18n/hi.po4
-rw-r--r--openerp/addons/base/i18n/hr.po4
-rw-r--r--openerp/addons/base/i18n/hu.po4
-rw-r--r--openerp/addons/base/i18n/hy.po4
-rw-r--r--openerp/addons/base/i18n/id.po36
-rw-r--r--openerp/addons/base/i18n/is.po4
-rw-r--r--openerp/addons/base/i18n/it.po4
-rw-r--r--openerp/addons/base/i18n/ja.po152
-rw-r--r--openerp/addons/base/i18n/ka.po4
-rw-r--r--openerp/addons/base/i18n/kk.po4
-rw-r--r--openerp/addons/base/i18n/ko.po4
-rw-r--r--openerp/addons/base/i18n/lt.po4
-rw-r--r--openerp/addons/base/i18n/lv.po11
-rw-r--r--openerp/addons/base/i18n/mk.po4
-rw-r--r--openerp/addons/base/i18n/mn.po31
-rw-r--r--openerp/addons/base/i18n/nb.po4
-rw-r--r--openerp/addons/base/i18n/nl.po6
-rw-r--r--openerp/addons/base/i18n/nl_BE.po4
-rw-r--r--openerp/addons/base/i18n/pl.po4
-rw-r--r--openerp/addons/base/i18n/pt.po4
-rw-r--r--openerp/addons/base/i18n/pt_BR.po4
-rw-r--r--openerp/addons/base/i18n/ro.po223
-rw-r--r--openerp/addons/base/i18n/ru.po4
-rw-r--r--openerp/addons/base/i18n/sk.po8
-rw-r--r--openerp/addons/base/i18n/sl.po4
-rw-r--r--openerp/addons/base/i18n/sq.po4
-rw-r--r--openerp/addons/base/i18n/sr.po4
-rw-r--r--openerp/addons/base/i18n/sr@latin.po4
-rw-r--r--openerp/addons/base/i18n/sv.po4
-rw-r--r--openerp/addons/base/i18n/th.po7
-rw-r--r--openerp/addons/base/i18n/tlh.po4
-rw-r--r--openerp/addons/base/i18n/tr.po4
-rw-r--r--openerp/addons/base/i18n/uk.po4
-rw-r--r--openerp/addons/base/i18n/ur.po4
-rw-r--r--openerp/addons/base/i18n/vi.po4
-rw-r--r--openerp/addons/base/i18n/zh_CN.po4
-rw-r--r--openerp/addons/base/i18n/zh_HK.po4
-rw-r--r--openerp/addons/base/i18n/zh_TW.po4
-rw-r--r--openerp/addons/base/ir/__init__.py1
-rw-r--r--openerp/addons/base/ir/ir_actions.py63
-rw-r--r--openerp/addons/base/ir/ir_actions.xml2
-rw-r--r--openerp/addons/base/ir/ir_attachment.py1
-rw-r--r--openerp/addons/base/ir/ir_fields.py11
-rw-r--r--openerp/addons/base/ir/ir_http.py59
-rw-r--r--openerp/addons/base/ir/ir_model.py90
-rw-r--r--openerp/addons/base/ir/ir_qweb.py850
-rw-r--r--openerp/addons/base/ir/ir_translation.py32
-rw-r--r--openerp/addons/base/ir/ir_translation_view.xml2
-rw-r--r--openerp/addons/base/ir/ir_ui_view.py823
-rw-r--r--openerp/addons/base/ir/ir_ui_view_view.xml9
-rw-r--r--openerp/addons/base/ir/ir_values.py15
-rw-r--r--openerp/addons/base/module/module.py7
-rw-r--r--openerp/addons/base/module/module_data.xml6
-rw-r--r--openerp/addons/base/res/res_company.py15
-rw-r--r--openerp/addons/base/res/res_company_view.xml44
-rw-r--r--openerp/addons/base/res/res_config.py26
-rw-r--r--openerp/addons/base/res/res_currency.py17
-rw-r--r--openerp/addons/base/res/res_lang.py43
-rw-r--r--openerp/addons/base/res/res_partner.py53
-rw-r--r--openerp/addons/base/res/res_partner_demo.xml174
-rw-r--r--openerp/addons/base/res/res_partner_demo.yml113
-rw-r--r--openerp/addons/base/res/res_partner_view.xml2
-rw-r--r--openerp/addons/base/res/res_users.py18
-rw-r--r--openerp/addons/base/res/res_users_view.xml2
-rw-r--r--openerp/addons/base/rng/view.rng1
-rw-r--r--openerp/addons/base/security/base_security.xml10
-rw-r--r--openerp/addons/base/security/ir.model.access.csv7
-rw-r--r--openerp/addons/base/static/img/public_user-image.pngbin0 -> 3193 bytes
-rw-r--r--openerp/addons/base/test/bug_lp541545.xml14
-rw-r--r--openerp/addons/base/test/test_context.xml20
-rw-r--r--openerp/addons/base/tests/__init__.py29
-rw-r--r--openerp/addons/base/tests/test_acl.py (renamed from openerp/tests/test_acl.py)6
-rw-r--r--openerp/addons/base/tests/test_base.py92
-rw-r--r--openerp/addons/base/tests/test_basecase.py (renamed from openerp/tests/test_basecase.py)2
-rw-r--r--openerp/addons/base/tests/test_db_cursor.py (renamed from openerp/tests/test_db_cursor.py)2
-rw-r--r--openerp/addons/base/tests/test_expression.py11
-rw-r--r--openerp/addons/base/tests/test_fields.py (renamed from openerp/tests/test_fields.py)63
-rw-r--r--openerp/addons/base/tests/test_func.py22
-rw-r--r--openerp/addons/base/tests/test_ir_actions.py3
-rw-r--r--openerp/addons/base/tests/test_ir_filters.py (renamed from openerp/tests/test_ir_filters.py)157
-rw-r--r--openerp/addons/base/tests/test_ir_sequence.py (renamed from openerp/tests/test_ir_sequence.py)2
-rw-r--r--[-rwxr-xr-x]openerp/addons/base/tests/test_mail.py (renamed from openerp/tests/test_mail.py)44
-rw-r--r--openerp/addons/base/tests/test_mail_examples.py (renamed from openerp/tests/test_mail_examples.py)148
-rw-r--r--openerp/addons/base/tests/test_misc.py (renamed from openerp/tests/test_misc.py)6
-rw-r--r--openerp/addons/base/tests/test_orm.py (renamed from openerp/tests/test_orm.py)21
-rw-r--r--openerp/addons/base/tests/test_osv.py (renamed from openerp/tests/test_osv.py)0
-rw-r--r--openerp/addons/base/tests/test_qweb.py80
-rw-r--r--openerp/addons/base/tests/test_translate.py (renamed from openerp/tests/test_translate.py)0
-rw-r--r--openerp/addons/base/tests/test_uninstall.py (renamed from openerp/tests/test_uninstall.py)8
-rw-r--r--openerp/addons/base/tests/test_view_validation.py (renamed from openerp/tests/test_view_validation.py)16
-rw-r--r--openerp/addons/base/tests/test_views.py553
-rw-r--r--openerp/addons/base/tests/test_xmlrpc.py33
-rw-r--r--openerp/addons/test_convert/__init__.py0
-rw-r--r--openerp/addons/test_convert/__openerp__.py5
-rw-r--r--openerp/addons/test_convert/test_file.txt1
-rw-r--r--openerp/addons/test_convert/tests/__init__.py6
-rw-r--r--openerp/addons/test_convert/tests/test_convert.py83
-rw-r--r--openerp/addons/test_converter/__init__.py2
-rw-r--r--openerp/addons/test_converter/__openerp__.py15
-rw-r--r--openerp/addons/test_converter/ir.model.access.csv4
-rw-r--r--openerp/addons/test_converter/models.py46
-rw-r--r--openerp/addons/test_converter/tests/__init__.py12
-rw-r--r--openerp/addons/test_converter/tests/test_html.py387
-rw-r--r--openerp/addons/test_converter/tests/test_vectors/imagebin0 -> 38067 bytes
-rw-r--r--openerp/addons/test_converter/tests/test_vectors/pdfbin0 -> 63391 bytes
-rw-r--r--openerp/addons/test_converter/tests/test_vectors/pptxbin0 -> 104835 bytes
-rw-r--r--openerp/addons/test_exceptions/__init__.py (renamed from openerp/tests/addons/test_exceptions/__init__.py)0
-rw-r--r--openerp/addons/test_exceptions/__openerp__.py (renamed from openerp/tests/addons/test_exceptions/__openerp__.py)0
-rw-r--r--openerp/addons/test_exceptions/ir.model.access.csv (renamed from openerp/tests/addons/test_exceptions/ir.model.access.csv)0
-rw-r--r--openerp/addons/test_exceptions/models.py (renamed from openerp/tests/addons/test_exceptions/models.py)0
-rw-r--r--openerp/addons/test_exceptions/view.xml (renamed from openerp/tests/addons/test_exceptions/view.xml)0
-rw-r--r--openerp/addons/test_impex/__init__.py (renamed from openerp/tests/addons/test_impex/__init__.py)0
-rw-r--r--openerp/addons/test_impex/__openerp__.py (renamed from openerp/tests/addons/test_impex/__openerp__.py)0
-rw-r--r--openerp/addons/test_impex/ir.model.access.csv (renamed from openerp/tests/addons/test_impex/ir.model.access.csv)0
-rw-r--r--openerp/addons/test_impex/models.py (renamed from openerp/tests/addons/test_impex/models.py)0
-rw-r--r--openerp/addons/test_impex/tests/__init__.py (renamed from openerp/tests/addons/test_impex/tests/__init__.py)0
-rw-r--r--openerp/addons/test_impex/tests/contacts.json (renamed from openerp/tests/addons/test_impex/tests/contacts.json)0
-rw-r--r--openerp/addons/test_impex/tests/contacts_big.json (renamed from openerp/tests/addons/test_impex/tests/contacts_big.json)0
-rw-r--r--openerp/addons/test_impex/tests/test_export.py (renamed from openerp/tests/addons/test_impex/tests/test_export.py)0
-rw-r--r--openerp/addons/test_impex/tests/test_import.py (renamed from openerp/tests/addons/test_impex/tests/test_import.py)0
-rw-r--r--openerp/addons/test_impex/tests/test_load.py (renamed from openerp/tests/addons/test_impex/tests/test_load.py)0
-rw-r--r--openerp/addons/test_limits/__init__.py (renamed from openerp/tests/addons/test_limits/__init__.py)0
-rw-r--r--openerp/addons/test_limits/__openerp__.py (renamed from openerp/tests/addons/test_limits/__openerp__.py)0
-rw-r--r--openerp/addons/test_limits/ir.model.access.csv (renamed from openerp/tests/addons/test_limits/ir.model.access.csv)0
-rw-r--r--openerp/addons/test_limits/models.py (renamed from openerp/tests/addons/test_limits/models.py)0
-rw-r--r--openerp/addons/test_uninstall/__init__.py (renamed from openerp/tests/addons/test_uninstall/__init__.py)0
-rw-r--r--openerp/addons/test_uninstall/__openerp__.py (renamed from openerp/tests/addons/test_uninstall/__openerp__.py)0
-rw-r--r--openerp/addons/test_uninstall/ir.model.access.csv (renamed from openerp/tests/addons/test_uninstall/ir.model.access.csv)0
-rw-r--r--openerp/addons/test_uninstall/models.py (renamed from openerp/tests/addons/test_uninstall/models.py)0
-rw-r--r--openerp/addons/test_workflow/__init__.py (renamed from openerp/tests/addons/test_workflow/__init__.py)0
-rw-r--r--openerp/addons/test_workflow/__openerp__.py (renamed from openerp/tests/addons/test_workflow/__openerp__.py)0
-rw-r--r--openerp/addons/test_workflow/data.xml (renamed from openerp/tests/addons/test_workflow/data.xml)0
-rw-r--r--openerp/addons/test_workflow/ir.model.access.csv (renamed from openerp/tests/addons/test_workflow/ir.model.access.csv)0
-rw-r--r--openerp/addons/test_workflow/models.py (renamed from openerp/tests/addons/test_workflow/models.py)0
-rw-r--r--openerp/addons/test_workflow/tests/__init__.py (renamed from openerp/tests/addons/test_workflow/tests/__init__.py)0
-rw-r--r--openerp/addons/test_workflow/tests/test_workflow.py (renamed from openerp/tests/addons/test_workflow/tests/test_workflow.py)0
-rw-r--r--openerp/cli/server.py50
-rw-r--r--openerp/http.py217
-rw-r--r--openerp/import_xml.rng28
-rw-r--r--openerp/modules/__init__.py12
-rw-r--r--openerp/modules/loading.py18
-rw-r--r--openerp/modules/module.py339
-rw-r--r--openerp/modules/registry.py47
-rw-r--r--openerp/osv/expression.py2
-rw-r--r--openerp/osv/fields.py68
-rw-r--r--openerp/osv/orm.py831
-rw-r--r--openerp/report/render/rml2pdf/trml2pdf.py2
-rw-r--r--openerp/report/report_sxw.py4
-rw-r--r--openerp/service/db.py4
-rw-r--r--openerp/service/model.py5
-rw-r--r--openerp/service/server.py153
-rw-r--r--openerp/sql_db.py30
-rw-r--r--openerp/tests/__init__.py49
-rw-r--r--openerp/tests/common.py225
-rw-r--r--openerp/tests/phantomtest.js145
-rw-r--r--openerp/tests/test_expression.py13
-rw-r--r--openerp/tests/test_xmlrpc.py82
-rw-r--r--openerp/tools/cache.py53
-rw-r--r--openerp/tools/config.py6
-rw-r--r--openerp/tools/convert.py45
-rw-r--r--openerp/tools/func.py15
-rw-r--r--openerp/tools/image.py11
-rw-r--r--openerp/tools/mail.py142
-rw-r--r--openerp/tools/misc.py103
-rw-r--r--openerp/tools/safe_eval.py57
-rw-r--r--openerp/tools/translate.py2
-rw-r--r--openerp/tools/view_validation.py7
-rw-r--r--openerp/tools/yaml_import.py13
-rw-r--r--openerp/workflow/instance.py2
-rw-r--r--openerpcommand/__init__.py3
-rw-r--r--openerpcommand/common.py8
-rw-r--r--openerpcommand/initialize.py54
-rw-r--r--openerpcommand/run_tests.py201
220 files changed, 7445 insertions, 3526 deletions
diff --git a/debian/control b/debian/control
index 74cd027427a..91ff36e34c9 100644
--- a/debian/control
+++ b/debian/control
@@ -16,6 +16,7 @@ Depends:
python,
postgresql-client,
python-dateutil,
+ python-decorator,
python-docutils,
python-feedparser,
python-gdata,
diff --git a/doc/03_module_dev_01.rst b/doc/03_module_dev_01.rst
index 0fbca9d14b4..f35dab539a4 100644
--- a/doc/03_module_dev_01.rst
+++ b/doc/03_module_dev_01.rst
@@ -172,40 +172,80 @@ is as follows:
</data>
</openerp>
-Record Tag
-//////////
+``<record>``
+////////////
-**Description**
+Defines a new record in a specified OpenERP model.
-The addition of new data is made with the record tag. This one takes a
-mandatory attribute : model. Model is the object name where the insertion has
-to be done. The tag record can also take an optional attribute: id. If this
-attribute is given, a variable of this name can be used later on, in the same
-file, to make reference to the newly created resource ID.
+``@model`` (required)
-A record tag may contain field tags. They indicate the record's fields value.
-If a field is not specified the default value will be used.
+ Name of the model in which this record will be created/inserted.
-The Record Field tag
-////////////////////
+``@id`` (optional)
-The attributes for the field tag are the following:
+ :term:`external ID` for the record, also allows referring to this record in
+ the rest of this file or in other files (through ``field/@ref`` or the
+ :py:func:`ref() <openerp.tools.convert._ref>` function)
-name : mandatory
- the field name
+A record tag generally contains multiple ``field`` tags specifying the values
+set on the record's fields when creating it. Fields left out will be set to
+their default value unless required.
+
+``<field>``
+///////////
+
+In its most basic use, the ``field`` tag will set its body (as a string) as
+the value of the corresponding ``record``'s ``@name`` field.
+
+Extra attributes can either preprocess the body or replace its use entirely:
+
+``@name`` (mandatory)
+
+ Name of the field in the containing ``record``'s model
+
+``@type`` (optional)
+
+ One of ``char``, ``int``, ``float``, ``list``, ``tuple``, ``xml`` or
+ ``html``, ``file`` or ``base64``. Converts the ``field``'s body to the
+ specified type (or validates the body's content)
+
+ * ``xml`` will join multiple XML nodes under a single ``<data>`` root
+ * in ``xml`` and ``html``, external ids can be referenced using
+ ``%(id_name)s``
+ * ``list`` and ``tuple``'s element are specified using ``<value>``
+ sub-nodes with the same attributes as ``field``.
+ * ``file`` expects a module-local path and will save the path prefixed with
+ the current module's name, separated by a ``,`` (comma). For use with
+ :py:func:`~openerp.modules.module.get_module_resource`.
+ * ``base64`` expects binary data, encodes it to base64 and sets it. Mostly
+ useful with ``@file``
+
+``@file``
+
+ Can be used with types ``char`` and ``base64``, sources the field's content
+ from the specified file instead of the field's text body.
+
+``@model``
+
+ Model used for ``@search``'s search, or registry object put in context for
+ ``@eval``. Required if ``@search`` but optional if ``@eval``.
+
+``@eval`` (optional)
+
+ A Python expression evaluated to obtain the value to set on the record
+
+``@ref`` (optional)
-eval : optional
- python expression that indicating the value to add
-
-ref
- reference to an id defined in this file
+ Links to an other record through its :term:`external id`. The module prefix
+ may be ommitted to link to a record defined in the same module.
-model
- model to be looked up in the search
+``@search`` (optional)
-search
- a query
+ Search domain (evaluated Python expression) into ``@model`` to get the
+ records to set on the field.
+ Sets all the matches found for m2m fields, the first id for other field
+ types.
**Example**
diff --git a/doc/06_ir_qweb.rst b/doc/06_ir_qweb.rst
new file mode 100644
index 00000000000..4f3284d913f
--- /dev/null
+++ b/doc/06_ir_qweb.rst
@@ -0,0 +1,98 @@
+.. _qweb:
+
+====
+QWeb
+====
+
+``t-field``
+===========
+
+The server version of qweb includes a directive dedicated specifically to
+formatting and rendering field values from
+:class:`~openerp.osv.orm.browse_record` objects.
+
+The directive is implemented through
+:meth:`~base.ir.ir_qweb.QWeb.render_tag_field` on the ``ir.qweb`` openerp
+object, and generally delegates to converters for rendering. These converters
+are obtained through :meth:`~base.ir.ir_qweb.QWeb.get_converter_for`.
+
+By default, the key for obtaining a converter is the type of the field's
+column, but this can be overridden by providing a ``widget`` as field option.
+
+Field options are specified through ``t-field-options``, which must be a JSON
+object (map). Custom widgets may define their own (possibly mandatory) options.
+
+Global options
+--------------
+
+A global option ``html-escape`` is provided. It defaults to ``True``, and for
+many (not all) fields it determines whether the field's output will be
+html-escaped before being output.
+
+Date and datetime converters
+----------------------------
+
+The default rendering for ``date`` and ``datetime`` fields. They render the
+field's value according to the current user's ``lang.date_format`` and
+``lang.time_format``. The ``datetime`` converter will also localize the value
+to the user's timezone (as defined by the ``tz`` context key, or the timezone
+in the user's profile if there is no ``tz`` key in the context).
+
+A custom format can be provided to use a non-default rendering. The custom
+format uses the ``format`` options key, and uses the
+`ldml date format patterns`_ [#ldml]_.
+
+For instance if one wanted a date field to be rendered as
+"(month) (day of month)" rather than whatever the default is, one could use:
+
+.. code-block:: xml
+
+ <span t-field="object.datefield" t-field-options='{"format": "MMMM d"}'/>
+
+Monetary converter (widget: ``monetary``)
+-----------------------------------------
+
+Used to format and render monetary value, requires a ``display_currency``
+options value which is a path from the rendering context to a ``res.currency``
+object. This object is used to set the right currency symbol, and set it at the
+right position relative to the formatted value.
+
+The field itself should be a float field.
+
+Relative Datetime (widget: ``relative``)
+----------------------------------------
+
+Used on a ``datetime`` field, formats it relatively to the current time
+(``datetime.now()``), e.g. if the field's value is 3 hours before now and the
+user's lang is english, it will render to *3 hours ago*.
+
+.. note:: this field uses babel's ``format_timedelta`` more or less directly
+ and will only display the biggest unit and round up at 85% e.g.
+ 1 hour 15 minutes will be rendered as *1 hour*, and 55 minutes will
+ also be rendered as *1 hour*.
+
+.. warning:: this converter *requires* babel 1.0 or more recent.
+
+Duration (widget: ``duration``)
+-------------------------------
+
+Renders a duration defined as a ``float`` to a human-readable localized string,
+e.g. ``1.5`` as hours in an english locale will be rendered to
+*1 hour 30 minutes*.
+
+Requires a ``unit`` option which may be one of ``second``, ``minute``,
+``hour``, ``day``, ``week``, ``month`` or ``year``. This specifies the unit in
+which the value should be interpreted before formatting.
+
+The duration must be a positive number, and no rounding is applied.
+
+.. [#ldml] in part because `babel`_ is used for rendering, as ``strftime``
+ would require altering the process's locale on the fly in order to
+ get correctly localized date and time output. Babel uses the CLDR
+ as its core and thus uses LDML date format patterns.
+
+.. _babel: http://babel.pocoo.org
+
+.. _ldml date format patterns:
+ http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
+
diff --git a/doc/06_misc.rst b/doc/06_misc.rst
index 5a4ae7e008a..d56b26fb018 100644
--- a/doc/06_misc.rst
+++ b/doc/06_misc.rst
@@ -11,3 +11,4 @@ Miscellanous
06_misc_user_img_specs.rst
06_misc_import.rst
06_misc_auto_join.rst
+ 06_ir_qweb.rst
diff --git a/doc/conf.py b/doc/conf.py
index 57edef310c9..19f2c9b727f 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -252,5 +252,4 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'python': ('http://docs.python.org/', None),
- 'openerpweb': ('http://doc.openerp.com/trunk/developers/web', None),
}
diff --git a/doc/ir_actions.rst b/doc/ir_actions.rst
index 31d22a7ead9..e54df3ce377 100644
--- a/doc/ir_actions.rst
+++ b/doc/ir_actions.rst
@@ -12,26 +12,20 @@ Server actions
.. currentmodule:: openerp.addons.base.ir.ir_actions
-.. autoclass:: actions_server
- :noindex:
+.. autoclass:: ir_actions_server
+ :members: run, _get_states
Adding a new sever action
-------------------------
The ``state`` field holds the various available types of server action. In order
-to add a new server action, the first thing to do is to override the ``_get_states``
+to add a new server action, the first thing to do is to override the :meth:`~.ir_actions_server._get_states`
method that returns the list of values available for the selection field.
-.. automethod:: actions_server._get_states
- :noindex:
-
-The method called when executing the server action is the ``run`` method. This
+The method called when executing the server action is the :meth:`~.ir_actions_server.run` method. This
method calls ``run_action_<STATE>``. When adding a new server action type, you
have to define the related method that will be called upon execution.
-.. automethod:: actions_server.run
- :noindex:
-
Changelog
---------
diff --git a/oe b/oe
index 59827731409..2da32cbe31d 100755
--- a/oe
+++ b/oe
@@ -1,5 +1,8 @@
#! /usr/bin/env python2
if __name__ == '__main__':
+ import sys
+ if sys.argv[1] == 'run-tests':
+ sys.exit(0)
import openerpcommand.main
openerpcommand.main.run()
diff --git a/openerp/__init__.py b/openerp/__init__.py
index a06c85d0c21..995822c9cb0 100644
--- a/openerp/__init__.py
+++ b/openerp/__init__.py
@@ -19,17 +19,27 @@
#
##############################################################################
-""" OpenERP core library..
-
-"""
-
-import sys
+""" OpenERP core library."""
+#----------------------------------------------------------
+# Running mode flags (gevent, prefork)
+#----------------------------------------------------------
# Is the server running with gevent.
+import sys
evented = False
if sys.modules.get("gevent") is not None:
evented = True
+# Is the server running in pefork mode (e.g. behind Gunicorn).
+# If this is True, the processes have to communicate some events,
+# e.g. database update or cache invalidation. Each process has also
+# its own copy of the data structure and we don't need to care about
+# locks between threads.
+multi_process = False
+
+#----------------------------------------------------------
+# libc UTC hack
+#----------------------------------------------------------
# Make sure the OpenERP server runs in UTC. This is especially necessary
# under Windows as under Linux it seems the real import of time is
# sufficiently deferred so that setting the TZ environment variable
@@ -40,9 +50,22 @@ import time # ... *then* import time.
del os
del time
+#----------------------------------------------------------
+# Shortcuts
+#----------------------------------------------------------
# The hard-coded super-user id (a.k.a. administrator, or root user).
SUPERUSER_ID = 1
+def registry(database_name):
+ """
+ Return the model registry for the given database. If the registry does not
+ exist yet, it is created on the fly.
+ """
+ return modules.registry.RegistryManager.get(database_name)
+
+#----------------------------------------------------------
+# Imports
+#----------------------------------------------------------
import addons
import cli
import conf
@@ -58,23 +81,6 @@ import service
import sql_db
import tools
import workflow
-# backward compatilbility
-# TODO: This is for the web addons, can be removed later.
-wsgi = service
-wsgi.register_wsgi_handler = wsgi.wsgi_server.register_wsgi_handler
-# Is the server running in multi-process mode (e.g. behind Gunicorn).
-# If this is True, the processes have to communicate some events,
-# e.g. database update or cache invalidation. Each process has also
-# its own copy of the data structure and we don't need to care about
-# locks between threads.
-multi_process = False
-
-def registry(database_name):
- """
- Return the model registry for the given database. If the registry does not
- exist yet, it is created on the fly.
- """
- return modules.registry.RegistryManager.get(database_name)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/__init__.py b/openerp/addons/__init__.py
index 9554e9bd850..e040e19defd 100644
--- a/openerp/addons/__init__.py
+++ b/openerp/addons/__init__.py
@@ -34,7 +34,4 @@ Importing them from here is deprecated.
"""
-# get_module_path is used only by base_module_quality
-from openerp.modules import get_module_resource, get_module_path
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/base/__init__.py b/openerp/addons/base/__init__.py
index a5bc4c59484..26b39de74ad 100644
--- a/openerp/addons/base/__init__.py
+++ b/openerp/addons/base/__init__.py
@@ -25,6 +25,7 @@ import module
import res
import report
import test
+import tests
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py
index 808dd18d3e5..3c3c290f986 100644
--- a/openerp/addons/base/__openerp__.py
+++ b/openerp/addons/base/__openerp__.py
@@ -92,8 +92,6 @@ The kernel of OpenERP, needed for all installation.
],
'test': [
'test/base_test.yml',
- 'test/test_context.xml',
- 'test/bug_lp541545.xml',
'test/test_osv_expression.yml',
'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules.
],
diff --git a/openerp/addons/base/base.sql b/openerp/addons/base/base.sql
index 1187f027bde..b59ef8fedc9 100644
--- a/openerp/addons/base/base.sql
+++ b/openerp/addons/base/base.sql
@@ -112,18 +112,6 @@ CREATE TABLE ir_act_client (
)
INHERITS (ir_actions);
-
-CREATE TABLE ir_ui_view (
- id serial NOT NULL,
- name varchar(64) DEFAULT ''::varchar NOT NULL,
- model varchar(64) DEFAULT ''::varchar NOT NULL,
- "type" varchar(64) DEFAULT 'form'::varchar NOT NULL,
- arch text NOT NULL,
- field_parent varchar(64),
- priority integer DEFAULT 5 NOT NULL,
- primary key(id)
-);
-
CREATE TABLE ir_ui_menu (
id serial NOT NULL,
parent_id int references ir_ui_menu on delete set null,
@@ -409,4 +397,4 @@ insert into ir_model_data (name,module,model,noupdate,res_id) VALUES ('main_comp
select setval('res_company_id_seq', 2);
select setval('res_users_id_seq', 2);
select setval('res_partner_id_seq', 2);
-select setval('res_currency_id_seq', 2); \ No newline at end of file
+select setval('res_currency_id_seq', 2);
diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml
index bd38f3a3db5..b6c12e111ff 100644
--- a/openerp/addons/base/base_data.xml
+++ b/openerp/addons/base/base_data.xml
@@ -91,6 +91,25 @@ Administrator</field>
<field eval="10" name="sequence"/>
</record>
+ <!--
+ A group dedicated to the portal users, making groups
+ restrictions more convenient.
+ -->
+ <record id="group_portal" model="res.groups">
+ <field name="name">Portal</field>
+ <field name="comment">Portal members have specific access rights (such as record rules and restricted menus).
+ They usually do not belong to the usual OpenERP groups.</field>
+ </record>
+ <!--
+ A group dedicated to the public user only, making groups
+ restrictions more convenient.
+ -->
+ <record id="group_public" model="res.groups">
+ <field name="name">Public</field>
+ <field name="comment">Public users have specific access rights (such as record rules and restricted menus).
+ They usually do not belong to the usual OpenERP groups.</field>
+ </record>
+
<!-- Basic fonts family included in PDF standart, will always be in the font list -->
<record model="res.font" id="base.font_helvetica">
<field name="name">Helvetica</field>
@@ -111,5 +130,21 @@ Administrator</field>
<field name="mode">all</field>
</record>
+ <record id="public_partner" model="res.partner">
+ <field name="name">Public user</field>
+ <field name="active" eval="False"/>
+ </record>
+
+ <record id="public_user" model="res.users">
+ <field name="name">Public user</field>
+ <field name="login">public</field>
+ <field name="password"></field>
+ <!-- Avoid auto-including this demo user in any default group -->
+ <field name="groups_id" eval="[(6,0,[ref('base.group_public')])]"/>
+ <field name="image" type="base64" file="base/static/img/public_user-image.png"/>
+ <field name="partner_id" ref="public_partner"/>
+ <field name="active" eval="False"/>
+ </record>
+
</data>
</openerp>
diff --git a/openerp/addons/base/base_demo.xml b/openerp/addons/base/base_demo.xml
index 7f44a911a90..9258dcf3553 100644
--- a/openerp/addons/base/base_demo.xml
+++ b/openerp/addons/base/base_demo.xml
@@ -1,17 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
+
<record id="partner_demo" model="res.partner">
<field name="name">Demo User</field>
<field name="company_id" ref="main_company"/>
<field name="customer" eval="False"/>
- <field name="email">demo@example.com</field>
+ <field name="email">demo@yourcompany.example.com</field>
+ <field name="street">Avenue des Dessus-de-Lives, 2</field>
+ <field name="city">Namur (Loyers)</field>
+ <field name="zip">5101</field>
+ <field name="country_id" ref="be"/>
</record>
<record id="main_partner" model="res.partner">
+ <field name="name">YourCompany</field>
+ <field name="street">1725 Slough Ave.</field>
+ <field name="city">Scranton</field>
+ <field name="zip">18540</field>
+ <field name="phone">+1 555 123 8069</field>
+ <field name="email">info@yourcompany.example.com</field>
+ <field name="website">www.example.com</field>
<field name="image" type="base64" file="base/static/img/main_partner-image.png"/>
</record>
+ <record id="main_company" model="res.company">
+ <field name="name">YourCompany</field>
+ </record>
+
+
<record id="user_demo" model="res.users">
<field name="partner_id" ref="base.partner_demo"/>
<field name="login">demo</field>
@@ -24,7 +41,7 @@ Mr Demo</field>
</record>
<record model="res.partner" id="base.partner_root">
- <field name="email">admin@example.com</field>
+ <field name="email">admin@yourcompany.example.com</field>
<field name="tz">Europe/Brussels</field>
<field name="image" type="base64" file="base/static/img/partner_root-image.jpg"/>
</record>
diff --git a/openerp/addons/base/i18n/ab.po b/openerp/addons/base/i18n/ab.po
index a96d2777f63..1ba79c773ab 100644
--- a/openerp/addons/base/i18n/ab.po
+++ b/openerp/addons/base/i18n/ab.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:15+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:21+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/af.po b/openerp/addons/base/i18n/af.po
index c290744207c..bd878c88ab3 100644
--- a/openerp/addons/base/i18n/af.po
+++ b/openerp/addons/base/i18n/af.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:15+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:22+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -60,12 +60,12 @@ msgstr "Kyk na argitektuur"
#. module: base
#: model:ir.module.module,summary:base.module_sale_stock
msgid "Quotation, Sale Orders, Delivery & Invoicing Control"
-msgstr ""
+msgstr "Kwotasie, Bestellins, Aflewerings en Faktuur beheer."
#. module: base
#: selection:ir.sequence,implementation:0
msgid "No gap"
-msgstr ""
+msgstr "Geep Spasie"
#. module: base
#: selection:base.language.install,lang:0
@@ -89,23 +89,24 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_point_of_sale
msgid "Touchscreen Interface for Shops"
-msgstr ""
+msgstr "Tasskerm koppelvlak vir Winkels"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
msgid "Indian Payroll"
-msgstr ""
+msgstr "Indiese Betaalstaat"
#. module: base
#: help:ir.cron,model:0
msgid ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
msgstr ""
+"Model naam waarin die metode wat geroep word verskyn, bv. \"res.partner\"."
#. module: base
#: view:ir.module.module:0
msgid "Created Views"
-msgstr ""
+msgstr "Geskepte Afbeelding"
#. module: base
#: model:ir.module.module,description:base.module_product_manufacturer
@@ -122,11 +123,24 @@ msgid ""
" * Product Attributes\n"
" "
msgstr ""
+"\n"
+"'n Module wat die vervaardegiers en eienskappe van die produk op die vorm "
+"byvoeg.\n"
+"===================================================================\n"
+"\n"
+"Jy behoort nu die volgende vir produkte te kan definieer:\n"
+"-----------------------------------------------------------------------------"
+"--\n"
+" * Vervaardiger\n"
+" * Vervaardiger Produk Naame\n"
+" * Vervaardiger Produk Kode\n"
+" * Produk Eienskappe\n"
+" "
#. module: base
#: field:ir.actions.client,params:0
msgid "Supplementary arguments"
-msgstr ""
+msgstr "Aanvullende argumente"
#. module: base
#: model:ir.module.module,description:base.module_google_base_account
@@ -135,11 +149,14 @@ msgid ""
"The module adds google user in res user.\n"
"========================================\n"
msgstr ""
+"\n"
+"Hierdie module voeg google user bu res.user.\n"
+"=====================================\n"
#. module: base
#: help:res.partner,employee:0
msgid "Check this box if this contact is an Employee."
-msgstr ""
+msgstr "Selekteer hierdie block as die kontak 'n Verknemer is."
#. module: base
#: help:ir.model.fields,domain:0
diff --git a/openerp/addons/base/i18n/am.po b/openerp/addons/base/i18n/am.po
index e2bcf465d33..4ace71b27a2 100644
--- a/openerp/addons/base/i18n/am.po
+++ b/openerp/addons/base/i18n/am.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:15+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:22+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -366,7 +366,7 @@ msgstr "አክቲቭ"
#. module: base
#: field:ir.actions.wizard,wiz_name:0
msgid "Wizard Name"
-msgstr "የዊዘርዱ ስም"
+msgstr ""
#. module: base
#: model:ir.module.module,description:base.module_knowledge
@@ -481,7 +481,7 @@ msgstr ""
msgid ""
"One of the records you are trying to modify has already been deleted "
"(Document type: %s)."
-msgstr "ለማሻሻል የሞከሩት ሰነድ ከዚህ በፊት የተሰረዘ ሆኖ ተገኝትዋል (የሰነዱ አይነት፡ %s)።"
+msgstr ""
#. module: base
#: help:ir.actions.act_window,views:0
diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po
index 48732c56d2b..f2b1d19a845 100644
--- a/openerp/addons/base/i18n/ar.po
+++ b/openerp/addons/base/i18n/ar.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:15+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:22+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/bg.po b/openerp/addons/base/i18n/bg.po
index 2c86fc15a6e..fb924a71ee6 100644
--- a/openerp/addons/base/i18n/bg.po
+++ b/openerp/addons/base/i18n/bg.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:16+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:23+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/bn.po b/openerp/addons/base/i18n/bn.po
index 19ee34efa00..dcf88ca7472 100644
--- a/openerp/addons/base/i18n/bn.po
+++ b/openerp/addons/base/i18n/bn.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-16 05:17+0000\n"
-"X-Generator: Launchpad (build 16901)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:23+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/bs.po b/openerp/addons/base/i18n/bs.po
index fcccf7deeb2..8bed1953e5e 100644
--- a/openerp/addons/base/i18n/bs.po
+++ b/openerp/addons/base/i18n/bs.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:16+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:23+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/ca.po b/openerp/addons/base/i18n/ca.po
index f58ffe6d688..f2ebada45af 100644
--- a/openerp/addons/base/i18n/ca.po
+++ b/openerp/addons/base/i18n/ca.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:16+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:23+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/cs.po b/openerp/addons/base/i18n/cs.po
index cae0bd5db27..b5287f5e5cf 100644
--- a/openerp/addons/base/i18n/cs.po
+++ b/openerp/addons/base/i18n/cs.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-06 04:39+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:24+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
"X-Poedit-Language: Czech\n"
#. module: base
@@ -38,7 +38,7 @@ msgstr "Svatá Helena"
#. module: base
#: view:ir.actions.report.xml:0
msgid "Other Configuration"
-msgstr "Další nastavení"
+msgstr "Ostatní nastavení"
#. module: base
#: selection:ir.property,type:0
@@ -69,7 +69,7 @@ msgstr "Nabídky, zakázky, řízení dopravy a fakturace"
#. module: base
#: selection:ir.sequence,implementation:0
msgid "No gap"
-msgstr "Bez mezer"
+msgstr "Bez mezery"
#. module: base
#: selection:base.language.install,lang:0
@@ -9335,7 +9335,7 @@ msgstr "Stránka dokumentu"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_ar
msgid "Argentina Localization Chart Account"
-msgstr ""
+msgstr "Argentinská účtová osnova"
#. module: base
#: field:ir.module.module,description_html:0
@@ -10393,6 +10393,10 @@ msgid ""
"=========================\n"
"\n"
msgstr ""
+"\n"
+"Zobrazení Openerp Web Diagramu.\n"
+"=========================\n"
+"\n"
#. module: base
#: model:ir.module.module,description:base.module_l10n_ch
diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po
index 93f9be42a2b..c6896676db7 100644
--- a/openerp/addons/base/i18n/da.po
+++ b/openerp/addons/base/i18n/da.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:24+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/de.po b/openerp/addons/base/i18n/de.po
index 8695d79921e..b7edb6538d3 100644
--- a/openerp/addons/base/i18n/de.po
+++ b/openerp/addons/base/i18n/de.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:26+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -74,12 +74,12 @@ msgstr "Lückenlos"
#. module: base
#: selection:base.language.install,lang:0
msgid "Hungarian / Magyar"
-msgstr "Hungarian / Magyar"
+msgstr "Ungarisch / Magyar"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (PY) / Español (PY)"
-msgstr "Spanish (PY) / Español (PY)"
+msgstr "Spanisch (PY) / Español (PY)"
#. module: base
#: model:ir.module.category,description:base.module_category_project_management
@@ -92,7 +92,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_point_of_sale
msgid "Touchscreen Interface for Shops"
-msgstr "Touchscreen Oberfläche für Shops"
+msgstr "Touchscreen-Oberfläche für Shops"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
@@ -191,7 +191,7 @@ msgstr "Zielzeitraum"
#. module: base
#: field:ir.actions.report.xml,report_rml:0
msgid "Main Report File Path"
-msgstr "Hauptreport Datei Pfad"
+msgstr "Hauptreport Dateipfad"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_analytic_plans
@@ -216,10 +216,10 @@ msgstr ""
"Erzeugen Sie Rechnungen auf Basis von Spesen und Zeiterfassungseinträgen.\n"
"========================================================\n"
"\n"
-"Modul zur Erzeugung von Rechnung auf Basis von Personalkosten "
+"Modul zur Erzeugung von Rechnungen auf Basis von Personalkosten "
"(Zeiterfassungseinträge, Spesen, ...).\n"
"\n"
-"Sie können Preislisten für eine Kostestelle definieren und Auswertungen "
+"Sie können Preislisten für eine Kostenstelle definieren und Auswertungen "
"erzeugen."
#. module: base
@@ -288,7 +288,7 @@ msgstr "Schrittweise Erhöhung"
#: model:ir.actions.act_window,name:base.action_res_company_tree
#: model:ir.ui.menu,name:base.menu_action_res_company_tree
msgid "Company's Structure"
-msgstr "Struktur des Betriebs"
+msgstr "Unternehmensstruktur"
#. module: base
#: selection:base.language.install,lang:0
@@ -298,7 +298,7 @@ msgstr "Inuktitut / ᐃᓄᒃᑎᑐᑦ"
#. module: base
#: model:res.groups,name:base.group_multi_currency
msgid "Multi Currencies"
-msgstr "Mehrwährung"
+msgstr "Mehrere Währungen"
#. module: base
#: model:ir.module.module,description:base.module_l10n_cl
@@ -320,7 +320,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale
msgid "Sales Management"
-msgstr "Verkaufs Management"
+msgstr "Verkaufsmanagement"
#. module: base
#: help:res.partner,user_id:0
@@ -329,7 +329,7 @@ msgid ""
"any."
msgstr ""
"Der interne Benutzer, der verantwortlich für die Kommunikation mit dem "
-"Kontakt verantwortlich ist (falls gewählt)."
+"Kontakt ist (falls gewählt)."
#. module: base
#: view:res.partner:0
@@ -357,7 +357,7 @@ msgid ""
"Database ID of record to open in form view, when ``view_mode`` is set to "
"'form' only"
msgstr ""
-"Datenbank ID des Datensatzes des Form Views, wenn als Ansichtsmodus nur "
+"Datenbank ID des Datensatzes des Formularansicht, wenn als Ansichtsmodus nur "
"'Form' gewählt wurde"
#. module: base
@@ -375,7 +375,7 @@ msgstr ""
" -client_print_multi\n"
" -client_action_relate\n"
" -tree_but_open\n"
-"Bei Vorgabefeldern eine wahlfreie Einstellung"
+"Bei Vorgabefeldern eine optionale Einstellung"
#. module: base
#: sql_constraint:res.lang:0
@@ -385,12 +385,12 @@ msgstr "Der Name der Sprache muss eindeutig sein!"
#. module: base
#: selection:res.request,state:0
msgid "active"
-msgstr "Aktiv"
+msgstr "aktiv"
#. module: base
#: field:ir.actions.wizard,wiz_name:0
msgid "Wizard Name"
-msgstr "Assistent Name"
+msgstr "Name für Assistent"
#. module: base
#: model:ir.module.module,description:base.module_knowledge
@@ -408,7 +408,7 @@ msgstr ""
"Installer für den administrativen Zugriff der Knowledge Base.\n"
"=====================================\n"
"\n"
-"Ermöglicht den Zugriff auf die Konfiguration der Knowledge Base, so das der "
+"Ermöglicht den Zugriff auf die Konfiguration der Knowledge Base, so dass der "
"Benutzer\n"
"das Dokumentenmanagement und das Wiki installieren kann.\n"
" "
@@ -416,7 +416,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_customer_relationship_management
msgid "Customer Relationship Management"
-msgstr "CRM Management"
+msgstr "Customer Relationship Management"
#. module: base
#: model:ir.module.module,description:base.module_delivery
@@ -458,7 +458,7 @@ msgstr "Fehler bei group_by Argument"
#. module: base
#: field:ir.module.category,child_ids:0
msgid "Child Applications"
-msgstr "abhängige Anwendungen"
+msgstr "Abhängige Anwendungen"
#. module: base
#: field:res.partner,credit_limit:0
@@ -470,7 +470,7 @@ msgstr "Kreditlinie"
#: field:ir.model.data,date_update:0
#: field:ir.model.relation,date_update:0
msgid "Update Date"
-msgstr "Datum Update"
+msgstr "Update des Datums"
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_action_rule
@@ -559,7 +559,7 @@ msgstr "Tuvalu"
#. module: base
#: field:ir.actions.configuration.wizard,note:0
msgid "Next Wizard"
-msgstr "Weiter Wizard"
+msgstr "Nächster Assistent"
#. module: base
#: field:res.lang,date_format:0
@@ -583,8 +583,8 @@ msgid ""
"You can not remove the admin user as it is used internally for resources "
"created by OpenERP (updates, module installation, ...)"
msgstr ""
-"Sie können den admin User nicht entfernen, da er intern für openERP "
-"Ressourcen benötigt wird (updates, module Installation etc.)"
+"Sie können den Admin User nicht entfernen, da er intern für openERP "
+"Ressourcen benötigt wird (Updates, Modulinstallation etc.)"
#. module: base
#: view:workflow.transition:0
@@ -599,7 +599,7 @@ msgstr "Französich Guyana"
#. module: base
#: model:ir.module.module,summary:base.module_hr
msgid "Jobs, Departments, Employees Details"
-msgstr "Stellen-, Abteilungs-, Mitabeiterdetails"
+msgstr "Stellen-, Abteilungs-, Mitarbeiterdetails"
#. module: base
#: model:ir.module.module,description:base.module_analytic
@@ -616,10 +616,10 @@ msgid ""
" "
msgstr ""
"\n"
-"Modul zur Bereitstellung der Analytischen Konten.\n"
+"Modul zur Bereitstellung der analytischen Konten.\n"
" ===============================================\n"
"\n"
-"In OpenERP werden Analytische Konten mit Konten des Hauptbuches verknüpft\n"
+"In OpenERP werden analytische Konten mit Konten des Hauptbuches verknüpft\n"
"jedoch komplett unabhängig verarbeitet. Daher können Sie diverse "
"analytische\n"
"Auswertungen und Prozesse anlegen ohne das diese Einfluss auf Ihre "
@@ -653,8 +653,8 @@ msgstr ""
"Organisation und Verwaltung von Events.\n"
"======================================\n"
"\n"
-"Das Event Modul ermöglicht Ihnen die effiziente Organisation Ihrer Events "
-"und der zugehörigen Aufgaben:\n"
+"Das Eventmodul ermöglicht Ihnen die effiziente Organisation Ihrer Events und "
+"der zugehörigen Aufgaben:\n"
"Planung, Verfolgung der Registrierungen, Anwesenheit, usw.\n"
"\n"
"Kernfunktionen\n"
@@ -717,7 +717,7 @@ msgstr ""
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (VE) / Español (VE)"
-msgstr "Spanish (VE) / Español (VE)"
+msgstr "Spanisch (VE) / Español (VE)"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_timesheet_invoice
@@ -784,7 +784,7 @@ msgstr "Postausgangsserver"
#: help:ir.actions.client,context:0
msgid ""
"Context dictionary as Python expression, empty by default (Default: {})"
-msgstr "Kontext Verzeichnis eines Python Ausdruckes (Standard: {} )"
+msgstr "Kontextverzeichnis eines Pythonausdruckes (Standard: {} )"
#. module: base
#: field:res.company,logo_web:0
@@ -858,7 +858,7 @@ msgstr ""
" * Finanzbuchhaltung\n"
" * Kostenrechnung\n"
" * Debitoren- und Kreditorenbuchhaltung\n"
-" * Steuern Verwaltung\n"
+" * Steuerabwicklung\n"
" * Budgets\n"
" * Kunden- und Lieferantenrechnungen\n"
" * Kontoauszüge\n"
@@ -897,7 +897,7 @@ msgstr ""
"Menü für Marketing.\n"
"====================\n"
"\n"
-"Enthält einen Installations-Assistenten für auf Marketing bezogene Module.\n"
+"Enthält einen Installations-Assistenten für auf Marketing relevante Module.\n"
" "
#. module: base
@@ -910,7 +910,7 @@ msgid ""
" "
msgstr ""
"\n"
-"OpenERP LinkeIn Modul.\n"
+"OpenERP LinkedIn Modul.\n"
"============================\n"
"\n"
"Diese Modul stellt die Integration von LinkedIn in OpenERP bereit.\n"
@@ -980,9 +980,9 @@ msgid ""
"image, with aspect ratio preserved. Use this field anywhere a small image is "
"required."
msgstr ""
-"Miniaturbild des Kontaktes. Es wird automatisch auf 64x64px "
-"heruntergerechnet unter Beibehaltung der Seitenverhältnisse. Benutzen Sie "
-"dieses Feld überall, wo ein Miniaturbild benötigt wird."
+"Miniaturbild des Kontakts. Es wird automatisch auf 64x64px heruntergerechnet "
+"unter Beibehaltung der Seitenverhältnisse. Benutzen Sie dieses Feld überall, "
+"wo ein Miniaturbild benötigt wird."
#. module: base
#: help:ir.actions.server,mobile:0
@@ -991,24 +991,24 @@ msgid ""
"invoice, then `object.invoice_address_id.mobile` is the field which gives "
"the correct mobile number"
msgstr ""
-"Stellt das Feld für die Mobiltelefon Nummer zur Verfügung. z.B. für "
+"Stellt das Feld für die Mobiltelefonnummer zur Verfügung. Z.B. für "
"Rechnungen (invoice) wird das Feld `object.invoice_address_id.mobile` die "
"richtige Mobiltelefonnummer anzeigen."
#. module: base
#: view:ir.mail_server:0
msgid "Security and Authentication"
-msgstr "Sicherheit und Berechtigungen"
+msgstr "Sicherheit und Authentifizierung"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_calendar
msgid "Web Calendar"
-msgstr "Web Kalender"
+msgstr "Webkalender"
#. module: base
#: selection:base.language.install,lang:0
msgid "Swedish / svenska"
-msgstr "Swedish / svenska"
+msgstr "Schwedisch / svenska"
#. module: base
#: field:base.language.export,name:0
@@ -1024,7 +1024,7 @@ msgstr "Serbien"
#. module: base
#: selection:ir.translation,type:0
msgid "Wizard View"
-msgstr "Assistent Ansicht"
+msgstr "Assistentansicht"
#. module: base
#: model:res.country,name:base.kh
@@ -1094,7 +1094,7 @@ msgstr ""
#. module: base
#: selection:base.language.install,lang:0
msgid "Albanian / Shqip"
-msgstr "Albanian / Shqip"
+msgstr "Albanisch / Shqip"
#. module: base
#: model:ir.ui.menu,name:base.menu_crm_config_opportunity
@@ -1114,7 +1114,8 @@ msgstr "Papua Neu-Guinea"
#. module: base
#: help:ir.actions.report.xml,report_type:0
msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..."
-msgstr "Report Typ, zB. pdf, html, raw, sxw, odt, html2html, mako2html, ..."
+msgstr ""
+"Reportformat, z.B. pdf, html, raw, sxw, odt, html2html, mako2html, ..."
#. module: base
#: model:ir.module.module,shortdesc:base.module_document_webdav
@@ -1124,7 +1125,7 @@ msgstr "Gemeinsame Verzeichnisse (WebDav)"
#. module: base
#: view:res.users:0
msgid "Email Preferences"
-msgstr "E-Mail Einstellungen"
+msgstr "E-Mail-Einstellungen"
#. module: base
#: code:addons/base/ir/ir_fields.py:195
@@ -1163,17 +1164,17 @@ msgstr "Spanien"
#: help:ir.actions.act_window,domain:0
msgid ""
"Optional domain filtering of the destination data, as a Python expression"
-msgstr "Optionaler Domain Filter - als Python Ausdruck"
+msgstr "Optionaler Domainfilter - als Python Ausdruck"
#. module: base
#: model:ir.model,name:base.model_base_module_upgrade
msgid "Module Upgrade"
-msgstr "Modul Aktualisierung"
+msgstr "Modulaktualisierung"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (UY) / Español (UY)"
-msgstr "Spanish (UY) / Español (UY)"
+msgstr "Spanisch (UY) / Español (UY)"
#. module: base
#: field:res.partner,mobile:0
@@ -1205,7 +1206,7 @@ msgstr ""
"Dieses Modul verwaltet die Anwesenheitszeiten von Mitarbeitern.\n"
"=========================================================\n"
"\n"
-"Führt Konten über die Anwesenheiten der Mitarbeiter aus Basis von Aktionen \n"
+"Führt Konten über die Anwesenheiten der Mitarbeiter auf Basis von Aktionen \n"
"(An- und Abmeldung) durch diese.\n"
" "
@@ -1217,7 +1218,7 @@ msgstr "Niue"
#. module: base
#: model:ir.module.module,shortdesc:base.module_membership
msgid "Membership Management"
-msgstr "Mitgliederverwaltung"
+msgstr "Mitgliedsverwaltung"
#. module: base
#: selection:ir.module.module,license:0
@@ -1227,7 +1228,7 @@ msgstr "Andere OSI genehmigten Lizenzen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_gantt
msgid "Web Gantt"
-msgstr "Gantt"
+msgstr "Web Gantt"
#. module: base
#: model:ir.actions.act_window,name:base.act_menu_create
@@ -1244,7 +1245,7 @@ msgstr "Indien"
#: model:ir.actions.act_window,name:base.res_request_link-act
#: model:ir.ui.menu,name:base.menu_res_request_link_act
msgid "Request Reference Types"
-msgstr "Anfrage Bezug Typen"
+msgstr "Anfrage Bezugstypen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_google_base_account
@@ -1254,7 +1255,7 @@ msgstr "Google-Benutzer"
#. module: base
#: model:ir.module.module,shortdesc:base.module_fleet
msgid "Fleet Management"
-msgstr "Fuhrpark Verwaltung"
+msgstr "Fuhrparkverwaltung"
#. module: base
#: help:ir.server.object.lines,value:0
@@ -1318,11 +1319,11 @@ msgid ""
"* Opportunities by Stage (graph)\n"
msgstr ""
"\n"
-"Das allgemeine OpenERP Customer Relationship Management\n"
+"Das allgemeine OpenERP \"Customer Relationship Management\"\n"
"====================================================\n"
"\n"
-"Diese Anwendung ermöglicht intelligent und effizient Interessenten, Chancen, "
-"Termine und Telefonate zu verwalten.\n"
+"Diese Anwendung ermöglicht, intelligent und effizient Interessenten, "
+"Chancen, Termine und Telefonate zu verwalten.\n"
"\n"
"Abgebildet werden Aufgaben wie Kommunikation, Identifikation, Priorisierung, "
"Übertragung, Beendigung und Benachrichtigung von Verkaufschancen.\n"
@@ -1330,7 +1331,7 @@ msgstr ""
"OpenERP sorgt dafür, dass alle Vorgänge durch Anwender, Kunden und "
"Lieferanten verfolgt werden können. Es können automatisch Erinnerungen "
"gesendet werden, sowie weitere Spezifikationen vorgenommen werden, um "
-"spezifische Massnahmen auszulösen oder bezüglich bestimmter definierter "
+"spezifische Maßnahmen auszulösen oder bezüglich bestimmter definierter "
"Ablaufregeln zu verfolgen. Das Beste ist, dass die Nutzer hierzu nichts "
"besonderes tun müssen. Das CRM-Modul verfügt über einen E-Mail-Ausgang für "
"die Synchronisation zwischen E-Mails und OpenERP. Auf diese Weise können die "
@@ -1343,22 +1344,22 @@ msgstr ""
#. module: base
#: selection:base.language.export,format:0
msgid "TGZ Archive"
-msgstr "TGZ Archive"
+msgstr "TGZ Archiv"
#. module: base
#: view:res.groups:0
msgid ""
"Users added to this group are automatically added in the following groups."
msgstr ""
-"Benutzer die zu dieser Gruppe hinzugefügt werden, werden auch zu den "
-"folgenden Gruppen hinzugefügt"
+"Benutzer, die zu dieser Gruppe hinzugefügt werden, werden auch zu den "
+"folgenden Gruppen hinzugefügt."
#. module: base
#: code:addons/base/ir/ir_model.py:732
#: code:addons/base/ir/ir_model.py:735
#, python-format
msgid "Document model"
-msgstr "Dokumenten Model"
+msgstr "Dokumentenmodell"
#. module: base
#: view:res.users:0
@@ -1436,6 +1437,48 @@ msgid ""
"come with any additional paid permission for online use of 'private "
"modules'.\n"
msgstr ""
+"\n"
+"Base module for the Brazilian localization\n"
+"==========================================\n"
+"\n"
+"This module consists in:\n"
+"\n"
+" - Generic Brazilian chart of accounts\n"
+" - Brazilian taxes such as:\n"
+"\n"
+" - IPI\n"
+" - ICMS\n"
+" - PIS\n"
+" - COFINS\n"
+" - ISS\n"
+" - IR\n"
+" - IRPJ\n"
+" - CSLL\n"
+"\n"
+"The field tax_discount has also been added in the account.tax.template and \n"
+"account.tax objects to allow the proper computation of some Brazilian VATs \n"
+"such as ICMS. The chart of account creation wizard has been extended to \n"
+"propagate those new data properly.\n"
+"\n"
+"It's important to note however that this module lack many implementations to "
+"\n"
+"use OpenERP properly in Brazil. Those implementations (such as the "
+"electronic \n"
+"fiscal Invoicing which is already operational) are brought by more than 15 \n"
+"additional modules of the Brazilian Launchpad localization project \n"
+"https://launchpad.net/openerp.pt-br-localiz and their dependencies in the \n"
+"extra addons branch. Those modules aim at not breaking with the remarkable \n"
+"OpenERP modularity, this is why they are numerous but small. One of the \n"
+"reasons for maintaining those modules apart is that Brazilian Localization \n"
+"leaders need commit rights agility to complete the localization as companies "
+"\n"
+"fund the remaining legal requirements (such as soon fiscal ledgers, \n"
+"accounting SPED, fiscal SPED and PAF ECF that are still missing as September "
+"\n"
+"2011). Those modules are also strictly licensed under AGPL V3 and today "
+"don't \n"
+"come with any additional paid permission for online use of 'private "
+"modules'.\n"
#. module: base
#: code:addons/orm.py:406
@@ -1444,8 +1487,8 @@ msgid ""
"Language with code \"%s\" is not defined in your system !\n"
"Define it through the Administration menu."
msgstr ""
-"Die Sprache mit dem Kürzel \"%s\" wurde nicht für Ihr System definiert!\n"
-"Definieren Sie diese Sprache über das Menü Administration."
+"Die Sprache mit dem Kürzel \"%s\" wurde nicht bereitgestellt!\n"
+"Ergänzen Sie diese Sprache über das Menü 'Administration'."
#. module: base
#: model:res.country,name:base.gu
@@ -1492,7 +1535,7 @@ msgstr "Cayman Inseln"
#. module: base
#: view:ir.rule:0
msgid "Record Rule"
-msgstr "Datensatz Regel"
+msgstr "Datensatzregel"
#. module: base
#: model:res.country,name:base.kr
@@ -1502,14 +1545,14 @@ msgstr "Südkorea"
#. module: base
#: model:ir.module.module,description:base.module_l10n_si
msgid "Kontni načrt za gospodarske družbe"
-msgstr ""
+msgstr "Kontni načrt za gospodarske družbe"
#. module: base
#: code:addons/orm.py:4920
#, python-format
msgid "Record #%d of %s not found, cannot copy!"
msgstr ""
-"Datensatz #%d von %s wurde nicht gefunden, kann somit nicht kopiert werden !"
+"Datensatz #%d von %s wurde nicht gefunden, kann nicht kopiert werden !"
#. module: base
#: field:ir.module.module,contributors:0
@@ -1539,7 +1582,7 @@ msgstr "Einstellungsmenu öffnen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (AR) / Español (AR)"
-msgstr "Spanish (AR) / Español (AR)"
+msgstr "Spanisch (AR) / Español (AR)"
#. module: base
#: model:res.country,name:base.ug
@@ -1574,7 +1617,7 @@ msgstr "Assistent.Datenfeld"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (GT) / Español (GT)"
-msgstr "Spanish (GT) / Español (GT)"
+msgstr "Spanisch (GT) / Español (GT)"
#. module: base
#: field:ir.mail_server,smtp_port:0
@@ -1584,7 +1627,7 @@ msgstr "SMTP-Port"
#. module: base
#: help:res.users,login:0
msgid "Used to log into the system"
-msgstr "Für die Systemanmeldung"
+msgstr "Für die Systemanmeldung verwendet"
#. module: base
#: view:base.language.export:0
@@ -1624,7 +1667,7 @@ msgstr "Tests"
#. module: base
#: field:ir.actions.report.xml,attachment:0
msgid "Save as Attachment Prefix"
-msgstr "Speichern als Anhangsprefix"
+msgstr "Als Anhangsprefix speichern"
#. module: base
#: field:ir.ui.view_sc,res_id:0
@@ -1640,7 +1683,7 @@ msgstr "Aktion URL"
#: field:base.module.import,module_name:0
#: field:ir.module.module,shortdesc:0
msgid "Module Name"
-msgstr "Modul Bezeichnung"
+msgstr "Modulbezeichnung"
#. module: base
#: model:res.country,name:base.mh
@@ -1711,7 +1754,7 @@ msgstr "Dokumentenverwaltungssystem"
#. module: base
#: model:ir.module.module,shortdesc:base.module_crm_claim
msgid "Claims Management"
-msgstr "Nachforderungsmanagement"
+msgstr "Forderungsmanagement"
#. module: base
#: model:ir.module.module,description:base.module_document_webdav
@@ -1748,7 +1791,7 @@ msgstr ""
"Durch diese Anwendung wird der WebDAV Server für Dokumente aktiviert.\n"
"===============================================================\n"
"\n"
-"Sie können dann jeden Datei Browser verwenden, um Remote Dateianhänge "
+"Sie können dann jeden Dateibrowser verwenden, um remote Dateianhänge "
"sichtbar zu machen .\n"
"\n"
"Durch die Installation kann der WebDAV Server über eine [webdav] Sektion in "
@@ -1759,19 +1802,19 @@ msgstr ""
"------------------------------------------------------\n"
"[webdav]:\n"
"+++++++++ \n"
-" * enable = True ; webdav Verbindung über den http(s) servers\n"
+" * enable = True ; Webdav Verbindung über den http(s) servers\n"
" * vdir = webdav ; das Hauptverzeichnis des WebDAV Servers\n"
" * Diese Standard bedeutet dass webdav über die\n"
" * URL \"http://localhost:8069/webdav/ verbunden wird.\n"
-" * verbose = True ; Aktivierung der verbose Benachrichtigung von webdav\n"
-" * debug = True ; Aktivierung der debug Nachrichten von webdav\n"
+" * verbose = True; Aktivierung der verbose-Benachrichtigung von webdav\n"
+" * debug = True; Aktivierung der debug-Nachrichten von webdav\n"
" * wenn diese Nachrichten weiter ge-routed werden sollen an das python "
"log System, \n"
" * mit den \"debug\" and \"debug_rpc\" Start Parametern, können diese\n"
-" * Option aktiviert werden\n"
+" * Optionen aktiviert werden.\n"
"\n"
-"Es wird auch das IETF RFC 5785 Protokoll für die Service Erkennung auf dem "
-"http server aktiviert,\n"
+"Es wird auch das IETF RFC 5785 Protokoll für die Serviceerkennung auf dem "
+"http-Server aktiviert,\n"
"wofür ebenfalls eine explizite Konfiguration in der openerp-server.conf "
"gebraucht wird.\n"
@@ -1861,7 +1904,7 @@ msgid ""
"If specified, this action will be opened at logon for this user, in addition "
"to the standard menu."
msgstr ""
-"Wenn definiert, dann wird diese Aktion zusätzlich zum Standardmenü geöffnet"
+"Wenn definiert, dann wird diese Aktion zusätzlich zum Standardmenü geöffnet."
#. module: base
#: model:res.country,name:base.mf
@@ -1886,6 +1929,15 @@ msgid ""
" * the main taxes used in Luxembourg\n"
" * default fiscal position for local, intracom, extracom "
msgstr ""
+"\n"
+"This is the base module to manage the accounting chart for Luxembourg.\n"
+"======================================================================\n"
+"\n"
+" * the Luxembourg Official Chart of Accounts (law of June 2009 + 2011 "
+"chart and Taxes),\n"
+" * the Tax Code Chart for Luxembourg\n"
+" * the main taxes used in Luxembourg\n"
+" * default fiscal position for local, intracom, extracom "
#. module: base
#: code:addons/base/module/wizard/base_update_translations.py:39
@@ -1902,7 +1954,7 @@ msgstr "Soziales Netzwerk"
#. module: base
#: view:res.lang:0
msgid "%Y - Year with century."
-msgstr "%Y - Jahr mit Jahrhundert."
+msgstr "%Y - Jahr (vierstellig)."
#. module: base
#: view:res.company:0
@@ -1942,11 +1994,11 @@ msgstr ""
"Das Basismodul für das Management von Mahlzeiten\n"
"============================================\n"
"\n"
-"Viele Unternehmen bieten Ihren Mitarbeitern die Möglichkeit belegte Brote, "
+"Viele Unternehmen bieten Ihren Mitarbeitern die Möglichkeit, belegte Brote, "
"Pizzen und anderes zu bestellen.\n"
"\n"
-"Für die Mittagessen Anforderungen und Bestellungen ist ein ordnungsgemäßes "
-"Mahlzeiten Management vor allem dann erforderlich, wenn die Anzahl der "
+"Für die Mittagessenanforderungen und Bestellungen ist ein ordnungsgemäßes "
+"Mahlzeitenmanagement vor allem dann erforderlich, wenn die Anzahl der "
"Mitarbeiter oder die Lieferantenauswahl wichtig ist.\n"
"\n"
"Das \"Mahlzeiten\"-Modul wurde entwickelt, um den Mitarbeitern hierzu die "
@@ -1955,7 +2007,7 @@ msgstr ""
"\n"
"Zusätzlich zum kompletten Mahlzeiten und Lieferanten-Management, bietet "
"dieses Modul die Möglichkeit, aktuelle Hinweise anzuzeigen sowie "
-"Bestellvorschläge auf Basis der Mitarbeiter Vorlieben vorzuschlagen.\n"
+"Bestellvorschläge auf Basis der Mitarbeitervorlieben vorzuschlagen.\n"
"Wenn Mitarbeiter für Ihre Mahlzeiten Zeit sparen sollen und vermieden werden "
"soll, dass sie immer Bargeld in der Tasche haben müssen, ist dieses Modul "
"unentbehrlich.\n"
@@ -1972,9 +2024,9 @@ msgid ""
"The field on the current object that links to the target object record (must "
"be a many2one, or an integer field with the record ID)"
msgstr ""
-"Das Feld des aktuellen Objektes das auf einen Datensatz eines anderen "
-"Objektes zeigt ( muss ein many2one sein oder eine Interger Zahl mit der ID "
-"des anderen Datensatzes)"
+"Das Feld des aktuellen Objektes, das auf einen Datensatz eines anderen "
+"Objektes zeigt (muss ein many2one sein oder eine Integer Zahl mit der ID des "
+"anderen Datensatzes)"
#. module: base
#: model:ir.model,name:base.model_res_bank
@@ -2041,7 +2093,7 @@ msgid ""
"used to refer to other modules data, as in module.reference_id"
msgstr ""
"'%s' beinhaltet zu viele Punkte. XML IDs sollen keine Punkte enthalten. "
-"Punkte werdfen verwendet um andere Module zu ferferenzieren wie zB. "
+"Punkte werden verwendet, um andere Module zu referenzieren wie zB. "
"module.reference_id"
#. module: base
@@ -2055,13 +2107,13 @@ msgid ""
"Access all the fields related to the current object using expressions, i.e. "
"object.partner_id.name "
msgstr ""
-"Zugriff auf alle Felder die mit dem aktuellen Objekt verbunden sind. zB "
+"Zugriff auf alle Felder ,die mit dem aktuellen Objekt verbunden sind. Z.B. "
"object.partner_id.name "
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_project_issue
msgid "Portal Issue"
-msgstr "Portal Problem"
+msgstr "Portalproblem"
#. module: base
#: model:ir.ui.menu,name:base.menu_tools
@@ -2084,7 +2136,7 @@ msgstr ""
"Manuell: Manuell gestartet.\n"
"Automatisch: Wird gestartet, wenn das System neu konfiguriert wird.\n"
"Einmalig manuell starten: Nachdem einmalig manuell gestartet wurde, wird es "
-"automatisch auf Erledigt gesetzt."
+"automatisch auf 'Erledigt' gesetzt."
#. module: base
#: field:res.partner,image_small:0
@@ -2110,7 +2162,7 @@ msgstr "Assistent Info"
#: model:ir.actions.act_window,name:base.action_wizard_lang_export
#: model:ir.ui.menu,name:base.menu_wizard_lang_export
msgid "Export Translation"
-msgstr "Exportiere Übersetzung"
+msgstr "Übersetzung exportieren"
#. module: base
#: model:ir.actions.act_window,name:base.action_server_action
@@ -2153,7 +2205,7 @@ msgid ""
"Accountant, before using it in a live Environment.\n"
msgstr ""
"\n"
-"Dieses Modul repräsentiert den Standard Kontenplan für Österreich auf Basis "
+"Dieses Modul repräsentiert den Standardkontenplan für Österreich auf Basis "
"der Vorlage des BMF.gv.at.\n"
"Bitte beachten Sie, daß dieser Kontenplan generell vor Inbetriebnahme "
"geprüft und möglicherweise auch angepasst werden sollte.\n"
@@ -2181,8 +2233,8 @@ msgstr ""
"Gibt dem Administrator Benutzerrechte zum Zugriff auf alle Funktionalitäten "
"des Finanzmoduls, wie z.B. Journal Einträge und Kontenplan.\n"
"\n"
-"Dem Administrator werden Verwaltungs- und Benutzer Rechte zugewiesen, der "
-"Demo Benutzer erhält nur Benutzer Rechte. \n"
+"Dem Administrator werden Verwaltungs- und Benutzerrechte zugewiesen, der "
+"Demobenutzer erhält nur Benutzerrechte. \n"
#. module: base
#: view:ir.sequence:0
@@ -2215,7 +2267,7 @@ msgstr "Niederlande"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_event
msgid "Portal Event"
-msgstr "Event Portal"
+msgstr "Eventportal"
#. module: base
#: selection:ir.translation,state:0
@@ -2269,10 +2321,10 @@ msgid ""
" "
msgstr ""
"\n"
-"Dieses Modul erweitert OpenERP um Freigabe Werkzeuge.\n"
+"Dieses Modul erweitert OpenERP um Freigabewerkzeuge.\n"
"==================================================\n"
"\n"
-"Es wird eine spezifische \"Freigeben\"- Schaltfläche hinzugefügt, die im Web-"
+"Es wird ein spezifischer \"Freigeben\"- Button hinzugefügt, der im Web-"
"Client verfügbar ist,\n"
"und die Freigabe beliebiger Arten von OpenERP Daten mit Kollegen, Kunden, "
"Freunden ermöglicht.\n"
@@ -2292,7 +2344,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_process
msgid "Enterprise Process"
-msgstr "Unternehmens Prozess"
+msgstr "Unternehmensprozess"
#. module: base
#: help:res.partner,supplier:0
@@ -2301,7 +2353,7 @@ msgid ""
"people will not see it when encoding a purchase order."
msgstr ""
"Aktivieren Sie diese Checkbox, wenn der Kontakt ein Lieferant ist. Wenn es "
-"nicht aktiviert ist, wird dieser Kontakt nicht im Einkaufs"
+"nicht aktiviert ist, wird dieser Kontakt nicht im Einkauf angezeigt."
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_evaluation
@@ -2311,7 +2363,7 @@ msgstr "Personalbeurteilung"
#. module: base
#: selection:ir.actions.server,state:0
msgid "Write Object"
-msgstr "Schreibe"
+msgstr "Objekt schreiben"
#. module: base
#: code:addons/base/res/res_company.py:68
@@ -2349,12 +2401,12 @@ msgstr "Aufgaben der Auftragserfassung"
#: code:addons/base/ir/ir_model.py:320
#, python-format
msgid "This column contains module data and cannot be removed!"
-msgstr "Diese Spalte enthält Modul Daten und kann nicht gelöscht werden!"
+msgstr "Diese Spalte enthält Moduldaten und kann nicht gelöscht werden!"
#. module: base
#: field:res.partner.bank,footer:0
msgid "Display on Reports"
-msgstr "Berichtsanzeige"
+msgstr "In Berichten anzeigen"
#. module: base
#: model:ir.module.module,description:base.module_project_timesheet
@@ -2401,7 +2453,7 @@ msgid ""
msgstr ""
"\n"
" * Multi Sprachunterstützung für Kontenpläne, Steuern , Steuerschlüssel,\n"
-" Buchhaltung Kontenpläne und Kostenstellen Kontenpläne und Journale.\n"
+" Buchhaltung Kontenpläne und Kostenstellen, Kontenpläne und Journale.\n"
" * Einrichtung-Assistenten für Veränderungen\n"
" - Kopieren Sie Übersetzungen für COA, Tax, Tax Code und Fiscal "
"Position aus\n"
@@ -2427,7 +2479,7 @@ msgstr "Formel"
#: code:addons/base/res/res_users.py:311
#, python-format
msgid "Can not remove root user!"
-msgstr "Kann den root Benutzer nicht entfernen!"
+msgstr "Kann den Root-Benutzer nicht entfernen!"
#. module: base
#: model:res.country,name:base.mw
@@ -2536,9 +2588,9 @@ msgid ""
"decimal number [00,53]. All days in a new year preceding the first Sunday "
"are considered to be in week 0."
msgstr ""
-"%U - Wochennummer des Jahres (Sontag als erster Wochentag) als Dezimalziffer "
-"[00,53]. Alle Tage der ersten Woche des neuen Jahres die auf einen Sonntag "
-"im alten Jahr folgen haben den Wert 0.."
+"%U - Wochennummer des Jahres (Sonntag als erster Wochentag) als "
+"Dezimalziffer [00,53]. Alle Tage der ersten Woche des neuen Jahres die auf "
+"einen Sonntag im alten Jahr folgen haben den Wert 0."
#. module: base
#: view:base.language.export:0
@@ -2572,7 +2624,7 @@ msgstr "Sekunden: %(sec)s"
#. module: base
#: field:ir.actions.act_window,view_mode:0
msgid "View Mode"
-msgstr "Ansicht Modus"
+msgstr "Ansichtmodus"
#. module: base
#: help:res.partner.bank,footer:0
@@ -2586,12 +2638,12 @@ msgstr ""
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish / Español"
-msgstr "Spanish / Español"
+msgstr "Spanisch / Español"
#. module: base
#: selection:base.language.install,lang:0
msgid "Korean (KP) / 한국어 (KP)"
-msgstr "Korean (KP) / 한국어 (KP)"
+msgstr "Koreanisch (KP) / 한국어 (KP)"
#. module: base
#: model:res.country,name:base.ax
@@ -2671,12 +2723,12 @@ msgstr "Methode"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_crypt
msgid "Password Encryption"
-msgstr "Passwort Verschlüsselung"
+msgstr "Passwortverschlüsselung"
#. module: base
#: view:workflow.activity:0
msgid "Workflow Activity"
-msgstr "Arbeitsfluss Aktivität"
+msgstr "Workflow-Aktivität"
#. module: base
#: model:ir.module.module,description:base.module_hr_timesheet_sheet
@@ -2721,7 +2773,7 @@ msgstr ""
"Wie sieht ein kompletter Vorgang für die Validierung der Zeiterfassung aus:\n"
"-----------------------------------------------------------------------------"
"-----------------------------------\n"
-"* Entwurfs Eingabeformular für die Arbeitszeit eines Mitarbeiters\n"
+"* Entwurf Eingabeformular für die Arbeitszeit eines Mitarbeiters\n"
"* Bestätigung am Ende des Zeitraums durch den Arbeitnehmer\n"
"* Bestätigung durch den Projektmanager\n"
"\n"
@@ -2786,7 +2838,7 @@ msgstr "Gruppen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (CL) / Español (CL)"
-msgstr "Spanish (CL) / Español (CL)"
+msgstr "Spanisch (CL) / Español (CL)"
#. module: base
#: model:res.country,name:base.bz
@@ -2796,7 +2848,7 @@ msgstr "Belize"
#. module: base
#: help:ir.actions.report.xml,header:0
msgid "Add or not the corporate RML header"
-msgstr "Firmen RML Header hinzufügen?"
+msgstr "Unternehmens-RML-Header hinzufügen?"
#. module: base
#: model:ir.module.module,description:base.module_portal_anonymous
@@ -2807,7 +2859,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Erlauben Sie Portalbesuche anonymer Benutzer\n"
+"Erlauben Sie Portalbesuche anonymer Benutzer.\n"
"======================================\n"
" "
@@ -2848,6 +2900,34 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+" \n"
+"Belgian localization for in- and outgoing invoices (prereq to "
+"account_coda):\n"
+"============================================================================"
+"\n"
+" - Rename 'reference' field labels to 'Communication'\n"
+" - Add support for Belgian Structured Communication\n"
+"\n"
+"A Structured Communication can be generated automatically on outgoing "
+"invoices according to the following algorithms:\n"
+"-----------------------------------------------------------------------------"
+"----------------------------------------\n"
+" 1) Random : +++RRR/RRRR/RRRDD+++\n"
+" **R..R =** Random Digits, **DD =** Check Digits\n"
+" 2) Date : +++DOY/YEAR/SSSDD+++\n"
+" **DOY =** Day of the Year, **SSS =** Sequence Number, **DD =** Check "
+"Digits\n"
+" 3) Customer Reference +++RRR/RRRR/SSSDDD+++\n"
+" **R..R =** Customer Reference without non-numeric characters, **SSS "
+"=** Sequence Number, **DD =** Check Digits \n"
+" \n"
+"The preferred type of Structured Communication and associated Algorithm can "
+"be\n"
+"specified on the Partner records. A 'random' Structured Communication will\n"
+"generated if no algorithm is specified on the Partner record. \n"
+"\n"
+" "
#. module: base
#: model:res.country,name:base.pl
@@ -2860,7 +2940,7 @@ msgid ""
"Comma-separated list of allowed view modes, such as 'form', 'tree', "
"'calendar', etc. (Default: tree,form)"
msgstr ""
-"Komma-getrennte Liste aller erlaubten Ansichstypen wie 'form', 'tree', "
+"Komma-getrennte Liste aller erlaubten Ansichtstypen wie 'form', 'tree', "
"'calendar', etc. (Default: tree,form)"
#. module: base
@@ -2872,13 +2952,13 @@ msgstr "Ein Beleg wurde seit der letzten Ansicht geändert (%s:%d)"
#. module: base
#: view:workflow:0
msgid "Workflow Editor"
-msgstr "Arbeitsfluss Editor"
+msgstr "Workflow-Editor"
#. module: base
#: selection:ir.module.module,state:0
#: selection:ir.module.module.dependency,state:0
msgid "To be removed"
-msgstr "wird entfernt"
+msgstr "Zu entfernen"
#. module: base
#: model:ir.model,name:base.model_ir_sequence
@@ -2921,7 +3001,7 @@ msgstr ""
"\n"
"Wie Karteikarten/Datensätze und Forderungsverwaltung, so sind auch der "
"Helpdesk\n"
-"und techn. Betreuung wichtige und gute Hilfmittel Ihre Maßnahmen "
+"und die techn. Betreuung wichtige und gute Hilfmittel Ihre Maßnahmen "
"festzuhalten.\n"
"Diese Erweiterung ist eher auf die (fern-) mündliche Hilfestellung "
"ausgerichtet, was\n"
@@ -2937,7 +3017,7 @@ msgid ""
"hierarchical tree view, or 'form' for a regular list view"
msgstr ""
"Ansichtstyp: Listenansichtstyp für die Benutzung in Listen, wird entweder "
-"auf 'Liste' für hierarchische Listenansicht oder auf \"Formular\" für "
+"auf \"Liste\" für hierarchische Listenansicht oder auf \"Formular\" für "
"normale Listenansicht gesetzt"
#. module: base
@@ -2991,11 +3071,11 @@ msgid ""
" "
msgstr ""
"\n"
-"Dies ist das Basis Modul zur Verwaltung von Produkten und Preislisten in "
+"Dies ist das Basismodul zur Verwaltung von Produkten und Preislisten in "
"OpenERP.\n"
"========================================================================\n"
"\n"
-"Das Modul unterstützt Varianten, unterschiedliche Preisberrechnungsmethoden, "
+"Das Modul unterstützt Varianten, unterschiedliche Preisberechnungsmethoden, "
"Lieferanten\n"
"-informationen, unterschiedliche Maßeinheiten, Verpackungen und "
"Eigenschaften für Produkte.\n"
@@ -3031,7 +3111,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Verwaltet die Standardwerte für Analytische Konten.\n"
+"Verwaltet die Standardwerte für analytische Konten.\n"
"==============================================\n"
"\n"
"Ermöglicht die automatische Auswahl von analytischen Konten basierend auf "
@@ -3060,7 +3140,7 @@ msgstr "Madagaskar"
msgid ""
"The Object name must start with x_ and not contain any special character !"
msgstr ""
-"Der Objekt Name muss mit einem x_ starten und darf keine Sonderzeichen "
+"Der Objektname muss mit einem x_ starten und darf keine Sonderzeichen "
"beinhalten"
#. module: base
@@ -3098,7 +3178,7 @@ msgstr "Benutzerdefinierte Fußzeile"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_crm
msgid "Opportunity to Quotation"
-msgstr "Konvertiere Verkaufschance zu Angebot"
+msgstr "Überführe Verkaufschance in Angebot"
#. module: base
#: model:ir.module.module,description:base.module_sale_analytic_plans
@@ -3144,7 +3224,7 @@ msgstr "Anguilla"
#. module: base
#: model:ir.actions.report.xml,name:base.report_ir_model_overview
msgid "Model Overview"
-msgstr "Modul Übersicht"
+msgstr "Modulübersicht"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_margin
@@ -3250,8 +3330,8 @@ msgstr ""
"Verwaltet Angebote und Aufträge\n"
"==================================\n"
"\n"
-"Diese Anwendung ermöglicht ihnen die effiziente Verwaltung Ihrer Ihrer "
-"Angebote und Aufträge mitsamt der Historie.\n"
+"Diese Anwendung ermöglicht ihnen die effiziente Verwaltung Ihrer Angebote "
+"und Aufträge mitsamt der Historie.\n"
"\n"
"Folgendermassen sieht der einfache Verkaufsworkflow aus:\n"
"\n"
@@ -3270,7 +3350,7 @@ msgstr ""
"Sie können zwischen verschiedenen Rechnungserzeugungsarten wählen:\n"
"* Bei Bedarf: Rechnungen werden manuell auf Basis von Auftragsbestätigungen "
"erzeugt\n"
-"* Lieferschein: Rechungen werden nach Erzeugung des Lieferscheins "
+"* Lieferschein: Rechnungen werden nach Erzeugung des Lieferscheins "
"(Lagerentnahme) auf dessen Basis erzeugt\n"
"* Vor Auslieferung: Ein Rechnungsentwurf wird erzeugt und muss vor der "
"Auslieferung bezahlt werden\n"
@@ -3307,7 +3387,7 @@ msgid ""
"================================================\n"
msgstr ""
"\n"
-"Modul zur Verknüpfung eines Google Dokumentes mit einem beliebigen Modell.\n"
+"Modul zur Verknüpfung eines Google Dokuments mit einem beliebigen Modell.\n"
"================================================\n"
#. module: base
@@ -3334,7 +3414,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Peruanischer Kontenplan und Steuer Lokalisierung nach PCGE 2010.\n"
+"Peruanischer Kontenplan und Steuerlokalisierung nach PCGE 2010.\n"
"========================================================================\n"
"\n"
"Plan contable peruano e impuestos de acuerdo a disposiciones vigentes de la\n"
@@ -3346,13 +3426,13 @@ msgstr ""
#: view:ir.actions.server:0
#: field:workflow.activity,action_id:0
msgid "Server Action"
-msgstr "Server Aktion"
+msgstr "Serveraktion"
#. module: base
#: help:ir.actions.client,params:0
msgid "Arguments sent to the client along withthe view tag"
msgstr ""
-"Argumente die zusammen mit der Sicht-Kennung an die Anwendung (client) "
+"Argumente, die zusammen mit der Sicht-Kennung an die Anwendung (client) "
"gesendet werden"
#. module: base
@@ -3373,7 +3453,7 @@ msgstr "Lettland"
#. module: base
#: view:ir.actions.server:0
msgid "Field Mappings"
-msgstr "Felder Zuordnungen"
+msgstr "Feldzuordnungen"
#. module: base
#: view:base.language.export:0
@@ -3397,8 +3477,8 @@ msgstr ""
"==================\n"
"\n"
"ACHTUNG: Dieses Modul ist momentan noch inkompatibel mit dem LDAP-Modul!\n"
-"Es deaktiviert die LDAP Authentifizierung, wenn das LDAP Modul installiert "
-"ist!\n"
+"Es deaktiviert die LDAP Authentifizierung, wenn sie zugleich installiert "
+"sind!\n"
#. module: base
#: model:res.groups,name:base.group_hr_manager
@@ -3515,13 +3595,13 @@ msgid ""
"(stacked)\n"
msgstr ""
"\n"
-"Grafik Ansichten im Web Client\n"
+"Grafische Auswertung im Web Client\n"
"==========================\n"
" * Erstellt eine <Graph> Ansicht und ermöglicht eine dynamische "
"Anpassung der Präsentation\n"
" * Folgende Diagrammtypen werden unterstützt: Torte, Linien, Flächen, "
"Balken, Radardiagramme\n"
-" * Gestapelte / Nicht gestapelte Diagramm Ansicht für Flächen und "
+" * Gestapelte / Nicht gestapelte Diagrammansicht für Flächen und "
"Balken\n"
" * Legende: oben, innen (oben / links), versteckt\n"
"     * Features: Download als PNG-oder CSV-, Daten-Browser, dynamischer "
@@ -3563,6 +3643,20 @@ msgid ""
" * Salary Maj, ONSS, Withholding Tax, Child Allowance, ...\n"
" "
msgstr ""
+"\n"
+"Belgian Payroll Rules.\n"
+"======================\n"
+"\n"
+" * Employee Details\n"
+" * Employee Contracts\n"
+" * Passport based Contract\n"
+" * Allowances/Deductions\n"
+" * Allow to configure Basic/Gross/Net Salary\n"
+" * Employee Payslip\n"
+" * Monthly Payroll Register\n"
+" * Integrated with Holiday Management\n"
+" * Salary Maj, ONSS, Withholding Tax, Child Allowance, ...\n"
+" "
#. module: base
#: code:addons/base/ir/ir_fields.py:174
@@ -3581,7 +3675,7 @@ msgstr ""
#. module: base
#: view:res.lang:0
msgid "%y - Year without century [00,99]."
-msgstr "%y - Jahr ohne Jahrhundert [00,99]."
+msgstr "%y - Jahr (zweistellig) [00,99]."
#. module: base
#: model:ir.module.module,description:base.module_account_anglo_saxon
@@ -3605,6 +3699,24 @@ msgid ""
"purchase price and fixed product standard price are booked on a separate \n"
"account."
msgstr ""
+"\n"
+"This module supports the Anglo-Saxon accounting methodology by changing the "
+"accounting logic with stock transactions.\n"
+"============================================================================="
+"========================================\n"
+"\n"
+"The difference between the Anglo-Saxon accounting countries and the Rhine \n"
+"(or also called Continental accounting) countries is the moment of taking \n"
+"the Cost of Goods Sold versus Cost of Sales. Anglo-Saxons accounting does \n"
+"take the cost when sales invoice is created, Continental accounting will \n"
+"take the cost at the moment the goods are shipped.\n"
+"\n"
+"This module will add this functionality by using a interim account, to \n"
+"store the value of shipped goods and will contra book this interim \n"
+"account when the invoice is created to transfer this amount to the \n"
+"debtor or creditor account. Secondly, price differences between actual \n"
+"purchase price and fixed product standard price are booked on a separate \n"
+"account."
#. module: base
#: model:res.country,name:base.si
@@ -3628,8 +3740,8 @@ msgstr ""
"Dieses Modul berücksichtigt Status und Stufe. Es ist eine Anpassung der "
"crm_base und crm_case Klassen aus dem CRM.\n"
"\n"
-" * \"base_state\": Status Management\n"
-" * \"base_stage\": Fortschritt Management\n"
+" * \"base_state\": Statusmanagement\n"
+" * \"base_stage\": Fortschrittsmanagement\n"
" "
#. module: base
@@ -3642,7 +3754,7 @@ msgstr "LinkedIn Integration"
#: code:addons/orm.py:2032
#, python-format
msgid "Invalid Object Architecture!"
-msgstr "Fehlerhafte Objekt Architektur !"
+msgstr "Fehlerhafte Objektarchitektur !"
#. module: base
#: code:addons/base/ir/ir_model.py:372
@@ -3700,7 +3812,7 @@ msgstr "Neuseeland"
#: view:ir.model.fields:0
#: field:res.partner.bank.type.field,name:0
msgid "Field Name"
-msgstr "Bezeichnung Feld"
+msgstr "Feldname"
#. module: base
#: model:ir.actions.act_window,help:base.action_country
@@ -3709,9 +3821,9 @@ msgid ""
"partner records. You can create or delete countries to make sure the ones "
"you are working on will be maintained."
msgstr ""
-"Anzeige und Verwaltung der Liste aller Länder, die zu Ihren Partnerdaten "
-"zugewiesen werden können. Sie können neue Länder hinzufügen oder auch "
-"vorhandene Einträge löschen. Sie können Länder hinzufügen oder löschen, um "
+"Anzeige und Verwaltung der Liste aller Länder, die Partnerdaten zugewiesen "
+"werden können. Sie können neue Länder hinzufügen oder auch vorhandene "
+"Einträge löschen. Sie können Länder hinzufügen oder löschen, um "
"sicherzustellen, dass Ihre benötigten Länder dauerhaft gewartet werden."
#. module: base
@@ -3722,7 +3834,7 @@ msgstr "Norfolk Insel"
#. module: base
#: selection:base.language.install,lang:0
msgid "Korean (KR) / 한국어 (KR)"
-msgstr "Korean (KR) / 한국어 (KR)"
+msgstr "Koreanisch (KR) / 한국어 (KR)"
#. module: base
#: help:ir.model.fields,model:0
@@ -3734,7 +3846,7 @@ msgstr "Die technische Bezeichnung des Moduls für das entsprechende Feld."
#: selection:ir.actions.server,state:0
#: view:ir.values:0
msgid "Client Action"
-msgstr "Anwendungsaktion"
+msgstr "Anwenderaktion"
#. module: base
#: model:ir.module.module,description:base.module_subscription
@@ -3761,10 +3873,10 @@ msgstr ""
"Diese Anwendung ermöglicht Ihnen, neue Belege zu erstellen und durch "
"Abonnements diese Belege regelmässig zu erstellen.\n"
"\n"
-"z. B. um automatisch monatliche Abrechnungen zu erzeugen:\n"
+"Z. B. um automatisch monatliche Abrechnungen zu erzeugen:\n"
"-------------------------------------------------------------\n"
" * Definieren Sie einen Dokumenttyp basierend auf dem Rechnungsobjekt\n"
-" * Definieren Sie einen Abo Zeitraum, dessen Quelle, das oben definierte "
+" * Definieren Sie einen Abozeitraum, dessen Quelle das oben definierte "
"Dokument \n"
" ist. Bestimmen Sie das Intervall zur Neuerstellung des Belegs sowie "
"den Partner mit \n"
@@ -3849,7 +3961,7 @@ msgstr "Unbekannte Berichtsart: %s"
#. module: base
#: model:ir.module.module,summary:base.module_hr_expense
msgid "Expenses Validation, Invoicing"
-msgstr "Spesen Bestätigung, Verrechnung"
+msgstr "Spesenbestätigung, Abrechnung"
#. module: base
#: model:ir.module.module,description:base.module_l10n_be_hr_payroll_account
@@ -3859,6 +3971,10 @@ msgid ""
"==========================================\n"
" "
msgstr ""
+"\n"
+"Accounting Data for Belgian Payroll Rules.\n"
+"==========================================\n"
+" "
#. module: base
#: model:res.country,name:base.am
@@ -3917,6 +4033,22 @@ msgid ""
" - Yearly Salary by Head and Yearly Salary by Employee Report\n"
" "
msgstr ""
+"\n"
+"Indian Payroll Salary Rules.\n"
+"============================\n"
+"\n"
+" -Configuration of hr_payroll for India localization\n"
+" -All main contributions rules for India payslip.\n"
+" * New payslip report\n"
+" * Employee Contracts\n"
+" * Allow to configure Basic / Gross / Net Salary\n"
+" * Employee PaySlip\n"
+" * Allowance / Deduction\n"
+" * Integrated with Holiday Management\n"
+" * Medical Allowance, Travel Allowance, Child Allowance, ...\n"
+" - Payroll Advice and Report\n"
+" - Yearly Salary by Head and Yearly Salary by Employee Report\n"
+" "
#. module: base
#: code:addons/orm.py:3871
@@ -3962,7 +4094,7 @@ msgstr ""
"Verwaltung der Spesen für Mitarbeiter\n"
"==============================\n"
"\n"
-"Diese Anwendung ermöglicht es Ihnen, die Spesen Ihrer Mitarbeitern zu "
+"Diese Anwendung ermöglicht es Ihnen, die Spesen Ihrer Mitarbeiter zu "
"verwalten. Sie gibt Ihnen Zugriff auf die Aufwandsabrechnungen Ihrer "
"Mitarbeiter und das Recht diese zu vervollständigen und zu bestätigen oder "
"zu verweigern. Nach der Bestätigung erstellt diese Anwendung eine "
@@ -3979,7 +4111,7 @@ msgstr ""
"* Bestätigung durch dessen Vorgesetzten\n"
"* Bestätigung durch den Buchhalter und Erhalt der Spesenabrechnung\n"
"\n"
-"Diese Anwendung nutzt weiterhin die Kostenstellen Integration und ist somit "
+"Diese Anwendung nutzt weiterhin die Kostenstellenintegration und ist somit "
"kompatibel zur Abrechnung an Kunden über die Anwendung der Zeiterfassung, "
"sodass es Ihnen möglich ist, sofern Sie mit Projekten arbeiten, erneut eine "
"neue Rechnung Ihrer Kundenspesen zu erstellen.\n"
@@ -4010,7 +4142,7 @@ msgstr "Österreich"
#: model:ir.ui.menu,name:base.menu_calendar_configuration
#: selection:ir.ui.view,type:0
msgid "Calendar"
-msgstr "Kalenderansicht"
+msgstr "Kalender"
#. module: base
#: model:ir.module.category,name:base.module_category_knowledge_management
@@ -4037,7 +4169,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_module_module_dependency
msgid "Module dependency"
-msgstr "Module Abhängigkeiten"
+msgstr "Modulabhängigkeiten"
#. module: base
#: model:res.country,name:base.bd
@@ -4051,7 +4183,7 @@ msgid ""
"way you want to print them in letters and other documents. Some example: "
"Mr., Mrs. "
msgstr ""
-"Verwaltet die Kontakt Anredeform, die Sie in Ihrem System z.B. beim "
+"Verwaltet die Kontakt-Anredeform, die Sie in Ihrem System z.B. beim "
"Ausdrucken von Belegen benötigen, z.B. Herr, Frau, etc. "
#. module: base
@@ -4059,7 +4191,7 @@ msgstr ""
#: view:res.groups:0
#: field:res.groups,model_access:0
msgid "Access Controls"
-msgstr "Zugriffskontolle"
+msgstr "Zugriffskontrolle"
#. module: base
#: code:addons/base/ir/ir_model.py:277
@@ -4068,13 +4200,13 @@ msgid ""
"The Selection Options expression is not a valid Pythonic expression.Please "
"provide an expression in the [('key','Label'), ...] format."
msgstr ""
-"Die Anweisung für die Auswahl ist kein gültiger Python Ausruck. Bitte "
+"Die Anweisung für die Auswahl ist kein gültiger Python-Ausruck. Bitte "
"hinterlegen Sie einen gültigen Ausdruck im Format [('key','Label'),...]."
#. module: base
#: model:res.groups,name:base.group_survey_user
msgid "Survey / User"
-msgstr "Überwachung / Benutzer"
+msgstr "Umfrage / Benutzer"
#. module: base
#: view:ir.module.module:0
@@ -4100,7 +4232,7 @@ msgstr "Währungscode (ISO 4217)"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_contract
msgid "Employee Contracts"
-msgstr "Mitarbeiter Verträge"
+msgstr "Mitarbeiterverträge"
#. module: base
#: view:ir.actions.server:0
@@ -4108,8 +4240,8 @@ msgid ""
"If you use a formula type, use a python expression using the variable "
"'object'."
msgstr ""
-"Wenn Sie einen Typ 'Formel' benutzen setze eine python Ausdruck mit der "
-"Variable 'object'"
+"Wenn Sie einen Typ 'Formel' benutzen, verwenden Sie einen Python-Ausdruck "
+"mit der Variable 'object'."
#. module: base
#: constraint:res.company:0
@@ -4119,18 +4251,18 @@ msgstr "Fehler! Sie können keine rekursiven Unternehmen erzeugen."
#. module: base
#: field:res.partner,birthdate:0
msgid "Birthdate"
-msgstr "Geb. Datum"
+msgstr "Geburtsdatum"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_title_contact
#: model:ir.ui.menu,name:base.menu_partner_title_contact
msgid "Contact Titles"
-msgstr "Partner Kontaktanrede"
+msgstr "Partner-Kontaktanrede"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_manufacturer
msgid "Products Manufacturers"
-msgstr "Produktehersteller"
+msgstr "Produkthersteller"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:240
@@ -4147,7 +4279,7 @@ msgstr "Umfrage"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (DO) / Español (DO)"
-msgstr "Spanish (DO) / Español (DO)"
+msgstr "Spanisch (DO) / Español (DO)"
#. module: base
#: model:ir.model,name:base.model_workflow_activity
@@ -4185,7 +4317,7 @@ msgstr "Finnish / Suomi"
#. module: base
#: view:ir.config_parameter:0
msgid "System Properties"
-msgstr "System Einstellungen"
+msgstr "Systemeinstellungen"
#. module: base
#: field:ir.sequence,prefix:0
@@ -4195,12 +4327,12 @@ msgstr "Prefix"
#. module: base
#: selection:base.language.install,lang:0
msgid "German / Deutsch"
-msgstr "German / Deutsch"
+msgstr "Deutsch / Deutsch"
#. module: base
#: view:ir.actions.server:0
msgid "Fields Mapping"
-msgstr "Felder Mappen"
+msgstr "Feldzuordnung"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_sir
@@ -4222,7 +4354,7 @@ msgid ""
msgstr ""
"\n"
"Dieses Modul dient der Verwaltung des englischen und französischen "
-"Kontenplan Kanadas in OpenERP.\n"
+"Kontenplans Kanadas in OpenERP.\n"
"============================================================================="
"==============\n"
"\n"
@@ -4260,7 +4392,7 @@ msgstr ""
#. module: base
#: field:ir.actions.server,fields_lines:0
msgid "Field Mappings."
-msgstr "Feld Zuordnung"
+msgstr "Feldzuordnung"
#. module: base
#: selection:res.request,priority:0
@@ -4308,9 +4440,9 @@ msgstr ""
"==========================================\n"
"\n"
"Die Fertigungsanwendung ermöglicht es Ihnen die Planung, Bestellung, "
-"Lagererung und Fertigung oder Montage von Produkten mittels Beschaffung von "
+"Lagerung und Fertigung oder Montage von Produkten mittels Beschaffung von "
"Rohstoffen und Komponenten abzudecken. Das Modul verwaltet den Verbrauch und "
-"die Produktionsmeldungen an Hand einer Stückliste und der definierten "
+"die Produktionsmeldungen anhand einer Stückliste und der definierten "
"notwendigen Vorgänge an Maschinen, speziellen Werkzeugen sowie der "
"menschlichen Arbeitszeit anhand der hinterlegten Arbeitspläne.\n"
"\n"
@@ -4354,7 +4486,7 @@ msgstr "Beschreibung"
#: model:ir.actions.act_window,name:base.action_workflow_instance_form
#: model:ir.ui.menu,name:base.menu_workflow_instance
msgid "Instances"
-msgstr "Objekte"
+msgstr "Instanzen"
#. module: base
#: model:ir.module.module,description:base.module_purchase_requisition
@@ -4422,7 +4554,7 @@ msgstr "Datenbankstruktur"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_mass_mail
msgid "Mass Mailing"
-msgstr "Massen Mailing"
+msgstr "Massenmailing"
#. module: base
#: model:res.country,name:base.yt
@@ -4432,7 +4564,7 @@ msgstr "Mayotte"
#. module: base
#: model:ir.module.module,shortdesc:base.module_crm_todo
msgid "Tasks on CRM"
-msgstr "Aufgaben der Kundenverwaltung"
+msgstr "Aufgaben der CRM-Verwaltung"
#. module: base
#: help:ir.model.fields,relation_field:0
@@ -4537,13 +4669,13 @@ msgid ""
" "
msgstr ""
"\n"
-"Dieses Modul erlaubt die Definition der Standard Kostenstelle für einen "
+"Dieses Modul erlaubt die Definition der Standardkostenstelle für einen "
"bestimmten Benutzer.\n"
"================================================== "
"==========================\n"
"\n"
"Dieser Standard wird meistens verwendet, wenn ein Benutzer seine "
-"Zeiterfassung vornimmt: Die Standard Werte werden abgerufen und die Felder "
+"Zeiterfassung vornimmt: Die Standardwerte werden abgerufen und die Felder "
"werden automatisch mit der zugewiesenen Kostenstelle ausgefüllt. Es gibt "
"dennoch weiter die Möglichkeit, die entsprechenden Werte abzuändern.\n"
"\n"
@@ -4568,7 +4700,7 @@ msgstr "Togo"
#: field:ir.actions.act_window,res_model:0
#: field:ir.actions.client,res_model:0
msgid "Destination Model"
-msgstr "Ziel Model"
+msgstr "Zielmodell"
#. module: base
#: selection:ir.sequence,implementation:0
@@ -4597,7 +4729,7 @@ msgstr "Zugriff verweigert"
#. module: base
#: field:res.company,name:0
msgid "Company Name"
-msgstr "Unternehmen"
+msgstr "Unternehmensname"
#. module: base
#: code:addons/orm.py:2808
@@ -4606,7 +4738,7 @@ msgid ""
"Invalid value for reference field \"%s.%s\" (last part must be a non-zero "
"integer): \"%s\""
msgstr ""
-"Ungültiger Wert für \"%s.%s\" (Der letzte Teil muss ein Ziffer ungleich "
+"Ungültiger Wert für \"%s.%s\" (der letzte Teil muss ein Ziffer ungleich "
"Null sein sein): \"%s\""
#. module: base
@@ -4647,6 +4779,29 @@ msgid ""
" payslip interface, but not in the payslip report\n"
" "
msgstr ""
+"\n"
+"French Payroll Rules.\n"
+"=====================\n"
+"\n"
+" - Configuration of hr_payroll for French localization\n"
+" - All main contributions rules for French payslip, for 'cadre' and 'non-"
+"cadre'\n"
+" - New payslip report\n"
+"\n"
+"TODO:\n"
+"-----\n"
+" - Integration with holidays module for deduction and allowance\n"
+" - Integration with hr_payroll_account for the automatic "
+"account_move_line\n"
+" creation from the payslip\n"
+" - Continue to integrate the contribution. Only the main contribution "
+"are\n"
+" currently implemented\n"
+" - Remake the report under webkit\n"
+" - The payslip.line with appears_in_payslip = False should appears in "
+"the\n"
+" payslip interface, but not in the payslip report\n"
+" "
#. module: base
#: model:res.country,name:base.pm
@@ -4656,7 +4811,7 @@ msgstr "St.-Pierre und Miquelon"
#. module: base
#: view:ir.actions.todo:0
msgid "Search Actions"
-msgstr "Such Aktionen"
+msgstr "Suchaktionen"
#. module: base
#: model:ir.module.module,description:base.module_base_calendar
@@ -4683,7 +4838,7 @@ msgstr ""
" - Kalender für Veranstaltungen\n"
" - wiederkehrende Veranstaltungen\n"
"\n"
-"Wenn Sie Ihre Termine verwalten möchten, sollte Sie hierzu die CRM Anwendung "
+"Wenn Sie Ihre Termine verwalten möchten, sollte Sie hierzu die CRM-Anwendung "
"installieren.\n"
" "
@@ -4749,7 +4904,7 @@ msgid ""
"Can not create the module file:\n"
" %s"
msgstr ""
-"Kann die Modul Datei nicht erstellen:\n"
+"Kann die Moduldatei nicht erstellen:\n"
"%s"
#. module: base
@@ -4766,7 +4921,7 @@ msgstr "Nauru"
#: code:addons/base/res/res_company.py:166
#, python-format
msgid "Reg"
-msgstr ""
+msgstr "Reg"
#. module: base
#: model:ir.model,name:base.model_ir_property
@@ -4820,7 +4975,7 @@ msgid ""
"Mail delivery failed via SMTP server '%s'.\n"
"%s: %s"
msgstr ""
-"Mail Versand schlug via SMTP Server '%s' fehl.\n"
+"E-Mailversand schlug via SMTP Server '%s' fehl.\n"
"%s: %s"
#. module: base
@@ -4872,6 +5027,40 @@ msgid ""
".. _link: http://puc.com.co/normatividad/\n"
" "
msgstr ""
+"\n"
+"Chart of account for Colombia\n"
+"=============================\n"
+"\n"
+"Source of this chart of account is here_.\n"
+"\n"
+"All the documentation available in this website is embeded in this module, "
+"to\n"
+"be sure when you open OpenERP it has all necesary information to manage \n"
+"accounting en Colombia.\n"
+"\n"
+"The law that enable this chart of account as valid for this country is \n"
+"available in this other link_.\n"
+"\n"
+"This module has the intention to put available out of the box the chart of \n"
+"account for Colombia in Openerp.\n"
+"\n"
+"We recommend install the module account_anglo_sxon to be able to have the "
+"cost\n"
+"accounting correctly setted in out invoices.\n"
+"\n"
+"After installing this module, the Configuration wizard for accounting is "
+"launched.\n"
+" * We have the account templates which can be helpful to generate Charts "
+"of Accounts.\n"
+" * On that particular wizard, you will be asked to pass the name of the "
+"company,\n"
+" the chart template to follow, the no. of digits to generate, the code "
+"for your\n"
+" account and bank account, currency to create journals.\n"
+"\n"
+".. _here: http://puc.com.co/\n"
+".. _link: http://puc.com.co/normatividad/\n"
+" "
#. module: base
#: model:ir.module.module,description:base.module_account_bank_statement_extensions
@@ -4903,9 +5092,9 @@ msgstr ""
"\n"
"Das Module ergänzt:\n"
" - Wertstellungsdatum\n"
-" - Stapel Zahlungen\n"
+" - Stapelzahlungen\n"
" - Nachvollziehbarkeit der Kontobewegungen\n"
-" - Bankauszug Anzeige der einzelnen Positionen\n"
+" - Bankauszuganzeige der einzelnen Positionen\n"
" - Bankkonto Saldo\n"
" - Verbesserte Verarbeitungsgeschwindigkeit beim Import von Auszügen "
"(durch\n"
@@ -4924,7 +5113,7 @@ msgstr "Bereit für Upgrade"
#. module: base
#: model:res.country,name:base.ly
msgid "Libya"
-msgstr "Lybien"
+msgstr "Libyen"
#. module: base
#: model:res.country,name:base.cf
@@ -5015,6 +5204,18 @@ msgid ""
"comptable\n"
"Seddik au cours du troisième trimestre 2010."
msgstr ""
+"\n"
+"This is the base module to manage the accounting chart for Maroc.\n"
+"=================================================================\n"
+"\n"
+"Ce Module charge le modèle du plan de comptes standard Marocain et permet "
+"de\n"
+"générer les états comptables aux normes marocaines (Bilan, CPC (comptes de\n"
+"produits et charges), balance générale à 6 colonnes, Grand livre "
+"cumulatif...).\n"
+"L'intégration comptable a été validé avec l'aide du Cabinet d'expertise "
+"comptable\n"
+"Seddik au cours du troisième trimestre 2010."
#. module: base
#: help:ir.module.module,auto_install:0
@@ -5024,8 +5225,8 @@ msgid ""
"always installed."
msgstr ""
"Ein selbst-installierendes Modul wird installiert, wenn alle Voraussetzungen "
-"erfüllt sind. Sind keine Abhängikeiten installiert, wird das Modul "
-"jedenfalls installiert."
+"erfüllt sind. Sind keine Abhängikeiten installiert, wird das Modul ebenfalls "
+"installiert."
#. module: base
#: model:ir.actions.act_window,name:base.res_lang_act_window
@@ -5049,7 +5250,7 @@ msgstr "Kontenpläne"
#. module: base
#: model:ir.ui.menu,name:base.menu_event_main
msgid "Events Organization"
-msgstr "Event Organisation"
+msgstr "Eventorganisation"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_customer_form
@@ -5072,12 +5273,12 @@ msgstr "Menü :"
#. module: base
#: selection:ir.model.fields,state:0
msgid "Base Field"
-msgstr "Basis Feld"
+msgstr "Basisfeld"
#. module: base
#: model:ir.module.category,name:base.module_category_managing_vehicles_and_contracts
msgid "Managing vehicles and contracts"
-msgstr "Verwaltet Autos und Verträge"
+msgstr "Verwaltet Fahrzeuge und Verträge"
#. module: base
#: model:ir.module.module,description:base.module_base_setup
@@ -5093,7 +5294,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Dieses Modul hilft bei der Einrichtung des Systems bei installation einer "
+"Dieses Modul hilft bei der Einrichtung des Systems bei Installation einer "
"neuen Datenbank.\n"
"==========================================================================\n"
"\n"
@@ -5138,7 +5339,7 @@ msgstr "Essensbestellung, Mahlzeiten, Essen"
#: field:ir.model.fields,required:0
#: field:res.partner.bank.type.field,required:0
msgid "Required"
-msgstr "erforderlich"
+msgstr "Erforderlich"
#. module: base
#: model:res.country,name:base.ro
@@ -5183,13 +5384,12 @@ msgstr ""
"Sie Portale einrichten.\n"
"============================================================================="
"===\n"
-"Ein Portal definiert eine bestimmtes Anwendermenü und Zugriffsrechte für "
+"Ein Portal definiert ein bestimmtes Anwendermenü und Zugriffsrechte für "
"seine Mitglieder. Dieses\n"
"Menü kann von Portalmitgliedern, anonymen Benutzern und anderern Benutzern, "
"die den Zugang\n"
-"hinsichtlich technischer Eigenschaften haben, gesehen werden. (z. B. der "
-"Administrator)\n"
-"Außerdem ist jedes Portalmitglied an einen bestimmten Partner gebunden.\n"
+" haben, gesehen werden. (z. B. der Administrator). Außerdem ist jedes "
+"Portalmitglied an einen bestimmten Partner gebunden.\n"
"\n"
"Das Modul verbindet Benutzergruppen mit den Portal-Nutzern (Hinzufügen zu "
"einer Gruppe\n"
@@ -5252,12 +5452,12 @@ msgstr "Vatikan (Heiliger Stuhl)"
#. module: base
#: field:base.module.import,module_file:0
msgid "Module .ZIP file"
-msgstr "Module .ZIP Datei"
+msgstr "Modul .ZIP Datei"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_17
msgid "Telecom sector"
-msgstr "Telekom Sektor"
+msgstr "Telekomsektor"
#. module: base
#: field:workflow.transition,trigger_model:0
@@ -5283,7 +5483,7 @@ msgstr "Eingehende Übergänge"
#. module: base
#: field:ir.values,value_unpickle:0
msgid "Default value or action reference"
-msgstr "Standard Wert oder Aktions Referenz"
+msgstr "Standardwert oder Aktionsreferenz"
#. module: base
#: model:ir.module.module,description:base.module_note_pad
@@ -5363,13 +5563,13 @@ msgid ""
"\n"
msgstr ""
"\n"
-"OpenERP Web Kalender Ansicht\n"
+"OpenERP Webkalender-Ansicht\n"
"\n"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (HN) / Español (HN)"
-msgstr "Spanish (HN) / Español (HN)"
+msgstr "Spanisch (HN) / Español (HN)"
#. module: base
#: view:ir.sequence.type:0
@@ -5415,15 +5615,15 @@ msgid ""
msgstr ""
"\n"
"=========================================\n"
-"Mit diesem Modul können Sie durch das Menü Berichtswesen / Finanzen / "
-"Finanzen Test eine manuelle Prüfung der Plausibilität Ihrer "
-"Finanzbuchhaltung durchführen und nach möglichen Ungereimtheiten suchen. \n"
+"Mit diesem Modul können Sie durch das Menü Berichtswesen / Finanzen / Finanz-"
+"Tests eine manuelle Prüfung der Plausibilität Ihrer Finanzbuchhaltung "
+"durchführen und nach möglichen Ungereimtheiten suchen. \n"
"\n"
"Sie können eine Abfrage schreiben, um Plausibilitätsprüfungen zu erstellen "
"und erhalten das Ergebnis der Prüfung\n"
"im PDF-Format, auf die Sie über das o.a. Menü zugreifen können. Dort wählen "
-"Sie dann den Test aus und drucken den Bericht durch Klick auf die "
-"Schaltfläche Drucken im Kopfbereich.\n"
+"Sie dann den Test aus und drucken den Bericht durch Klick auf den Button "
+"'Drucken' im Kopfbereich.\n"
#. module: base
#: field:ir.module.module,license:0
@@ -5433,7 +5633,7 @@ msgstr "Lizenz"
#. module: base
#: field:ir.attachment,url:0
msgid "Url"
-msgstr "Url"
+msgstr "URL"
#. module: base
#: selection:ir.translation,type:0
@@ -5504,7 +5704,7 @@ msgid ""
" * Effective Date\n"
msgstr ""
"\n"
-"Ergänzen Sie zusätzliche Datum Informationen zum Auftrag.\n"
+"Ergänzen Sie zusätzliche Datumsinformationen zum Auftrag.\n"
"=========================================================\n"
"\n"
"Sie können die folgenden zusätzlichen Daten zu einem Kundenauftrag "
@@ -5513,7 +5713,7 @@ msgstr ""
"--------------------------------------\n"
" * Wunschtermin\n"
" * Bestätigter Termin\n"
-" * tatsächlicher Termin\n"
+" * Tatsächlicher Termin\n"
#. module: base
#: field:ir.actions.server,srcmodel_id:0
@@ -5526,7 +5726,7 @@ msgstr ""
#: field:ir.model.relation,model:0
#: view:ir.values:0
msgid "Model"
-msgstr "Standard"
+msgstr "Modell"
#. module: base
#: view:base.language.install:0
@@ -5535,7 +5735,7 @@ msgid ""
"preferences of the user and open a new menu to view the changes."
msgstr ""
"Die ausgewählte Sprache wurde installiert. Sie müssen die Vorgaben für den "
-"Benutzer ändern und eine neues Menü öffnen um die neue Spache zu sehen."
+"Benutzer ändern und ein neues Menü öffnen um die neue Sprache zu sehen."
#. module: base
#: field:ir.actions.act_window.view,view_id:0
@@ -5549,7 +5749,7 @@ msgstr "Ansicht"
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "no"
-msgstr "Nein"
+msgstr "nein"
#. module: base
#: model:ir.module.module,description:base.module_crm_partner_assign
@@ -5644,11 +5844,49 @@ msgid ""
"Accounts in OpenERP: the first with the type 'RIB', the second with the type "
"'IBAN'. \n"
msgstr ""
+"\n"
+"This module lets users enter the banking details of Partners in the RIB "
+"format (French standard for bank accounts details).\n"
+"============================================================================="
+"==============================================\n"
+"\n"
+"RIB Bank Accounts can be entered in the \"Accounting\" tab of the Partner "
+"form by specifying the account type \"RIB\". \n"
+"\n"
+"The four standard RIB fields will then become mandatory:\n"
+"-------------------------------------------------------- \n"
+" - Bank Code\n"
+" - Office Code\n"
+" - Account number\n"
+" - RIB key\n"
+" \n"
+"As a safety measure, OpenERP will check the RIB key whenever a RIB is saved, "
+"and\n"
+"will refuse to record the data if the key is incorrect. Please bear in mind "
+"that\n"
+"this can only happen when the user presses the 'save' button, for example on "
+"the\n"
+"Partner Form. Since each bank account may relate to a Bank, users may enter "
+"the\n"
+"RIB Bank Code in the Bank form - it will the pre-fill the Bank Code on the "
+"RIB\n"
+"when they select the Bank. To make this easier, this module will also let "
+"users\n"
+"find Banks using their RIB code.\n"
+"\n"
+"The module base_iban can be a useful addition to this module, because French "
+"banks\n"
+"are now progressively adopting the international IBAN format instead of the "
+"RIB format.\n"
+"The RIB and IBAN codes for a single account can be entered by recording two "
+"Bank\n"
+"Accounts in OpenERP: the first with the type 'RIB', the second with the type "
+"'IBAN'. \n"
#. module: base
#: model:res.country,name:base.ps
msgid "Palestinian Territory, Occupied"
-msgstr "Palästiensische Autonomiegebiete"
+msgstr "Palästinensische Autonomiegebiete"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_ch
@@ -5677,7 +5915,7 @@ msgstr "Als \"Zu erledigen\" setzen"
#. module: base
#: view:res.lang:0
msgid "%c - Appropriate date and time representation."
-msgstr "%c - Datums und Zeitangabe."
+msgstr "%c - Datums- und Zeitangabe."
#. module: base
#: code:addons/base/res/res_config.py:420
@@ -5748,18 +5986,18 @@ msgstr "Postausgang-Server (SMTP)"
#, python-format
msgid "You try to remove a module that is installed or will be installed"
msgstr ""
-"Sie versuchen ein Modul zu entfernen welches bereits installiert ist oder "
-"soeben in Installation begriffen ist"
+"Sie versuchen ein Modul zu entfernen, welches bereits installiert ist oder "
+"soeben installiert wird."
#. module: base
#: view:base.module.upgrade:0
msgid "The selected modules have been updated / installed !"
-msgstr "Die gewählten Module wurden aktualisiert / installiert"
+msgstr "Die gewählten Module wurden aktualisiert / installiert."
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (PR) / Español (PR)"
-msgstr "Spanish (PR) / Español (PR)"
+msgstr "Spanisch (PR) / Español (PR)"
#. module: base
#: model:ir.module.module,description:base.module_crm_profiling
@@ -5786,18 +6024,18 @@ msgstr ""
"Diese Anwendung ermöglicht eine Segmentierung von Partnern\n"
"====================================================\n"
"\n"
-"Die Profile Funktion aus der früheren Segmentierung Anwendung wurde als "
+"Die Profilfunktion aus der früheren Segmentierung Anwendung wurde als "
"Grundlage genommen und verbessert. \n"
"Durch Verwendung des neuen Konzepts für Fragebögen können Sie jetzt auch "
"einzelne Fragen aus einem Fragebogen direkt \n"
"bei einem Partner verwenden und zur Segmentierung anwenden. \n"
"\n"
"Es erfolgte eine Zusammenführung mit den Features der früheren CRM & SRM "
-"Segmentierung Anwendung, da sich einige überlappende Funktionalitäten "
+"Segmentierungsanwendung, da sich einige überlappende Funktionalitäten "
"ergeben haben . \n"
"\n"
" ** Hinweis: ** Diese Anwendung ist nicht kompatibel mit der Anwendung "
-"Segmentierung, da die Plattform prinzipiell identisch ist.\n"
+"Segmentierung, da es umbenannt wurde.\n"
" "
#. module: base
@@ -5813,7 +6051,7 @@ msgid ""
"object.partner_id.name ]]`"
msgstr ""
"E-Mail Inhalt, der auch Python Ausdrücke in doppelten Klammern enthalten "
-"kann, ähnlich wie ein Bedingungsfeld, z.B. `Sehr Geehrte(r) [[ "
+"kann, ähnlich wie ein Bedingungsfeld, z.B. `Sehr geehrte(r) [[ "
"object.partner_id.name ]]`"
#. module: base
@@ -5836,17 +6074,17 @@ msgstr "Portugiesisch (BR)"
#. module: base
#: model:ir.model,name:base.model_ir_needaction_mixin
msgid "ir.needaction_mixin"
-msgstr ""
+msgstr "ir.needaction_mixin"
#. module: base
#: view:base.language.export:0
msgid "This file was generated using the universal"
-msgstr "Die Dateianzeige wurde von der Standard Sprache generiert"
+msgstr "Die Dateianzeige wurde von der Standardsprache generiert"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_7
msgid "IT Services"
-msgstr "IT Services"
+msgstr "IT-Services"
#. module: base
#: model:ir.module.category,name:base.module_category_specific_industry_applications
@@ -5905,7 +6143,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung fügt Status, Datum Beginn, Datum Ende im Aktenreiter "
+"Diese Anwendung fügt Status, Beginndatum, Enddatum im Aktenreiter "
"Arbeitsaufträge hinzu\n"
"============================================================================="
"=\n"
@@ -5922,23 +6160,23 @@ msgstr ""
"Dieses ist eine Ansicht auf 'Arbeitsaufträge' Positionen eines "
"Fertigungsauftrags.\n"
"\n"
-"Neue Schaltflächen in der Formular Ansicht des Fertigungsauftrags im "
+"Neuer Button in der Formularansicht des Fertigungsauftrags im "
"\"Arbeitsaufträge\" Aktenreiter:\n"
"-----------------------------------------------------------------------------"
"-----------------------------------------------------------------------------"
"----------\n"
-" * Start (Ändert Status auf In Bearbeitung), Startdatum\n"
-" * Erledigt (Ändert Status auf Erledigt), Endedatum\n"
-" * Zurücksetzen (Ändert Status auf Entwurf)\n"
-" * Abbrechen (Ändert Status auf Abgebrochen)\n"
+" * Start (ändert Status auf 'In Bearbeitung'), Startdatum\n"
+" * Erledigt (ändert Status auf 'Erledigt'), Enddatum\n"
+" * Zurücksetzen (ändert Status auf 'Entwurf')\n"
+" * Abbrechen (ändert Status auf 'Abgebrochen')\n"
"\n"
-"Wenn der Fertigungsauftrag 'Bereit zur Produktion \"ist, müssen die "
+"Wenn der Fertigungsauftrag 'Bereit zur Produktion' ist, müssen die "
"Arbeitspositionen\n"
"\"bestätigt\" werden. Wenn der Produktionsauftrag abgeschlossen wird, "
"müssen\n"
"auch alle Arbeitspositionen erledigt sein.\n"
"\n"
-"Das Feld 'Arbeitsstunden' ist die Zeitspanne zwischen Endedatum - "
+"Das Feld 'Arbeitsstunden' ist die Zeitspanne zwischen Enddatum - "
"Startdatum.\n"
"Hierdurch kann dann die theoretische Auftragsdauer mit der tatsächlichen \n"
"Dauer verglichen werden. \n"
@@ -5962,7 +6200,7 @@ msgstr "Lesotho"
#. module: base
#: view:base.language.export:0
msgid ", or your preferred text editor"
-msgstr ", oder Ihrem bevorzugten Text Editor"
+msgstr ", oder Ihrem bevorzugten Texteditor"
#. module: base
#: model:ir.module.module,shortdesc:base.module_crm_partner_assign
@@ -5983,7 +6221,7 @@ msgstr "Übersetzte Begriffe"
#. module: base
#: selection:base.language.install,lang:0
msgid "Abkhazian / аҧсуа"
-msgstr "Abkhazian / аҧсуа"
+msgstr "Abchasisch / аҧсуа"
#. module: base
#: view:base.module.configuration:0
@@ -6045,7 +6283,7 @@ msgstr "Benin"
#: model:ir.actions.act_window,name:base.action_res_partner_bank_type_form
#: model:ir.ui.menu,name:base.menu_action_res_partner_bank_typeform
msgid "Bank Account Types"
-msgstr "Bankkonto Typen"
+msgstr "Typen von Bankkonten"
#. module: base
#: help:ir.sequence,suffix:0
@@ -6065,7 +6303,7 @@ msgstr "ir.actions.actions"
#. module: base
#: selection:ir.model.fields,select_level:0
msgid "Not Searchable"
-msgstr "keine Suche möglich"
+msgstr "Keine Suche möglich"
#. module: base
#: view:ir.config_parameter:0
@@ -6169,7 +6407,7 @@ msgstr "Installiert"
#. module: base
#: selection:base.language.install,lang:0
msgid "Ukrainian / українська"
-msgstr "Ukrainian / українська"
+msgstr "Ukrainisch / українська"
#. module: base
#: model:res.country,name:base.sn
@@ -6231,7 +6469,7 @@ msgstr "Ausdruck der gültig sein muss, wenn die Transition erfolgen soll."
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (PA) / Español (PA)"
-msgstr "Spanish (PA) / Español (PA)"
+msgstr "Spanisch (PA) / Español (PA)"
#. module: base
#: view:res.currency:0
@@ -6295,7 +6533,7 @@ msgstr "Datum"
#. module: base
#: model:ir.module.module,shortdesc:base.module_event_moodle
msgid "Event Moodle"
-msgstr "Moodle Veranstaltungen"
+msgstr "Moodle Kurse"
#. module: base
#: model:ir.module.module,description:base.module_email_template
@@ -6428,12 +6666,12 @@ msgstr "Dezimalzeichen"
#: code:addons/orm.py:5319
#, python-format
msgid "Missing required value for the field '%s'."
-msgstr "Es fehlt der verantwortliche Wert für das Feld '%s'."
+msgstr "Ein erforderlicher Wert für das Feld '%s' fehlt."
#. module: base
#: view:ir.rule:0
msgid "Write Access Right"
-msgstr "Schreib Zugangsberechtigung"
+msgstr "Schreibzugriffsberechtigung"
#. module: base
#: model:ir.actions.act_window,help:base.action_res_groups
@@ -6449,14 +6687,14 @@ msgstr ""
"zugewiesen wird und Zugriff für spezifizierte Anwendungen und Aufgaben des "
"Systems ermöglicht. Sie können eigene neue Gruppen definieren oder "
"vorhandene Gruppen modifizieren, um die verfügbaren Ansichten für die "
-"Benutzer der Gruppe zu verwalten. Ausserdem kann auch der Lese, Schreib, "
-"Ausführen und Löschen Zugriff hierüber gesteuert werden."
+"Benutzer der Gruppe zu verwalten. Ausserdem kann auch der Lese-, Schreib,- "
+"Ausführungs- und Löschzugriff hierüber gesteuert werden."
#. module: base
#: view:ir.filters:0
#: field:ir.filters,name:0
msgid "Filter Name"
-msgstr "Filter Bezeichnung"
+msgstr "Filterbezeichnung"
#. module: base
#: view:ir.attachment:0
@@ -6520,7 +6758,7 @@ msgstr ""
#. module: base
#: selection:ir.translation,type:0
msgid "Wizard Button"
-msgstr "Assistent-Taste"
+msgstr "Assistent-Button"
#. module: base
#: view:ir.model.fields:0
@@ -6553,7 +6791,7 @@ msgstr "Sambia"
#. module: base
#: view:ir.actions.todo:0
msgid "Launch Configuration Wizard"
-msgstr "Starte Konfigurations Assistenten"
+msgstr "Starte Konfigurationsassistenten"
#. module: base
#: model:ir.module.module,summary:base.module_mrp
@@ -6563,12 +6801,12 @@ msgstr "Produktionsaufträge, Stücklisten, Arbeitspläne"
#. module: base
#: field:ir.attachment,name:0
msgid "Attachment Name"
-msgstr "Dateianhang Bezeichnung"
+msgstr "Dateianhangbezeichnung"
#. module: base
#: view:ir.module.module:0
msgid "Cancel Upgrade"
-msgstr "Abbrechen"
+msgstr "Upgrade abbrechen"
#. module: base
#: model:ir.module.module,description:base.module_report_webkit
@@ -6629,7 +6867,7 @@ msgid ""
msgstr ""
"\n"
"Dieses Modul fügt einen neue Berichtsanwendung basierend auf WebKit-"
-"Bibliothek (wkhtmltopdf) um Berichte, die in HTML + CSS gestaltet sind "
+"Bibliothek (wkhtmltopdf) um Berichte, die in HTML + CSS gestaltet sind zu "
"unterstützen.\n"
"============================================================================="
"========================================\n"
@@ -6641,16 +6879,16 @@ msgstr ""
"Die Anwendung ermöglicht:\n"
"------------------\n"
"- HTML Berichtsdefinition\n"
-"- MultiKopfzeile Unterstützung\n"
+"- Multi-Kopfzeile Unterstützung\n"
"- Multi-Logo\n"
"- Multi betriebliche Unterstützung\n"
-"- HTML-und CSS-3-Unterstützung (In das Grenze des tatsächlichen WebKit-"
+"- HTML-und CSS-3-Unterstützung (in der Grenze des tatsächlichen WebKit-"
"Version)\n"
"- JavaScript-Unterstützung\n"
"- Raw HTML-Fehlerbeseitiger\n"
"- Buch Druckfunktionen\n"
-"- Seitenränder Festlegung\n"
-"- Papierformat Festlegung\n"
+"- Seitenränder festlegen\n"
+"- Papierformat festlegen\n"
"\n"
"Mehrere Kopfzeilen und Logos können pro Unternehmen festgelegt werden. CSS "
"Stil, Kopf-und\n"
@@ -6681,9 +6919,9 @@ msgstr ""
"der Standardwert ``wkhtmltopdf`` auf Ubuntu dieses Problem habt.\n"
"\n"
"\n"
-"was zu tun ist:\n"
+"Was zu tun ist:\n"
"-----\n"
-"* Unterstützung von JavaScript Aktivierung Deaktivierung\n"
+"* Unterstützung von JavaScript Aktivierung deaktivieren\n"
"* Sortieren und buchen Sie Format-Unterstützung\n"
"* Zip zurück zur getrennten PDF\n"
"* Web-Client WYSIWYG\n"
@@ -6712,7 +6950,7 @@ msgstr "%w - Wochentagnummer [0(Sunday),6]."
#: field:ir.attachment,res_name:0
#: field:ir.ui.view_sc,resource:0
msgid "Resource Name"
-msgstr "Ressource Bezeichnung"
+msgstr "Ressourcen-Bezeichnung"
#. module: base
#: model:ir.ui.menu,name:base.menu_ir_filters
@@ -6770,13 +7008,13 @@ msgstr "Montserrat"
#. module: base
#: model:ir.module.module,shortdesc:base.module_decimal_precision
msgid "Decimal Precision Configuration"
-msgstr "Dezimalstellen Konfiguration"
+msgstr "Dezimalstellen-Konfiguration"
#. module: base
#: model:ir.model,name:base.model_ir_actions_act_url
#: selection:ir.ui.menu,action:0
msgid "ir.actions.act_url"
-msgstr ""
+msgstr "ir.actions.act_url"
#. module: base
#: model:ir.ui.menu,name:base.menu_translation_app
@@ -6815,12 +7053,12 @@ msgstr "Englisch (UK)"
#. module: base
#: selection:base.language.install,lang:0
msgid "Japanese / 日本語"
-msgstr "Japanese / 日本語"
+msgstr "Japanisch / 日本語"
#. module: base
#: model:ir.model,name:base.model_base_language_import
msgid "Language Import"
-msgstr "Sprache Import"
+msgstr "Sprachimport"
#. module: base
#: help:workflow.transition,act_from:0
@@ -6828,7 +7066,7 @@ msgid ""
"Source activity. When this activity is over, the condition is tested to "
"determine if we can start the ACT_TO activity."
msgstr ""
-"Quell-Aktivität. Wenn diese beendet ist wird die Bedingung getestet um "
+"Quell-Aktivität. Wenn diese beendet ist, wird die Bedingung getestet um "
"festzustellen ob ACT_TO Aktivität begonnen werden kann."
#. module: base
@@ -6888,10 +7126,10 @@ msgstr ""
"\n"
"Nach der Installation dieser Anwendung werden die eingegebenen Werte im "
"Bereich\n"
-"der Mehrwertsteuer der Partner wird für alle unterstützten Ländern "
-"validiert. Das Land\n"
-"wird von abgeleitetet von dem 2-Buchstaben-Ländercode, der der "
-"Mehrwertsteuer-Nummer\n"
+"der Mehrwertsteuer der Partner für alle unterstützten Ländern validiert. Das "
+"Land\n"
+"wird abgeleitetet von dem 2-Buchstaben-Ländercode, der der Mehrwertsteuer-"
+"Nummer\n"
"vorangestellt ist, z. B. wird BE0477472701 nach den belgischen Vorschriften "
"validiert.\n"
"\n"
@@ -7041,12 +7279,12 @@ msgstr "Titel"
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "true"
-msgstr "Wahr"
+msgstr "wahr"
#. module: base
#: model:ir.model,name:base.model_base_language_install
msgid "Install Language"
-msgstr "Installiere Sprache"
+msgstr "Sprache installieren"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_11
@@ -7081,7 +7319,7 @@ msgstr "Finanzen & Controlling"
#. module: base
#: field:ir.actions.server,write_id:0
msgid "Write Id"
-msgstr "SchreibID"
+msgstr "Schreib ID"
#. module: base
#: model:ir.ui.menu,name:base.menu_product
@@ -7204,14 +7442,14 @@ msgid ""
"deleting it (if you delete a native record rule, it may be re-created when "
"you reload the module."
msgstr ""
-"Wenn Sie das Aktiv Feld deaktivieren, wird dieser Eintrag deaktiviert ohne "
+"Wenn Sie das Aktiv-Feld deaktivieren, wird dieser Eintrag deaktiviert ohne "
"dabei gelöscht zu werden (wenn Sie eine systemeigene Datensatz Regel "
"löschen, kann diese beim erneuten Laden des Moduls erneut erstellt werden)."
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (BO) / Español (BO)"
-msgstr "Spanish (BO) / Español (BO)"
+msgstr "Spanisch (BO) / Español (BO)"
#. module: base
#: model:ir.module.module,description:base.module_board
@@ -7246,12 +7484,14 @@ msgstr "USA kleinere amerikanische Überseeinseln"
msgid ""
"How many times the method is called,\n"
"a negative number indicates no limit."
-msgstr "Wie oft diese Methode aufgerufen wurde"
+msgstr ""
+"Wie oft diese Methode aufgerufen wurde,\n"
+"eine negative Zahl bedeutet: kein Limit."
#. module: base
#: field:res.partner.bank.type.field,bank_type_id:0
msgid "Bank Type"
-msgstr "Bank Typ"
+msgstr "Banktyp"
#. module: base
#: code:addons/base/res/res_users.py:99
@@ -7309,7 +7549,7 @@ msgstr "res.partner.title"
#. module: base
#: view:res.partner.bank:0
msgid "Bank Account Owner"
-msgstr "Bankkonto Eigentümer"
+msgstr "Eigentümer des Bankkontos"
#. module: base
#: model:ir.module.category,name:base.module_category_uncategorized
@@ -7351,9 +7591,9 @@ msgid ""
"form, signal tests the name of the pressed button. If signal is NULL, no "
"button is necessary to validate this transition."
msgstr ""
-"Wenn der Transition durch eine Schaltfläche im Anwendungsprogramm ausgelöst "
-"wird, wird der Name der gedrückten Schaltfläche getestet. Wenn das Signal "
-"NULL ist, dann ist keine Schaltfläche für die Validierung notwendig."
+"Wenn der Transition durch einen Button im Anwendungsprogramm ausgelöst wird, "
+"wird der Name des gedrückten Buttons getestet. Wenn das Signal NULL ist, "
+"dann ist kein Button für die Validierung notwendig."
#. module: base
#: field:ir.ui.view.custom,ref_id:0
@@ -7394,12 +7634,12 @@ msgstr "Meine Banken"
#. module: base
#: sql_constraint:ir.filters:0
msgid "Filter names must be unique"
-msgstr "Filter Bezeichnungen müssen einmalig sein"
+msgstr "Filterbezeichnungen müssen einmalig sein"
#. module: base
#: help:multi_company.default,object_id:0
msgid "Object affected by this rule"
-msgstr "Objekt, dass von dieser Regel betroffen ist."
+msgstr "Objekt, das von dieser Regel betroffen ist."
#. module: base
#: selection:ir.actions.act_window,target:0
@@ -7409,7 +7649,7 @@ msgstr "Inline Anzeige"
#. module: base
#: field:ir.filters,is_default:0
msgid "Default filter"
-msgstr "Standard Filter"
+msgstr "Standardfilter"
#. module: base
#: report:ir.module.reference:0
@@ -7419,7 +7659,7 @@ msgstr "Verzeichnis"
#. module: base
#: field:wizard.ir.model.menu.create,name:0
msgid "Menu Name"
-msgstr "Menü Bezeichnung"
+msgstr "Menübezeichnung"
#. module: base
#: field:ir.values,key2:0
@@ -7522,6 +7762,98 @@ msgid ""
"If required, you can manually adjust the descriptions via the CODA "
"configuration menu.\n"
msgstr ""
+"\n"
+"Module to import CODA bank statements.\n"
+"======================================\n"
+"\n"
+"Supported are CODA flat files in V2 format from Belgian bank accounts.\n"
+"----------------------------------------------------------------------\n"
+" * CODA v1 support.\n"
+" * CODA v2.2 support.\n"
+" * Foreign Currency support.\n"
+" * Support for all data record types (0, 1, 2, 3, 4, 8, 9).\n"
+" * Parsing & logging of all Transaction Codes and Structured Format \n"
+" Communications.\n"
+" * Automatic Financial Journal assignment via CODA configuration "
+"parameters.\n"
+" * Support for multiple Journals per Bank Account Number.\n"
+" * Support for multiple statements from different bank accounts in a "
+"single \n"
+" CODA file.\n"
+" * Support for 'parsing only' CODA Bank Accounts (defined as type='info' "
+"in \n"
+" the CODA Bank Account configuration records).\n"
+" * Multi-language CODA parsing, parsing configuration data provided for "
+"EN, \n"
+" NL, FR.\n"
+"\n"
+"The machine readable CODA Files are parsed and stored in human readable "
+"format in \n"
+"CODA Bank Statements. Also Bank Statements are generated containing a subset "
+"of \n"
+"the CODA information (only those transaction lines that are required for the "
+"\n"
+"creation of the Financial Accounting records). The CODA Bank Statement is a "
+"\n"
+"'read-only' object, hence remaining a reliable representation of the "
+"original\n"
+"CODA file whereas the Bank Statement will get modified as required by "
+"accounting \n"
+"business processes.\n"
+"\n"
+"CODA Bank Accounts configured as type 'Info' will only generate CODA Bank "
+"Statements.\n"
+"\n"
+"A removal of one object in the CODA processing results in the removal of the "
+"\n"
+"associated objects. The removal of a CODA File containing multiple Bank \n"
+"Statements will also remove those associated statements.\n"
+"\n"
+"The following reconciliation logic has been implemented in the CODA "
+"processing:\n"
+"-----------------------------------------------------------------------------"
+"--\n"
+" 1) The Company's Bank Account Number of the CODA statement is compared "
+"against \n"
+" the Bank Account Number field of the Company's CODA Bank Account \n"
+" configuration records (whereby bank accounts defined in type='info' \n"
+" configuration records are ignored). If this is the case an 'internal "
+"transfer'\n"
+" transaction is generated using the 'Internal Transfer Account' field "
+"of the \n"
+" CODA File Import wizard.\n"
+" 2) As a second step the 'Structured Communication' field of the CODA "
+"transaction\n"
+" line is matched against the reference field of in- and outgoing "
+"invoices \n"
+" (supported : Belgian Structured Communication Type).\n"
+" 3) When the previous step doesn't find a match, the transaction "
+"counterparty is \n"
+" located via the Bank Account Number configured on the OpenERP "
+"Customer and \n"
+" Supplier records.\n"
+" 4) In case the previous steps are not successful, the transaction is "
+"generated \n"
+" by using the 'Default Account for Unrecognized Movement' field of the "
+"CODA \n"
+" File Import wizard in order to allow further manual processing.\n"
+"\n"
+"In stead of a manual adjustment of the generated Bank Statements, you can "
+"also \n"
+"re-import the CODA after updating the OpenERP database with the information "
+"that \n"
+"was missing to allow automatic reconciliation.\n"
+"\n"
+"Remark on CODA V1 support:\n"
+"~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+"In some cases a transaction code, transaction category or structured \n"
+"communication code has been given a new or clearer description in CODA "
+"V2.The\n"
+"description provided by the CODA configuration tables is based upon the CODA "
+"\n"
+"V2.2 specifications.\n"
+"If required, you can manually adjust the descriptions via the CODA "
+"configuration menu.\n"
#. module: base
#: view:ir.attachment:0
@@ -7543,12 +7875,12 @@ msgstr "Inkrementierung muss positiv sein"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_cancel
msgid "Cancel Journal Entries"
-msgstr "Storniere Journaleinträge"
+msgstr "Journaleinträge stornieren"
#. module: base
#: field:res.partner,tz_offset:0
msgid "Timezone offset"
-msgstr "Zeitzonen Differenz"
+msgstr "Zeitzonendifferenz"
#. module: base
#: model:ir.module.module,description:base.module_marketing_campaign
@@ -7599,9 +7931,9 @@ msgstr ""
"------------------------------------------------------------------------\n"
" * Erstellen Sie Marketing-Kampagnen wie Workflows, einschließlich E-Mail-"
"Vorlagen zum \n"
-" Versenden, Berichte auszudrucken und per E-Mail zu versenden, "
+" Versenden, Berichte ausdrucken und per E-Mail versenden, "
"benutzerdefinierte Aktionen \n"
-" * Definieren Sie Eingabe Segmente, die die Elemente auswählen, die der "
+" * Definieren Sie Eingabesegmente, die die Elemente auswählen, die der "
"Kampagne hinzugefügt\n"
" werden sollen (z. B. Interessenten aus bestimmten Ländern). \n"
" * Führen Sie Kampagne im Simulationsmodus aus, um diese in Echtzeit zu "
@@ -7713,7 +8045,7 @@ msgstr ""
#. module: base
#: field:base.module.update,add:0
msgid "Number of modules added"
-msgstr "Anzahl neuer Module"
+msgstr "Anzahl neu hinzugefügter Module"
#. module: base
#: view:res.currency:0
@@ -7723,12 +8055,12 @@ msgstr "Preis Dezimalstellen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Latvian / latviešu valoda"
-msgstr "Latvian / latviešu valoda"
+msgstr "Lettisch / latviešu valoda"
#. module: base
#: selection:base.language.install,lang:0
msgid "French / Français"
-msgstr "French / Français"
+msgstr "Französisch / Français"
#. module: base
#: view:ir.module.module:0
@@ -7794,6 +8126,34 @@ msgid ""
" http://www.rrif.hr/dok/preuzimanje/rrif-rp2012.rar\n"
"\n"
msgstr ""
+"\n"
+"Croatian localisation.\n"
+"======================\n"
+"\n"
+"Author: Goran Kliska, Slobodni programi d.o.o., Zagreb\n"
+" http://www.slobodni-programi.hr\n"
+"\n"
+"Contributions:\n"
+" Tomislav Bošnjaković, Storm Computers: tipovi konta\n"
+" Ivan Vađić, Slobodni programi: tipovi konta\n"
+"\n"
+"Description:\n"
+"\n"
+"Croatian Chart of Accounts (RRIF ver.2012)\n"
+"\n"
+"RRIF-ov računski plan za poduzetnike za 2012.\n"
+"Vrste konta\n"
+"Kontni plan prema RRIF-u, dorađen u smislu kraćenja naziva i dodavanja "
+"analitika\n"
+"Porezne grupe prema poreznoj prijavi\n"
+"Porezi PDV obrasca\n"
+"Ostali porezi \n"
+"Osnovne fiskalne pozicije\n"
+"\n"
+"Izvori podataka:\n"
+" http://www.rrif.hr/dok/preuzimanje/rrif-rp2011.rar\n"
+" http://www.rrif.hr/dok/preuzimanje/rrif-rp2012.rar\n"
+"\n"
#. module: base
#: view:ir.actions.act_window:0
@@ -7823,14 +8183,14 @@ msgstr "Curaçao"
#. module: base
#: view:ir.sequence:0
msgid "Current Year without Century: %(y)s"
-msgstr "Aktuelles Jahr ohne Jahrhundert: %(y)s"
+msgstr "Aktuelles Jahr (zweistellig): %(y)s"
#. module: base
#: model:ir.actions.act_window,name:base.ir_config_list_action
#: view:ir.config_parameter:0
#: model:ir.ui.menu,name:base.ir_config_menu
msgid "System Parameters"
-msgstr "System Parameter"
+msgstr "Systemparameter"
#. module: base
#: help:ir.actions.client,tag:0
@@ -7902,7 +8262,7 @@ msgstr "Sudan"
#: field:res.currency.rate,currency_rate_type_id:0
#: view:res.currency.rate.type:0
msgid "Currency Rate Type"
-msgstr "Währungsumrechungs Typ"
+msgstr "Währungsumrechungs-Typ"
#. module: base
#: model:ir.module.module,description:base.module_l10n_fr
@@ -7940,6 +8300,38 @@ msgid ""
"\n"
"**Credits:** Sistheo, Zeekom, CrysaLEAD, Akretion and Camptocamp.\n"
msgstr ""
+"\n"
+"This is the module to manage the accounting chart for France in OpenERP.\n"
+"========================================================================\n"
+"\n"
+"This module applies to companies based in France mainland. It doesn't apply "
+"to\n"
+"companies based in the DOM-TOMs (Guadeloupe, Martinique, Guyane, Réunion, "
+"Mayotte).\n"
+"\n"
+"This localisation module creates the VAT taxes of type 'tax included' for "
+"purchases\n"
+"(it is notably required when you use the module 'hr_expense'). Beware that "
+"these\n"
+"'tax included' VAT taxes are not managed by the fiscal positions provided by "
+"this\n"
+"module (because it is complex to manage both 'tax excluded' and 'tax "
+"included'\n"
+"scenarios in fiscal positions).\n"
+"\n"
+"This localisation module doesn't properly handle the scenario when a France-"
+"mainland\n"
+"company sells services to a company based in the DOMs. We could manage it in "
+"the\n"
+"fiscal positions, but it would require to differentiate between 'product' "
+"VAT taxes\n"
+"and 'service' VAT taxes. We consider that it is too 'heavy' to have this by "
+"default\n"
+"in l10n_fr; companies that sell services to DOM-based companies should "
+"update the\n"
+"configuration of their taxes and fiscal positions manually.\n"
+"\n"
+"**Credits:** Sistheo, Zeekom, CrysaLEAD, Akretion and Camptocamp.\n"
#. module: base
#: model:res.country,name:base.fm
@@ -8006,12 +8398,12 @@ msgstr "Zeitformat"
#. module: base
#: field:res.company,rml_header3:0
msgid "RML Internal Header for Landscape Reports"
-msgstr "RML Interne Kopfzeile für Querfomat Berichte"
+msgstr "RML Interne Kopfzeile für Querfomat-erichte"
#. module: base
#: model:res.groups,name:base.group_partner_manager
msgid "Contact Creation"
-msgstr "Kontakt Anlage"
+msgstr "Kontakt erstellen"
#. module: base
#: view:ir.module.module:0
@@ -8034,7 +8426,7 @@ msgstr "Bericht in xml"
#: view:ir.module.module:0
#: model:ir.ui.menu,name:base.menu_management
msgid "Modules"
-msgstr "Übersicht Module"
+msgstr "Module"
#. module: base
#: view:workflow.activity:0
@@ -8050,7 +8442,7 @@ msgstr "Sub Workflow"
#: view:res.bank:0
#: field:res.partner,bank_ids:0
msgid "Banks"
-msgstr "Bank Verzeichnis"
+msgstr "Bankverzeichnis"
#. module: base
#: model:ir.module.module,description:base.module_web
@@ -8093,7 +8485,7 @@ msgstr "Kann die Module Datei nicht erzeugen: %s!"
#. module: base
#: field:ir.server.object.lines,server_id:0
msgid "Object Mapping"
-msgstr "Objekte Mapping"
+msgstr "Objekt-Mapping"
#. module: base
#: field:ir.module.category,xml_id:0
@@ -8114,7 +8506,7 @@ msgstr "Vereinigtes Königreich"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_pa
msgid "Panama Localization Chart Account"
-msgstr ""
+msgstr "Panama Localization Chart Account"
#. module: base
#: help:res.partner.category,active:0
@@ -8136,7 +8528,7 @@ msgstr "Botswana"
#. module: base
#: view:res.partner.title:0
msgid "Partner Titles"
-msgstr "Partner Gesellschaften"
+msgstr "Partnergesellschaften"
#. module: base
#: code:addons/base/ir/ir_fields.py:196
@@ -8195,7 +8587,7 @@ msgid ""
"this object as this object is for reporting purpose."
msgstr ""
"Sie können diesen Vorgang nicht ausführen. Die Erstellung eines neuen "
-"Datensatzes wurde für dieses Objekt nicht freigegeben, das dieses Objekt "
+"Datensatzes wurde für dieses Objekt nicht freigegeben, da dieses Objekt "
"lediglich für die Auswertungen benötigt wird."
#. module: base
@@ -8256,7 +8648,7 @@ msgstr "Betrag danach"
#. module: base
#: selection:base.language.install,lang:0
msgid "Lithuanian / Lietuvių kalba"
-msgstr "Lithuanian / Lietuvių kalba"
+msgstr "Littauisch / Lietuvių kalba"
#. module: base
#: help:ir.actions.server,record_id:0
@@ -8298,7 +8690,7 @@ msgid ""
"will be overwritten and replaced by those in this file"
msgstr ""
"Wenn Sie diese Option aktivieren, werden bestehende Übersetzungen (inklusive "
-"kundenspezifische) überschrieben und durch den Inhalt der Datei ersetzt."
+"kundenspezifischen) überschrieben und durch den Inhalt der Datei ersetzt."
#. module: base
#: field:ir.ui.view,inherit_id:0
@@ -8316,7 +8708,7 @@ msgstr "Ursprungsbezeichnung"
#: model:ir.ui.menu,name:base.menu_project_config
#: model:ir.ui.menu,name:base.menu_project_report
msgid "Project"
-msgstr "Projekte"
+msgstr "Projekt"
#. module: base
#: field:ir.ui.menu,web_icon_hover_data:0
@@ -8333,7 +8725,7 @@ msgstr "Moduldatei erfolgreich importiert"
#: view:ir.model.constraint:0
#: model:ir.ui.menu,name:base.ir_model_constraint_menu
msgid "Model Constraints"
-msgstr "Model Abhängigkeiten"
+msgstr "Modell-Abhängigkeiten"
#. module: base
#: model:ir.actions.act_window,name:base.action_workflow_transition_form
@@ -8362,6 +8754,11 @@ msgid ""
"============================================================\n"
" "
msgstr ""
+"\n"
+"添加中文省份数据\n"
+"科目类型\\会计科目表模板\\增值税\\辅助核算类别\\管理会计凭证簿\\财务会计凭证簿\n"
+"============================================================\n"
+" "
#. module: base
#: model:res.country,name:base.lc
@@ -8456,8 +8853,8 @@ msgstr ""
"diesem Projekt verbracht hat,\n"
"verursacht dementsprechend Kosten auf dieser Projektkostenstelle. \n"
"\n"
-"Das Modul bietet außerdem Auswertungen zur Rückverfolgung der Mitarbeiter "
-"Arbeitszeit in Projekten.\n"
+"Das Modul bietet außerdem Auswertungen zur Rückverfolgung der "
+"Mitarbeiterarbeitszeit in Projekten.\n"
"Es ist dadurch vollständig in die OpenERP Kostenrechnung integriert und "
"ermöglicht dem Management \n"
"ein effizientes Projektcontrolling.\n"
@@ -8499,7 +8896,7 @@ msgstr "Direkte Installation der Module"
#. module: base
#: view:ir.actions.server:0
msgid "Field Mapping"
-msgstr "Felder Mapping"
+msgstr "Feld- Mapping"
#. module: base
#: field:ir.model.fields,ttype:0
@@ -8528,6 +8925,14 @@ msgid ""
"includes\n"
"taxes and the Quetzal currency."
msgstr ""
+"\n"
+"This is the base module to manage the accounting chart for Guatemala.\n"
+"=====================================================================\n"
+"\n"
+"Agrega una nomenclatura contable para Guatemala. También icluye impuestos y\n"
+"la moneda del Quetzal. -- Adds accounting chart for Guatemala. It also "
+"includes\n"
+"taxes and the Quetzal currency."
#. module: base
#: selection:res.lang,direction:0
@@ -8554,7 +8959,7 @@ msgstr "Vietnam"
#. module: base
#: field:res.users,signature:0
msgid "Signature"
-msgstr "Signatur"
+msgstr "Unterschrift"
#. module: base
#: field:res.partner.category,complete_name:0
@@ -8564,7 +8969,7 @@ msgstr "Vollständiger Name"
#. module: base
#: view:ir.attachment:0
msgid "on"
-msgstr ""
+msgstr "an"
#. module: base
#: view:ir.property:0
@@ -8652,8 +9057,8 @@ msgstr ""
"Verwenden Sie automatisierte Aktionen, um automatisch diese Maßnahmen für "
"verschiedene Rechner auszulösen.\n"
"\n"
-"** Beispiel: ** Interssent A wird von einem bestimmten Benutzer erstellt und "
-"kann automatisch einem bestimmten\n"
+"** Beispiel: ** Interessent A wird von einem bestimmten Benutzer erstellt "
+"und kann automatisch einem bestimmten\n"
"Verkaufsteam zugeordnet werden oder eine Chance, die auch noch nach 14 Tagen "
"den Status \"ausstehend\"\n"
"könnte eine automatische Erinnerungs-E-Mail auslösen.\n"
@@ -8668,7 +9073,7 @@ msgstr "Position"
#: view:res.partner:0
#: field:res.partner,child_ids:0
msgid "Contacts"
-msgstr "Partner Kontakte"
+msgstr "Partner-Kontakte"
#. module: base
#: model:res.country,name:base.fo
@@ -8694,7 +9099,7 @@ msgstr "Ecuador Buchführung"
#. module: base
#: field:res.partner.category,name:0
msgid "Category Name"
-msgstr "Kategorie Bezeichnung"
+msgstr "Kategorienname"
#. module: base
#: model:res.country,name:base.mp
@@ -8773,7 +9178,7 @@ msgstr ""
"Phasen,\n"
" die im Status Entwurf, offene und ausstehend des Projekts gegeben "
"sind. Wenn kein\n"
-" Projekt angegebenen ist, dann werden alle Phase im Entwurf, offen und "
+" Projekt angegebenen ist, dann werden alle Phasen im Entwurf, offen und "
"ausstehend genommen.\n"
" * Berechnung Aufgabenplanung: Diese funktioniert genauso wie die "
"Planerfunktion bei der\n"
@@ -8891,10 +9296,10 @@ msgid ""
"time values: your computer's timezone."
msgstr ""
"Die Zeitzone des Partners wird genutzt, um korrekte Datums- und Zeitwerte "
-"für Druck Berichte anzugeben. Es ist wichitg, einen Wert für dieses Feld "
-"festzulegen. Sie sollten die gleiche Zeitzone nutzen, die sonst verwendet "
-"wird, um Datums- und Zeitwerte zu holen und zu übergeben: Die Zeitzone Ihres "
-"Computers."
+"für den Druck von Berichten anzugeben. Es ist wichtig, einen Wert für dieses "
+"Feld festzulegen. Sie sollten die gleiche Zeitzone nutzen, die sonst "
+"verwendet wird, um Datums- und Zeitwerte zu holen und zu übergeben: Die "
+"Zeitzone Ihres Computers."
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_analytic_default
@@ -8922,17 +9327,17 @@ msgstr "Burundi"
#: view:base.module.configuration:0
#: view:base.module.update:0
msgid "Close"
-msgstr "Fertig"
+msgstr "Schließen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (MX) / Español (MX)"
-msgstr "Spanish (MX) / Español (MX)"
+msgstr "Spanisch (MX) / Español (MX)"
#. module: base
#: view:ir.actions.todo:0
msgid "Wizards to be Launched"
-msgstr "zu startende Assistenten"
+msgstr "Zu startende Assistenten"
#. module: base
#: model:res.country,name:base.bt
@@ -8964,7 +9369,7 @@ msgstr "Nächste Nummer dieser Sequenz"
#. module: base
#: view:res.partner:0
msgid "at"
-msgstr ""
+msgstr "bei"
#. module: base
#: view:ir.rule:0
@@ -9041,7 +9446,7 @@ msgstr "Reklamationsportal"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_pe
msgid "Peru Localization Chart Account"
-msgstr ""
+msgstr "Peru Localization Chart Account"
#. module: base
#: model:ir.module.module,description:base.module_auth_oauth
@@ -9102,7 +9507,7 @@ msgstr "RML Internal Header"
#. module: base
#: field:ir.actions.act_window,search_view_id:0
msgid "Search View Ref."
-msgstr "Suche Ansicht Referenz"
+msgstr "Suche Ansichtsreferenz"
#. module: base
#: help:res.users,partner_id:0
@@ -9140,7 +9545,7 @@ msgstr "Liste der Module, in denen ein Feld definiert ist."
#. module: base
#: selection:base.language.install,lang:0
msgid "Chinese (CN) / 简体中文"
-msgstr "Chinese (CN) / 简体中文"
+msgstr "Chinesisch (CN) / 简体中文"
#. module: base
#: field:ir.model.fields,selection:0
@@ -9244,13 +9649,12 @@ msgstr ""
"============================================\n"
"\n"
"Geben Sie die Werte Ihres POP / IMAP-Kontos / Ihrer Konten ein und alle "
-"eingehenden E-Mails auf\n"
-"diesen Konten werden automatisch in Ihr OpenERP System heruntergeladen. "
-"Alle\n"
-"POP3/IMAP-compatible Servern werden unterstützt, auch diejenigen, die ein\n"
+"eingehenden E-Mails auf diesen Konten werden automatisch in Ihr OpenERP "
+"System heruntergeladen. Alle\n"
+"POP3/IMAP-Kompatible Servern werden unterstützt, auch diejenigen, die eine\n"
"verschlüsseltes SSL / TLS-Verbindung erfordern.\n"
"\n"
-"Dies kann verwendet werden, um auf einfache Weise E-Mail-basierede "
+"Dies kann verwendet werden, um auf einfache Weise E-Mail-basierende "
"Arbeitsabläufe für viele E-Mail-fähigen OpenERP Dokumente zu erstellen, wie "
"zum Beispiel: \n"
"-----------------------------------------------------------------------------"
@@ -9261,7 +9665,7 @@ msgstr ""
" * Projektaufgaben\n"
" * Personalwesen Neueinstellungen (Bewerber)\n"
"\n"
-"Installieren Sie einfach die jeweilige Anwendung, und Sie können jede dieser "
+"Installieren Sie einfach die jeweilige Anwendung und Sie können jede dieser "
"Dokumenttypen\n"
"(Interessenten, Projektprobleme) Ihren eingehenden E-Mail-Konten zuweisen. "
"Neue E-Mails erzeugen\n"
@@ -9300,7 +9704,7 @@ msgid ""
"Allow you to define your own currency rate types, like 'Average' or 'Year to "
"Date'. Leave empty if you simply want to use the normal 'spot' rate type"
msgstr ""
-"Heir können Sie spezielle Währungstpyen Ihres Unternehmens definieren. zB "
+"Hier können Sie spezielle Währungstpyen Ihres Unternehmens definieren. zB "
"\"Durchschnitt\" oder \"Year To Date\". Leer lassen für den normalen "
"Tageskurs"
@@ -9312,7 +9716,7 @@ msgstr "Unbekannt"
#. module: base
#: model:ir.actions.act_window,name:base.action_res_users_my
msgid "Change My Preferences"
-msgstr "Einstellungen jetzt vornehmen"
+msgstr "Einstellungen jetzt ändern"
#. module: base
#: code:addons/base/ir/ir_actions.py:171
@@ -9337,7 +9741,7 @@ msgstr ""
"Registrierungs-Nummer für OpenERP\n"
"======================================================================\n"
"\n"
-"Romanian accounting chart and localization.\n"
+"Rumänischer Kontenrahmen und Loklaisierung.\n"
" "
#. module: base
@@ -9391,17 +9795,17 @@ msgstr "11. %U or %W ==> 48 (49. Woche)"
#. module: base
#: model:ir.model,name:base.model_res_partner_bank_type_field
msgid "Bank type fields"
-msgstr "Bank Typen Felder"
+msgstr "Banktyp-Felder"
#. module: base
#: constraint:ir.rule:0
msgid "Rules can not be applied on Transient models."
-msgstr "Regeln können nicht auf Vorübergehende Varianten angewandt werden"
+msgstr "Regeln können nicht auf vorübergehende Varianten angewandt werden"
#. module: base
#: selection:base.language.install,lang:0
msgid "Dutch / Nederlands"
-msgstr "Dutch / Nederlands"
+msgstr "Niederländisch / Nederlands"
#. module: base
#: selection:res.company,paper_format:0
@@ -9435,15 +9839,13 @@ msgstr ""
#. module: base
#: model:ir.actions.act_window,name:base.bank_account_update
msgid "Company Bank Accounts"
-msgstr "Unternehmens Bankkonten"
+msgstr "Bankkonten des Unternehmens"
#. module: base
#: code:addons/base/res/res_users.py:473
#, python-format
msgid "Setting empty passwords is not allowed for security reasons!"
-msgstr ""
-"Die Vergabe eines nicht ausgefüllten Passwortes ist aus Sucherheitsgründen "
-"nicht erlaubt!"
+msgstr "Leere Passwortfelder sind aus Sucherheitsgründen nicht erlaubt!"
#. module: base
#: help:ir.mail_server,smtp_pass:0
@@ -9489,12 +9891,12 @@ msgstr "Assistent"
#: code:addons/base/ir/ir_fields.py:303
#, python-format
msgid "database id"
-msgstr ""
+msgstr "database id"
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_import
msgid "Base import"
-msgstr "Standard Import"
+msgstr "Standard-Import"
#. module: base
#: report:ir.module.reference:0
@@ -9538,7 +9940,7 @@ msgstr "Objektfeld"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (PE) / Español (PE)"
-msgstr "Spanish (PE) / Español (PE)"
+msgstr "Spanisch (PE) / Español (PE)"
#. module: base
#: selection:base.language.install,lang:0
@@ -9589,7 +9991,7 @@ msgstr ""
#. module: base
#: view:res.partner.bank:0
msgid "Bank accounts belonging to one of your companies"
-msgstr "Bankkonten, die zu einer Ihrer Unternehmen gehören"
+msgstr "Bankkonten, die zu einem Ihrer Unternehmen gehören"
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_plans
@@ -9661,7 +10063,7 @@ msgstr "Aktion der Anwendungsprogramme"
#. module: base
#: field:res.partner.bank.type,field_ids:0
msgid "Type Fields"
-msgstr "Typ Felder"
+msgstr "Typ-Felder"
#. module: base
#: model:ir.module.module,summary:base.module_hr_recruitment
@@ -9746,7 +10148,7 @@ msgstr "Projektmanagement"
#. module: base
#: view:ir.module.module:0
msgid "Cancel Uninstall"
-msgstr "Abbrechen"
+msgstr "Deinstallieren abbrechen"
#. module: base
#: view:res.bank:0
@@ -9761,12 +10163,12 @@ msgstr "Analytische Konten"
#. module: base
#: model:ir.model,name:base.model_ir_model_constraint
msgid "ir.model.constraint"
-msgstr ""
+msgstr "ir.model.constraint"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_graph
msgid "Graph Views"
-msgstr "Diagramm Ansichten"
+msgstr "Diagramm-Ansichten"
#. module: base
#: help:ir.model.relation,name:0
@@ -9781,7 +10183,7 @@ msgid ""
"===================================================\n"
msgstr ""
"\n"
-"Der Kern von OpenERP, der für alle die Installation benötigt wird.\n"
+"Der Kern von OpenERP, der für alle weiteren Installationen benötigt wird.\n"
#. module: base
#: model:ir.model,name:base.model_ir_server_object_lines
@@ -9811,7 +10213,7 @@ msgstr "Management der Zahlungserinnerungen"
#. module: base
#: field:workflow.workitem,inst_id:0
msgid "Instance"
-msgstr "Objekt"
+msgstr "Instanz"
#. module: base
#: help:ir.actions.report.xml,attachment:0
@@ -9821,7 +10223,7 @@ msgid ""
"with the object and time variables."
msgstr ""
"Das ist der Dateiname des Anhanges unter dem Ausdrucke gespeichert werden. "
-"Leer lassen, wenn Ausdrucke nicht gespeichert wreden sollen. Die Verwendung "
+"Leer lassen, wenn Ausdrucke nicht gespeichert werden sollen. Die Verwendung "
"von Python Ausdrücken sowie Objekt und Zeitvariablen ist möglich."
#. module: base
@@ -9868,7 +10270,7 @@ msgstr "Web Icon Grafik"
#. module: base
#: field:ir.actions.server,wkf_model_id:0
msgid "Target Object"
-msgstr "Ziel Objekt"
+msgstr "Zielobjekt"
#. module: base
#: selection:ir.model.fields,select_level:0
@@ -9883,7 +10285,7 @@ msgstr "Bundeslandkürzel (max. 3 Buchstaben)"
#. module: base
#: model:res.country,name:base.hk
msgid "Hong Kong"
-msgstr "Hong Kong"
+msgstr "Hongkong"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_sale
@@ -9916,7 +10318,7 @@ msgid ""
"Model to which this entry applies - helper field for setting a model, will "
"automatically set the correct model name"
msgstr ""
-"Modell, für das dieser EIntrag gilt. Wir automatisch den richtigen "
+"Modell, für das dieser Eintrag gilt. Wird automatisch den richtigen "
"Modellnamen speichern"
#. module: base
@@ -9976,6 +10378,44 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"This is the module to manage the accounting chart for Netherlands in "
+"OpenERP.\n"
+"============================================================================="
+"\n"
+"\n"
+"Read changelog in file __openerp__.py for version information.\n"
+"Dit is een basismodule om een uitgebreid grootboek- en BTW schema voor\n"
+"Nederlandse bedrijven te installeren in OpenERP versie 7.0.\n"
+"\n"
+"De BTW rekeningen zijn waar nodig gekoppeld om de juiste rapportage te "
+"genereren,\n"
+"denk b.v. aan intracommunautaire verwervingen waarbij u 21% BTW moet "
+"opvoeren,\n"
+"maar tegelijkertijd ook 21% als voorheffing weer mag aftrekken.\n"
+"\n"
+"Na installatie van deze module word de configuratie wizard voor 'Accounting' "
+"aangeroepen.\n"
+" * U krijgt een lijst met grootboektemplates aangeboden waarin zich ook "
+"het\n"
+" Nederlandse grootboekschema bevind.\n"
+"\n"
+" * Als de configuratie wizard start, wordt u gevraagd om de naam van uw "
+"bedrijf\n"
+" in te voeren, welke grootboekschema te installeren, uit hoeveel "
+"cijfers een\n"
+" grootboekrekening mag bestaan, het rekeningnummer van uw bank en de "
+"currency\n"
+" om Journalen te creeren.\n"
+"\n"
+"Let op!! -> De template van het Nederlandse rekeningschema is opgebouwd uit "
+"4\n"
+"cijfers. Dit is het minimale aantal welk u moet invullen, u mag het aantal "
+"verhogen.\n"
+"De extra cijfers worden dan achter het rekeningnummer aangevult met "
+"'nullen'.\n"
+"\n"
+" "
#. module: base
#: help:ir.rule,global:0
@@ -10048,13 +10488,13 @@ msgstr ""
"organisieren, persönliche Aufgabenlisten\n"
"zu organisieren, etc. Jeder Benutzer verwaltet seine eigenen persönlichen "
"Notizen. Notizen stehen nur\n"
-"dem Autor zur Verfügung, aber können auch an andere Benutzer freigegeben "
+"dem Autor zur Verfügung, können jedoch auch an andere Benutzer freigegeben "
"werden, sodass mehrere\n"
"Personen an der gleichen Notiz in Echtzeit arbeiten können. Es ist sehr "
"effizient, um Sitzungsprotokolle\n"
"zu teilen.\n"
"\n"
-"Notizen finden Sie in im \"Home\"-Menü.\n"
+"Notizen finden Sie im \"Home\"-Menü.\n"
#. module: base
#: model:res.country,name:base.dm
@@ -10089,7 +10529,7 @@ msgstr "Dokumentenseite"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_ar
msgid "Argentina Localization Chart Account"
-msgstr ""
+msgstr "Argentina Localization Chart Account"
#. module: base
#: field:ir.module.module,description_html:0
@@ -10128,14 +10568,14 @@ msgstr "Individualisierte Ansicht"
#: view:base.module.import:0
#: model:ir.actions.act_window,name:base.action_view_base_module_import
msgid "Module Import"
-msgstr "Modul Import"
+msgstr "Modul-Import"
#. module: base
#: model:ir.actions.act_window,name:base.act_values_form_action
#: model:ir.ui.menu,name:base.menu_values_form_action
#: view:ir.values:0
msgid "Action Bindings"
-msgstr "Aktions Bindungen"
+msgstr "Aktionsbindungen"
#. module: base
#: help:res.partner,lang:0
@@ -10180,7 +10620,7 @@ msgid ""
"to perform a periodical evaluation of their colleagues.\n"
msgstr ""
"\n"
-"Regelmäßige Mitarbeiter Bewertung und Beurteilungen\n"
+"Regelmäßige Mitarbeiterbewertung und Beurteilungen\n"
"=============================================\n"
"\n"
"Durch die Nutzung dieser Anwendung erhalten Sie die erforderliche "
@@ -10189,11 +10629,11 @@ msgstr ""
"und externen Mitarbeiter können sowohl die Mitarbeiter als auch Ihr "
"Unternehmen profitieren. \n"
"\n"
-"Eine Bewertungsplan kann hierzu jedem Mitarbeiter zugeordnet werden. Diese "
-"Pläne definieren die Häufigkeit und die Art und Weise, wie Sie Ihre "
-"regelmäßigen persönlichen Auswertungen verwalten. Sie werden in der Lage "
-"sein, Maßnahmen zur Personalentwicklung zu definieren und Fragebögen zu "
-"jedem einzelnen Schritt anzuhängen. \n"
+"Eine Bewertungsplan kann jedem Mitarbeiter zugeordnet werden. Diese Pläne "
+"definieren die Häufigkeit und die Art und Weise, wie Sie Ihre regelmäßigen "
+"persönlichen Auswertungen verwalten. Sie werden in der Lage sein, Maßnahmen "
+"zur Personalentwicklung zu definieren und Fragebögen zu jedem einzelnen "
+"Schritt anzuhängen. \n"
"\n"
"Verwalten Sie dabei Mitarbeiterbewertungen in bi-direktionaler Weise: In der "
"Mitarbeiterhierachie von unten nach oben, von oben nach unten, "
@@ -10202,10 +10642,10 @@ msgstr ""
"\n"
"Wesentliche Funktionen der Anwendung\n"
"-------------------------------------------------\n"
-"* Möglichkeit Mitarbeiter Bewertungen zu erstellen.\n"
+"* Möglichkeit Mitarbeiterbewertungen zu erstellen.\n"
"* Eine Bewertung kann dabei von einem Mitarbeiter für dessen untergeordnete "
-"Kollegen oder Auszubildende sowie seinem entgegengesetzt in Richtung seines "
-"vorgesetzten Managers erstellt werden.\n"
+"Kollegen oder Auszubildende sowie für seinen vorgesetzten Managers erstellt "
+"werden.\n"
"* Die Bewertung erfolgt nach einem definierten Plan, bei dem verschiedene "
"Umfragen erzeugt werden können. Jede Umfrage kann dabei von einer bestimmten "
"Hierarchieebene der Mitarbeiter beantwortet werden. Die abschließende "
@@ -10228,13 +10668,13 @@ msgstr "Update der Module"
msgid ""
"Unable to upgrade module \"%s\" because an external dependency is not met: %s"
msgstr ""
-"Es ist nicht möglich das Modul \"%s\" upzudaten, da folgende externe "
-"Moduleabhängigkeit nicht erfüllt werden konnte: \"%s\""
+"Es ist nicht möglich, das Modul \"%s\" upzudaten, da folgende externe "
+"Modulabhängigkeit nicht erfüllt werden konnte: \"%s\""
#. module: base
#: model:ir.module.module,shortdesc:base.module_account
msgid "eInvoicing"
-msgstr "eRechnung"
+msgstr "E-Rechnung"
#. module: base
#: code:addons/base/res/res_users.py:171
@@ -10247,7 +10687,7 @@ msgid ""
msgstr ""
"Bitte bedenken Sie, dass aktuell angezeigte Ansichten und Formulare nicht "
"zwingend bei einem anderen Unternehmen (Mandant) auch vorhanden sind. Wenn "
-"Sie noch nicht abgespeicherte Änderungen haben, sichern Sie bitte, dass alle "
+"Sie noch nicht abgespeicherte Änderungen haben, denken Sie daran, dass alle "
"Formulare vor Beendigung nochmals gespeichert werden."
#. module: base
@@ -10264,7 +10704,7 @@ msgstr "Weiter"
#. module: base
#: selection:base.language.install,lang:0
msgid "Thai / ภาษาไทย"
-msgstr "Thailand / ภาษาไทย"
+msgstr "Thailändisch / ภาษาไทย"
#. module: base
#: model:ir.module.module,description:base.module_l10n_bo
@@ -10276,6 +10716,12 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"Bolivian accounting chart and tax localization.\n"
+"\n"
+"Plan contable boliviano e impuestos de acuerdo a disposiciones vigentes\n"
+"\n"
+" "
#. module: base
#: view:res.lang:0
@@ -10285,7 +10731,7 @@ msgstr "%j - Tag des Jahres [001,366]."
#. module: base
#: selection:base.language.install,lang:0
msgid "Slovenian / slovenščina"
-msgstr "Slovenian / slovenščina"
+msgstr "Slovenisch / slovenščina"
#. module: base
#: field:res.currency,position:0
@@ -10316,7 +10762,7 @@ msgstr ""
#. module: base
#: field:ir.actions.report.xml,attachment_use:0
msgid "Reload from Attachment"
-msgstr "Erneuert Laden vom Anhang"
+msgstr "Erneut aus Anhang laden"
#. module: base
#: model:res.country,name:base.mx
@@ -10333,7 +10779,7 @@ msgid ""
"(Document type: %s)"
msgstr ""
"Für diese Art Dokument, kann es sinnvoll sein, nur auf die selbst erstellten "
-"Dokumente zuzugreifen.\n"
+"Datensätze zuzugreifen.\n"
"\n"
"(Dokumententyp: %s)"
@@ -10348,7 +10794,7 @@ msgid ""
"This field specifies whether the model is transient or not (i.e. if records "
"are automatically deleted from the database or not)"
msgstr ""
-"Diese Feld legt fest, ob das Model 'transient' oder nicht (z.B. wenn "
+"Diese Feld legt fest, ob das Modell 'transient' ist oder nicht (z.B. wenn "
"Datensätze automatisch aus der Datenbank gelöscht werden sollen oder nicht)"
#. module: base
@@ -10373,7 +10819,7 @@ msgstr "Datei"
#. module: base
#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_install
msgid "Module Upgrade Install"
-msgstr "Durchführung der Modul Aktualisierung"
+msgstr "Durchführung der Modul-Aktualisierung"
#. module: base
#: model:ir.model,name:base.model_ir_actions_configuration_wizard
@@ -10439,17 +10885,17 @@ msgstr ""
"==================================\n"
"Mit dieser Anwendung hilft OpenERP Ihnen bei der Verwaltung Ihre Fahrzeuge,\n"
"die Verträge für diese Fahrzeuge sowie Dienstleistungen, Kraftstoff,\n"
-"Fahrtbucheinträge, Kosten und viele andere Funktionen, die notwendig sind "
+"Fahrtenbucheinträge, Kosten und viele andere Funktionen, die notwendig sind "
"um\n"
"ihren Fuhrpark zu verwalten. \n"
"\n"
"Hauptfunktionen\n"
"-------------\n"
-"* Hinzufügen von Fahrzeugen zu Ihrem Fuhrpark\n"
+"* Hinzufügen von Fahrzeugen aus Ihrem Fuhrpark\n"
"* Verwalten von Verträgen für Fahrzeuge\n"
"* Erinnerungen wenn ein Vertrag ausläuft\n"
"* Hinzufügen von Dienstleistungen, Kraftstoff und Fahrtbucheinträge, "
-"Kilometerzähler Werte für alle Fahrzeuge\n"
+"Kilometerzähler, Werte für alle Fahrzeuge\n"
"* Alle Kosten aufzeigen, die mit einem Fahrzeug oder einer Art von "
"Dienstleistung zusammenhängen\n"
"* Auswertungsgrafik für die Kosten\n"
@@ -10457,12 +10903,12 @@ msgstr ""
#. module: base
#: field:multi_company.default,company_dest_id:0
msgid "Default Company"
-msgstr "Standard Mandant"
+msgstr "Standard-Mandant"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (EC) / Español (EC)"
-msgstr "Spanish (EC) / Español (EC)"
+msgstr "Spanisch (EC) / Español (EC)"
#. module: base
#: help:ir.ui.view,xml_id:0
@@ -10482,17 +10928,17 @@ msgstr "Amerikanisch-Samoa"
#. module: base
#: view:ir.attachment:0
msgid "My Document(s)"
-msgstr "Meine Dokumente"
+msgstr "Mein(e) Dokument(e)"
#. module: base
#: help:ir.actions.act_window,res_model:0
msgid "Model name of the object to open in the view window"
-msgstr "Name der Modells, dass in dem neuen Fenser geöffnet werden soll."
+msgstr "Modellname, dass in dem neuen Fenster geöffnet werden soll."
#. module: base
#: field:ir.model.fields,selectable:0
msgid "Selectable"
-msgstr "Suchbar"
+msgstr "Auswählbar"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:222
@@ -10527,12 +10973,12 @@ msgstr "Iteration"
#: code:addons/orm.py:4347
#, python-format
msgid "UserError"
-msgstr "Benutzer Fehler"
+msgstr "Benutzerfehler"
#. module: base
#: model:ir.module.module,summary:base.module_project_issue
msgid "Support, Bug Tracker, Helpdesk"
-msgstr "Support, Bug Tracker, Helpdesk"
+msgstr "Support, Bugtracker, Helpdesk"
#. module: base
#: model:res.country,name:base.ae
@@ -10553,7 +10999,7 @@ msgstr ""
msgid ""
"Unable to delete this document because it is used as a default property"
msgstr ""
-"Es ist nicht möglich diesen Beleg zu löschen, da er als Standard Eigenschaft "
+"Es ist nicht möglich, diesen Beleg zu löschen, da er als Standardeigenschaft "
"verwendet wird."
#. module: base
@@ -10591,7 +11037,7 @@ msgstr ""
#. module: base
#: view:ir.values:0
msgid "Action Reference"
-msgstr "Aktion Referenz"
+msgstr "Aktionsreferenz"
#. module: base
#: model:ir.module.module,description:base.module_auth_ldap
@@ -10701,8 +11147,8 @@ msgstr ""
"========================================================\n"
"\n"
"Dieses Modul ermöglicht es Benutzern, sich mit ihrem LDAP-Benutzernamen und "
-"Passwort anzumelden und erstellt währenddesse automatisch OpenERP Nutzer für "
-"sie.\n"
+"Passwort anzumelden und erstellt währenddessen automatisch OpenERP Nutzer "
+"für sie.\n"
"\n"
"**Hinweis:** Diese Modul funktioniert nur auf Servern, die die Anwendung "
"Python's \"Idap\" installiert haben.\n"
@@ -10711,15 +11157,15 @@ msgstr ""
"--------------\n"
"Nach der Installation dieser Anwendung, müssen Sie die LDAP Parameter in der "
"Registerkarte\n"
-"Konfiguration Ihrer Unternehmens Details konfigurieren. Verschiedene "
+"Konfiguration Ihrer Unternehmensdetails konfigurieren. Verschiedene "
"Unternehmen haben möglicherweise\n"
"verschiedene LDAP Server, so lange Sie eindeutige Benutzernamen haben "
-"(Benuternamen müssen in\n"
+"(Benutzernamen müssen in\n"
"OpenERP einzigartig sein, selbst über mehrere Unternehmen). \n"
"\n"
"Anonyme LDAP-Bindung wird ebenfalls unterstützt (für LDAP-Server, die es "
"erlauben), indem\n"
-"Sie einfaches LDAP-Benutzer und Passwort in der LDAP-Konfiguration leer "
+"Sie einfach LDAP-Benutzer und Passwort in der LDAP-Konfiguration leer "
"lassen. Dies\n"
"erlaubt keine anonyme Authentifizierung für Benutzer, es ist lediglich für "
"das Master-LDAP-Konto,\n"
@@ -10727,7 +11173,7 @@ msgstr ""
"Sie versuchen ihn\n"
"zu authentifizieren.\n"
"\n"
-"Sicherung der Verbindung mit STARTTLS steht für LDAP Server zur dessen "
+"Sicherung der Verbindung mit STARTTLS steht für LDAP Server zur "
"Unterstützung zur Verfügung, durch\n"
"Freigabe der TLS Option in der LDAP Konfiguration. \n"
"\n"
@@ -10735,13 +11181,13 @@ msgstr ""
"hier Idap.conf\n"
"manpage: manpage: \"Idap.conf(5)\". \n"
"\n"
-"Sicherheits-Überlegungen:\n"
+"Sicherheitsüberlegungen:\n"
"-------------------------------------\n"
"Benutzer LDAP Passwörter werden niemals in der OpenERP Datenbank "
"gespeichert, der LDAP Server\n"
"wird abgefragt, wenn ein Benutzer authentifiziert werden muss. Es erfolgt "
"keine Vervielfältigung des\n"
-"Passwortes und Passwörter werden nur an einer Stelle verwaltet.\n"
+"Passwortes. Passwörter werden nur an einer Stelle verwaltet.\n"
"\n"
"Open ERP gelingt es nicht, Passwortänderungen in LDAP zu verwalten, sodass "
"jede Änderung des Passworts\n"
@@ -10763,9 +11209,9 @@ msgstr ""
"\n"
"Da LDAP Benutzer standardmäßig leere Passwörter in der lokalen OpenEPR "
"Datenbank\n"
-"haben (was bedeutet, kein Zugriff), schlägt der erste Schritt immer fehl und "
+"haben (was bedeutet: kein Zugriff), schlägt der erste Schritt immer fehl und "
"der LDAP Server\n"
-"wird abgefragt, um die Authendifizierung durchzuführen.\n"
+"wird abgefragt, um die Authentifizierung durchzuführen.\n"
"\n"
"Aktivieren der STARTTLS sorgt dafür, dass die Abfrage der Authentifizierung "
"an den LDAP-Server verschlüsselt ist.\n"
@@ -10776,7 +11222,7 @@ msgstr ""
"*Benutzervorlage*\n"
"auszuwählen. Wenn diese gesetzt ist, wird der Benutzer als Vorlage genutzt, "
"um lokale Benutzer\n"
-"zu erstellen, wannimmer jemand zum ersten mal über die LDAP-"
+"zu erstellen, wann immer jemand zum ersten mal über die LDAP-"
"Authentifizierung authentifiziert wird. \n"
"Dies ermöglicht die Voreinstellung der Standard-Gruppen und Menüs der "
"Erstanwender.\n"
@@ -10785,7 +11231,7 @@ msgstr ""
"dieses Passwort\n"
" für jeden neuen LDAP Benutzer zugewiesen, am wirksamsten setzten "
"Sie ein \n"
-" *Master Passwort* für dies Benutzer (solange bis sie manuell "
+" *Master Passwort* für diese Benutzer (solange bis sie manuell "
"geändert werden). In der \n"
" Regel wollen Sie das nicht. Ein einfacher Weg, um eine "
"Benutzervorlage zu erstellen, ist\n"
@@ -10799,9 +11245,10 @@ msgstr ""
"\n"
"Interaktion mit base_crypt:\n"
"-------------------------------------\n"
-"Die Anwendung base_crypt ist nicht kompatibel mit dieser Anwendungund wird "
-"LDAP\n"
-"Authentifizierung deaktivieren, wenn es zur gleichen Zeit installiert wird.\n"
+"Die Anwendung base_crypt ist nicht kompatibel mit dieser Anwendungund. Sie "
+"wird die LDAP\n"
+"Authentifizierung deaktivieren, wenn sie zur gleichen Zeit installiert "
+"wird.\n"
" "
#. module: base
@@ -10855,7 +11302,7 @@ msgstr "Solomoninseln"
#: code:addons/orm.py:4685
#, python-format
msgid "AccessError"
-msgstr "ZugrifffFehler"
+msgstr "Zugriffsfehler"
#. module: base
#: model:ir.module.module,description:base.module_web_gantt
@@ -10866,14 +11313,14 @@ msgid ""
"\n"
msgstr ""
"\n"
-"OpenERP Web Gantt Diagramm Ansicht.\n"
+"OpenERP Web Gantt Diagrammansicht.\n"
"==================================\n"
"\n"
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_status
msgid "State/Stage Management"
-msgstr "Status/Stufen Verwaltung"
+msgstr "Status/Stufen-Verwaltung"
#. module: base
#: model:ir.module.category,name:base.module_category_warehouse_management
@@ -10903,8 +11350,8 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung zeigt die grundlegenden Prozesse, an denen die ausgewählten "
-"Anwendungen und in der Reihenfolge ihres Auftreten sie beteiligt sind.\n"
+"Diese Anwendung zeigt die grundlegenden Prozesse der ausgewählten "
+"Anwendungen und die Reihenfolge ihres Abarbeitung\n"
"============================================================================="
"=========================\n"
"\n"
@@ -10996,8 +11443,8 @@ msgstr ""
"fällig sind. Details finden Sie unten.\n"
"Wurde der Betrag bereits bezahlt, ignorieren Sie bitte diese Nachricht. "
"Ansonsten senden Sie uns bitte den unten \n"
-"angegeben Betrag. Wenn Sie Fragen zu Ihrem Konto haben, kontaktieren Sie uns "
-"bitte.\n"
+"angegebenen Betrag. Wenn Sie Fragen zu Ihrem Konto haben, kontaktieren Sie "
+"uns bitte.\n"
"\n"
"Vielen Dank für Ihre Kooperation.\n"
"\n"
@@ -11006,7 +11453,7 @@ msgstr ""
#. module: base
#: view:ir.module.category:0
msgid "Module Category"
-msgstr "Module Kategorie"
+msgstr "Modulkategorie"
#. module: base
#: model:res.country,name:base.us
@@ -11031,17 +11478,17 @@ msgstr "Stufen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Flemish (BE) / Vlaams (BE)"
-msgstr "Flemish (BE) / Vlaams (BE)"
+msgstr "Flämisch (BE) / Vlaams (BE)"
#. module: base
#: selection:base.language.install,lang:0
msgid "Vietnamese / Tiếng Việt"
-msgstr "Vietnamese / Tiếng Việt"
+msgstr "Vietnameseisch / Tiếng Việt"
#. module: base
#: field:ir.cron,interval_number:0
msgid "Interval Number"
-msgstr "Intervalle Nummern"
+msgstr "Intervallnummer"
#. module: base
#: model:res.country,name:base.dz
@@ -11059,7 +11506,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung fügt eine Liste der Mitarbeiter zu der Kontaktseite Ihres "
+"Diese Anwendung fügt eine Liste der Mitarbeiter zur Kontaktseite Ihres "
"Portals wenn HR und portal_crm (welches die Kontaktseite erstellt) "
"installiert sind.\n"
"============================================================================="
@@ -11082,7 +11529,7 @@ msgstr "Ansichtstyp"
#. module: base
#: model:ir.ui.menu,name:base.next_id_2
msgid "User Interface"
-msgstr "Benutzer Interface"
+msgstr "Benutzer-Interface"
#. module: base
#: model:ir.module.module,shortdesc:base.module_mrp_byproduct
@@ -11131,6 +11578,12 @@ msgid ""
"Indian accounting chart and localization.\n"
" "
msgstr ""
+"\n"
+"Indian Accounting: Chart of Account.\n"
+"====================================\n"
+"\n"
+"Indian accounting chart and localization.\n"
+" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_uy
@@ -11140,7 +11593,7 @@ msgstr "Urugay - Kontenführung"
#. module: base
#: model:ir.ui.menu,name:base.menu_administration_shortcut
msgid "Custom Shortcuts"
-msgstr "benutzerdefinierte Tastaturkürzel"
+msgstr "Benutzerdefinierte Tastaturkürzel"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_si
@@ -11161,11 +11614,11 @@ msgid ""
msgstr ""
"\n"
"Ermöglicht das Abbrechen von Buchungseinträgen\n"
-"=============================?==========\n"
+"=========================================\n"
"\n"
"Diese Anwendung fügt das Feld \"Erlaube das Abbrechen von Einträgen\" in der "
"Formularansicht des Journals\n"
-"hinzu. Wenn dieses auf wahr gesetzt wird, ermöglicht es dem Benutzer "
+"hinzu. Wenn dieses auf 'wahr' gesetzt wird, ermöglicht es dem Benutzer "
"Einträge & Rechnungen abzubrechen.\n"
" "
@@ -11196,7 +11649,7 @@ msgstr "Der Datensatz kann augenblicklich nicht verändert werden."
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Manually"
-msgstr "Starte Manuell"
+msgstr "Starte manuell"
#. module: base
#: model:res.country,name:base.be
@@ -11246,7 +11699,7 @@ msgstr "Unternehmen"
#. module: base
#: help:res.currency,symbol:0
msgid "Currency sign, to be used when printing amounts."
-msgstr "Währungssymbol für geduckte Berichte"
+msgstr "Währungssymbol für gedruckte Berichte"
#. module: base
#: view:res.lang:0
@@ -11267,7 +11720,7 @@ msgstr "Modul %s existiert nicht!"
#. module: base
#: model:ir.module.module,shortdesc:base.module_mrp_jit
msgid "Just In Time Scheduling"
-msgstr "Just in Time Terminierung"
+msgstr "Just in Time-Terminierung"
#. module: base
#: view:ir.actions.server:0
@@ -11292,8 +11745,8 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung fügt eine Kontaktseite (mit einem Kontaktformular, welches "
-"einen Interessenten erstellt, wenn möglich) zu Ihrem Portal hinzu, wenn CRM "
+"Diese Anwendung fügt eine Kontaktseite zu Ihrem Portal hinzu (mit einem "
+"optionalen Kontaktformular, welches einen Interessenten erstellt), wenn CRM "
"und Portal installiert sind. \n"
"============================================================================="
"=======================================================\n"
@@ -11340,7 +11793,7 @@ msgid ""
"\n"
msgstr ""
"\n"
-"OpenERP Web Diagramm Ansicht.\n"
+"OpenERP Web Diagrammansicht.\n"
"=============================\n"
"\n"
@@ -11430,9 +11883,9 @@ msgstr ""
" - Rechnungen\n"
" - Zahlungen / Erstattungen\n"
"\n"
-"Wenn Online-Zahlungs-Käufe konfiguriert sind, wird Portalbenutzer auch die "
+"Wenn Online-Zahlungs-Käufe konfiguriert sind, wird Portalbenutzern auch die "
"Möglichkeit gegeben,\n"
-"noch nicht bezhalte Bestellungen und Rechnungen online zu bezahlen. Paypal "
+"noch nicht bezahlte Bestellungen und Rechnungen online zu bezahlen. Paypal "
"ist standardmäßig enthalten,\n"
"Sie müssen einfach ein Paypal-Konto in den Einstellungen der Buchhaltung / "
"Fakturierung konfigurieren.\n"
@@ -11586,14 +12039,14 @@ msgid ""
" "
msgstr ""
"\n"
-"Dieses Modul fügt Unterstützung für Zeitnachweise zu Problemen und -Fehlern "
+"Dieses Modul fügt Unterstützung für Zeitnachweise zu Problemen und Fehlern "
"der Projektplanung hinzu.\n"
"============================================================================="
"===========\n"
"\n"
-"Arbeitsprotokolle (Rapporte) können verwendet werden, um die für "
+"Arbeitsprotokolle (Rapporte) können verwendet werden, um für die "
"Problembehebung und \n"
-"Fehlerbeseitigung aufgebrachte Zeit festzuhalten und Nachweis zu führen.\n"
+"Fehlerbeseitigung aufgebrachte Zeit festzuhalten und Nachweise zu führen.\n"
" "
#. module: base
@@ -11604,7 +12057,7 @@ msgstr "Guyana"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_expiry
msgid "Products Expiry Date"
-msgstr "Produkt Ablaufdatum"
+msgstr "Produkt-Ablaufdatum"
#. module: base
#: code:addons/base/res/res_config.py:419
@@ -11647,7 +12100,7 @@ msgstr "Sprache"
#. module: base
#: selection:ir.property,type:0
msgid "Boolean"
-msgstr "Logisch"
+msgstr "Boolean"
#. module: base
#: help:ir.mail_server,smtp_encryption:0
@@ -11669,7 +12122,7 @@ msgstr ""
#. module: base
#: view:ir.model:0
msgid "Fields Description"
-msgstr "Felder Beschreibung"
+msgstr "Feldbeschreibungen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic_contract_hr_expense
@@ -11689,7 +12142,7 @@ msgstr "Vertragsmanagement: hr_expense Link"
#: view:res.partner:0
#: view:workflow.activity:0
msgid "Group By..."
-msgstr "Gruppiert je..."
+msgstr "Gruppieren nach ..."
#. module: base
#: view:base.module.update:0
@@ -11706,8 +12159,8 @@ msgid ""
"=========================\n"
msgstr ""
"\n"
-"Diese Anwendung ist zum Modifizieren der analytischen Kontoansicht, um "
-"einige Daten im Zusammenhang mit dem hr_expense module zu zeigen.\n"
+"Diese Anwendung ist zum Modifizieren der analytischen Kontenansicht, um "
+"einige Daten im Zusammenhang mit dem hr_expense Modul zu zeigen.\n"
"============================================================================="
"=========================\n"
@@ -11719,7 +12172,7 @@ msgstr "Abgespeicherter Dateiname"
#. module: base
#: field:res.partner,use_parent_address:0
msgid "Use Company Address"
-msgstr "Benutze die Firmenadresse"
+msgstr "Unternehmensanschrift verwenden"
#. module: base
#: model:ir.module.module,summary:base.module_hr_holidays
@@ -11743,7 +12196,7 @@ msgstr ""
#: selection:ir.module.module,state:0
#: selection:ir.module.module.dependency,state:0
msgid "To be installed"
-msgstr "Zu Installieren"
+msgstr "Zu installieren"
#. module: base
#: view:ir.model:0
@@ -11834,7 +12287,7 @@ msgstr "Wert"
#: selection:ir.translation,type:0
#: field:res.partner.bank.type,code:0
msgid "Code"
-msgstr "Kurzbezeichnung"
+msgstr "Code"
#. module: base
#: model:ir.model,name:base.model_res_config_installer
@@ -11866,7 +12319,8 @@ msgstr "Mehrteilige Unternehmen (z. B. Filialbetrieb)"
msgid ""
"If specified, the action will replace the standard menu for this user."
msgstr ""
-"Wenn definiert, dann ersetzt dies Aktion das Standardmneü für diesen Benutzer"
+"Wenn definiert, dann ersetzt diese Aktion das Standardmenü für diesen "
+"Benutzer"
#. module: base
#: model:ir.actions.report.xml,name:base.preview_report
@@ -11887,7 +12341,7 @@ msgstr "Sequenzcode"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (CO) / Español (CO)"
-msgstr "Spanish (CO) / Español (CO)"
+msgstr "Spanisch (CO) / Español (CO)"
#. module: base
#: view:base.module.configuration:0
@@ -11967,7 +12421,7 @@ msgstr "Art"
#: code:addons/orm.py:4647
#, python-format
msgid "This method does not exist anymore"
-msgstr "Diese Methode existiert zwischenzeitlich nicht mehr"
+msgstr "Diese Methode existiert nicht mehr"
#. module: base
#: view:base.update.translations:0
@@ -12035,7 +12489,7 @@ msgstr "Vertragsverwaltung"
#. module: base
#: selection:base.language.install,lang:0
msgid "Chinese (TW) / 正體字"
-msgstr "Chinese (TW) / 正體字"
+msgstr "Chinesisch (TW) / 正體字"
#. module: base
#: model:ir.model,name:base.model_res_request
@@ -12050,7 +12504,7 @@ msgstr "Mittelgroßes Bild"
#. module: base
#: view:ir.model:0
msgid "In Memory"
-msgstr "In Memory"
+msgstr "Im Speicher"
#. module: base
#: view:ir.actions.todo:0
@@ -12084,7 +12538,7 @@ msgstr "Panama"
msgid ""
"The group that a user must have to be authorized to validate this transition."
msgstr ""
-"Die Gruppe der ein Benutzer angehören muss, um diesen Ablauf zu genehmigen."
+"Die Gruppe, der ein Benutzer angehören muss, um diesen Ablauf zu genehmigen."
#. module: base
#: constraint:res.users:0
@@ -12101,7 +12555,7 @@ msgstr "Gibraltar"
#. module: base
#: field:ir.actions.report.xml,report_name:0
msgid "Service Name"
-msgstr "Dienst Name"
+msgstr "Dienstname"
#. module: base
#: model:res.country,name:base.pn
@@ -12118,8 +12572,8 @@ msgstr "Tags"
msgid ""
"We suggest to reload the menu tab to see the new menus (Ctrl+T then Ctrl+R)."
msgstr ""
-"Wir empfehlen das Menü neu zuladen um die neuen Menüs zu sehen. (Strg+T dann "
-"Strg+R)"
+"Wir empfehlen dis Seite neu zuladen, um die neuen Menüs zu sehen. (Strg+T "
+"dann Strg+R)"
#. module: base
#: model:ir.actions.act_window,name:base.action_rule
@@ -12142,7 +12596,7 @@ msgstr "Portal"
#. module: base
#: selection:ir.translation,state:0
msgid "To Translate"
-msgstr "zu übersetzen"
+msgstr "Zu übersetzen"
#. module: base
#: code:addons/base/ir/ir_fields.py:294
@@ -12194,7 +12648,7 @@ msgstr "Klicken Sie hier, um Ihr Firmenlogo einzubinden."
#. module: base
#: view:res.lang:0
msgid "%A - Full weekday name."
-msgstr "%A - Ausgeschriebener Wochentag"
+msgstr "%A - Wochentag (ausgeschrieben)"
#. module: base
#: help:ir.values,user_id:0
@@ -12283,7 +12737,7 @@ msgstr "Andere Aktionen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_be_coda
msgid "Belgium - Import Bank CODA Statements"
-msgstr ""
+msgstr "Belgium - Import Bank CODA Statements"
#. module: base
#: selection:ir.actions.todo,state:0
@@ -12313,7 +12767,7 @@ msgstr "Schreibrechte"
#. module: base
#: view:res.lang:0
msgid "%m - Month number [01,12]."
-msgstr "%m - Monat Nummer [01,12]."
+msgstr "%m - Monatsnummer [01,12]."
#. module: base
#: view:res.bank:0
@@ -12357,7 +12811,7 @@ msgstr "Portal HR Mitarbeiter"
#. module: base
#: selection:base.language.install,lang:0
msgid "Estonian / Eesti keel"
-msgstr "Estonian / Eesti keel"
+msgstr "Estnisch / Eesti keel"
#. module: base
#: help:ir.actions.server,write_id:0
@@ -12366,7 +12820,7 @@ msgid ""
"If it is empty it will refer to the active id of the object."
msgstr ""
"Angabe des Feldnames auf den sich die Datensatz ID bei Schreibvorgängen "
-"bezieht. Wenn leer, dann wird auf den Aktuellen Datensatz verwiesen."
+"bezieht. Wenn leer, dann wird auf den aktuellen Datensatz verwiesen."
#. module: base
#: selection:ir.module.module,license:0
@@ -12380,8 +12834,8 @@ msgid ""
"Insufficient fields to generate a Calendar View for %s, missing a date_stop "
"or a date_delay"
msgstr ""
-"Ungültige Felder für die Erzeugung eines Kalenders für %s, es fehlt ein Ende "
-"Datum oder ein Ende Verzögerung Datum"
+"Ungültige Felder für die Erzeugung eines Kalenders für %s. Es fehlt ein "
+"Endedatum oder ein Ende-Verzögerungsdatum"
#. module: base
#: field:workflow.activity,action:0
@@ -12399,7 +12853,7 @@ msgid ""
"Manage the partner titles you want to have available in your system. The "
"partner titles is the legal status of the company: Private Limited, SA, etc."
msgstr ""
-"Verwaltung der Gesellschaftsform, die Sie in Ihrem System brauchen. Der "
+"Verwaltung der Gesellschaftsform, die Sie in Ihrem System brauchen. Die "
"Partner Anrede repräsentiert dabei meistens die Rechtsform des Unternehmens "
"(z.B. OHG, KG, GmbH, GmbH&Co.KG etc.)"
@@ -12442,8 +12896,8 @@ msgstr ""
"\n"
"Eine Ressource stellt etwas dar, das geplant werden kann (ein Entwickler für "
"eine Aufgabe oder einen Arbeitsplatz für Fertigungsaufträge). Diese "
-"Anwendung verwaltet einen Ressourcen Kalender, der jeder Ressource "
-"zugeordnet ist. Er verwaltet auch die Fehlzeiten jeder Ressource.\n"
+"Anwendung verwaltet einen Ressourcenkalender, der jeder Ressource zugeordnet "
+"ist. Er verwaltet auch die Fehlzeiten jeder Ressource.\n"
" "
#. module: base
@@ -12486,20 +12940,20 @@ msgstr ""
"--------------------------------------------\n"
" Konfiguration / Stufen der Verfolgung\n"
" \n"
-"Sobald diese definiert sind, können sie automatisch jeden Tag Mahnungen "
+"Sobald diese definiert sind, können Sie automatisch jeden Tag Mahnungen "
"drucken, durch einen einfach Klick auf das Menü:\n"
"-----------------------------------------------------------------------------"
"-----------------------------------------------------------------------------"
"-------------------------------------------------\n"
" Zahlungsverfolgung / E-Mail und Briefe senden\n"
"\n"
-"Es wird ein PDF generiert / eine E-Mail gesendet / verschiedene Aktionen "
-"festgesetzt entsprechend den verschiedenen\n"
+"Es wird eine PDF-Datei generiert / eine E-Mail gesendet / verschiedene "
+"Aktionen festgesetzt entsprechend den verschiedenen\n"
"Mahnstufen, die definiert sind. Sie können verschiedene Methoden für "
"verschiedene Unternehmen festlegen. \n"
"\n"
-"Beachten Sie, dass wenn Sie die Mahnstufe eines Partners kontrollieren "
-"wollen, sie dieses mithilfe des Menüs tun können:\n"
+"Beachten Sie: wenn Sie die Mahnstufe eines Partners kontrollieren wollen, "
+"können Sie dieses mit Hilfe des Menüs tun:\n"
"-----------------------------------------------------------------------------"
"-----------------------------------------------------------------------------"
"---------------------------------------------\n"
@@ -12512,7 +12966,7 @@ msgstr ""
msgid ""
"Please contact your system administrator if you think this is an error."
msgstr ""
-"Bitte kontaktieren Sie Ihren System Administrator, falls Sie meinen, das es "
+"Bitte kontaktieren Sie Ihren Systemadministrator, falls Sie meinen, dass es "
"sich um einen Fehler handelt."
#. module: base
@@ -12561,8 +13015,8 @@ msgid ""
"One of the documents you are trying to access has been deleted, please try "
"again after refreshing."
msgstr ""
-"Eines der Dokumente, auf das Sie versuchen zuzugreifen, wurde gelöscht, "
-"bitte versuchen Sie es erneut nach einer Aktualisierung."
+"Eines der Dokumente, auf das Sie versuchen zuzugreifen, wurde gelöscht. "
+"Bitte versuchen Sie es erneut nach einer Aktualisierung."
#. module: base
#: model:ir.model,name:base.model_ir_mail_server
@@ -12572,7 +13026,7 @@ msgstr "ir.mail_server"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (CR) / Español (CR)"
-msgstr "Spanish (CR) / Español (CR)"
+msgstr "Spanisch (CR) / Español (CR)"
#. module: base
#: view:ir.rule:0
@@ -12584,10 +13038,10 @@ msgid ""
msgstr ""
"Globale -nicht gruppenspezifische- Regeln sind Einschränkungen, die nicht "
"umgangen werden können.\r\n"
-"Lokale Gruppenrechte erweitern die Berechtigungen innerhalb der Globalen "
+"Lokale Gruppenrechte erweitern die Berechtigungen innerhalb der globalen "
"Regeln.\r\n"
"Die erste Gruppe beschränkt die globalen Rechte, alle zusätzlichen erweitern "
-"die gruppenlokalen Rechte."
+"die lokalen Gruppenrechte."
#. module: base
#: field:res.currency.rate,rate:0
@@ -12607,7 +13061,7 @@ msgstr "Beispiele"
#. module: base
#: field:ir.default,value:0
msgid "Default Value"
-msgstr "Standard Wert"
+msgstr "Standardwert"
#. module: base
#: model:ir.model,name:base.model_res_country_state
@@ -12649,8 +13103,8 @@ msgid ""
"for the currency: %s \n"
"at the date: %s"
msgstr ""
-"Konnte für die \n"
-"Währung %s am\n"
+"Für die Währung %s \n"
+"konnte am\n"
"Stichtag: %s\n"
"keinen Wechselkurs ermitteln."
@@ -12688,28 +13142,28 @@ msgid ""
"applicant from the kanban view.\n"
msgstr ""
"\n"
-"Verwalten Sie Arbeitsplätze und den Einstellungsprozess\n"
+"Verwalten Sie Stellen und den Einstellungsprozess\n"
"==============================================\n"
"\n"
-"Diese Anwendung ermöglicht Ihnen die Planung, Eingabe und Ihrer "
-"Arbeitsplätze und Stellenangebote, sowie die Rückverfolgung Ihrer Bewerber, "
-"Planung und Durchführung von Vorstellungsgesprächen etc.\n"
+"Diese Anwendung ermöglicht Ihnen die Planung, Eingabe und Ihrer Stellen und "
+"Stellenangebote, sowie die Rückverfolgung Ihrer Bewerber, Planung und "
+"Durchführung von Vorstellungsgesprächen etc.\n"
"\n"
-"Die Anwendung ist vollständig in das E-Mail und Nachrichtensystem "
+"Die Anwendung ist vollständig in das E-Mail- und Nachrichtensystem "
"integriert, um automatisch und regelmässig gesendete E-Mails an "
"<jobs@yourcompany.com> in die Liste der neuen Bewerber zu importieren. "
"Ebenfalls ist diese Anwendung nahtlos in das System der Dokumentenverwaltung "
"integriert, um in der Datenbank Lebensläufe zu speichern, sowie nach "
-"bestimmten Kandidaten zu suchen. Nicht zuletzt ist die Umfragen Anwendung "
+"bestimmten Kandidaten zu suchen. Nicht zuletzt ist die Umfragenanwendung "
"komplett eingebunden, um Ihnen die Möglichkeit zu bieten, die Vorstellungs- "
"oder Einstellungsgespräche für die verschiedene Arbeitsplätze zu definieren. "
"Sie können sehr einfach die verschiedenen Phasen des Gespräches festlegen "
-"Ihre Bewerber dann aus der Kanbanansicht bewerten.\n"
+"und ihre Bewerber dann aus der Kanbanansicht bewerten.\n"
#. module: base
#: field:ir.model.fields,model:0
msgid "Object Name"
-msgstr "Objekt Bezeichnung"
+msgstr "Objekt-Bezeichnung"
#. module: base
#: help:ir.actions.server,srcmodel_id:0
@@ -12825,7 +13279,7 @@ msgid ""
"you need.\n"
msgstr ""
"\n"
-"Fügt Berichte zum Menü der Produkte hinzu, welches Verkaufszahlen, Käufe, "
+"Fügt Berichte zum Menü der Produkte hinzu, welches Verkaufszahlen, Einkäufe, "
"Margen und \n"
"andere interessante Indikatoren aus Rechnungen errechnet.\n"
"==========================================================================\n"
@@ -12865,7 +13319,7 @@ msgstr "Zugriff verweigert"
#. module: base
#: field:ir.ui.menu,child_id:0
msgid "Child IDs"
-msgstr "untergeordnete Kennungen"
+msgstr "Untergeordnete IDs"
#. module: base
#: code:addons/base/ir/ir_actions.py:702
@@ -12897,7 +13351,7 @@ msgstr ""
#. module: base
#: view:base.module.import:0
msgid "Import module"
-msgstr "Import-Modul"
+msgstr "Modul importieren"
#. module: base
#: field:ir.actions.server,loop_action:0
@@ -12927,7 +13381,7 @@ msgstr "Laos"
#: field:res.partner,email:0
#, python-format
msgid "Email"
-msgstr "E-Mail Adresse"
+msgstr "E-Mail"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_12
@@ -12970,8 +13424,8 @@ msgid ""
" - uid: current user id\n"
" - context: current context"
msgstr ""
-"Bedingung, die geprüft wird bevor die Aktion ausgeführt wird, anderenfalls "
-"die Auführung unterbindet.\n"
+"Bedingung, die geprüft wird bevor die Aktion ausgeführt wird, andernfalls "
+"die Ausführung unterbindet.\n"
"Beispiel: object.list_price > 5000\n"
"Es ist ein Python-Ausdruck der folgende Werte nutzen kann:\n"
"- self: ORM-Modell des Datensatzes über den die Aktion ausgelöst wurde\n"
@@ -12986,12 +13440,13 @@ msgstr ""
#: view:ir.rule:0
msgid ""
"2. Group-specific rules are combined together with a logical OR operator"
-msgstr "2. Gruppenspezifische Regeln sind mit logisch ODER verbunden"
+msgstr ""
+"2. Gruppenspezifische Regeln sind mit einem logisch ODER-Operator verbunden"
#. module: base
#: model:res.country,name:base.bl
msgid "Saint Barthélémy"
-msgstr ""
+msgstr "Saint Barthélémy"
#. module: base
#: selection:ir.module.module,license:0
@@ -13006,12 +13461,12 @@ msgstr "Equador"
#. module: base
#: model:ir.model,name:base.model_workflow
msgid "workflow"
-msgstr "workflow"
+msgstr "Workflow"
#. module: base
#: view:ir.rule:0
msgid "Read Access Right"
-msgstr "Schreibe Benutzerrecht"
+msgstr "Benutzer-Schreibrecht"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic_user_function
@@ -13029,7 +13484,7 @@ msgstr ""
#. module: base
#: view:ir.model.data:0
msgid "Updatable"
-msgstr "aktualisierbar"
+msgstr "Aktualisierbar"
#. module: base
#: view:res.lang:0
@@ -13070,7 +13525,7 @@ msgstr "Übersetzt"
#: model:ir.actions.act_window,name:base.action_inventory_form
#: model:ir.ui.menu,name:base.menu_action_inventory_form
msgid "Default Company per Object"
-msgstr "Standard Unternehmen je Objekt"
+msgstr "Standard-Unternehmen je Objekt"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_hello
@@ -13110,7 +13565,7 @@ msgstr "Marketing-Kampagnen"
#. module: base
#: field:res.country.state,name:0
msgid "State Name"
-msgstr "Bundesland Bezeichnung"
+msgstr "Bundesland"
#. module: base
#: help:ir.attachment,type:0
@@ -13268,17 +13723,17 @@ msgstr "Demonstration der web/javasript Tests"
#. module: base
#: field:workflow.transition,signal:0
msgid "Signal (Button Name)"
-msgstr ""
+msgstr "Signal (Buttonname)"
#. module: base
#: view:ir.actions.act_window:0
msgid "Open Window"
-msgstr "Öffne Fenster"
+msgstr "Fenster öffnen"
#. module: base
#: field:ir.actions.act_window,auto_search:0
msgid "Auto Search"
-msgstr "Selbständige Suche"
+msgstr "Automatische Suche"
#. module: base
#: field:ir.actions.act_window,filter:0
@@ -13323,25 +13778,25 @@ msgid ""
" "
msgstr ""
"\n"
-"Modul zur Auslösung von Warnungen in OpenERP-Objekten.\n"
+"Modul zum Auslösen von Warnungen in OpenERP-Objekten.\n"
"==================================================\n"
"\n"
"Warn-Hinweise können für Objekte, wie Verkaufsaufträge, Bestellungen,\n"
-"Kommissionierungen und Rechnungen, ausgelöst werden. Die Mitteilung \n"
+"Kommissionierungen und Rechnungen ausgelöst werden. Die Mitteilung \n"
"wird ausgelöst durch das Onchange-Ereignis des jeweiligen Formulars.\n"
" "
#. module: base
#: field:res.users,partner_id:0
msgid "Related Partner"
-msgstr "zugehöriger Partner"
+msgstr "Zugehöriger Partner"
#. module: base
#: code:addons/osv.py:172
#: code:addons/osv.py:174
#, python-format
msgid "Integrity Error"
-msgstr "Datenintegritäts Fehler"
+msgstr "Datenintegritäts-Fehler"
#. module: base
#: model:ir.module.module,description:base.module_l10n_pa
@@ -13356,6 +13811,15 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"Panamenian accounting chart and tax localization.\n"
+"\n"
+"Plan contable panameño e impuestos de acuerdo a disposiciones vigentes\n"
+"\n"
+"Con la Colaboración de \n"
+"- AHMNET CORP http://www.ahmnet.com\n"
+"\n"
+" "
#. module: base
#: code:addons/base/ir/ir_model.py:296
@@ -13382,7 +13846,7 @@ msgstr "RML Inhalte"
#. module: base
#: view:res.lang:0
msgid "Update Terms"
-msgstr "Aktualisiere Begriffe"
+msgstr "Begriffe aktualisieren"
#. module: base
#: field:res.request,act_to:0
@@ -13517,47 +13981,44 @@ msgstr ""
"-----------------------------------------------------------------------------"
"-------\n"
" * Produktherstellungsketten zu verwalten\n"
-" * Standard Standorte je Produkt zu verwalten\n"
-" * Routen innerhalb Ihres Lagers nach Bedarf der Unternehmensbedürfnisse "
-"zu definieren, wie z. B. :\n"
+" * Standardstandorte je Produkt zu verwalten\n"
+" * Routen innerhalb Ihres Lagers nach Bedarf zu definieren, wie z. B. :\n"
" - Qualitätskontrolle\n"
" - After Sales Services\n"
-" - Lieferanten Rücksendungen\n"
+" - Lieferanten-Rücksendungen\n"
"\n"
" * Hilfen bei der Verwaltung von Mieten, durch die Erzeugung "
"automatischer Rückgabewegungen für gemietete Produkte.\n"
"\n"
"Sobald diese Anwendung installiert ist, erscheint eine zusätzliche "
"Registerkarte im Produktformular,\n"
-"wo Sie Push- und Pullablaufspezifikationen hinzufügen können. Die Demodaten "
-"für Produkt CPU1\n"
+"in der Sie Push- und Pullablaufspezifikationen hinzufügen können. Die "
+"Demodaten für Produkt CPU1\n"
"für dieses push / pull: \n"
"\n"
"Push Abläufe:\n"
"-------------------\n"
"Push Abläufe sind nützlich, wenn die Ankunft eines bestimmten Produkts an "
"einem bestimmten\n"
-"Ort immer gefolgt ist von einem bestimmten Wechsel zu einem anderen Ort, "
-"gegebenenenfalls\n"
+"Ort immer den Wechsel zu einem anderen Ort auslöst, gegebenenenfalls\n"
"nach einer gewissen Verzögerung. Die ursprüngliche Lageranwendung "
"unterstützt bereits\n"
-"solche Push Ablaufdaten zu den Orten selbst, kann diese aber nicht pro "
+"solche Push-Ablaufdaten zu den Orten selbst, kann diese aber nicht pro "
"Produkt\n"
"verfeinern. \n"
"\n"
-"Eine Push Ablauf Spezifikation gibt an, welcher Ort an bestimmte Orte "
-"gebunden ist\n"
+"Eine Push-Ablaufspezifikation gibt an, welcher Ort mit anderen Orten\n"
"und mit welchen Parametern verbunden ist. Sobald eine bestimmte Menge von "
"Produkten\n"
"an den Ursprungsort bewegt wird, wird eine verkettete Bewegung "
"entsprechender Parameter\n"
-"automatisch für die Ablauf Spezifikation (Zielort, Verspätung, Art der "
+"automatisch für die Ablaufspezifikation (Zielort, Verspätung, Art der "
"Bewegung,\n"
"Journal) vorgesehen. Die neue Bewegung kann automatisch verarbeitet werden "
"oder erfordert,\n"
"abhängig von den Parametern, eine manuelle Bestätigung. \n"
"\n"
-"Push Ablauf:\n"
+"Pull Ablauf:\n"
"--------------------\n"
"Pull Abläufe sind ein wenig anders als Push Abläufe, in dem Sinne, dass sie "
"nicht\n"
@@ -13566,7 +14027,7 @@ msgstr ""
"Produkt. Ein\n"
"klassisches Beispiel für Pull Abläufe ist, wenn Sie ein Outlet Unternehmen "
"haben, mit einer\n"
-"Muttergesellschaft, die verantwortlich für die Lieferungen an das Outlet "
+"Muttergesellschaft, die verantwortlich ist für die Lieferungen an das Outlet-"
"Unternehmen.\n"
"\n"
" [ Kunde ] <- A - [ Outlet ] <- B - [ Muttergesellschaft ] <~ C ~ [ "
@@ -13574,24 +14035,22 @@ msgstr ""
"\n"
"Wenn ein neuer Beschaffungsauftrag (A, zum Beispiel entstanden aus der "
"Bestätigung eines\n"
-"Verakufsauftrages) im Outlet Unternehmen ankommt, wird er in einen anderen "
+"Verkaufsauftrages) im Outlet-Unternehmen ankommt, wird er in einen anderen "
"Beschaffungsauftrag\n"
"umgewandelt (B, mithilfe des Pull Ablaufes des Types \"Bewegen\") angefragt "
-"von der Muttergeseellschaft. \n"
+"von der Muttergesellschaft. \n"
"Wenn der Beschaffungsauftrag B durch die Muttergesellschaft verarbeitet wird "
"und wenn das Produkt\n"
"im Lager nicht vorrätig ist, kann es in eine Bestellung (C) an einen "
"Lieferanten (Pull Ablauf des\n"
"Types Beschaffung) umgewandelt werden. Das Ergebnis ist, dass die "
"Bestellung, die benötigt wird,\n"
-"den ganzen Weg zwischen dem Kunden und dem Lieferanten geschoben wird. \n"
+"den ganzen Weg zwischen dem Kunden und dem Lieferanten auslöst. \n"
"\n"
"Technisch erlauben Pull Abläufe die unterschiedliche Verarbeitung der\n"
-"Beschaffungsaufträge, nicht nur betrachtet je Produkt, sonder auch abhängig "
-"davon,\n"
-"welcher Ort erhält das \"Bedürfnis\" für dieses Produkt (d. h. der Zielort "
-"dieses\n"
-"Beschaffungsauftrages).\n"
+"Beschaffungsaufträge, nicht nur je Produkt, sonder auch abhängig davon,\n"
+"welcher Ort das \"Bedürfnis\" für dieses Produkt (d. h. der Zielort dieses\n"
+"Beschaffungsauftrages) benannt hat.\n"
"\n"
"Anwendungsfall:\n"
"--------------------------\n"
@@ -13619,13 +14078,12 @@ msgid ""
"The decimal precision is configured per company.\n"
msgstr ""
"\n"
-"Konfigurieren Sie den Preis in der Exaktheit, wie Sie ihn für "
-"unterschiedliche Arten der Nutzung gebrauchen: Buchhaltung, Verkauf, "
-"Einkauf\n"
+"Konfigurieren Sie den Preis in der Genauigkeit, die Sie für unterschiedliche "
+"Nutzungen benötigen: Buchhaltung, Verkauf, Einkauf\n"
"============================================================================="
"====================\n"
"\n"
-"Die Nachkommastellen wird pro Unternehmen konfiguriert.\n"
+"Die Nachkommastellen werden pro Unternehmen konfiguriert.\n"
#. module: base
#: selection:res.company,paper_format:0
@@ -13645,7 +14103,7 @@ msgstr "Kunde"
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (NI) / Español (NI)"
-msgstr "Spanish (NI) / Español (NI)"
+msgstr "Spanisch (NI) / Español (NI)"
#. module: base
#: model:ir.module.module,description:base.module_pad_project
@@ -13656,14 +14114,14 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung ergänzt ein PAD in allen Projekt Kanban Ansichten.\n"
+"Diese Anwendung ergänzt ein PAD in allen Projekt Kanbanansichten.\n"
"==========================================================\n"
" \n"
" repräsentiert einen Zeilenumbruch. Starten Sie hierzu einfach eine neue "
"Zeile in Ihrer Übersetzung.\n"
" repräsentiert ein Leerzeichen. Geben Sie einfach an der passenden Position "
"der Übersetzung ein \n"
-"Leezeichen ein.\n"
+"Leerzeichen ein.\n"
" "
#. module: base
@@ -13738,7 +14196,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_fields_converter
msgid "ir.fields.converter"
-msgstr ""
+msgstr "ir.fields.converter"
#. module: base
#: code:addons/base/res/res_partner.py:439
@@ -13761,12 +14219,12 @@ msgstr "Komoren"
#. module: base
#: view:ir.module.module:0
msgid "Cancel Install"
-msgstr "Installation Abbrechen"
+msgstr "Installation abbrechen"
#. module: base
#: model:ir.model,name:base.model_ir_model_relation
msgid "ir.model.relation"
-msgstr ""
+msgstr "ir.model.relation"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_check_writing
@@ -13793,7 +14251,7 @@ msgstr ""
"Diese Anwendung bietet das Outlook Plug-in\n"
"=====================================\n"
"\n"
-"Das Outlook Plugin ermöglicht Ihnen ein Objekt auszuwählen, das Sie gerne "
+"Das Outlook Plugin ermöglicht Ihnen ein Objekt auszuwählen, dem Sie gerne "
"Ihrer\n"
" E-Mail und dessen Anhang aus MS Outlook hinzufügen möchten. Sie können "
"einen Partner,\n"
@@ -13805,7 +14263,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_bo
msgid "Bolivia Localization Chart Account"
-msgstr ""
+msgstr "Bolivia Localization Chart Account"
#. module: base
#: model:ir.module.module,description:base.module_plugin_thunderbird
@@ -13822,7 +14280,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Dieses Modul wird für das Thunderbird-Plugin benötig, damit dieses "
+"Dieses Modul wird für das Thunderbird-Plugin benötigt, damit dieses "
"eingesetzt werden kann.\n"
"========================================================================\n"
"\n"
@@ -13845,7 +14303,7 @@ msgstr "Legende für Datum- und Zeit-Darstellungen"
#. module: base
#: selection:ir.actions.server,state:0
msgid "Copy Object"
-msgstr "Kopiere Objekt"
+msgstr "Objekt kopieren"
#. module: base
#: field:ir.actions.server,trigger_name:0
@@ -13922,7 +14380,7 @@ msgstr ""
"-----------------------------------------------------------------------------"
"------------------------------------------------\n"
" * isolieren der Umsätze von verschiedenen Abteilungen\n"
-" * Journalen für Lieferungen per LKW oder per UPS\n"
+" * Journale für Lieferungen per LKW oder per UPS\n"
"\n"
"Journale haben einen Verantwortlichen und entwickeln sich zwischen "
"verschieden Zuständen:\n"
@@ -13949,7 +14407,7 @@ msgstr ""
#: code:addons/base/ir/ir_mail_server.py:474
#, python-format
msgid "Mail delivery failed"
-msgstr "Mail Auslieferung fehlgeschlagen"
+msgstr "Mailversand fehlgeschlagen"
#. module: base
#: view:ir.actions.act_window:0
@@ -14059,7 +14517,7 @@ msgstr ""
"Diese Anwendung erstellt Kurse und Schüler automatisch in Ihrer Moodle-"
"Plattform,\n"
"um Zeitverschwendung zu vermeiden.\n"
-"Nun haben sie eine einfache Möglichkeit, Schulungen oder Kurse mit OpenERP "
+"Nun haben Sie eine einfache Möglichkeit, Schulungen oder Kurse mit OpenERP "
"und Moodle zu erstellen. \n"
"\n"
"SCHRITTE ZUM KONFIGURIEREN:\n"
@@ -14077,7 +14535,7 @@ msgstr ""
"\n"
"2. Erstellen Sie eine Bestätigungsemail mit Login und Passwort\n"
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
-"Wir empfehlen Ihnen dringen, diese folgenden Zeilen am Ende Ihrer "
+"Wir empfehlen Ihnen dringend, die folgenden Zeilen am Ende Ihrer "
"Bestätigungsemail hinzuzufügen, um Ihren Abonnenten Login und Passwort von "
"Moodle mitzuteilen.\n"
"\n"
@@ -14114,7 +14572,7 @@ msgstr ""
#. module: base
#: field:ir.ui.view_sc,user_id:0
msgid "User Ref."
-msgstr "Benutzer Referenz"
+msgstr "Benutzer-Referenz"
#. module: base
#: code:addons/base/ir/ir_fields.py:226
@@ -14143,7 +14601,7 @@ msgstr "Wiederverkäufer"
#: field:ir.model.fields,readonly:0
#: field:res.partner.bank.type.field,readonly:0
msgid "Readonly"
-msgstr "Lesen"
+msgstr "Nur Lesen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_gt
@@ -14184,7 +14642,7 @@ msgstr ""
msgid ""
"Please make sure no workitems refer to an activity before deleting it!"
msgstr ""
-"Bitte stellen Sie sicher, das keine Aufgaben sich mehr auf Ihre Tätigkeit "
+"Bitte stellen Sie sicher, dass keine Aufgaben mehr auf Ihre Tätigkeit "
"referenzieren, bevor Sie sie löschen!"
#. module: base
@@ -14237,17 +14695,17 @@ msgstr "4. %b, %B ==> Dez, Dezember"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_cl
msgid "Chile Localization Chart Account"
-msgstr ""
+msgstr "Chile Localization Chart Account"
#. module: base
#: selection:base.language.install,lang:0
msgid "Sinhalese / සිංහල"
-msgstr "Sinhalese / සිංහල"
+msgstr "Sinhalesisch / සිංහල"
#. module: base
#: selection:res.request,state:0
msgid "waiting"
-msgstr "Wartend"
+msgstr "wartend"
#. module: base
#: model:ir.model,name:base.model_workflow_triggers
@@ -14292,7 +14750,7 @@ msgstr ""
#. module: base
#: field:ir.actions.act_window,view_id:0
msgid "View Ref."
-msgstr "Ansicht Referenz"
+msgstr "Ansichtsreferenz"
#. module: base
#: model:ir.module.category,description:base.module_category_sales_management
@@ -14352,7 +14810,7 @@ msgstr ""
#: field:ir.actions.server,type:0
#: field:ir.actions.wizard,type:0
msgid "Action Type"
-msgstr "Aktionart"
+msgstr "Aktionsart"
#. module: base
#: code:addons/base/module/module.py:372
@@ -14363,14 +14821,14 @@ msgid ""
msgstr ""
"Sie versuchen das Modul '%s' zu installieren, welches eine Abhängigkeit zum "
"Modul '%s' aufweist.\n"
-"Allerdings kann dieses vorausgesetzte Modul nicht installiert werden."
+"Allerdings kann dieses notwendige Modul nicht installiert werden."
#. module: base
#: view:base.language.import:0
#: model:ir.actions.act_window,name:base.action_view_base_import_language
#: model:ir.ui.menu,name:base.menu_view_base_import_language
msgid "Import Translation"
-msgstr "Importiere Übersetzung"
+msgstr "Übersetzung importieren"
#. module: base
#: view:ir.module.module:0
@@ -14445,7 +14903,7 @@ msgstr "Bedingungen"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_other_form
msgid "Other Partners"
-msgstr "andere Partner"
+msgstr "Andere Partner"
#. module: base
#: field:base.language.install,state:0
@@ -14482,7 +14940,7 @@ msgstr "Standard Wert (pickled) oder Referenz zu einer Aktion"
#. module: base
#: field:ir.actions.report.xml,auto:0
msgid "Custom Python Parser"
-msgstr "benutzerdefinierter Python Parser"
+msgstr "Benutzerdefinierter Python Parser"
#. module: base
#: sql_constraint:res.groups:0
@@ -14492,7 +14950,7 @@ msgstr "Der Name der Gruppe muss eindeutig sein!"
#. module: base
#: help:ir.translation,module:0
msgid "Module this term belongs to"
-msgstr "Anwendung zu der diese Ausdrucksweise dazu gehört"
+msgstr "Anwendung zu der diese Ausdruck gehört"
#. module: base
#: model:ir.module.module,description:base.module_web_view_editor
@@ -14551,6 +15009,13 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"Argentinian accounting chart and tax localization.\n"
+"==================================================\n"
+"\n"
+"Plan contable argentino e impuestos de acuerdo a disposiciones vigentes\n"
+"\n"
+" "
#. module: base
#: code:addons/fields.py:130
@@ -14597,7 +15062,7 @@ msgstr "Lohnbuchhaltung"
#. module: base
#: view:res.users:0
msgid "Change password"
-msgstr "Ändere Passwort"
+msgstr "Passwort ändern"
#. module: base
#: model:res.country,name:base.sr
@@ -14617,7 +15082,7 @@ msgstr "Erstellungsmonat"
#. module: base
#: field:ir.module.module,demo:0
msgid "Demo Data"
-msgstr "Demo Daten"
+msgstr "Demodaten"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_mister
@@ -14647,12 +15112,12 @@ msgstr "Modell für das dieser Eintrag gilt"
#. module: base
#: field:res.country,address_format:0
msgid "Address Format"
-msgstr "Adressenformat"
+msgstr "Adressformat"
#. module: base
#: model:ir.model,name:base.model_change_password_user
msgid "Change Password Wizard User"
-msgstr "Passwortänderung Assistent"
+msgstr "Passwortänderungs-Assistent"
#. module: base
#: model:res.groups,name:base.group_no_one
@@ -14693,11 +15158,41 @@ msgid ""
"proposed, \n"
"but you will need set manually account defaults for taxes.\n"
msgstr ""
+"\n"
+"Chart of Account for Venezuela.\n"
+"===============================\n"
+"\n"
+"Venezuela doesn't have any chart of account by law, but the default\n"
+"proposed in OpenERP should comply with some Accepted best practices in "
+"Venezuela, \n"
+"this plan comply with this practices.\n"
+"\n"
+"This module has been tested as base for more of 1000 companies, because \n"
+"it is based in a mixtures of most common softwares in the Venezuelan \n"
+"market what will allow for sure to accountants feel them first steps with \n"
+"OpenERP more confortable.\n"
+"\n"
+"This module doesn't pretend be the total localization for Venezuela, \n"
+"but it will help you to start really quickly with OpenERP in this country.\n"
+"\n"
+"This module give you.\n"
+"---------------------\n"
+"\n"
+"- Basic taxes for Venezuela.\n"
+"- Have basic data to run tests with community localization.\n"
+"- Start a company from 0 if your needs are basic from an accounting PoV.\n"
+"\n"
+"We recomend install account_anglo_saxon if you want valued your \n"
+"stocks as Venezuela does with out invoices.\n"
+"\n"
+"If you install this module, and select Custom chart a basic chart will be "
+"proposed, \n"
+"but you will need set manually account defaults for taxes.\n"
#. module: base
#: selection:base.language.install,lang:0
msgid "Occitan (FR, post 1500) / Occitan"
-msgstr "Occitan (FR, post 1500) / Okzitan"
+msgstr "Occitanisch (FR, post 1500) / Okzitan"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:215
@@ -14734,9 +15229,9 @@ msgid ""
"OpenERP. They are launched during the installation of new modules, but you "
"can choose to restart some wizards manually from this menu."
msgstr ""
-"Konfigurationsassistenen helfen bei der Konfiguration einer neuen OpenERP "
+"Konfigurationsassistenten helfen bei der Konfiguration einer neuen OpenERP "
"Instanz. Sie werden nach der Installation von neuen Modulen aufgerufen und "
-"können auch manuell im Administrator Menu aufgerufen werden."
+"können auch manuell im Administratormenu aufgerufen werden."
#. module: base
#: field:ir.actions.report.xml,report_sxw:0
@@ -14824,7 +15319,7 @@ msgstr ""
"Soziales Netzwerk für Unternehmen\n"
"=================================\n"
"Die Anwendung Soziales Netzwerk ermöglicht allen Anwendungen in OpenERP die "
-"Nutzung eines voll integrierten E-Mail und Nachrichten Management System und "
+"Nutzung eines voll integrierten E-Mail und Nachrichten Managementsystem und "
"realisiert damit eine einheitliche, übergreifende und zusätzliche generische "
"Kommunikationsplattform für alle OpenERP Anwendungen. \n"
"\n"
@@ -14836,10 +15331,10 @@ msgstr ""
"\n"
"Wesentliche Funktionen:\n"
"-----------------------------------\n"
-"* Verbesserte Kommunikations-Historie für OpenERP Geschäftsvorfälle, die "
+"* Verbesserte Kommunikations-Historie für OpenERP-Geschäftsvorfälle, die "
"auch Thema einer EMail sein können\n"
-"* Abonnement-Mechanismus, um über neue Nachrichten zu interessanten "
-"Vorfällen auf dem Laufenden gehalten zu werden\n"
+"* Abonnement-Mechanismus, um über neue Nachrichten zu interessanten Fällen "
+"auf dem Laufenden gehalten zu werden\n"
"* Einheitlichte und zentrale Feeds-Seite, um die neusten Nachrichten und "
"Aktivitäten in Echtzeit zu empfangen\n"
"* Benutzer Mailversand über die zentrale Startseite\n"
@@ -14848,8 +15343,8 @@ msgstr ""
"Management-System - das die koordinierte Steuerung des E-Mail Versands in "
"vordefinierten Zeitabständen ermöglicht\n"
"* Benutzerfreundlicher und einfacher E-Mail Editor, der auch als "
-"Konfigurationsassistent für Marketing-Email Aktivitäten genutzt werden kann "
-"und fähig ist, die Interpretation von einfachen *Platzhalter Ausdrücken* mit "
+"Konfigurationsassistent für Marketing-E-Mail Aktivitäten genutzt werden kann "
+"und fähig ist, die Interpretation von einfachen *Platzhalterausdrücken* mit "
"dynamischen Daten aus OpenERP zu ersetzen, sobald Mails tatsächlich durch "
"Kampagnen gesendet werden.\n"
" "
@@ -14881,7 +15376,7 @@ msgstr "Auslösedatum"
#. module: base
#: selection:base.language.install,lang:0
msgid "Croatian / hrvatski jezik"
-msgstr "Kroatien / hrvatski jezik"
+msgstr "Kroatisch / hrvatski jezik"
#. module: base
#: model:ir.module.module,description:base.module_l10n_uy
@@ -14943,7 +15438,7 @@ msgstr "ir.values"
#. module: base
#: model:ir.model,name:base.model_base_module_update
msgid "Update Module"
-msgstr "Aktualisiere Modul"
+msgstr "Update Module"
#. module: base
#: view:ir.model.fields:0
@@ -14953,7 +15448,7 @@ msgstr "Übersetzen"
#. module: base
#: field:res.request.history,body:0
msgid "Body"
-msgstr "Textkörper"
+msgstr "Mitteilung"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:221
@@ -15047,7 +15542,7 @@ msgstr "Filter für meine Dokumente"
#. module: base
#: model:ir.module.module,summary:base.module_project_gtd
msgid "Personal Tasks, Contexts, Timeboxes"
-msgstr "Persönliche Aufgaben, Kontext, Zeitkonten"
+msgstr "Persönliche Aufgaben, Kontexte, Zeitkonten"
#. module: base
#: model:ir.module.module,description:base.module_l10n_cr
@@ -15069,6 +15564,22 @@ msgid ""
"please go to http://translations.launchpad.net/openerp-costa-rica.\n"
" "
msgstr ""
+"\n"
+"Chart of accounts for Costa Rica.\n"
+"=================================\n"
+"\n"
+"Includes:\n"
+"---------\n"
+" * account.type\n"
+" * account.account.template\n"
+" * account.tax.template\n"
+" * account.tax.code.template\n"
+" * account.chart.template\n"
+"\n"
+"Everything is in English with Spanish translation. Further translations are "
+"welcome,\n"
+"please go to http://translations.launchpad.net/openerp-costa-rica.\n"
+" "
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_supplier_form
@@ -15198,9 +15709,9 @@ msgstr ""
"-----------------------------------------------------------------------------"
"---\n"
" * Freie Mitglieder\n"
-" * assoziiertes Mitglieder\n"
-" * zahlende Mitglieder\n"
-" * Spezielle Mitglied Preise\n"
+" * Assoziiertes Mitglieder\n"
+" * Zahlende Mitglieder\n"
+" * Spezielle Mitgliedspreise\n"
"\n"
"Es ist in das Umsatz und Rechnungswesen integriert, was Ihnen die "
"Möglichkeit bietet, automatisch zu fakturieren und Vorschläge für "
@@ -15226,7 +15737,7 @@ msgstr "Einstellungen"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_9
msgid "Components Buyer"
-msgstr "Komponenten Käufer"
+msgstr "Komponenten-Käufer"
#. module: base
#: model:ir.module.module,description:base.module_web_tests_demo
@@ -15332,8 +15843,8 @@ msgid ""
"The object that should receive the workflow signal (must have an associated "
"workflow)"
msgstr ""
-"Das Objekt, dass das Arbeitsfluss Signal empfangen soll (muss einen "
-"zugeordneten Arbeitsfluss haben)"
+"Das Objekt, dass das Workflowsignal empfangen soll (muss einen zugeordneten "
+"Workflow haben)"
#. module: base
#: model:ir.module.category,description:base.module_category_account_voucher
@@ -15348,7 +15859,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.eh
msgid "Western Sahara"
-msgstr "WestSahara"
+msgstr "Westliche Sahara"
#. module: base
#: model:ir.module.category,name:base.module_category_account_voucher
@@ -15445,7 +15956,7 @@ msgstr "5. %y, %Y ==> 08, 2008"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_ltd
msgid "ltd"
-msgstr "mbH"
+msgstr "GmbH"
#. module: base
#: model:ir.module.module,description:base.module_crm_claim
@@ -15465,7 +15976,7 @@ msgstr ""
"\n"
"Verwalten von Kunden-Forderungen\n"
"==============================\n"
-"Diese Anwendung ermöglicht Ihnen Ihre Kunden / Lieferanten Forderungen und "
+"Diese Anwendung ermöglicht Ihnen, Ihre Kunden-/ Lieferantenforderungen und -"
"Beschwerden zu verfolgen. \n"
"\n"
"Es ist komplett in die E-Mail Schnittstelle integriert, sodass Sie "
@@ -15540,9 +16051,9 @@ msgid ""
"128x128px image, with aspect ratio preserved. Use this field in form views "
"or some kanban views."
msgstr ""
-"mittlere Bildgröße dieses Kontakts. Es wird vermutlich auf 128x128px Image "
-"verändert unter Beibehaltung der Formate. Benutzen Sie das Feld in einfachen "
-"Formularanzeigen oder Kanban Ansichten."
+"Mittlere Bildgröße dieses Kontakts. Es wird vermutlich auf 128x128px Image "
+"verändert unter Beibehaltung des Seitenverhältnisses. Benutzen Sie das Feld "
+"in einfachen Formularanzeigen oder Kanbanansichten."
#. module: base
#: view:base.update.translations:0
@@ -15570,7 +16081,7 @@ msgstr "Irak"
#: model:ir.ui.menu,name:base.menu_association
#: model:ir.ui.menu,name:base.menu_report_association
msgid "Association"
-msgstr "Verein/Gesellschaft"
+msgstr "Verein/Verband"
#. module: base
#: view:ir.actions.server:0
@@ -15597,7 +16108,7 @@ msgstr "ir.sequence.type"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_be_hr_payroll_account
msgid "Belgium - Payroll with Accounting"
-msgstr ""
+msgstr "Belgien - Lohnabrechnung"
#. module: base
#: selection:base.language.export,format:0
@@ -15628,6 +16139,15 @@ msgid ""
" - InfoLogic UK counties listing\n"
" - a few other adaptations"
msgstr ""
+"\n"
+"This is the latest UK OpenERP localisation necessary to run OpenERP "
+"accounting for UK SME's with:\n"
+"============================================================================="
+"====================\n"
+" - a CT600-ready chart of accounts\n"
+" - VAT100-ready tax structure\n"
+" - InfoLogic UK counties listing\n"
+" - a few other adaptations"
#. module: base
#: selection:ir.model,state:0
@@ -15655,7 +16175,7 @@ msgstr "Steuer-Nr."
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_bank_statement_extensions
msgid "Bank Statement Extensions to Support e-banking"
-msgstr "Kontoauszug Erweiterungen zur Unterstützung von E-Banking"
+msgstr "Kontoauszugs-Erweiterungen zur Unterstützung von E-Banking"
#. module: base
#: field:ir.model.fields,field_description:0
@@ -15670,7 +16190,7 @@ msgstr "Dschibuti"
#. module: base
#: field:ir.translation,value:0
msgid "Translation Value"
-msgstr "Übersetzung"
+msgstr "Übersetzungswert"
#. module: base
#: model:res.country,name:base.ag
@@ -15704,7 +16224,7 @@ msgstr "Information"
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "false"
-msgstr ""
+msgstr "falsch"
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_analysis
@@ -15747,7 +16267,7 @@ msgstr ""
"\n"
" * Aufwandseingabe\n"
" * Zahlungserfassung\n"
-" * Unternehmen Beteiligungsverwaltung\n"
+" * Unternehmens-Beteiligungsverwaltung\n"
" "
#. module: base
@@ -15758,7 +16278,7 @@ msgstr "Übergeordneter Partner"
#. module: base
#: view:base.module.update:0
msgid "Update Module List"
-msgstr "Aktualisiere Modulliste"
+msgstr "Modulliste aktualisieren"
#. module: base
#: code:addons/base/res/res_users.py:685
@@ -15772,7 +16292,7 @@ msgstr "Andere"
#. module: base
#: selection:base.language.install,lang:0
msgid "Turkish / Türkçe"
-msgstr "Turkish / Türkçe"
+msgstr "Türkisch / Türkçe"
#. module: base
#: model:ir.actions.act_window,name:base.action_workflow_activity_form
@@ -15878,7 +16398,7 @@ msgstr "Wallis- und Futuna-Inseln"
#. module: base
#: help:multi_company.default,name:0
msgid "Name it to easily find a record"
-msgstr "Benennen Sie den Datensatz um Ihn leichter wiederzufinden"
+msgstr "Benennen Sie den Datensatz, um Ihn leichter wiederzufinden"
#. module: base
#: model:ir.module.module,description:base.module_hr
@@ -15903,15 +16423,14 @@ msgstr ""
"Personalwirtschaft\n"
"================\n"
"\n"
-"Diese Anwendung ermöglicht Ihnen, wichtige Aspekte Ihrer Mitarbeiter und "
-"andere Details wie Kenntnisse, Kontaktdaten, Arbeitszeiten,... zu verwalten. "
-"\n"
+"Diese Anwendung ermöglicht Ihnen, wichtige Daten Ihrer Mitarbeiter und "
+"Details wie Kenntnisse, Kontaktdaten, Arbeitszeiten,... zu verwalten. \n"
"\n"
"\n"
"Sie können Folgendes verwalten:\n"
"------------------------------------------------------\n"
-"* Mitarbeiter und Hierarchien: Sie können Ihre Mitarbeiter mit Benutzer-und "
-"Anzeige Hierarchien definieren\n"
+"* Mitarbeiter und Hierarchien: Sie können Ihre Mitarbeiter mit Benutzer- und "
+"Anzeige-Hierarchien definieren\n"
"* Personalwirtschaft Abteilungen\n"
"* Personalwirtschaft Arbeitsplätze\n"
" "
@@ -15966,7 +16485,7 @@ msgid ""
msgstr ""
"\n"
"Mit dieser Anwendung können Administratoren jede Benutzerhandlung für alle "
-"Objekt des Systems verfolgen\n"
+"Objekte des Systems verfolgen\n"
"============================================================================="
"==============\n"
"\n"
@@ -15993,7 +16512,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_event
msgid "Events Organisation"
-msgstr "Veranstaltungs Organisation"
+msgstr "Veranstaltungs-Organisation"
#. module: base
#: model:ir.actions.act_window,name:base.ir_sequence_actions
@@ -16114,13 +16633,13 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung fügt eine Verknüpfung zu ein oder mehreren möglichen Fällen "
-"im CRM hinzu. \n"
+"Diese Anwendung fügt eine Verknüpfung zu einen oder mehreren Fällen im CRM "
+"hinzu. \n"
"===========================================================================\n"
"\n"
"Diese Verknüpfung ermöglicht es Ihnen, einen Kundenauftrag, basierend auf "
"dem ausgewählten Fall,\n"
-"zu erstellen Wenn verschiedene Fälle geöffnet sind (eine Liste), wird ein "
+"zu erstellen. Wenn verschiedene Fälle geöffnet sind (eine Liste), wird ein "
"Verkaufsauftrag pro Fall\n"
"erstellt. Der Fall wird dann geschlossen und mit dem erzeugten Kundenauftrag "
"verbunden.\n"
@@ -16133,7 +16652,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.bq
msgid "Bonaire, Sint Eustatius and Saba"
-msgstr ""
+msgstr "Bonaire, Sint Eustatius und Saba"
#. module: base
#: model:ir.actions.report.xml,name:base.ir_module_reference_print
@@ -16265,6 +16784,16 @@ msgstr ""
"\n"
"Am Ende des Preislisten-Formulars wird ein Kontrollkästchen \"Rabatt "
"sichtbar\" hinzugefügt.\n"
+"\n"
+"**Beispiel:**\n"
+" Für das Produkt PC1 und den Partner \"Asustek\": if listprice=450, und "
+"der Preis\n"
+" wird auf Grundlage der Asustek Preisliste 225 kalkuliert. Wenn die "
+"Checkbox aktiviert ist\n"
+" wird die Bestellzeile folgendes anzeigen: Preis/Einheit=450, "
+"Discount=50,00, Nettopreis=225.\n"
+" Ist die Checkbox nicht aktiv wird folgendes angezeigt:\n"
+" Preis/Einheit=225, Discount=0,00, Nettopreis=225.\n"
" "
#. module: base
@@ -16331,7 +16860,7 @@ msgstr "TLS (STARTTLS)"
#: help:ir.actions.act_window,usage:0
msgid "Used to filter menu and home actions from the user form."
msgstr ""
-"Wird verwendet um Menu und Startseiten des Benutzer-Formulars zu filtern"
+"Wird verwendet um Menus und Startseiten des Benutzer-Formulars zu filtern"
#. module: base
#: model:res.country,name:base.sa
@@ -16354,12 +16883,12 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung bietet dem Benutzer die Möglichkeit, um Fertigung und "
-"Verkauf gleichzeitig zu installieren. \n"
+"Diese Anwendung bietet dem Benutzer die Möglichkeit, Fertigung und Verkauf "
+"gleichzeitig zu installieren. \n"
"============================================================================="
"=================\n"
"\n"
-"Es wird grundsätzlich verwendet, wenn wir den Überblick über "
+"Das Modul wird grundsätzlich verwendet, wenn wir den Überblick über "
"Fertigungsaufträge, die aus Verkaufsaufträge erstellt werden, behalten "
"wollen. Es fügt Verkaufsnamen und Verkaufsreferenzen dem Fertigungsauftrag "
"hinzu.\n"
@@ -16409,7 +16938,7 @@ msgstr ""
#: code:addons/base/module/wizard/base_module_configuration.py:38
#, python-format
msgid "System Configuration done"
-msgstr "System Konfiguration erledigt"
+msgstr "System-Konfiguration erledigt"
#. module: base
#: field:ir.attachment,db_datas:0
@@ -16532,8 +17061,8 @@ msgid ""
"3. If user belongs to several groups, the results from step 2 are combined "
"with logical OR operator"
msgstr ""
-"3. Wenn ein Benutzer verschiedenen Gruppen angehört werden die Ergebnisse "
-"aus Schritt 2 mit logisch ODER verknüpft."
+"3. Wenn ein Benutzer verschiedenen Gruppen angehört, werden die Ergebnisse "
+"aus Schritt 2 mit einem logisch OR-Operator verknüpft."
#. module: base
#: model:ir.module.module,description:base.module_l10n_be
@@ -16581,6 +17110,48 @@ msgid ""
"\n"
" "
msgstr ""
+"\n"
+"This is the base module to manage the accounting chart for Belgium in "
+"OpenERP.\n"
+"============================================================================="
+"=\n"
+"\n"
+"After installing this module, the Configuration wizard for accounting is "
+"launched.\n"
+" * We have the account templates which can be helpful to generate Charts "
+"of Accounts.\n"
+" * On that particular wizard, you will be asked to pass the name of the "
+"company,\n"
+" the chart template to follow, the no. of digits to generate, the code "
+"for your\n"
+" account and bank account, currency to create journals.\n"
+"\n"
+"Thus, the pure copy of Chart Template is generated.\n"
+"\n"
+"Wizards provided by this module:\n"
+"--------------------------------\n"
+" * Partner VAT Intra: Enlist the partners with their related VAT and "
+"invoiced\n"
+" amounts. Prepares an XML file format.\n"
+" \n"
+" **Path to access :** Invoicing/Reporting/Legal Reports/Belgium "
+"Statements/Partner VAT Intra\n"
+" * Periodical VAT Declaration: Prepares an XML file for Vat Declaration "
+"of\n"
+" the Main company of the User currently Logged in.\n"
+" \n"
+" **Path to access :** Invoicing/Reporting/Legal Reports/Belgium "
+"Statements/Periodical VAT Declaration\n"
+" * Annual Listing Of VAT-Subjected Customers: Prepares an XML file for "
+"Vat\n"
+" Declaration of the Main company of the User currently Logged in Based "
+"on\n"
+" Fiscal year.\n"
+" \n"
+" **Path to access :** Invoicing/Reporting/Legal Reports/Belgium "
+"Statements/Annual Listing Of VAT-Subjected Customers\n"
+"\n"
+" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_gengo
@@ -16604,12 +17175,12 @@ msgstr "El Salvador"
#: field:res.partner,phone:0
#, python-format
msgid "Phone"
-msgstr "Tel"
+msgstr "Telefon"
#. module: base
#: field:res.groups,menu_access:0
msgid "Access Menu"
-msgstr "Rechte Menü"
+msgstr "Rechtemenü"
#. module: base
#: model:res.country,name:base.th
@@ -16629,7 +17200,7 @@ msgstr "Rechnungen versenden und Zahlung überwachen"
#. module: base
#: model:ir.ui.menu,name:base.menu_crm_config_lead
msgid "Leads & Opportunities"
-msgstr "Leads und Chancen"
+msgstr "Interessenten und Chancen"
#. module: base
#: model:res.country,name:base.gg
@@ -16639,7 +17210,7 @@ msgstr "Guernsey"
#. module: base
#: selection:base.language.install,lang:0
msgid "Romanian / română"
-msgstr "Romänisch / română"
+msgstr "Rumänisch / română"
#. module: base
#: model:ir.module.module,description:base.module_l10n_mx
@@ -16664,6 +17235,25 @@ msgid ""
".. SAT: http://www.sat.gob.mx/\n"
" "
msgstr ""
+"\n"
+"Minimal accounting configuration for Mexico.\n"
+"============================================\n"
+"\n"
+"This Chart of account is a minimal proposal to be able to use OoB the \n"
+"accounting feature of Openerp.\n"
+"\n"
+"This doesn't pretend be all the localization for MX it is just the minimal \n"
+"data required to start from 0 in mexican localization.\n"
+"\n"
+"This modules and its content is updated frequently by openerp-mexico team.\n"
+"\n"
+"With this module you will have:\n"
+"\n"
+" - Minimal chart of account tested in production eviroments.\n"
+" - Minimal chart of taxes, to comply with SAT_ requirements.\n"
+"\n"
+".. SAT: http://www.sat.gob.mx/\n"
+" "
#. module: base
#: model:ir.module.module,description:base.module_l10n_tr
@@ -16678,28 +17268,37 @@ msgid ""
" bilgileriniz, ilgili para birimi gibi bilgiler isteyecek.\n"
" "
msgstr ""
+"\n"
+"Türkiye için Tek düzen hesap planı şablonu OpenERP Modülü.\n"
+"==========================================================\n"
+"\n"
+"Bu modül kurulduktan sonra, Muhasebe yapılandırma sihirbazı çalışır\n"
+" * Sihirbaz sizden hesap planı şablonu, planın kurulacağı şirket, banka "
+"hesap\n"
+" bilgileriniz, ilgili para birimi gibi bilgiler isteyecek.\n"
+" "
#. module: base
#: selection:workflow.activity,join_mode:0
#: selection:workflow.activity,split_mode:0
msgid "And"
-msgstr "und"
+msgstr "Und"
#. module: base
#: help:ir.values,res_id:0
msgid ""
"Database identifier of the record to which this applies. 0 = for all records"
-msgstr "Kennung des Datensatzes auf den dies zutrifft. 0 = alle Datensatze"
+msgstr "Kennung des Datensatzes auf den dies zutrifft. 0 = alle Datensätze"
#. module: base
#: field:ir.model.fields,relation:0
msgid "Object Relation"
-msgstr "Objekt Beziehungen"
+msgstr "Objekt-Beziehungen"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_voucher
msgid "eInvoicing & Payments"
-msgstr "eRechnung & Zahlungen"
+msgstr "E-Rechnungen & Zahlungen"
#. module: base
#: view:ir.rule:0
@@ -16802,18 +17401,18 @@ msgid ""
msgstr ""
"Verwaltung und Anpassung der Anzeige von Einträgen im Systemmenü. Sie können "
"einen Eintrag durch Aktivieren zu Beginn jeder Zeile und durch Klick auf den "
-"Button löschen. Einträge können zu bestimmten Gruppen zugewiesen werden, um "
-"bestimmten Benutzern Berechtigungen und Zugriff zu geben."
+"Button löschen. Einträge können bestimmten Gruppen zugewiesen werden, um "
+"Nutzern Berechtigungen und Zugriff zu geben."
#. module: base
#: field:ir.ui.view,field_parent:0
msgid "Child Field"
-msgstr "(Unter-) Feld"
+msgstr "Unter-Feld"
#. module: base
#: view:ir.rule:0
msgid "Detailed algorithm:"
-msgstr "detaillierte Berechnung:"
+msgstr "Detaillierte Berechnung:"
#. module: base
#: field:ir.actions.act_url,usage:0
@@ -16849,7 +17448,7 @@ msgstr ""
#. module: base
#: selection:ir.module.module,state:0
msgid "Not Installable"
-msgstr "nicht installierbar"
+msgstr "Nicht installierbar"
#. module: base
#: help:res.lang,iso_code:0
@@ -16859,7 +17458,7 @@ msgstr "Der ISO Code ist der Name der po Datei für Übersetzungen"
#. module: base
#: report:ir.module.reference:0
msgid "View :"
-msgstr "Sicht :"
+msgstr "Ansicht :"
#. module: base
#: field:ir.model.fields,view_load:0
@@ -16880,6 +17479,16 @@ msgid ""
" - Regional State listings\n"
" "
msgstr ""
+"\n"
+"Base Module for Ethiopian Localization\n"
+"======================================\n"
+"\n"
+"This is the latest Ethiopian OpenERP localization and consists of:\n"
+" - Chart of Accounts\n"
+" - VAT tax structure\n"
+" - Withholding tax structure\n"
+" - Regional State listings\n"
+" "
#. module: base
#: view:res.users:0
@@ -16904,7 +17513,7 @@ msgstr "Web Icon Datei"
#. module: base
#: model:ir.ui.menu,name:base.menu_view_base_module_upgrade
msgid "Apply Scheduled Upgrades"
-msgstr "Starte geplante Aktualsierungen"
+msgstr "Starte Installation"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_journal
@@ -16929,7 +17538,7 @@ msgstr "Persisch / Persien"
#. module: base
#: view:base.language.export:0
msgid "Export Settings"
-msgstr "Export Einstellungen"
+msgstr "Export-Einstellungen"
#. module: base
#: field:ir.actions.act_window,src_model:0
@@ -17159,7 +17768,7 @@ msgstr "Argentinien"
#. module: base
#: field:res.groups,full_name:0
msgid "Group Name"
-msgstr "Gruppenbezeichnung"
+msgstr "Gruppenname"
#. module: base
#: model:res.country,name:base.bh
@@ -17230,7 +17839,7 @@ msgstr ""
" * Möglichkeit zur Konfiguration des Grundlohns / Brutto- / Netto Gehalt\n"
" * Mitarbeiter Lohn- und Gehaltsabrechnung\n"
" * Monatliche Lohn- und Gehaltsabrechnung\n"
-" * Integration mit der Urlaubsverwaltung\n"
+" * Integration in die Urlaubsverwaltung\n"
" "
#. module: base
@@ -17311,7 +17920,7 @@ msgstr ""
"folgende\n"
"Eigenschaften erfüllt:\n"
" * Produktart = Dienstleistung\n"
-" * Beschaffung Methode (Auftragsabwicklung) = MTO (Make to Order)\n"
+" * Beschaffungsmethode (Auftragsabwicklung) = MTO (Make to Order)\n"
" * Lieferungs- / Beschaffungsmethode = Fertigung\n"
"\n"
"Wenn ein Projekt als Produkt angegeben ist (oben in der Registerkarte "
@@ -17473,7 +18082,7 @@ msgid ""
"====================================\n"
msgstr ""
"\n"
-"Benutzern erlauben, über OpenID anzumelden. \n"
+"Benutzern erlauben sich über OpenID anzumelden. \n"
"===========================================\n"
#. module: base
@@ -17491,7 +18100,7 @@ msgstr "Cookinseln"
#. module: base
#: field:ir.model.data,noupdate:0
msgid "Non Updatable"
-msgstr "Nicht Updatefähig"
+msgstr "Nicht updatefähig"
#. module: base
#: selection:base.language.install,lang:0
@@ -17520,8 +18129,8 @@ msgid ""
"Helps you handle your accounting needs, if you are not an accountant, we "
"suggest you to install only the Invoicing."
msgstr ""
-"Unterstützt Sie bei Ihrem Bedarf an Finanzbuchhaltung. Sind Sie kein "
-"Buchhalten, so empfehlen wir Ihnen\r\n"
+"Unterstützt Sie der Finanzbuchhaltung. Sind Sie kein Buchhalter, so "
+"empfehlen wir Ihnen\r\n"
"(sofern wegen anderer Abhängigkeiten möglich) nur das Rechnungswesen zu "
"installieren."
@@ -17616,7 +18225,7 @@ msgstr "%X - Angebrachte Zeitpräsentation."
#. module: base
#: selection:base.language.install,lang:0
msgid "Spanish (SV) / Español (SV)"
-msgstr "Spanish (SV) / Español (SV)"
+msgstr "Spanisch (SV) / Español (SV)"
#. module: base
#: help:res.lang,grouping:0
@@ -17626,7 +18235,7 @@ msgid ""
"1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as "
"106,500. Provided ',' as the thousand separator in each case."
msgstr ""
-"Das Trennzeichenformat sollte [,n] entsprechen mit 0 < n, beginnenend bei "
+"Das Trennzeichenformat sollte [,n] entsprechen mit 0 < n, beginnend bei "
"Einer-Stelle. -1 beendet die Trennung. Z. B. [3,2,-1] bei 106500 entspricht "
"1,06,500; [1,2,-1] würde dann 106,50,0 ergeben; [3] wird 106,500 daraus "
"erstellen. Vorausgesetzt ',' sei jeweils der Tausender-Trenner."
@@ -17649,6 +18258,15 @@ msgid ""
"taxes\n"
"and the Lempira currency."
msgstr ""
+"\n"
+"This is the base module to manage the accounting chart for Honduras.\n"
+"====================================================================\n"
+" \n"
+"Agrega una nomenclatura contable para Honduras. También incluye impuestos y "
+"la\n"
+"moneda Lempira. -- Adds accounting chart for Honduras. It also includes "
+"taxes\n"
+"and the Lempira currency."
#. module: base
#: model:res.country,name:base.jp
@@ -17751,7 +18369,7 @@ msgstr "Kanadische Buchführung"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_co
msgid "Colombian - Accounting"
-msgstr "Kolumbien - Accounting"
+msgstr "Kolumbien - Buchführung"
#. module: base
#: model:ir.module.module,description:base.module_account_voucher
@@ -17786,14 +18404,14 @@ msgstr ""
"Buchhaltungsexperte sind. Es bietet Ihnen einen einfachen Weg, Ihre "
"Lieferanten- und Kundenabrechnungen zu verfolgen. \n"
"\n"
-"Sie können zum Beispiel diese vereinfachte Buchhaltung verwenden, wenn Sie "
-"mit einem (externen) Buchhalter zusammenarbeiten, der Ihre Bücher führt, Sie "
-"aber dennoch zeitnahe Ihre Zahlungen verfolgen möchtet. \n"
+"Sie können diese vereinfachte Buchhaltung verwenden, wenn Sie mit einem "
+"(externen) Buchhalter zusammenarbeiten, der Ihre Bücher führt, Sie aber "
+"dennoch zeitnahe Ihre Zahlungen verfolgen möchten. \n"
"\n"
"Das Fakturierungssystem beinhaltet Belege und Quittungen (ein einfacher Weg, "
"um den Überblick über Verkäufe und Einkäufe zu behalten). Es ermöglicht "
-"Ihnen ebenfalls eine einfache Methode, um Zahlungen zu registrieren, ohne "
-"dass Sie dabei komplett abstrakte Konten kodieren.\n"
+"Ihnen, Zahlungen zu registrieren, ohne dass Sie dabei komplett abstrakte "
+"Konten kodieren.\n"
"\n"
"Diese Anwendung verwaltet:\n"
"\n"
@@ -17818,7 +18436,7 @@ msgstr "Landesschlüssel (locale)"
#. module: base
#: field:workflow.activity,split_mode:0
msgid "Split Mode"
-msgstr "Modus Aufteilung"
+msgstr "Modus aufteilen"
#. module: base
#: view:base.module.upgrade:0
@@ -17853,7 +18471,7 @@ msgstr "Chile"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_view_editor
msgid "View Editor"
-msgstr "Ansichten Editor"
+msgstr "Ansichten-Editor"
#. module: base
#: view:ir.cron:0
@@ -17892,7 +18510,7 @@ msgstr "Berechtigungsgruppen"
#. module: base
#: selection:base.language.install,lang:0
msgid "Italian / Italiano"
-msgstr "Italian / Italiano"
+msgstr "Italienisch / Italiano"
#. module: base
#: view:ir.actions.server:0
@@ -17923,7 +18541,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Diese Anwendung ermöglicht die Just In Time Berechnung der "
+"Diese Anwendung ermöglicht die Just-In-Time-Berechnung der "
"Beschaffungsaufträge\n"
"=========================================================================\n"
"\n"
@@ -18074,12 +18692,12 @@ msgstr ""
"==============================================================\n"
"\n"
"Das Lager- und Bestandsmanagement basiert auf einer hierarchischen "
-"Lagerstruktur, von Lager bis zu Lagerplätzen. Die\n"
+"Lagerstruktur, von Lagern bis zu Lagerplätzen. Die\n"
"doppelte Buchführung ermöglicht es Ihnen, sowohl Kunden- und "
"Lieferantenlager als auch die Bestände der Fertigprodukte zu verwalten. \n"
"\n"
"OpenERP bietet die Möglichkeit, Losgrößen- und Seriennummern zu verwalten, "
-"um die vollständige Rückverfolgbarkeit zu gewährleisten, die für "
+"um die vollständige Rückverfolgung zu gewährleisten, die für "
"Industriebetriebe und andere Branchen zwingend erforderlich ist. \n"
"\n"
"Wesentliche Funktionen\n"
@@ -18109,7 +18727,7 @@ msgid ""
"Tax Identification Number. Check the box if this contact is subjected to "
"taxes. Used by the some of the legal statements."
msgstr ""
-"Steuer-ID. Aktivieren sie diese wenn der Kontakt der Besteuerung unterliegt. "
+"Steuer-ID. Aktivieren Sie diese wenn der Kontakt der Besteuerung unterliegt. "
"Wird von diversen steuerrechtlich relevanten Berichten benötigt."
#. module: base
@@ -18141,7 +18759,7 @@ msgstr ""
"Dies ist die Anwendung zur Berechnung der Beschaffungen\n"
"===================================================\n"
"\n"
-"Im MPR Prozess werden Beschaffungsaufträge erstellt, um Fertigungsaufträge\n"
+"Im MPR Prozess werden Beschaffungsaufträge erstellt, um Fertigungsaufträge,\n"
"Bestellungen und Lagerbereitstellungen zu starten. Beschaffungsaufträge "
"werden\n"
"automatisch durch das System erstellt und solange kein Problem besteht, wird "
@@ -18279,7 +18897,7 @@ msgstr "Monate"
#. module: base
#: view:workflow.instance:0
msgid "Workflow Instances"
-msgstr "Arbeitsablauf-Abschnitte"
+msgstr "Workflow Instanzen"
#. module: base
#: code:addons/base/res/res_partner.py:684
@@ -18312,7 +18930,7 @@ msgstr "Objekt anlegen"
#. module: base
#: model:res.country,name:base.ss
msgid "South Sudan"
-msgstr ""
+msgstr "Südsudan"
#. module: base
#: field:ir.filters,context:0
@@ -18390,8 +19008,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Die Basisanwendung zur zum Verwalten des analytischen Vertriebs und "
-"Bestellungen\n"
+"Basisanwendung zum Verwalten des analytischen Vertriebs und Bestellungen\n"
"==========================================================================\n"
"\n"
"Ermöglicht es dem Benutzer, mehrere Analysepläne zu erstellen. Diese können "
diff --git a/openerp/addons/base/i18n/el.po b/openerp/addons/base/i18n/el.po
index cb9ce61e0de..4e3ca231f5a 100644
--- a/openerp/addons/base/i18n/el.po
+++ b/openerp/addons/base/i18n/el.po
@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:26+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
"X-Poedit-Country: GREECE\n"
"X-Poedit-Language: Greek\n"
"X-Poedit-SourceCharset: utf-8\n"
diff --git a/openerp/addons/base/i18n/en_GB.po b/openerp/addons/base/i18n/en_GB.po
index 56f70fd1bd4..2d994f939da 100644
--- a/openerp/addons/base/i18n/en_GB.po
+++ b/openerp/addons/base/i18n/en_GB.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:36+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es.po b/openerp/addons/base/i18n/es.po
index 68e90567030..1742dcd47b4 100644
--- a/openerp/addons/base/i18n/es.po
+++ b/openerp/addons/base/i18n/es.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:22+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:33+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_AR.po b/openerp/addons/base/i18n/es_AR.po
index 85bd6468f6e..566df655074 100644
--- a/openerp/addons/base/i18n/es_AR.po
+++ b/openerp/addons/base/i18n/es_AR.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:35+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_BO.po b/openerp/addons/base/i18n/es_BO.po
index 5918b34d299..31a6b94f4a3 100644
--- a/openerp/addons/base/i18n/es_BO.po
+++ b/openerp/addons/base/i18n/es_BO.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:37+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_CL.po b/openerp/addons/base/i18n/es_CL.po
index 8ba653712dd..f9fcdca13d4 100644
--- a/openerp/addons/base/i18n/es_CL.po
+++ b/openerp/addons/base/i18n/es_CL.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:36+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_CR.po b/openerp/addons/base/i18n/es_CR.po
index 90c54e13663..11a0d4a251e 100644
--- a/openerp/addons/base/i18n/es_CR.po
+++ b/openerp/addons/base/i18n/es_CR.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:37+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
"Language: \n"
#. module: base
diff --git a/openerp/addons/base/i18n/es_DO.po b/openerp/addons/base/i18n/es_DO.po
index 1278b692e48..ea34722c84f 100644
--- a/openerp/addons/base/i18n/es_DO.po
+++ b/openerp/addons/base/i18n/es_DO.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:36+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po
index cef5d9ce7b2..186faa9b581 100644
--- a/openerp/addons/base/i18n/es_EC.po
+++ b/openerp/addons/base/i18n/es_EC.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:26+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:38+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_MX.po b/openerp/addons/base/i18n/es_MX.po
index b78548d1afa..d89de25fdd9 100644
--- a/openerp/addons/base/i18n/es_MX.po
+++ b/openerp/addons/base/i18n/es_MX.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:26+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:38+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_PE.po b/openerp/addons/base/i18n/es_PE.po
index 96d7a10338d..a6f2ee68a72 100644
--- a/openerp/addons/base/i18n/es_PE.po
+++ b/openerp/addons/base/i18n/es_PE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:26+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:38+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/es_VE.po b/openerp/addons/base/i18n/es_VE.po
index 696e146c023..d7e904151fb 100644
--- a/openerp/addons/base/i18n/es_VE.po
+++ b/openerp/addons/base/i18n/es_VE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:35+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/et.po b/openerp/addons/base/i18n/et.po
index 7e6b03f4476..4c01f795065 100644
--- a/openerp/addons/base/i18n/et.po
+++ b/openerp/addons/base/i18n/et.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:24+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/eu.po b/openerp/addons/base/i18n/eu.po
index a0b2ee01155..0be7283054d 100644
--- a/openerp/addons/base/i18n/eu.po
+++ b/openerp/addons/base/i18n/eu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:16+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:23+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/fa.po b/openerp/addons/base/i18n/fa.po
index 2bb16fb0d41..8e74b1763f3 100644
--- a/openerp/addons/base/i18n/fa.po
+++ b/openerp/addons/base/i18n/fa.po
@@ -9,8 +9,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:30+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
"X-Poedit-Country: IRAN, ISLAMIC REPUBLIC OF\n"
"X-Poedit-Language: Persian\n"
diff --git a/openerp/addons/base/i18n/fa_AF.po b/openerp/addons/base/i18n/fa_AF.po
index d0dd2d6cde2..71f3a3149b4 100644
--- a/openerp/addons/base/i18n/fa_AF.po
+++ b/openerp/addons/base/i18n/fa_AF.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:26+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:38+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/fi.po b/openerp/addons/base/i18n/fi.po
index 802ac1cf105..baf411092bc 100644
--- a/openerp/addons/base/i18n/fi.po
+++ b/openerp/addons/base/i18n/fi.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:25+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -25,7 +25,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Moduuli Šekkien kirjoittamisen ja tulostamiseen.\n"
+"Moduuli Shekkien kirjoittamisen ja tulostamiseen.\n"
"===========================================\n"
" "
@@ -129,7 +129,7 @@ msgstr ""
"Moduuli joka lisää valmistajat ja ominaisuudet tuotelomakkeelle.\n"
"=========================================================\n"
"\n"
-"Voit net määritellä tuotteelle seuraavat tiedot:\n"
+"Voit nyt määritellä tuotteelle seuraavat tiedot:\n"
"---------------------------------------------------------\n"
" * Valmistaja\n"
" * Valmistajan tuotenimi\n"
@@ -688,7 +688,7 @@ msgstr "Palau"
#. module: base
#: view:res.partner:0
msgid "Sales & Purchases"
-msgstr "Myynti ja hankinta"
+msgstr "Myynnit & Ostot"
#. module: base
#: view:ir.translation:0
@@ -3836,7 +3836,7 @@ msgstr "Raportointi"
#: field:res.partner,title:0
#: field:res.partner.title,name:0
msgid "Title"
-msgstr "Yhtiömuoto"
+msgstr "Titteli"
#. module: base
#: help:ir.property,res_id:0
@@ -10138,7 +10138,7 @@ msgstr ""
#: view:res.groups:0
#: field:res.partner,comment:0
msgid "Notes"
-msgstr "Huomautukset"
+msgstr "Muistiinpanot"
#. module: base
#: field:ir.config_parameter,value:0
@@ -13158,7 +13158,7 @@ msgstr ""
#. module: base
#: field:res.company,company_registry:0
msgid "Company Registry"
-msgstr "Yritysrekisteri"
+msgstr "Y-tunnus"
#. module: base
#: view:ir.actions.report.xml:0
@@ -13471,7 +13471,7 @@ msgstr "Riippuvuudet:"
#. module: base
#: field:res.company,vat:0
msgid "Tax ID"
-msgstr "Vero ID"
+msgstr "VAT-numero"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_bank_statement_extensions
@@ -13821,7 +13821,7 @@ msgstr "Marokko - Kirjanpito"
#: field:res.bank,bic:0
#: field:res.partner.bank,bank_bic:0
msgid "Bank Identifier Code"
-msgstr "BIC koodi"
+msgstr "BIC-koodi"
#. module: base
#: view:base.language.export:0
@@ -15482,7 +15482,7 @@ msgstr "Matkapuhelinnumero"
#: model:ir.model,name:base.model_res_partner_category
#: view:res.partner.category:0
msgid "Partner Categories"
-msgstr "Kumppanien ryhmät"
+msgstr "Kumppaniryhmät"
#. module: base
#: view:base.module.upgrade:0
@@ -15690,7 +15690,7 @@ msgstr ""
#. module: base
#: view:res.partner:0
msgid "Internal Notes"
-msgstr "Sisäiset huomautukset"
+msgstr "Sisäiset muistiinpanot"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_pvt_ltd
diff --git a/openerp/addons/base/i18n/fr.po b/openerp/addons/base/i18n/fr.po
index fc4373ffaaa..5c779ab7aa9 100644
--- a/openerp/addons/base/i18n/fr.po
+++ b/openerp/addons/base/i18n/fr.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:25+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -11393,7 +11393,7 @@ msgstr "Islande"
#: model:ir.actions.act_window,name:base.ir_action_window
#: model:ir.ui.menu,name:base.menu_ir_action_window
msgid "Window Actions"
-msgstr "Actions de fênetres"
+msgstr "Actions de fenêtres"
#. module: base
#: model:ir.module.module,description:base.module_portal_project_issue
diff --git a/openerp/addons/base/i18n/fr_CA.po b/openerp/addons/base/i18n/fr_CA.po
index cdc0cc1e702..73af473040b 100644
--- a/openerp/addons/base/i18n/fr_CA.po
+++ b/openerp/addons/base/i18n/fr_CA.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:36+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/gl.po b/openerp/addons/base/i18n/gl.po
index cf625207475..deab7d8a675 100644
--- a/openerp/addons/base/i18n/gl.po
+++ b/openerp/addons/base/i18n/gl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:26+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/gu.po b/openerp/addons/base/i18n/gu.po
index 549794983b9..c12e8215468 100644
--- a/openerp/addons/base/i18n/gu.po
+++ b/openerp/addons/base/i18n/gu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:26+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/he.po b/openerp/addons/base/i18n/he.po
index 081ddb2fa8b..3b59cc71343 100644
--- a/openerp/addons/base/i18n/he.po
+++ b/openerp/addons/base/i18n/he.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:26+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -1148,7 +1148,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_fleet
msgid "Fleet Management"
-msgstr ""
+msgstr "ניהול צי רכב"
#. module: base
#: help:ir.server.object.lines,value:0
@@ -1230,7 +1230,7 @@ msgstr ""
#. module: base
#: view:res.users:0
msgid "Change the user password."
-msgstr ""
+msgstr "שנה את סיסמת המשתמש."
#. module: base
#: view:res.lang:0
@@ -1255,7 +1255,7 @@ msgstr "סוג"
#. module: base
#: field:ir.mail_server,smtp_user:0
msgid "Username"
-msgstr ""
+msgstr "שם משתמש"
#. module: base
#: model:ir.module.module,description:base.module_l10n_br
@@ -1380,7 +1380,7 @@ msgstr ""
#. module: base
#: field:ir.module.module,contributors:0
msgid "Contributors"
-msgstr ""
+msgstr "תורמים"
#. module: base
#: field:ir.rule,perm_unlink:0
@@ -1390,17 +1390,17 @@ msgstr ""
#. module: base
#: selection:ir.property,type:0
msgid "Char"
-msgstr ""
+msgstr "תו"
#. module: base
#: field:ir.module.category,visible:0
msgid "Visible"
-msgstr ""
+msgstr "גלוי"
#. module: base
#: model:ir.actions.client,name:base.action_client_base_menu
msgid "Open Settings Menu"
-msgstr ""
+msgstr "פתח תפריט הגדרות"
#. module: base
#: selection:base.language.install,lang:0
@@ -1425,7 +1425,7 @@ msgstr "Niger"
#. module: base
#: selection:base.language.install,lang:0
msgid "Chinese (HK)"
-msgstr ""
+msgstr "סינית (הונג-קונג)"
#. module: base
#: model:res.country,name:base.ba
@@ -1480,7 +1480,7 @@ msgstr "חבילת שפה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_tests
msgid "Tests"
-msgstr ""
+msgstr "בדיקות"
#. module: base
#: field:ir.actions.report.xml,attachment:0
@@ -1528,7 +1528,7 @@ msgstr ""
#: view:ir.ui.view:0
#: selection:ir.ui.view,type:0
msgid "Search"
-msgstr ""
+msgstr "חיפוש"
#. module: base
#: code:addons/osv.py:154
@@ -1556,7 +1556,7 @@ msgstr "אשפים"
#: code:addons/base/res/res_users.py:131
#, python-format
msgid "Operation Canceled"
-msgstr ""
+msgstr "הפעולה בוטלה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_document
@@ -1671,7 +1671,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.mf
msgid "Saint Martin (French part)"
-msgstr ""
+msgstr "סנט מרטין (החלק הצרפתי)"
#. module: base
#: model:ir.model,name:base.model_ir_exports
@@ -1702,7 +1702,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_social_network
#: model:ir.module.module,shortdesc:base.module_mail
msgid "Social Network"
-msgstr ""
+msgstr "רשת חברתית"
#. module: base
#: view:res.lang:0
@@ -1830,12 +1830,12 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_project_issue
msgid "Portal Issue"
-msgstr ""
+msgstr "פנייה בפורטל"
#. module: base
#: model:ir.ui.menu,name:base.menu_tools
msgid "Tools"
-msgstr ""
+msgstr "כלים"
#. module: base
#: selection:ir.property,type:0
@@ -1854,12 +1854,12 @@ msgstr ""
#. module: base
#: field:res.partner,image_small:0
msgid "Small-sized image"
-msgstr ""
+msgstr "תמונה קטנה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_stock
msgid "Warehouse Management"
-msgstr ""
+msgstr "ניהול מחסן"
#. module: base
#: model:ir.model,name:base.model_res_request_link
@@ -1963,12 +1963,12 @@ msgstr "Netherlands"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_event
msgid "Portal Event"
-msgstr ""
+msgstr "אירוע בפורטל"
#. module: base
#: selection:ir.translation,state:0
msgid "Translation in Progress"
-msgstr ""
+msgstr "תרגום בתהליך"
#. module: base
#: model:ir.model,name:base.model_ir_rule
@@ -1983,7 +1983,7 @@ msgstr "ימים"
#. module: base
#: model:ir.module.module,summary:base.module_fleet
msgid "Vehicle, leasing, insurances, costs"
-msgstr ""
+msgstr "רכב, ליסינג, ביטוח, עלויות"
#. module: base
#: view:ir.model.access:0
@@ -2020,7 +2020,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_process
msgid "Enterprise Process"
-msgstr ""
+msgstr "תהליך ארגוני"
#. module: base
#: help:res.partner,supplier:0
@@ -2162,7 +2162,7 @@ msgstr ""
#: code:addons/base/res/res_users.py:337
#, python-format
msgid "%s (copy)"
-msgstr ""
+msgstr "%s (העתק)"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_chart
@@ -2201,7 +2201,7 @@ msgstr ""
#. module: base
#: field:ir.ui.menu,complete_name:0
msgid "Full Path"
-msgstr ""
+msgstr "נתיב מלא"
#. module: base
#: view:base.language.export:0
@@ -2227,7 +2227,7 @@ msgstr ""
#: model:ir.ui.menu,name:base.menu_administration
#: model:res.groups,name:base.group_system
msgid "Settings"
-msgstr ""
+msgstr "הגדרות"
#. module: base
#: selection:ir.actions.act_window,view_type:0
@@ -2245,7 +2245,7 @@ msgstr "צור / כתוב / העתק"
#. module: base
#: view:ir.sequence:0
msgid "Second: %(sec)s"
-msgstr ""
+msgstr "שניות: %(sec)s"
#. module: base
#: field:ir.actions.act_window,view_mode:0
@@ -2272,7 +2272,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.ax
msgid "Åland Islands"
-msgstr ""
+msgstr "איי‬ ‫אלאנד"
#. module: base
#: field:res.company,logo:0
@@ -2293,7 +2293,7 @@ msgstr "חלון חדש"
#. module: base
#: field:ir.values,action_id:0
msgid "Action (change only)"
-msgstr ""
+msgstr "פעולה (שינוי בלבד)"
#. module: base
#: model:ir.module.module,shortdesc:base.module_subscription
@@ -2313,7 +2313,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_tools
msgid "Extra Tools"
-msgstr ""
+msgstr "כלים נוספים"
#. module: base
#: view:ir.attachment:0
@@ -2345,7 +2345,7 @@ msgstr "שיטה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_crypt
msgid "Password Encryption"
-msgstr ""
+msgstr "הצפנת סיסמה"
#. module: base
#: view:workflow.activity:0
@@ -2389,7 +2389,7 @@ msgstr ""
#. module: base
#: field:change.password.user,new_passwd:0
msgid "New Password"
-msgstr ""
+msgstr "סיסמה חדשה"
#. module: base
#: model:ir.actions.act_window,help:base.action_ui_view
@@ -2401,7 +2401,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_setup
msgid "Initial Setup Tools"
-msgstr ""
+msgstr "כלי הגדרות ראשוניות"
#. module: base
#: field:ir.actions.act_window,groups_id:0
@@ -2532,7 +2532,7 @@ msgstr ""
#. module: base
#: field:ir.mail_server,smtp_debug:0
msgid "Debugging"
-msgstr ""
+msgstr "ניפוי שגיאות"
#. module: base
#: model:ir.module.module,description:base.module_crm_helpdesk
@@ -2676,7 +2676,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_crm
msgid "Opportunity to Quotation"
-msgstr ""
+msgstr "הזדמנות להצעה"
#. module: base
#: model:ir.module.module,description:base.module_sale_analytic_plans
@@ -2722,7 +2722,7 @@ msgstr ""
#. module: base
#: model:ir.ui.menu,name:base.menu_invoiced
msgid "Invoicing"
-msgstr ""
+msgstr "הפקת חשבוניות"
#. module: base
#: field:ir.ui.view_sc,name:0
@@ -2732,7 +2732,7 @@ msgstr "שם מקוצר"
#. module: base
#: field:res.partner,contact_address:0
msgid "Complete Address"
-msgstr ""
+msgstr "כתובת מלאה"
#. module: base
#: help:ir.actions.act_window,limit:0
@@ -2908,13 +2908,13 @@ msgstr ""
#: model:res.groups,name:base.group_sale_manager
#: model:res.groups,name:base.group_tool_manager
msgid "Manager"
-msgstr ""
+msgstr "מנהל"
#. module: base
#: code:addons/base/ir/ir_model.py:726
#, python-format
msgid "Sorry, you are not allowed to access this document."
-msgstr ""
+msgstr "מצטערים, אינך רשאי לגשת למסמך זה."
#. module: base
#: model:res.country,name:base.py
@@ -2929,7 +2929,7 @@ msgstr "Fiji"
#. module: base
#: view:ir.actions.report.xml:0
msgid "Report Xml"
-msgstr ""
+msgstr "דוח XML"
#. module: base
#: model:ir.module.module,description:base.module_purchase
@@ -3000,7 +3000,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "yes"
-msgstr ""
+msgstr "כן"
#. module: base
#: field:ir.model.fields,serialization_field_id:0
@@ -3113,7 +3113,7 @@ msgstr ""
#: code:addons/base/res/res_currency.py:52
#, python-format
msgid "Error!"
-msgstr ""
+msgstr "שגיאה!"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_fr_rib
@@ -3216,7 +3216,7 @@ msgstr ""
#: view:res.users:0
#, python-format
msgid "Application"
-msgstr ""
+msgstr "יישום"
#. module: base
#: model:res.groups,comment:base.group_hr_manager
@@ -3262,7 +3262,7 @@ msgstr "Cuba"
#: code:addons/report_sxw.py:443
#, python-format
msgid "Unknown report type: %s"
-msgstr ""
+msgstr "סוג דוח לא מוכר: %s"
#. module: base
#: model:ir.module.module,summary:base.module_hr_expense
@@ -3457,7 +3457,7 @@ msgstr ""
#. module: base
#: model:res.groups,name:base.group_survey_user
msgid "Survey / User"
-msgstr ""
+msgstr "סקר / משתמש"
#. module: base
#: view:ir.module.module:0
@@ -3511,7 +3511,7 @@ msgstr "תואר אנשי קשר"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_manufacturer
msgid "Products Manufacturers"
-msgstr ""
+msgstr "יצרני מוצרים"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:240
@@ -3523,7 +3523,7 @@ msgstr ""
#: model:ir.module.module,shortdesc:base.module_survey
#: model:ir.ui.menu,name:base.next_id_10
msgid "Survey"
-msgstr ""
+msgstr "סקר"
#. module: base
#: selection:base.language.install,lang:0
@@ -3565,7 +3565,7 @@ msgstr ""
#. module: base
#: view:ir.config_parameter:0
msgid "System Properties"
-msgstr ""
+msgstr "מאפייני מערכת"
#. module: base
#: field:ir.sequence,prefix:0
@@ -3717,7 +3717,7 @@ msgstr "Antarctica"
#. module: base
#: view:res.partner:0
msgid "Persons"
-msgstr ""
+msgstr "אנשים"
#. module: base
#: view:base.language.import:0
@@ -3775,7 +3775,7 @@ msgstr ""
#: field:res.company,rml_footer:0
#: field:res.company,rml_footer_readonly:0
msgid "Report Footer"
-msgstr ""
+msgstr "כותרת תחתונה של הדו\"ח"
#. module: base
#: selection:res.lang,direction:0
@@ -3807,7 +3807,7 @@ msgstr "פעולות מתוזמנות"
#: model:ir.ui.menu,name:base.menu_lunch_reporting
#: model:ir.ui.menu,name:base.menu_reporting
msgid "Reporting"
-msgstr ""
+msgstr "דוחות"
#. module: base
#: field:res.partner,title:0
@@ -3879,7 +3879,7 @@ msgstr ""
#. module: base
#: selection:ir.sequence,implementation:0
msgid "Standard"
-msgstr ""
+msgstr "רגיל"
#. module: base
#: model:res.country,name:base.ru
@@ -3898,7 +3898,7 @@ msgstr ""
#: code:addons/orm.py:3902
#, python-format
msgid "Access Denied"
-msgstr ""
+msgstr "הגישה נדחתה"
#. module: base
#: field:res.company,name:0
@@ -3981,7 +3981,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.je
msgid "Jersey"
-msgstr ""
+msgstr "ג'רזי"
#. module: base
#: model:ir.model,name:base.model_ir_translation
@@ -4006,7 +4006,7 @@ msgstr "%x - ייצוג תאריך הולם."
#. module: base
#: view:res.partner:0
msgid "Tag"
-msgstr ""
+msgstr "תגית"
#. module: base
#: view:res.lang:0
@@ -4046,7 +4046,7 @@ msgstr ""
#. module: base
#: model:res.country,name:base.sk
msgid "Slovakia"
-msgstr ""
+msgstr "סלובקיה"
#. module: base
#: model:res.country,name:base.nr
@@ -4234,7 +4234,7 @@ msgstr "Portugal"
#. module: base
#: model:ir.module.module,shortdesc:base.module_share
msgid "Share any Document"
-msgstr ""
+msgstr "לשתף כל מסמך"
#. module: base
#: field:workflow.transition,group_id:0
@@ -4261,7 +4261,7 @@ msgstr ""
#: field:ir.actions.server,help:0
#: field:ir.actions.wizard,help:0
msgid "Action description"
-msgstr ""
+msgstr "תיאור הפעולה"
#. module: base
#: model:ir.module.module,description:base.module_l10n_ma
@@ -4305,7 +4305,7 @@ msgstr "Xor"
#. module: base
#: model:ir.module.category,name:base.module_category_localization_account_charts
msgid "Account Charts"
-msgstr ""
+msgstr "תרשימי חשבון"
#. module: base
#: model:ir.ui.menu,name:base.menu_event_main
@@ -4338,7 +4338,7 @@ msgstr "שדה בסיס"
#. module: base
#: model:ir.module.category,name:base.module_category_managing_vehicles_and_contracts
msgid "Managing vehicles and contracts"
-msgstr ""
+msgstr "ניהול רכבים וחוזים"
#. module: base
#: model:ir.module.module,description:base.module_base_setup
@@ -4384,7 +4384,7 @@ msgstr "ברירת מחדל"
#. module: base
#: model:ir.module.module,summary:base.module_lunch
msgid "Lunch Order, Meal, Food"
-msgstr ""
+msgstr "הזמנת ארוחות ומזון"
#. module: base
#: view:ir.model.fields:0
@@ -4452,12 +4452,12 @@ msgstr ""
#. module: base
#: model:ir.module.module,summary:base.module_sale
msgid "Quotations, Sales Orders, Invoicing"
-msgstr ""
+msgstr "הצעות מחיר, הזמנות רכש, חשבוניות"
#. module: base
#: field:res.partner,parent_id:0
msgid "Related Company"
-msgstr ""
+msgstr "חברה מקושרת"
#. module: base
#: help:ir.actions.act_url,help:0
@@ -4548,7 +4548,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_project_timesheet
msgid "Bill Time on Tasks"
-msgstr ""
+msgstr "חיוב זמן עבודה על משימות"
#. module: base
#: model:ir.module.category,name:base.module_category_marketing
@@ -4628,7 +4628,7 @@ msgstr "רשיון"
#. module: base
#: field:ir.attachment,url:0
msgid "Url"
-msgstr ""
+msgstr "קישור"
#. module: base
#: selection:ir.translation,type:0
@@ -4712,7 +4712,7 @@ msgstr "תצוגה"
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "no"
-msgstr ""
+msgstr "לא"
#. module: base
#: model:ir.module.module,description:base.module_crm_partner_assign
@@ -4818,7 +4818,7 @@ msgstr "מחבר"
#. module: base
#: view:ir.actions.todo:0
msgid "Set as Todo"
-msgstr ""
+msgstr "סמן לביצוע"
#. module: base
#: view:res.lang:0
@@ -4883,7 +4883,7 @@ msgstr "כללים"
#. module: base
#: field:ir.mail_server,smtp_host:0
msgid "SMTP Server"
-msgstr ""
+msgstr "שרת SMTP"
#. module: base
#: code:addons/base/module/module.py:320
@@ -4946,7 +4946,7 @@ msgstr "רצפי עבודה"
#. module: base
#: model:ir.ui.menu,name:base.next_id_73
msgid "Purchase"
-msgstr ""
+msgstr "רכש"
#. module: base
#: selection:base.language.install,lang:0
@@ -4987,7 +4987,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:327
#, python-format
msgid "name"
-msgstr ""
+msgstr "שם"
#. module: base
#: model:ir.module.module,description:base.module_mrp_operations
@@ -5080,7 +5080,7 @@ msgstr "שגיאה הופיעה בזמן נתינת תוקף לשדה(ות) %s:
#. module: base
#: view:ir.property:0
msgid "Generic"
-msgstr ""
+msgstr "גנרי"
#. module: base
#: model:ir.module.module,shortdesc:base.module_document_ftp
@@ -5110,7 +5110,7 @@ msgstr "הגדר אפס/לא תקף"
#. module: base
#: view:res.users:0
msgid "Save"
-msgstr ""
+msgstr "שמור"
#. module: base
#: field:ir.actions.report.xml,report_xml:0
@@ -5126,7 +5126,7 @@ msgstr "Benin"
#: model:ir.actions.act_window,name:base.action_res_partner_bank_type_form
#: model:ir.ui.menu,name:base.menu_action_res_partner_bank_typeform
msgid "Bank Account Types"
-msgstr ""
+msgstr "סוגי חשבונות בנק"
#. module: base
#: help:ir.sequence,suffix:0
@@ -5219,7 +5219,7 @@ msgstr ""
#: code:addons/base/ir/ir_fields.py:337
#, python-format
msgid "Unknown sub-field '%s'"
-msgstr ""
+msgstr "תת-שדה לא ידוע '%s'"
#. module: base
#: model:res.country,name:base.za
@@ -5262,7 +5262,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_recruitment
msgid "Recruitment Process"
-msgstr ""
+msgstr "תהליך גיוס"
#. module: base
#: model:res.country,name:base.br
@@ -5325,7 +5325,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_localization
#: model:ir.ui.menu,name:base.menu_localisation
msgid "Localization"
-msgstr ""
+msgstr "התאמת שפה"
#. module: base
#: model:ir.module.module,description:base.module_web_api
@@ -5420,7 +5420,7 @@ msgstr "תפריט שותף"
#. module: base
#: field:res.partner.bank,owner_name:0
msgid "Account Owner Name"
-msgstr ""
+msgstr "שם בעל החשבון"
#. module: base
#: code:addons/base/ir/ir_model.py:420
@@ -5447,7 +5447,7 @@ msgstr ""
#. module: base
#: view:ir.rule:0
msgid "Write Access Right"
-msgstr ""
+msgstr "הרשאות כתיבה"
#. module: base
#: model:ir.actions.act_window,help:base.action_res_groups
@@ -5476,7 +5476,7 @@ msgstr "היסטוריה"
#. module: base
#: model:res.country,name:base.im
msgid "Isle of Man"
-msgstr ""
+msgstr "האי מאן"
#. module: base
#: help:ir.actions.client,res_model:0
@@ -5538,7 +5538,7 @@ msgstr "שדה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_project_long_term
msgid "Long Term Projects"
-msgstr ""
+msgstr "פרויקטים ארוכי טווח"
#. module: base
#: model:res.country,name:base.ve
@@ -5558,12 +5558,12 @@ msgstr "Zambia"
#. module: base
#: view:ir.actions.todo:0
msgid "Launch Configuration Wizard"
-msgstr ""
+msgstr "הפעל אשף הגדרות"
#. module: base
#: model:ir.module.module,summary:base.module_mrp
msgid "Manufacturing Orders, Bill of Materials, Routing"
-msgstr ""
+msgstr "הזמנות ייצור, חומרי גלם, ניתוב"
#. module: base
#: field:ir.attachment,name:0
@@ -5636,7 +5636,7 @@ msgstr ""
#. module: base
#: model:res.groups,name:base.group_sale_salesman_all_leads
msgid "See all Leads"
-msgstr ""
+msgstr "צפה בכל הלידים"
#. module: base
#: model:res.country,name:base.ci
@@ -5662,7 +5662,7 @@ msgstr "שם מקור"
#. module: base
#: model:ir.ui.menu,name:base.menu_ir_filters
msgid "User-defined Filters"
-msgstr ""
+msgstr "מסננים בהגדרת המשתמש"
#. module: base
#: field:ir.actions.act_window_close,name:0
@@ -5751,7 +5751,7 @@ msgstr "מודול"
#. module: base
#: selection:base.language.install,lang:0
msgid "English (UK)"
-msgstr ""
+msgstr "אנגלית (בריטניה)‏"
#. module: base
#: selection:base.language.install,lang:0
@@ -5774,7 +5774,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_generic_modules_accounting
#: view:res.company:0
msgid "Accounting"
-msgstr ""
+msgstr "חשבונאות"
#. module: base
#: model:ir.module.module,description:base.module_base_vat
@@ -5840,7 +5840,7 @@ msgstr ""
#. module: base
#: selection:base.language.install,lang:0
msgid "English (CA)"
-msgstr ""
+msgstr "אנגלית (קנדה)"
#. module: base
#: model:ir.module.category,name:base.module_category_human_resources
@@ -5871,7 +5871,7 @@ msgstr ""
#. module: base
#: view:ir.translation:0
msgid "Comments"
-msgstr ""
+msgstr "הערות"
#. module: base
#: model:res.country,name:base.et
@@ -5881,7 +5881,7 @@ msgstr "Ethiopia"
#. module: base
#: model:ir.module.category,name:base.module_category_authentication
msgid "Authentication"
-msgstr ""
+msgstr "אימות"
#. module: base
#: model:res.country,name:base.sj
@@ -5909,13 +5909,13 @@ msgstr "קבץ לפי"
#. module: base
#: view:res.config.installer:0
msgid "title"
-msgstr ""
+msgstr "כותרת"
#. module: base
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "true"
-msgstr ""
+msgstr "אמת"
#. module: base
#: model:ir.model,name:base.model_base_language_install
@@ -5925,12 +5925,12 @@ msgstr "התקן שפה"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_11
msgid "Services"
-msgstr ""
+msgstr "שירותים"
#. module: base
#: view:ir.translation:0
msgid "Translation"
-msgstr ""
+msgstr "תרגום"
#. module: base
#: selection:res.request,state:0
@@ -5950,7 +5950,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_accounting_and_finance
msgid "Accounting & Finance"
-msgstr ""
+msgstr "חשבונאות וכספים"
#. module: base
#: field:ir.actions.server,write_id:0
@@ -5960,7 +5960,7 @@ msgstr "מזהה כתיבה"
#. module: base
#: model:ir.ui.menu,name:base.menu_product
msgid "Products"
-msgstr ""
+msgstr "מוצרים"
#. module: base
#: model:ir.actions.act_window,name:base.act_values_form_defaults
@@ -5982,7 +5982,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_usability
#: view:res.users:0
msgid "Usability"
-msgstr ""
+msgstr "שימושיות"
#. module: base
#: field:ir.actions.act_window,domain:0
@@ -6103,7 +6103,7 @@ msgstr "שם הקבוצה אינו יכול להתחיל ב \"-\""
#: view:ir.module.module:0
#: model:ir.ui.menu,name:base.module_mi
msgid "Apps"
-msgstr ""
+msgstr "יישומים"
#. module: base
#: view:ir.ui.view_sc:0
@@ -6151,12 +6151,12 @@ msgstr "בעלי חשבון הבנק"
#. module: base
#: model:ir.module.category,name:base.module_category_uncategorized
msgid "Uncategorized"
-msgstr ""
+msgstr "ללא קטגוריה"
#. module: base
#: view:res.partner:0
msgid "Phone:"
-msgstr ""
+msgstr "טלפון:"
#. module: base
#: field:res.partner,is_company:0
@@ -6179,7 +6179,7 @@ msgstr "Guadeloupe (French)"
#: code:addons/base/res/res_lang.py:189
#, python-format
msgid "User Error"
-msgstr ""
+msgstr "שגיאת משתמש"
#. module: base
#: help:workflow.transition,signal:0
@@ -6223,7 +6223,7 @@ msgstr ""
#. module: base
#: sql_constraint:ir.filters:0
msgid "Filter names must be unique"
-msgstr ""
+msgstr "שמות המסננים חייבים להיות ייחודיים"
#. module: base
#: help:multi_company.default,object_id:0
@@ -6377,7 +6377,7 @@ msgstr ""
#. module: base
#: field:res.partner,tz_offset:0
msgid "Timezone offset"
-msgstr ""
+msgstr "הזחות אזור זמן"
#. module: base
#: model:ir.module.module,description:base.module_marketing_campaign
@@ -6439,7 +6439,7 @@ msgstr ""
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Automatically"
-msgstr ""
+msgstr "הפעל אוטומטית"
#. module: base
#: help:ir.model.fields,translate:0
@@ -6491,7 +6491,7 @@ msgstr "מספר מודולים נוספו"
#. module: base
#: view:res.currency:0
msgid "Price Accuracy"
-msgstr ""
+msgstr "דיוק במחיר"
#. module: base
#: selection:base.language.install,lang:0
@@ -6513,12 +6513,12 @@ msgstr "תפריטים שנוצרו"
#: view:ir.module.module:0
#, python-format
msgid "Uninstall"
-msgstr ""
+msgstr "הסר התקנה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_budget
msgid "Budgets Management"
-msgstr ""
+msgstr "ניהול תקציב"
#. module: base
#: field:workflow.triggers,workitem_id:0
@@ -6620,7 +6620,7 @@ msgstr ""
#. module: base
#: field:res.partner.bank.type,format_layout:0
msgid "Format Layout"
-msgstr ""
+msgstr "תצורת תצוגה"
#. module: base
#: model:ir.module.module,description:base.module_document_ftp
@@ -6663,7 +6663,7 @@ msgstr "Sudan"
#: field:res.currency.rate,currency_rate_type_id:0
#: view:res.currency.rate.type:0
msgid "Currency Rate Type"
-msgstr ""
+msgstr "סוג שער מטבע"
#. module: base
#: model:ir.module.module,description:base.module_l10n_fr
@@ -6716,7 +6716,7 @@ msgstr "תפריטים"
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Manually Once"
-msgstr ""
+msgstr "הפעל ידנית פעם אחת"
#. module: base
#: view:workflow:0
@@ -6782,7 +6782,7 @@ msgstr "הוגדרו דוחות"
#. module: base
#: model:ir.module.module,shortdesc:base.module_project_gtd
msgid "Todo Lists"
-msgstr ""
+msgstr "רשימות משימות לביצוע"
#. module: base
#: view:ir.actions.report.xml:0
@@ -6827,12 +6827,12 @@ msgstr ""
#. module: base
#: view:ir.sequence:0
msgid "Week of the Year: %(woy)s"
-msgstr ""
+msgstr "שבוע בשנה: %(woy)s"
#. module: base
#: field:res.users,id:0
msgid "ID"
-msgstr ""
+msgstr "מזהה"
#. module: base
#: field:ir.cron,doall:0
@@ -6906,7 +6906,7 @@ msgstr "הוסף רענן-אוטומטית בתצוגה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_crm_profiling
msgid "Customer Profiling"
-msgstr ""
+msgstr "מיפוי פרופיל לקוחות"
#. module: base
#: selection:ir.cron,interval_type:0
@@ -6933,7 +6933,7 @@ msgstr ""
#. module: base
#: view:ir.filters:0
msgid "Filters visible only for one user"
-msgstr ""
+msgstr "מסננים המוצגים למשתמש אחד בלבד"
#. module: base
#: model:ir.model,name:base.model_ir_attachment
@@ -6976,7 +6976,7 @@ msgstr ""
#. module: base
#: selection:res.currency,position:0
msgid "After Amount"
-msgstr ""
+msgstr "לאחר הסכום"
#. module: base
#: selection:base.language.install,lang:0
@@ -7010,7 +7010,7 @@ msgstr ""
#. module: base
#: view:res.lang:0
msgid "%S - Seconds [00,61]."
-msgstr ""
+msgstr "%S - שניות [00,61]."
#. module: base
#: help:base.language.import,overwrite:0
@@ -7035,7 +7035,7 @@ msgstr ""
#: model:ir.ui.menu,name:base.menu_project_config
#: model:ir.ui.menu,name:base.menu_project_report
msgid "Project"
-msgstr ""
+msgstr "פרוייקט"
#. module: base
#: field:ir.ui.menu,web_icon_hover_data:0
@@ -7103,7 +7103,7 @@ msgstr "Somalia"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_doctor
msgid "Dr."
-msgstr ""
+msgstr "ד\"ר"
#. module: base
#: model:res.groups,name:base.group_user
@@ -7157,7 +7157,7 @@ msgstr ""
#: field:res.company,state_id:0
#: field:res.partner.bank,state_id:0
msgid "Fed. State"
-msgstr ""
+msgstr "מדינה פדרלית"
#. module: base
#: field:ir.actions.server,copy_object:0
@@ -7167,7 +7167,7 @@ msgstr "העתק של"
#. module: base
#: field:ir.model.data,display_name:0
msgid "Record Name"
-msgstr ""
+msgstr "שם הרשומה"
#. module: base
#: model:ir.model,name:base.model_ir_actions_client
@@ -7253,7 +7253,7 @@ msgstr "שם מלא"
#. module: base
#: view:ir.attachment:0
msgid "on"
-msgstr ""
+msgstr "ב־"
#. module: base
#: view:ir.property:0
@@ -7275,7 +7275,7 @@ msgstr ""
#. module: base
#: model:ir.ui.menu,name:base.menu_project_long_term
msgid "Long Term Planning"
-msgstr ""
+msgstr "תכנון לטווח ארוך"
#. module: base
#: field:ir.actions.server,message:0
@@ -7303,17 +7303,17 @@ msgstr ""
#: view:res.users:0
#: view:wizard.ir.model.menu.create:0
msgid "or"
-msgstr ""
+msgstr "או"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_accountant
msgid "Accounting and Finance"
-msgstr ""
+msgstr "חשבונאות וכספים"
#. module: base
#: view:ir.module.module:0
msgid "Upgrade"
-msgstr ""
+msgstr "שדרג"
#. module: base
#: model:ir.module.module,description:base.module_base_action_rule
@@ -7351,7 +7351,7 @@ msgstr "Faroe Islands"
#. module: base
#: field:ir.mail_server,smtp_encryption:0
msgid "Connection Security"
-msgstr ""
+msgstr "אבטחת החיבור"
#. module: base
#: code:addons/base/ir/ir_actions.py:606
@@ -7377,7 +7377,7 @@ msgstr "Northern Mariana Islands"
#. module: base
#: field:change.password.user,user_login:0
msgid "User Login"
-msgstr ""
+msgstr "התחברות משתמש"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_hn
@@ -7387,7 +7387,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_report_intrastat
msgid "Intrastat Reporting"
-msgstr ""
+msgstr "דיווח מיידי"
#. module: base
#: code:addons/base/res/res_users.py:131
@@ -7440,7 +7440,7 @@ msgstr ""
#. module: base
#: selection:ir.property,type:0
msgid "Integer"
-msgstr ""
+msgstr "מספר שלם"
#. module: base
#: help:ir.actions.report.xml,report_rml:0
@@ -7452,7 +7452,7 @@ msgstr ""
#. module: base
#: model:res.partner.category,name:base.res_partner_category_14
msgid "Manufacturer"
-msgstr ""
+msgstr "יצרן"
#. module: base
#: help:res.users,company_id:0
@@ -7548,7 +7548,7 @@ msgstr "mdx"
#. module: base
#: view:ir.cron:0
msgid "Scheduled Action"
-msgstr ""
+msgstr "פעולה מתוזמנת"
#. module: base
#: model:res.country,name:base.bi
@@ -7571,7 +7571,7 @@ msgstr ""
#. module: base
#: view:ir.actions.todo:0
msgid "Wizards to be Launched"
-msgstr ""
+msgstr "אשפים שיופעלו"
#. module: base
#: model:res.country,name:base.bt
@@ -7597,7 +7597,7 @@ msgstr ""
#. module: base
#: view:res.partner:0
msgid "at"
-msgstr ""
+msgstr "ב־"
#. module: base
#: view:ir.rule:0
@@ -7638,7 +7638,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_localization_payroll
#: model:ir.module.module,shortdesc:base.module_hr_payroll
msgid "Payroll"
-msgstr ""
+msgstr "שכר"
#. module: base
#: model:ir.actions.act_window,help:base.action_country_state
@@ -7739,7 +7739,7 @@ msgstr ""
#. module: base
#: view:ir.mail_server:0
msgid "Test Connection"
-msgstr ""
+msgstr "בדיקת החיבור"
#. module: base
#: model:res.country,name:base.mm
@@ -7759,7 +7759,7 @@ msgstr "סינית / 简体中文"
#. module: base
#: field:ir.model.fields,selection:0
msgid "Selection Options"
-msgstr ""
+msgstr "אפשרויות בחירה"
#. module: base
#: field:res.bank,street:0
@@ -7912,7 +7912,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_project
msgid "Portal Project"
-msgstr ""
+msgstr "פורטל פרוייקט"
#. module: base
#: model:res.country,name:base.cc
@@ -7930,7 +7930,7 @@ msgstr ""
#: view:res.partner:0
#: field:res.partner,user_id:0
msgid "Salesperson"
-msgstr ""
+msgstr "איש מכירות"
#. module: base
#: view:res.lang:0
@@ -7955,7 +7955,7 @@ msgstr "הולנדית / Nederlands"
#. module: base
#: selection:res.company,paper_format:0
msgid "US Letter"
-msgstr ""
+msgstr "מכתב ארה\"ב"
#. module: base
#: model:ir.actions.act_window,help:base.action_partner_customer_form
@@ -7973,7 +7973,7 @@ msgstr ""
#. module: base
#: model:ir.actions.act_window,name:base.bank_account_update
msgid "Company Bank Accounts"
-msgstr ""
+msgstr "חשבונות בנק של החברה"
#. module: base
#: code:addons/base/res/res_users.py:473
@@ -8009,7 +8009,7 @@ msgstr ""
#. module: base
#: model:res.partner.bank.type,name:base.bank_normal
msgid "Normal Bank Account"
-msgstr ""
+msgstr "חשבון בנק רגיל"
#. module: base
#: field:change.password.user,wizard_id:0
@@ -8036,7 +8036,7 @@ msgstr "1cm 28cm 20cm 28cm"
#. module: base
#: field:ir.module.module,maintainer:0
msgid "Maintainer"
-msgstr ""
+msgstr "מתחזק"
#. module: base
#: field:ir.sequence,suffix:0
@@ -8178,17 +8178,17 @@ msgstr ""
#. module: base
#: view:ir.values:0
msgid "Client Actions"
-msgstr ""
+msgstr "פעולות לקוח"
#. module: base
#: field:res.partner.bank.type,field_ids:0
msgid "Type Fields"
-msgstr ""
+msgstr "שדות סוג"
#. module: base
#: model:ir.module.module,summary:base.module_hr_recruitment
msgid "Jobs, Recruitment, Applications, Job Interviews"
-msgstr ""
+msgstr "משרות, גיוס, הגשת מועמדות, ראיונות למשרה"
#. module: base
#: code:addons/base/module/module.py:539
@@ -8263,7 +8263,7 @@ msgstr "ir.ui.menu"
#. module: base
#: model:ir.module.module,shortdesc:base.module_project
msgid "Project Management"
-msgstr ""
+msgstr "ניהול פרוייקט"
#. module: base
#: view:ir.module.module:0
@@ -8273,7 +8273,7 @@ msgstr "בטל הסרת התקנה"
#. module: base
#: view:res.bank:0
msgid "Communication"
-msgstr ""
+msgstr "תקשורת"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic
@@ -8288,7 +8288,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_graph
msgid "Graph Views"
-msgstr ""
+msgstr "תצוגות תרשימים"
#. module: base
#: help:ir.model.relation,name:0
@@ -8316,7 +8316,7 @@ msgstr ""
#. module: base
#: view:ir.model.access:0
msgid "Access Control"
-msgstr ""
+msgstr "בקרת גישה"
#. module: base
#: model:res.country,name:base.kw
@@ -8404,7 +8404,7 @@ msgstr "Hong Kong"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_sale
msgid "Portal Sale"
-msgstr ""
+msgstr "פורטל מכירות"
#. module: base
#: field:ir.default,ref_id:0
@@ -8727,7 +8727,7 @@ msgstr ""
#. module: base
#: view:res.lang:0
msgid "%j - Day of the year [001,366]."
-msgstr ""
+msgstr "%j - יום בשנה [001,366]."
#. module: base
#: selection:base.language.install,lang:0
@@ -8788,7 +8788,7 @@ msgstr ""
#: code:addons/base/ir/ir_mail_server.py:445
#, python-format
msgid "Missing SMTP Server"
-msgstr ""
+msgstr "שרת SMTP חסר"
#. module: base
#: sql_constraint:ir.translation:0
@@ -8842,7 +8842,7 @@ msgstr "רב פעולות"
#. module: base
#: model:ir.module.module,summary:base.module_mail
msgid "Discussions, Mailing Lists, News"
-msgstr ""
+msgstr "דיונים, רשימות מכותבים, חדשות"
#. module: base
#: model:ir.module.module,description:base.module_fleet
@@ -8893,7 +8893,7 @@ msgstr "American Samoa"
#. module: base
#: view:ir.attachment:0
msgid "My Document(s)"
-msgstr ""
+msgstr "המסמכ(ים) שלי"
#. module: base
#: help:ir.actions.act_window,res_model:0
@@ -8943,7 +8943,7 @@ msgstr "משתמש שגוי"
#. module: base
#: model:ir.module.module,summary:base.module_project_issue
msgid "Support, Bug Tracker, Helpdesk"
-msgstr ""
+msgstr "תמיכה, מעקב באגים, מוקד עזרה"
#. module: base
#: model:res.country,name:base.ae
@@ -8968,17 +8968,17 @@ msgstr ""
#. module: base
#: model:res.partner.category,name:base.res_partner_category_5
msgid "Silver"
-msgstr ""
+msgstr "כסף"
#. module: base
#: field:res.partner.title,shortcut:0
msgid "Abbreviation"
-msgstr ""
+msgstr "קיצור"
#. module: base
#: model:ir.ui.menu,name:base.menu_crm_case_job_req_main
msgid "Recruitment"
-msgstr ""
+msgstr "גיוס"
#. module: base
#: model:ir.module.module,description:base.module_l10n_gr
@@ -9115,12 +9115,12 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_mrp_repair
msgid "Repairs Management"
-msgstr ""
+msgstr "ניהול תיקונים"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_asset
msgid "Assets Management"
-msgstr ""
+msgstr "ניהול נכסים"
#. module: base
#: view:ir.model.access:0
@@ -9163,12 +9163,12 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_base_status
msgid "State/Stage Management"
-msgstr ""
+msgstr "ניהול מצב/שלב"
#. module: base
#: model:ir.module.category,name:base.module_category_warehouse_management
msgid "Warehouse"
-msgstr ""
+msgstr "מחסן"
#. module: base
#: field:ir.exports,resource:0
@@ -9212,12 +9212,12 @@ msgstr "תרגומים"
#. module: base
#: view:ir.actions.report.xml:0
msgid "Report"
-msgstr ""
+msgstr "דוח"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_prof
msgid "Prof."
-msgstr ""
+msgstr "פרופ'"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:241
@@ -9245,7 +9245,7 @@ msgstr "אתר"
#. module: base
#: selection:ir.mail_server,smtp_encryption:0
msgid "None"
-msgstr ""
+msgstr "אף אחד"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_holidays
@@ -9280,7 +9280,7 @@ msgstr "United States"
#. module: base
#: view:ir.ui.view:0
msgid "Architecture"
-msgstr ""
+msgstr "ארכיטקטורה"
#. module: base
#: model:res.country,name:base.ml
@@ -9290,7 +9290,7 @@ msgstr "Mali"
#. module: base
#: model:ir.ui.menu,name:base.menu_project_config_project
msgid "Stages"
-msgstr ""
+msgstr "שלבים"
#. module: base
#: selection:base.language.install,lang:0
@@ -9444,7 +9444,7 @@ msgstr ""
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Manually"
-msgstr ""
+msgstr "הפעל ידנית"
#. module: base
#: model:res.country,name:base.be
@@ -9502,7 +9502,7 @@ msgstr ""
#. module: base
#: field:ir.model.fields,on_delete:0
msgid "On Delete"
-msgstr ""
+msgstr "בעת מחיקה"
#. module: base
#: code:addons/base/ir/ir_model.py:347
@@ -9669,7 +9669,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase
msgid "Purchase Management"
-msgstr ""
+msgstr "ניהול רכש"
#. module: base
#: field:ir.module.module,published_version:0
@@ -9827,7 +9827,7 @@ msgstr "שם השפה"
#. module: base
#: selection:ir.property,type:0
msgid "Boolean"
-msgstr ""
+msgstr "בוליאני"
#. module: base
#: help:ir.mail_server,smtp_encryption:0
@@ -9888,12 +9888,12 @@ msgstr ""
#. module: base
#: field:res.partner,use_parent_address:0
msgid "Use Company Address"
-msgstr ""
+msgstr "השתמש בכתובת חברה"
#. module: base
#: model:ir.module.module,summary:base.module_hr_holidays
msgid "Holidays, Allocation and Leave Requests"
-msgstr ""
+msgstr "חופשות, הקצאות ובקשות חופש"
#. module: base
#: model:ir.module.module,description:base.module_web_hello
@@ -10009,7 +10009,7 @@ msgstr "הצג"
#. module: base
#: model:res.groups,name:base.group_multi_company
msgid "Multi Companies"
-msgstr ""
+msgstr "חברות מרובות"
#. module: base
#: help:res.users,menu_id:0
@@ -10020,7 +10020,7 @@ msgstr ""
#. module: base
#: model:ir.actions.report.xml,name:base.preview_report
msgid "Preview Report"
-msgstr ""
+msgstr "תצוגה מקדימה בדוח"
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase_analytic_plans
@@ -10184,7 +10184,7 @@ msgstr "res.request"
#. module: base
#: field:res.partner,image_medium:0
msgid "Medium-sized image"
-msgstr ""
+msgstr "תמונה בגודל בינוני"
#. module: base
#: view:ir.model:0
@@ -10194,7 +10194,7 @@ msgstr "בזכרון"
#. module: base
#: view:ir.actions.todo:0
msgid "Todo"
-msgstr ""
+msgstr "משימות לביצוע"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_visible_discount
@@ -10237,7 +10237,7 @@ msgstr "Gibraltar"
#. module: base
#: field:ir.actions.report.xml,report_name:0
msgid "Service Name"
-msgstr ""
+msgstr "שם השירות"
#. module: base
#: model:res.country,name:base.pn
@@ -10247,7 +10247,7 @@ msgstr "Pitcairn Island"
#. module: base
#: field:res.partner,category_id:0
msgid "Tags"
-msgstr ""
+msgstr "תגיות"
#. module: base
#: view:base.module.upgrade:0
@@ -10271,7 +10271,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_portal
#: model:ir.module.module,shortdesc:base.module_portal
msgid "Portal"
-msgstr ""
+msgstr "פורטל"
#. module: base
#: selection:ir.translation,state:0
@@ -10391,7 +10391,7 @@ msgstr ""
#: model:ir.ui.menu,name:base.menu_sales
#: model:ir.ui.menu,name:base.next_id_64
msgid "Sales"
-msgstr ""
+msgstr "מכירות"
#. module: base
#: field:ir.actions.server,child_ids:0
@@ -10463,12 +10463,12 @@ msgstr ""
#: view:ir.actions.todo:0
#: selection:ir.actions.todo,state:0
msgid "To Do"
-msgstr ""
+msgstr "מטלה לביצוע"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_hr_employees
msgid "Portal HR employees"
-msgstr ""
+msgstr "פורטל משאבי אנוש לעובדים"
#. module: base
#: selection:base.language.install,lang:0
@@ -10505,7 +10505,7 @@ msgstr "פעולת Python"
#. module: base
#: selection:base.language.install,lang:0
msgid "English (US)"
-msgstr ""
+msgstr "אנגלית (ארה״ב)"
#. module: base
#: model:ir.actions.act_window,help:base.action_partner_title_partner
@@ -10716,7 +10716,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_stock
msgid "Sales and Warehouse Management"
-msgstr ""
+msgstr "ניהול מכירות ומחסן"
#. module: base
#: model:ir.module.module,description:base.module_hr_recruitment
@@ -10780,7 +10780,7 @@ msgstr ""
#. module: base
#: help:res.partner,ean13:0
msgid "BarCode"
-msgstr ""
+msgstr "ברקוד"
#. module: base
#: help:ir.model.fields,model_id:0
@@ -10876,7 +10876,7 @@ msgstr ""
#: code:addons/base/ir/ir_model.py:1031
#, python-format
msgid "Permission Denied"
-msgstr ""
+msgstr "ההרשאה נדחתה"
#. module: base
#: field:ir.ui.menu,child_id:0
@@ -10944,7 +10944,7 @@ msgstr "דוא\"ל"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_12
msgid "Office Supplies"
-msgstr ""
+msgstr "ציוד משרדי"
#. module: base
#: field:ir.attachment,res_model:0
@@ -10964,7 +10964,7 @@ msgstr ""
#. module: base
#: view:res.partner.bank:0
msgid "Information About the Bank"
-msgstr ""
+msgstr "מידע על הבנק"
#. module: base
#: help:ir.actions.server,condition:0
@@ -11012,7 +11012,7 @@ msgstr "רצף עבודה"
#. module: base
#: view:ir.rule:0
msgid "Read Access Right"
-msgstr ""
+msgstr "הרשאת כתיבה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic_user_function
@@ -11060,7 +11060,7 @@ msgstr "ערבית / الْعَرَبيّة"
#. module: base
#: selection:ir.translation,state:0
msgid "Translated"
-msgstr ""
+msgstr "מתורגם"
#. module: base
#: model:ir.actions.act_window,name:base.action_inventory_form
@@ -11155,7 +11155,7 @@ msgstr ""
#. module: base
#: view:ir.filters:0
msgid "Shared"
-msgstr ""
+msgstr "משותף"
#. module: base
#: code:addons/base/module/module.py:357
@@ -11180,7 +11180,7 @@ msgstr "Belarus"
#: field:ir.actions.client,name:0
#: field:ir.actions.server,name:0
msgid "Action Name"
-msgstr ""
+msgstr "שם פעולה"
#. module: base
#: model:ir.actions.act_window,help:base.action_res_users
@@ -11194,7 +11194,7 @@ msgstr ""
#. module: base
#: selection:res.request,priority:0
msgid "Normal"
-msgstr ""
+msgstr "רגילה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase_double_validation
@@ -11206,7 +11206,7 @@ msgstr ""
#: field:res.company,street2:0
#: field:res.partner,street2:0
msgid "Street2"
-msgstr ""
+msgstr "רחוב2"
#. module: base
#: model:ir.actions.act_window,name:base.action_view_base_module_update
@@ -11239,12 +11239,12 @@ msgstr ""
#: model:res.groups,name:base.group_tool_user
#: view:res.users:0
msgid "User"
-msgstr ""
+msgstr "משתמש"
#. module: base
#: model:res.country,name:base.pr
msgid "Puerto Rico"
-msgstr ""
+msgstr "פורטו ריקו"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_tests_demo
@@ -11259,12 +11259,12 @@ msgstr ""
#. module: base
#: view:ir.actions.act_window:0
msgid "Open Window"
-msgstr ""
+msgstr "פתח חלון"
#. module: base
#: field:ir.actions.act_window,auto_search:0
msgid "Auto Search"
-msgstr ""
+msgstr "חיפוש אוטומטי"
#. module: base
#: field:ir.actions.act_window,filter:0
@@ -11274,12 +11274,12 @@ msgstr "מסנן"
#. module: base
#: model:res.country,name:base.ch
msgid "Switzerland"
-msgstr ""
+msgstr "שוויץ"
#. module: base
#: model:res.country,name:base.gd
msgid "Grenada"
-msgstr ""
+msgstr "גרנדה"
#. module: base
#: help:res.partner,customer:0
@@ -11344,7 +11344,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_mrp_operations
msgid "Manufacturing Operations"
-msgstr ""
+msgstr "תפעול הייצור"
#. module: base
#: view:base.language.export:0
@@ -11501,7 +11501,7 @@ msgstr ""
#. module: base
#: selection:res.company,paper_format:0
msgid "A4"
-msgstr ""
+msgstr "A4"
#. module: base
#: view:res.config.installer:0
@@ -11885,7 +11885,7 @@ msgstr "ביטוי לולאה"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_16
msgid "Retailer"
-msgstr ""
+msgstr "קמעונאי"
#. module: base
#: view:ir.model.fields:0
@@ -12014,12 +12014,12 @@ msgstr ""
#. module: base
#: view:ir.mail_server:0
msgid "Connection Information"
-msgstr ""
+msgstr "פרטי החיבור"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_prof
msgid "Professor"
-msgstr ""
+msgstr "פרופסור"
#. module: base
#: model:res.country,name:base.hm
@@ -12046,12 +12046,12 @@ msgstr ""
#. module: base
#: field:res.users,login_date:0
msgid "Latest connection"
-msgstr ""
+msgstr "חיבור אחרון"
#. module: base
#: field:res.groups,implied_ids:0
msgid "Inherits"
-msgstr ""
+msgstr "יורש"
#. module: base
#: selection:ir.translation,type:0
@@ -12124,12 +12124,12 @@ msgstr "קטגוריה"
#: selection:ir.attachment,type:0
#: selection:ir.property,type:0
msgid "Binary"
-msgstr ""
+msgstr "בינארי"
#. module: base
#: model:res.partner.title,name:base.res_partner_title_doctor
msgid "Doctor"
-msgstr ""
+msgstr "דוקטור"
#. module: base
#: model:ir.module.module,description:base.module_mrp_repair
@@ -12161,7 +12161,7 @@ msgstr "Costa Rica"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_ldap
msgid "Authentication via LDAP"
-msgstr ""
+msgstr "אימות באמצעות LDAP"
#. module: base
#: view:workflow.activity:0
@@ -12171,7 +12171,7 @@ msgstr "תנאים"
#. module: base
#: model:ir.actions.act_window,name:base.action_partner_other_form
msgid "Other Partners"
-msgstr ""
+msgstr "שותפים אחרים"
#. module: base
#: field:base.language.install,state:0
@@ -12186,7 +12186,7 @@ msgstr ""
#: view:workflow.workitem:0
#: field:workflow.workitem,state:0
msgid "Status"
-msgstr ""
+msgstr "סטטוס"
#. module: base
#: model:ir.actions.act_window,name:base.action_currency_form
@@ -12308,12 +12308,12 @@ msgstr ""
#. module: base
#: model:res.partner.category,name:base.res_partner_category_6
msgid "Bronze"
-msgstr ""
+msgstr "ברונזה"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_payroll_account
msgid "Payroll Accounting"
-msgstr ""
+msgstr "חשבונאות שכר"
#. module: base
#: view:res.users:0
@@ -12343,7 +12343,7 @@ msgstr "נתונים לדוגמא"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_mister
msgid "Mr."
-msgstr ""
+msgstr "מר"
#. module: base
#: model:res.country,name:base.mv
@@ -12353,7 +12353,7 @@ msgstr "Maldives"
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_crm
msgid "Portal CRM"
-msgstr ""
+msgstr "פורטל ניהול קשרי לקוחות"
#. module: base
#: model:ir.ui.menu,name:base.next_id_4
@@ -12368,7 +12368,7 @@ msgstr ""
#. module: base
#: field:res.country,address_format:0
msgid "Address Format"
-msgstr ""
+msgstr "תצורת הכתובת"
#. module: base
#: model:ir.model,name:base.model_change_password_user
@@ -12427,13 +12427,15 @@ msgid ""
"Here is what we got instead:\n"
" %s"
msgstr ""
+"הנה מה שקיבלנו במקום זאת:\n"
+" %s"
#. module: base
#: model:ir.actions.act_window,name:base.action_model_data
#: view:ir.model.data:0
#: model:ir.ui.menu,name:base.ir_model_data_menu
msgid "External Identifiers"
-msgstr ""
+msgstr "מזהים חיצוניים"
#. module: base
#: selection:base.language.install,lang:0
@@ -12490,7 +12492,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_point_of_sale
#: model:ir.module.module,shortdesc:base.module_point_of_sale
msgid "Point of Sale"
-msgstr ""
+msgstr "נקודת מכירה"
#. module: base
#: model:ir.module.module,description:base.module_mail
@@ -12679,7 +12681,7 @@ msgstr ""
#. module: base
#: view:ir.attachment:0
msgid "Filter on my documents"
-msgstr ""
+msgstr "סנן את המסמכים שלי"
#. module: base
#: model:ir.module.module,summary:base.module_project_gtd
@@ -12712,7 +12714,7 @@ msgstr ""
#: model:ir.ui.menu,name:base.menu_procurement_management_supplier_name
#: view:res.partner:0
msgid "Suppliers"
-msgstr ""
+msgstr "ספקים"
#. module: base
#: field:res.request,ref_doc2:0
@@ -12732,7 +12734,7 @@ msgstr "Gabon"
#. module: base
#: model:ir.module.module,summary:base.module_stock
msgid "Inventory, Logistic, Storage"
-msgstr ""
+msgstr "מלאי, לוגיסטיקה, אחסנה"
#. module: base
#: view:ir.actions.act_window:0
@@ -12795,7 +12797,7 @@ msgstr "Cyprus"
#. module: base
#: field:res.users,new_password:0
msgid "Set Password"
-msgstr ""
+msgstr "קבע סיסמה"
#. module: base
#: field:ir.actions.server,subject:0
@@ -12838,7 +12840,7 @@ msgstr "מאת"
#. module: base
#: view:res.users:0
msgid "Preferences"
-msgstr ""
+msgstr "העדפות"
#. module: base
#: model:res.partner.category,name:base.res_partner_category_9
@@ -12919,7 +12921,7 @@ msgstr ""
#. module: base
#: model:ir.ui.menu,name:base.menu_custom
msgid "Technical"
-msgstr ""
+msgstr "טכני"
#. module: base
#: model:res.country,name:base.cn
@@ -12948,7 +12950,7 @@ msgstr "Western Sahara"
#. module: base
#: model:ir.module.category,name:base.module_category_account_voucher
msgid "Invoicing & Payments"
-msgstr ""
+msgstr "חשבוניות ותשלומים"
#. module: base
#: model:ir.actions.act_window,help:base.action_res_company_form
@@ -13021,7 +13023,7 @@ msgstr "5. %y, %Y ==> 08, 2008"
#. module: base
#: model:res.partner.title,shortcut:base.res_partner_title_ltd
msgid "ltd"
-msgstr ""
+msgstr "בע\"מ"
#. module: base
#: model:ir.module.module,description:base.module_crm_claim
@@ -13087,7 +13089,7 @@ msgstr "לא ידוע"
#. module: base
#: field:res.currency,symbol:0
msgid "Symbol"
-msgstr ""
+msgstr "סמל"
#. module: base
#: help:res.partner,image_medium:0
@@ -13100,13 +13102,13 @@ msgstr ""
#. module: base
#: view:base.update.translations:0
msgid "Synchronize Translation"
-msgstr ""
+msgstr "סנכרן תרגום"
#. module: base
#: view:res.partner.bank:0
#: field:res.partner.bank,bank_name:0
msgid "Bank Name"
-msgstr ""
+msgstr "שם הבנק"
#. module: base
#: model:res.country,name:base.ki
@@ -13140,7 +13142,7 @@ msgstr ""
#: model:ir.module.module,shortdesc:base.module_contacts
#: model:ir.ui.menu,name:base.menu_config_address_book
msgid "Address Book"
-msgstr ""
+msgstr "פנקס כתובות"
#. module: base
#: model:ir.model,name:base.model_ir_sequence_type
@@ -13160,7 +13162,7 @@ msgstr "קובץ CSV"
#. module: base
#: field:res.company,account_no:0
msgid "Account No."
-msgstr ""
+msgstr "חשבון מס'"
#. module: base
#: code:addons/base/res/res_lang.py:185
@@ -13238,7 +13240,7 @@ msgstr "Zaire"
#. module: base
#: model:ir.module.module,summary:base.module_project
msgid "Projects, Tasks"
-msgstr ""
+msgstr "פרוייקטים, משימות"
#. module: base
#: field:ir.attachment,res_id:0
@@ -13257,7 +13259,7 @@ msgstr "מידע"
#: code:addons/base/ir/ir_fields.py:146
#, python-format
msgid "false"
-msgstr ""
+msgstr "שקרי"
#. module: base
#: model:ir.module.module,description:base.module_account_analytic_analysis
@@ -15026,7 +15028,7 @@ msgstr "מצב"
#: model:ir.actions.client,name:base.modules_updates_act_cl
#: model:ir.ui.menu,name:base.menu_module_updates
msgid "Updates"
-msgstr ""
+msgstr "עדכונים"
#. module: base
#: help:res.currency,rate:0
@@ -15344,7 +15346,7 @@ msgstr "זה חברה?"
#: field:res.partner.bank,name:0
#, python-format
msgid "Bank Account"
-msgstr ""
+msgstr "חשבון בנק"
#. module: base
#: model:res.country,name:base.kp
@@ -15443,7 +15445,7 @@ msgstr "רוסית / русский язык"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_signup
msgid "Signup"
-msgstr ""
+msgstr "הרשמה"
#~ msgid "Metadata"
#~ msgstr "נתוני מטא"
diff --git a/openerp/addons/base/i18n/hi.po b/openerp/addons/base/i18n/hi.po
index 833c63f3b75..854c1445870 100644
--- a/openerp/addons/base/i18n/hi.po
+++ b/openerp/addons/base/i18n/hi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:27+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/hr.po b/openerp/addons/base/i18n/hr.po
index c55ce6f2618..5879a1a5096 100644
--- a/openerp/addons/base/i18n/hr.po
+++ b/openerp/addons/base/i18n/hr.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:22+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:32+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
"Language: hr\n"
#. module: base
diff --git a/openerp/addons/base/i18n/hu.po b/openerp/addons/base/i18n/hu.po
index 6f3e6c62926..a2b2b32d75b 100644
--- a/openerp/addons/base/i18n/hu.po
+++ b/openerp/addons/base/i18n/hu.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:18+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:27+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/hy.po b/openerp/addons/base/i18n/hy.po
index 45a96e5bf82..6a2b22db2f4 100644
--- a/openerp/addons/base/i18n/hy.po
+++ b/openerp/addons/base/i18n/hy.po
@@ -9,8 +9,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:16+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:22+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/id.po b/openerp/addons/base/i18n/id.po
index fcdd4ef5da2..92763eb1b10 100644
--- a/openerp/addons/base/i18n/id.po
+++ b/openerp/addons/base/i18n/id.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:27+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -58,7 +58,7 @@ msgstr ""
#: field:ir.ui.view,arch:0
#: field:ir.ui.view.custom,arch:0
msgid "View Architecture"
-msgstr "Arsitektur View"
+msgstr "Lihat Arsitektur"
#. module: base
#: model:ir.module.module,summary:base.module_sale_stock
@@ -86,13 +86,13 @@ msgid ""
"Helps you manage your projects and tasks by tracking them, generating "
"plannings, etc..."
msgstr ""
-"Memungkinkan Anda untuk mengelola proyek dan tugas dengan cara melacaknya, "
-"menghasilkan perencanaan dan lain sebagainya ..."
+"Membantu anda mengelola proyek dan tugas dengan cara melacak, menghasilkan "
+"perencanaan, dan lain sebagainya..."
#. module: base
#: model:ir.module.module,summary:base.module_point_of_sale
msgid "Touchscreen Interface for Shops"
-msgstr "Antarmuka layar sentuh untuk digunakan di toko"
+msgstr "Antarmuka Layar Sentuh untuk Toko"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_in_hr_payroll
@@ -104,12 +104,12 @@ msgstr "Payroll untuk India"
msgid ""
"Model name on which the method to be called is located, e.g. 'res.partner'."
msgstr ""
-"Sebutkan nama model yang mana metode ini akan dipanggil, misal 'res.partner'."
+"Nama model dimana terletak metode yang akan dipanggil, contoh 'res.partner'."
#. module: base
#: view:ir.module.module:0
msgid "Created Views"
-msgstr "View yang diciptakan"
+msgstr "Tampilan yang Diciptakan"
#. module: base
#: model:ir.module.module,description:base.module_product_manufacturer
@@ -127,17 +127,17 @@ msgid ""
" "
msgstr ""
"\n"
-"Modul ini berfungsi untuk menambahkan nama produsen beserta atributnya pada "
+"Sebuah modul yang berfungsi menambahkan nama produsen dan keterangan pada "
"formulir produk.\n"
"============================================================================="
-"==\n"
+"=====\n"
"\n"
-"Anda dapat mengisi data-data berikut pada produk:\n"
-"------------------------------------------------\n"
-"* Nama produsen\n"
-"* Nama produk produsen\n"
-"* Code produk produsen\n"
-"* Atribut produk\n"
+"Anda sekarang dapat menentukan data berikut untuk sebuah produk:\n"
+"-------------------------------------------------------------------\n"
+" * Produsen\n"
+" * Nama Produk Produsen\n"
+" * Kode Produk Produsen\n"
+" * Keterangan Produk\n"
" "
#. module: base
@@ -153,8 +153,8 @@ msgid ""
"========================================\n"
msgstr ""
"\n"
-"Modul ini akan menambahkan google user dalam obyek res.user\n"
-"====================================================\n"
+"Modul ini menambahkan pengguna google dalam res user.\n"
+"======================================================\n"
#. module: base
#: help:res.partner,employee:0
diff --git a/openerp/addons/base/i18n/is.po b/openerp/addons/base/i18n/is.po
index f776572f35e..693c2c845ef 100644
--- a/openerp/addons/base/i18n/is.po
+++ b/openerp/addons/base/i18n/is.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:27+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/it.po b/openerp/addons/base/i18n/it.po
index 8ae15fb89c5..f99d805b221 100644
--- a/openerp/addons/base/i18n/it.po
+++ b/openerp/addons/base/i18n/it.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:28+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/ja.po b/openerp/addons/base/i18n/ja.po
index 911b8439b4b..7acfaa75b85 100644
--- a/openerp/addons/base/i18n/ja.po
+++ b/openerp/addons/base/i18n/ja.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:28+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -480,7 +480,7 @@ msgstr ""
#. module: base
#: field:ir.model.relation,name:0
msgid "Relation Name"
-msgstr ""
+msgstr "リレーション名"
#. module: base
#: view:ir.rule:0
@@ -976,7 +976,7 @@ msgstr "ジンバブエ"
#: help:ir.model.constraint,type:0
msgid ""
"Type of the constraint: `f` for a foreign key, `u` for other constraints."
-msgstr ""
+msgstr "制約のタイプ:`f`は外部キー、`u`は他の制約"
#. module: base
#: view:ir.actions.report.xml:0
@@ -1105,7 +1105,7 @@ msgstr "アンドラ公国"
#. module: base
#: field:ir.rule,perm_read:0
msgid "Apply for Read"
-msgstr ""
+msgstr "読み込みに適用"
#. module: base
#: model:res.country,name:base.mn
@@ -1322,7 +1322,7 @@ msgstr "貢献者"
#. module: base
#: field:ir.rule,perm_unlink:0
msgid "Apply for Delete"
-msgstr ""
+msgstr "削除に適用"
#. module: base
#: selection:ir.property,type:0
@@ -1420,7 +1420,7 @@ msgstr "テスト"
#. module: base
#: field:ir.actions.report.xml,attachment:0
msgid "Save as Attachment Prefix"
-msgstr ""
+msgstr "添付ファイルのプリフィックスとして保存"
#. module: base
#: field:ir.ui.view_sc,res_id:0
@@ -1718,7 +1718,7 @@ msgstr "見積り要求や仕入先請求書といった発注関係のプロセ
#. module: base
#: help:res.partner,website:0
msgid "Website of Partner or Company"
-msgstr ""
+msgstr "取引先または会社のWebサイト"
#. module: base
#: help:base.language.install,overwrite:0
@@ -1792,6 +1792,9 @@ msgid ""
"Launch Manually Once: after having been launched manually, it sets "
"automatically to Done."
msgstr ""
+"手動:手動で起動します。\n"
+"自動:システムを再設定するたびに実行します。\n"
+"手動でいったん起動:手動で起動した後は自動に設定されます。"
#. module: base
#: field:res.partner,image_small:0
@@ -1936,7 +1939,7 @@ msgstr "読み込みアクセス"
#. module: base
#: help:ir.attachment,res_id:0
msgid "The record id this is attached to"
-msgstr ""
+msgstr "これに添付するレコードID"
#. module: base
#: model:ir.module.module,description:base.module_share
@@ -1969,7 +1972,7 @@ msgstr "企業の処理"
msgid ""
"Check this box if this contact is a supplier. If it's not checked, purchase "
"people will not see it when encoding a purchase order."
-msgstr ""
+msgstr "連絡先が仕入先の場合はこのボックスをチェックします。チェックしない場合、発注書を作成する際に表示されません。"
#. module: base
#: model:ir.module.module,shortdesc:base.module_hr_evaluation
@@ -2255,7 +2258,7 @@ msgstr "バハマ"
#. module: base
#: field:ir.rule,perm_create:0
msgid "Apply for Create"
-msgstr ""
+msgstr "作成に適用"
#. module: base
#: model:ir.module.category,name:base.module_category_tools
@@ -2277,7 +2280,7 @@ msgstr "アイルランド"
msgid ""
"Appears by default on the top right corner of your printed documents (report "
"header)."
-msgstr ""
+msgstr "印刷された文書(レポートヘッダ)の右上隅にデフォルトで表示されます。"
#. module: base
#: field:base.module.update,update:0
@@ -2292,7 +2295,7 @@ msgstr "メソッド"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_crypt
msgid "Password Encryption"
-msgstr ""
+msgstr "パスワード暗号化"
#. module: base
#: view:workflow.activity:0
@@ -2509,7 +2512,7 @@ msgstr ""
msgid ""
"View type: Tree type to use for the tree view, set to 'tree' for a "
"hierarchical tree view, or 'form' for a regular list view"
-msgstr ""
+msgstr "ビュータイプ:ツリー表示に使用する型式、階層ツリー表示のための「ツリー」または通常のリスト表示のための「フォーム」に設定"
#. module: base
#: sql_constraint:ir.ui.view_sc:0
@@ -3280,7 +3283,7 @@ msgstr "スウェーデン"
#. module: base
#: field:ir.actions.report.xml,report_file:0
msgid "Report File"
-msgstr ""
+msgstr "レポートファイル"
#. module: base
#: selection:ir.actions.act_window.view,view_mode:0
@@ -3595,7 +3598,7 @@ msgstr ""
#. module: base
#: field:base.language.export,modules:0
msgid "Modules To Export"
-msgstr ""
+msgstr "エクスポートするモジュール"
#. module: base
#: model:res.country,name:base.mt
@@ -3855,7 +3858,7 @@ msgstr "トーゴ"
#: field:ir.actions.act_window,res_model:0
#: field:ir.actions.client,res_model:0
msgid "Destination Model"
-msgstr ""
+msgstr "宛先モデル"
#. module: base
#: selection:ir.sequence,implementation:0
@@ -4202,7 +4205,7 @@ msgstr ""
#. module: base
#: model:ir.actions.server,name:base.action_run_ir_action_todo
msgid "Run Remaining Action Todo"
-msgstr ""
+msgstr "Todoアクションの残りを実行"
#. module: base
#: field:res.partner,ean13:0
@@ -4988,7 +4991,7 @@ msgstr ""
#. module: base
#: help:ir.attachment,res_model:0
msgid "The database object this attachment will be attached to"
-msgstr ""
+msgstr "この添付ファイルに添付されるデータベースオブジェクト"
#. module: base
#: code:addons/base/ir/ir_fields.py:327
@@ -5122,7 +5125,7 @@ msgstr "保存"
#. module: base
#: field:ir.actions.report.xml,report_xml:0
msgid "XML Path"
-msgstr ""
+msgstr "XMLパス"
#. module: base
#: model:res.country,name:base.bj
@@ -5519,7 +5522,7 @@ msgstr "ブーベ島"
#. module: base
#: field:ir.model.constraint,type:0
msgid "Constraint Type"
-msgstr ""
+msgstr "制約タイプ"
#. module: base
#: field:res.company,child_ids:0
@@ -5658,7 +5661,7 @@ msgstr ""
#. module: base
#: model:res.groups,name:base.group_sale_salesman_all_leads
msgid "See all Leads"
-msgstr ""
+msgstr "全ての見込み客を参照"
#. module: base
#: model:res.country,name:base.ci
@@ -5684,7 +5687,7 @@ msgstr "リソース名"
#. module: base
#: model:ir.ui.menu,name:base.menu_ir_filters
msgid "User-defined Filters"
-msgstr ""
+msgstr "ユーザ定義のフィルタ"
#. module: base
#: field:ir.actions.act_window_close,name:0
@@ -6074,6 +6077,8 @@ msgid ""
"deleting it (if you delete a native record rule, it may be re-created when "
"you reload the module."
msgstr ""
+"アクティブなフィールドのチェックを外すと、レコードのルールを削除せずに無効化します(レコードのルールを削除すると、モジュールを再ロードするときに再作成され"
+"ます)。"
#. module: base
#: selection:base.language.install,lang:0
@@ -6237,7 +6242,7 @@ msgstr ""
#: help:res.country.state,name:0
msgid ""
"Administrative divisions of a country. E.g. Fed. State, Departement, Canton"
-msgstr ""
+msgstr "国の行政区画。たとえば連邦、省、州。"
#. module: base
#: view:res.partner.bank:0
@@ -6257,12 +6262,12 @@ msgstr "このルールにより影響を受けたオブジェクト"
#. module: base
#: selection:ir.actions.act_window,target:0
msgid "Inline View"
-msgstr ""
+msgstr "インラインビュー"
#. module: base
#: field:ir.filters,is_default:0
msgid "Default filter"
-msgstr ""
+msgstr "デフォルトのフィルタ"
#. module: base
#: report:ir.module.reference:0
@@ -6630,7 +6635,7 @@ msgstr "世紀なしの現在年: %(y)s"
#: view:ir.config_parameter:0
#: model:ir.ui.menu,name:base.ir_config_menu
msgid "System Parameters"
-msgstr ""
+msgstr "システムパラメータ"
#. module: base
#: help:ir.actions.client,tag:0
@@ -6805,7 +6810,7 @@ msgstr "ランドスケープレポート用RML内部ヘッダ"
#. module: base
#: model:res.groups,name:base.group_partner_manager
msgid "Contact Creation"
-msgstr ""
+msgstr "連絡先作成"
#. module: base
#: view:ir.module.module:0
@@ -7083,7 +7088,7 @@ msgstr "モジュールファイルのインポートが成功しました。"
#: view:ir.model.constraint:0
#: model:ir.ui.menu,name:base.ir_model_constraint_menu
msgid "Model Constraints"
-msgstr ""
+msgstr "モデル制約"
#. module: base
#: model:ir.actions.act_window,name:base.action_workflow_transition_form
@@ -7198,7 +7203,7 @@ msgstr "のコピー"
#. module: base
#: field:ir.model.data,display_name:0
msgid "Record Name"
-msgstr ""
+msgstr "レコード名"
#. module: base
#: model:ir.model,name:base.model_ir_actions_client
@@ -7214,7 +7219,7 @@ msgstr "イギリス領インド洋地域"
#. module: base
#: model:ir.actions.server,name:base.action_server_module_immediate_install
msgid "Module Immediate Install"
-msgstr ""
+msgstr "モジュール即時インストール"
#. module: base
#: view:ir.actions.server:0
@@ -7565,6 +7570,8 @@ msgid ""
"use the same timezone that is otherwise used to pick and render date and "
"time values: your computer's timezone."
msgstr ""
+"取引先のタイムゾーン。印刷するレポート内に適切な日付と時刻を出力するために使用します。このフィールドに値を設定することは重要です。日付と時刻を選択して表示"
+"するのでなければ、あなたのコンピュータと同じタイムゾーンを使用すべきです。"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_analytic_default
@@ -7633,7 +7640,7 @@ msgstr ""
#. module: base
#: view:ir.rule:0
msgid "Rule Definition (Domain Filter)"
-msgstr ""
+msgstr "ルール定義(ドメインフィルタ)"
#. module: base
#: selection:ir.actions.act_url,target:0
@@ -8009,6 +8016,12 @@ msgid ""
" </p>\n"
" "
msgstr ""
+"<p class=\"oe_view_nocontent_create\">\n"
+" クリックしてアドレス帳に連絡先を追加してください。\n"
+" </p><p>\n"
+" OpenERPは顧客、ディスカッション、商機の履歴、文書など関連するすべての活動の追跡を容易にします。\n"
+" </p>\n"
+" "
#. module: base
#: model:ir.actions.act_window,name:base.bank_account_update
@@ -8340,7 +8353,7 @@ msgstr ""
#. module: base
#: help:ir.model.relation,name:0
msgid "PostgreSQL table name implementing a many2many relation."
-msgstr ""
+msgstr "多対多の関係を実装するPostgreSQLのテーブル名。"
#. module: base
#: model:ir.module.module,description:base.module_base
@@ -8441,7 +8454,7 @@ msgstr "常時検索可能"
#. module: base
#: help:res.country.state,code:0
msgid "The state code in max. three chars."
-msgstr ""
+msgstr "最大3文字の州コード。"
#. module: base
#: model:res.country,name:base.hk
@@ -8604,7 +8617,7 @@ msgstr "ドミニカ"
#. module: base
#: field:ir.translation,name:0
msgid "Translated field"
-msgstr ""
+msgstr "翻訳フィールド"
#. module: base
#: model:ir.module.module,shortdesc:base.module_stock_location
@@ -8682,7 +8695,7 @@ msgstr "アクション結合"
msgid ""
"If the selected language is loaded in the system, all documents related to "
"this contact will be printed in this language. If not, it will be English."
-msgstr ""
+msgstr "選択された言語がシステムにロードされている場合、この連絡先に関連するすべての文書はこの言語で印刷されます。そうでない場合は英語です。"
#. module: base
#: model:ir.module.module,description:base.module_hr_evaluation
@@ -8839,7 +8852,7 @@ msgstr ""
msgid ""
"This field specifies whether the model is transient or not (i.e. if records "
"are automatically deleted from the database or not)"
-msgstr ""
+msgstr "このフィールドはモデルが一時的かどうか(レコードがデータベースから自動的に削除されるかどうか)を指定します。"
#. module: base
#: code:addons/base/ir/ir_mail_server.py:445
@@ -9231,7 +9244,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_warehouse_management
msgid "Warehouse"
-msgstr ""
+msgstr "倉庫"
#. module: base
#: field:ir.exports,resource:0
@@ -9568,7 +9581,7 @@ msgstr "%H - 時(24時間表示)[00,23]."
#. module: base
#: field:ir.model.fields,on_delete:0
msgid "On Delete"
-msgstr ""
+msgstr "削除時"
#. module: base
#: code:addons/base/ir/ir_model.py:347
@@ -9782,7 +9795,7 @@ msgstr "ドイツ"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_oauth
msgid "OAuth2 Authentication"
-msgstr ""
+msgstr "OAuth2認証"
#. module: base
#: view:workflow:0
@@ -9825,7 +9838,7 @@ msgstr "通貨コードは会社ごとに固有でなければいけません。
#: code:addons/base/module/wizard/base_export_language.py:39
#, python-format
msgid "New Language (Empty translation template)"
-msgstr ""
+msgstr "新しい言語 (空の翻訳テンプレート)"
#. module: base
#: help:ir.actions.server,email:0
@@ -10025,6 +10038,12 @@ msgid ""
" </p>\n"
" "
msgstr ""
+"<p class=\"oe_view_nocontent_create\">\n"
+" クリックしてアドレス帳に連絡先を追加してください。\n"
+" </p><p>\n"
+" OpenERPは仕入先、ディスカッション、購入の履歴、文書など関連するすべての活動の追跡を容易にします。\n"
+" </p>\n"
+" "
#. module: base
#: model:res.country,name:base.lr
@@ -10296,7 +10315,7 @@ msgstr "ファイルの内容"
#: view:ir.model.relation:0
#: model:ir.ui.menu,name:base.ir_model_relation_menu
msgid "ManyToMany Relations"
-msgstr ""
+msgstr "多対多の関係"
#. module: base
#: model:res.country,name:base.pa
@@ -10400,7 +10419,7 @@ msgstr "OpenERPは自動的に次の番号に要求されているサイズにå¿
#. module: base
#: help:ir.model.constraint,name:0
msgid "PostgreSQL constraint or foreign key name."
-msgstr ""
+msgstr "PostgreSQLの制約や外部キーの名前。"
#. module: base
#: view:res.company:0
@@ -10425,7 +10444,7 @@ msgstr "ギニアビサウ"
#. module: base
#: field:ir.actions.report.xml,header:0
msgid "Add RML Header"
-msgstr ""
+msgstr "RMLヘッダを追加"
#. module: base
#: help:res.company,rml_footer:0
@@ -10547,7 +10566,7 @@ msgstr "イタリア"
#. module: base
#: model:res.groups,name:base.group_sale_salesman
msgid "See Own Leads"
-msgstr ""
+msgstr "自分の見込み客を参照"
#. module: base
#: view:ir.actions.todo:0
@@ -11057,7 +11076,7 @@ msgstr "オフィス用品"
#. module: base
#: field:ir.attachment,res_model:0
msgid "Resource Model"
-msgstr ""
+msgstr "リソースモデル"
#. module: base
#: code:addons/custom.py:555
@@ -11184,7 +11203,7 @@ msgstr ""
#: model:ir.actions.act_window,name:base.action_inventory_form
#: model:ir.ui.menu,name:base.menu_action_inventory_form
msgid "Default Company per Object"
-msgstr ""
+msgstr "オブジェクトごとのデフォルト会社"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_hello
@@ -11229,7 +11248,7 @@ msgstr "州名"
#. module: base
#: help:ir.attachment,type:0
msgid "Binary File or URL"
-msgstr ""
+msgstr "バイナリファイルまたはURL"
#. module: base
#: code:addons/base/ir/ir_fields.py:313
@@ -11374,7 +11393,7 @@ msgstr ""
#. module: base
#: field:workflow.transition,signal:0
msgid "Signal (Button Name)"
-msgstr ""
+msgstr "シグナル(ボタン名)"
#. module: base
#: view:ir.actions.act_window:0
@@ -11404,7 +11423,7 @@ msgstr "グレナダ"
#. module: base
#: help:res.partner,customer:0
msgid "Check this box if this contact is a customer."
-msgstr ""
+msgstr "連絡先が顧客の場合はこのボックスをチェックします。"
#. module: base
#: view:ir.actions.server:0
@@ -11439,7 +11458,7 @@ msgstr ""
#. module: base
#: field:res.users,partner_id:0
msgid "Related Partner"
-msgstr ""
+msgstr "関連取引先"
#. module: base
#: code:addons/osv.py:172
@@ -11719,6 +11738,7 @@ msgid ""
"(if you delete a native ACL, it will be re-created when you reload the "
"module."
msgstr ""
+"アクティブなフィールドのチェックを外すと、ACLを削除せずに無効化します(ACLを削除すると、モジュールを再ロードするときに再作成されます)。"
#. module: base
#: model:ir.model,name:base.model_ir_fields_converter
@@ -12185,7 +12205,7 @@ msgstr "見積書、販売注文書、請求書の処理に役立ちます。"
#. module: base
#: field:res.users,login_date:0
msgid "Latest connection"
-msgstr ""
+msgstr "最後の接続"
#. module: base
#: field:res.groups,implied_ids:0
@@ -12349,7 +12369,7 @@ msgstr "デフォルト値、またはアクションへの参照"
#. module: base
#: field:ir.actions.report.xml,auto:0
msgid "Custom Python Parser"
-msgstr ""
+msgstr "特注のPythonパーサ"
#. module: base
#: sql_constraint:res.groups:0
@@ -12933,7 +12953,7 @@ msgstr "ニューカレドニア(フランス領)"
#. module: base
#: field:ir.model,osv_memory:0
msgid "Transient Model"
-msgstr ""
+msgstr "過度的なモデル"
#. module: base
#: model:res.country,name:base.cy
@@ -13073,7 +13093,7 @@ msgstr "送信メールサーバ"
#. module: base
#: model:ir.ui.menu,name:base.menu_custom
msgid "Technical"
-msgstr ""
+msgstr "技術"
#. module: base
#: model:res.country,name:base.cn
@@ -13290,7 +13310,7 @@ msgstr "起動するアクション"
#: field:ir.model,modules:0
#: field:ir.model.fields,modules:0
msgid "In Modules"
-msgstr ""
+msgstr "モジュールリスト"
#. module: base
#: model:ir.module.module,shortdesc:base.module_contacts
@@ -13783,7 +13803,7 @@ msgstr ""
msgid ""
"Check this to define the report footer manually. Otherwise it will be "
"filled in automatically."
-msgstr ""
+msgstr "レポートフッタをマニュアルで定義する場合はチェックしてください。それ以外は自動で入力されます。"
#. module: base
#: view:res.partner:0
@@ -13829,7 +13849,7 @@ msgstr "ソース"
#: field:ir.model.constraint,date_init:0
#: field:ir.model.relation,date_init:0
msgid "Initialization Date"
-msgstr ""
+msgstr "初期化の日付"
#. module: base
#: model:res.country,name:base.vu
@@ -13998,7 +14018,7 @@ msgstr "複数ドキュメントのアクション"
#: model:ir.actions.act_window,name:base.action_partner_title_partner
#: model:ir.ui.menu,name:base.menu_partner_title_partner
msgid "Titles"
-msgstr ""
+msgstr "敬称"
#. module: base
#: model:ir.module.module,description:base.module_anonymization
@@ -14298,7 +14318,7 @@ msgstr "ヘルプデスク"
#. module: base
#: field:ir.rule,perm_write:0
msgid "Apply for Write"
-msgstr ""
+msgstr "読み込みに適用"
#. module: base
#: field:ir.ui.menu,parent_left:0
@@ -14456,7 +14476,7 @@ msgstr "ペルシア語 / فارس"
#. module: base
#: view:base.language.export:0
msgid "Export Settings"
-msgstr ""
+msgstr "エクスポート設定"
#. module: base
#: field:ir.actions.act_window,src_model:0
@@ -15333,7 +15353,7 @@ msgstr ""
#. module: base
#: field:ir.model.data,complete_name:0
msgid "Complete ID"
-msgstr ""
+msgstr "完了ID"
#. module: base
#: model:ir.module.module,description:base.module_stock
@@ -15488,7 +15508,7 @@ msgstr "購買依頼"
#. module: base
#: selection:ir.actions.act_window,target:0
msgid "Inline Edit"
-msgstr ""
+msgstr "インライン編集"
#. module: base
#: selection:ir.cron,interval_type:0
@@ -15555,6 +15575,12 @@ msgid ""
" </p>\n"
" "
msgstr ""
+"<p class=\"oe_view_nocontent_create\">\n"
+" クリックしてアドレス帳に連絡先を追加してください。\n"
+" </p><p>\n"
+" OpenERPは顧客、ディスカッション、商機の履歴、文書など関連するすべての活動の追跡を容易にします。\n"
+" </p>\n"
+" "
#. module: base
#: model:res.partner.category,name:base.res_partner_category_2
diff --git a/openerp/addons/base/i18n/ka.po b/openerp/addons/base/i18n/ka.po
index 233c92e7f4f..a07e569fc58 100644
--- a/openerp/addons/base/i18n/ka.po
+++ b/openerp/addons/base/i18n/ka.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:25+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/kk.po b/openerp/addons/base/i18n/kk.po
index 97404913ea3..fd1401f3b2f 100644
--- a/openerp/addons/base/i18n/kk.po
+++ b/openerp/addons/base/i18n/kk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:28+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/ko.po b/openerp/addons/base/i18n/ko.po
index 0cc3f2c2375..68a67e8dd50 100644
--- a/openerp/addons/base/i18n/ko.po
+++ b/openerp/addons/base/i18n/ko.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:19+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:28+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/lt.po b/openerp/addons/base/i18n/lt.po
index b6c3036e35e..860fd218a82 100644
--- a/openerp/addons/base/i18n/lt.po
+++ b/openerp/addons/base/i18n/lt.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:29+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/lv.po b/openerp/addons/base/i18n/lv.po
index 5eb342ee81a..7267dd928f4 100644
--- a/openerp/addons/base/i18n/lv.po
+++ b/openerp/addons/base/i18n/lv.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:29+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -16519,3 +16519,10 @@ msgstr ""
#~ msgstr ""
#~ "Nevar izveidot dokumentu (%s) ! Pārbaudiet, vai lietotājs pieder kādai no "
#~ "šīm grupām: %s."
+
+#~ msgid ""
+#~ "\n"
+#~ " "
+#~ msgstr ""
+#~ "\n"
+#~ " "
diff --git a/openerp/addons/base/i18n/mk.po b/openerp/addons/base/i18n/mk.po
index 9ecb4b8bbd1..ca43ebc0830 100644
--- a/openerp/addons/base/i18n/mk.po
+++ b/openerp/addons/base/i18n/mk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:29+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/mn.po b/openerp/addons/base/i18n/mn.po
index 706bb7920e4..2399a1f42fb 100644
--- a/openerp/addons/base/i18n/mn.po
+++ b/openerp/addons/base/i18n/mn.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:29+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -3094,7 +3094,7 @@ msgstr "Моделийн Тойм"
#. module: base
#: model:ir.module.module,shortdesc:base.module_product_margin
msgid "Margins by Products"
-msgstr "Захалбар Бараагаар"
+msgstr "Бохир ашиг Бараагаар"
#. module: base
#: model:ir.ui.menu,name:base.menu_invoiced
@@ -5214,7 +5214,7 @@ msgstr ""
" * Дагавар\n"
" * Дараагийн Дугаар\n"
" * Нэмэгдэх Тоо\n"
-" * Гүйцээлтийн тоо\n"
+" * Дугаарлалтын гүйцээлт\n"
" "
#. module: base
@@ -7400,7 +7400,7 @@ msgid ""
" "
msgstr ""
"\n"
-"Энэ модуль нь борлуулалтын захиалга дээр 'Тодотгол' нэмдэг.\n"
+"Энэ модуль нь борлуулалтын захиалга дээр 'Бохир ашиг' нэмдэг.\n"
"=============================================\n"
"\n"
"Нэгж үнэ, Өртөг үнийг харьцуулан бохир ашгийг харуулдаг.\n"
@@ -11017,7 +11017,7 @@ msgstr "Өөриймшүүлсэн"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_margin
msgid "Margins in Sales Orders"
-msgstr "Борлуулалтын захиалгын зөрүү"
+msgstr "Борлуулалтын захиалгын бохир ашиг"
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase
@@ -12353,7 +12353,7 @@ msgid ""
"you need.\n"
msgstr ""
"\n"
-"Бараанд борлуулалт, худалдан авалт, тохируулалт зэрэг олон сонирхолтой "
+"Бараанд борлуулалт, худалдан авалт, бохир ашиг зэрэг олон сонирхолтой "
"үзүүлэлтийг тооцолох тайлангийн менюг нэмдэг.\n"
"============================================================================="
"================================================\n"
@@ -13178,7 +13178,7 @@ msgstr "Гүйцэтгэх дараагийн огноо"
#. module: base
#: field:ir.sequence,padding:0
msgid "Number Padding"
-msgstr "Тоон дугаарын гүйцээлт"
+msgstr "Дугаарын гүйцээлт"
#. module: base
#: help:multi_company.default,field_id:0
@@ -14808,6 +14808,15 @@ msgid ""
"automatically new claims based on incoming emails.\n"
" "
msgstr ""
+"\n"
+"\n"
+"Захиалагчийн Гомдлын Менежмент.\n"
+"=======================\n"
+"Энэ аппликэйшн нь захиалагч/нийлүүлэгчийн гомдлыг хөтлөх боломжийг олгодог.\n"
+"\n"
+"Энэ модуль нь эмэйл үүдтэй бүрэн уялддаг тул ирж буй имэйлээс\n"
+"автоматаар гомдлыг үүсгэх боломжтой.\n"
+" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_test
@@ -18259,9 +18268,6 @@ msgstr "Бүртгүүлэх"
#~ msgid "View Ordering"
#~ msgstr "Дэлгэц эрэмблэлт"
-#~ msgid "Number padding"
-#~ msgstr "Тоон дугаарын урт"
-
#~ msgid "Object Identifiers"
#~ msgstr "Обьект бүрдүүлбэр"
@@ -24122,3 +24128,6 @@ msgstr "Бүртгүүлэх"
#~ msgid "Retro-Planning on Events"
#~ msgstr "Үйл явдлын хойноос урагшаа төлөвлөлт"
+
+#~ msgid "Number padding"
+#~ msgstr "Тоон дугаарын гүйцээлт"
diff --git a/openerp/addons/base/i18n/nb.po b/openerp/addons/base/i18n/nb.po
index bc8ed2c449b..24238f3930a 100644
--- a/openerp/addons/base/i18n/nb.po
+++ b/openerp/addons/base/i18n/nb.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:20+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:29+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/nl.po b/openerp/addons/base/i18n/nl.po
index f30cb856d70..262497dc979 100644
--- a/openerp/addons/base/i18n/nl.po
+++ b/openerp/addons/base/i18n/nl.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:17+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:24+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -1625,7 +1625,7 @@ msgstr ""
#: model:ir.module.category,name:base.module_category_purchase_management
#: model:ir.ui.menu,name:base.menu_purchase_root
msgid "Purchases"
-msgstr "Inkoop"
+msgstr "Inkopen"
#. module: base
#: model:res.country,name:base.md
diff --git a/openerp/addons/base/i18n/nl_BE.po b/openerp/addons/base/i18n/nl_BE.po
index 21629cb5933..f8fd7bf1233 100644
--- a/openerp/addons/base/i18n/nl_BE.po
+++ b/openerp/addons/base/i18n/nl_BE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:36+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/pl.po b/openerp/addons/base/i18n/pl.po
index 1800d2cd113..743a7aa0584 100644
--- a/openerp/addons/base/i18n/pl.po
+++ b/openerp/addons/base/i18n/pl.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:21+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:30+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/pt.po b/openerp/addons/base/i18n/pt.po
index 60cee2dde48..0b8bb5e0298 100644
--- a/openerp/addons/base/i18n/pt.po
+++ b/openerp/addons/base/i18n/pt.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:21+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:30+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po
index 9fc05c5a779..005ec2713fe 100644
--- a/openerp/addons/base/i18n/pt_BR.po
+++ b/openerp/addons/base/i18n/pt_BR.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:24+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:35+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/ro.po b/openerp/addons/base/i18n/ro.po
index c69dafdf288..e9a77c2cb6a 100644
--- a/openerp/addons/base/i18n/ro.po
+++ b/openerp/addons/base/i18n/ro.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:21+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:31+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -26,7 +26,7 @@ msgid ""
msgstr ""
"\n"
"Modul pentru Bifeaza Scriere si Bifeaza Imprimare.\n"
-"================================================\n"
+"==================================================\n"
" "
#. module: base
@@ -129,7 +129,7 @@ msgid ""
msgstr ""
"\n"
"Un modul care adauga producatori si atribute la formularul produsului.\n"
-"====================================================================\n"
+"======================================================================\n"
"\n"
"Acum puteti defini urmatoarele pentru un produs:\n"
"-----------------------------------------------\n"
@@ -153,7 +153,7 @@ msgid ""
msgstr ""
"\n"
"Acest modul adauga utilizatorul google la utilizatorul res.\n"
-"========================================\n"
+"===========================================================\n"
#. module: base
#: help:res.partner,employee:0
@@ -212,7 +212,7 @@ msgid ""
msgstr ""
"\n"
"Generează Facturi din Cheltuieli, Înregistrări ale Fișelor de Pontaj.\n"
-"========================================================\n"
+"=====================================================================\n"
"\n"
"Modul pentru generarea facturilor pe baza costurilor (resurse umane, "
"cheltuieli, ...).\n"
@@ -249,7 +249,7 @@ msgstr "Eroare constrângere"
#. module: base
#: model:ir.model,name:base.model_ir_ui_view_custom
msgid "ir.ui.view.custom"
-msgstr "ir.ui.vizualizare.personalizata"
+msgstr "ir.ui.view.custom"
#. module: base
#: code:addons/base/ir/ir_model.py:374
@@ -405,7 +405,7 @@ msgid ""
msgstr ""
"\n"
"Programul de instalare Ascuns bazat pe cunostinte.\n"
-"=====================================\n"
+"==================================================\n"
"\n"
"Face Configuratia Aplicatiei Cunostinte disponibila, de unde puteti instala\n"
"documente si Ascuns bazat pe Wiki.\n"
@@ -431,7 +431,8 @@ msgstr ""
"\n"
"Va permite sa adaugati metode de livrare la comenzile de vanzare si "
"ridicare.\n"
-"==============================================================\n"
+"============================================================================="
+"\n"
"\n"
"Va puteti defini propriile grile de preturi pentru transport si livrare. "
"Atunci cand creati \n"
@@ -617,7 +618,7 @@ msgid ""
msgstr ""
"\n"
"Modul pentru definirea obiectului contabilitatii analitice.\n"
-"===============================================\n"
+"===========================================================\n"
"\n"
"In OpenERP, conturile analitice sunt legate de conturile generale, dar sunt "
"tratate\n"
@@ -650,7 +651,7 @@ msgid ""
msgstr ""
"\n"
"Organizarea si gestionarea Evenimentelor.\n"
-"======================================\n"
+"=========================================\n"
"\n"
"Modulul eveniment va permite sa organizati eficient evenimente si toate "
"sarcinile asociate lor: planificare, urmarirea inregistrarii,\n"
@@ -855,7 +856,7 @@ msgid ""
msgstr ""
"\n"
"Contabilitate si Management Financiar.\n"
-"====================================\n"
+"======================================\n"
"\n"
"Modulul Finante si contabilitate acopera:\n"
"--------------------------------------------\n"
@@ -899,7 +900,7 @@ msgid ""
msgstr ""
"\n"
"Meniul pentru Marketing.\n"
-"=======================\n"
+"========================\n"
"\n"
"Contine programul de instalare pentru modulele legate de marketing.\n"
" "
@@ -915,7 +916,7 @@ msgid ""
msgstr ""
"\n"
"Modulul OpenERP Web LinkedIn.\n"
-"============================\n"
+"=============================\n"
"Acest modul asigura Integrarea lui LinkedIn in OpenERP.\n"
" "
@@ -950,7 +951,7 @@ msgstr "Data urmatoarei executii planificate pentru aceasta sarcina."
#. module: base
#: model:ir.model,name:base.model_ir_ui_view
msgid "ir.ui.view"
-msgstr "ir.ui.vizualizare"
+msgstr "ir.ui.view"
#. module: base
#: model:res.country,name:base.er
@@ -975,7 +976,7 @@ msgstr "România - Contabilitate"
#. module: base
#: model:ir.model,name:base.model_res_config_settings
msgid "res.config.settings"
-msgstr "res.configurare.setari"
+msgstr "res.config.settings"
#. module: base
#: help:res.partner,image_small:0
@@ -996,8 +997,8 @@ msgid ""
"the correct mobile number"
msgstr ""
"Furnizeaza campurile care sunt folosite pentru a cauta numarul de telefon "
-"mobil, de exemplu dumneavoastra selectati factura, atunci "
-"`obiect.factura_adresa_id.mobil` este campul care va da numarul corect de "
+"mobil, de exemplu dumneavoastra selectati factura, atunci "
+"`object.invoice_address_id.mobile` este campul care va da numarul corect de "
"telefon mobil"
#. module: base
@@ -1072,7 +1073,7 @@ msgid ""
msgstr ""
"\n"
"Gestioneaza concediile si cererile de alocare\n"
-"=====================================\n"
+"=============================================\n"
"\n"
"Aceasta aplicatie controleaza programul de concedii al companiei "
"dumneavoastra. Le permite angajatilor sa solicite concedii. Astfel, "
@@ -1331,7 +1332,7 @@ msgid ""
msgstr ""
"\n"
"Managementul general OpenERP al Relatiilor cu Clientii\n"
-" ====================================================\n"
+"======================================================\n"
" \n"
"Aceasta aplicatie permite unui grup de oameni sa gestioneze in mod "
"inteligent si eficient piste, oportunitati, intalniri si apeluri "
@@ -1356,7 +1357,7 @@ msgstr ""
" \n"
"\n"
"Tabloul de bord pentru MRC va include:\n"
-" -------------------------------\n"
+"--------------------------------------\n"
" * Veniturile Planificate dupa Etapa si Utilizator (grafic)\n"
" * Oportunitati dupa Etapa (grafic)\n"
@@ -1932,7 +1933,7 @@ msgstr "Sfantul Martin (partea franceza)"
#. module: base
#: model:ir.model,name:base.model_ir_exports
msgid "ir.exports"
-msgstr "ir.exporturi"
+msgstr "ir.exports"
#. module: base
#: model:ir.module.module,description:base.module_l10n_lu
@@ -2011,7 +2012,7 @@ msgid ""
msgstr ""
"\n"
"Modulul de baza pentru gestionarea pranzului.\n"
-"================================\n"
+"=============================================\n"
"\n"
"Multe companii comanda sandwich-uri, pizza si alte mancaruri de la "
"furnizorii obisnuiti, pentru angajatii lor pentru a le oferi mai multe "
@@ -2056,7 +2057,7 @@ msgstr "Bancă"
#. module: base
#: model:ir.model,name:base.model_ir_exports_line
msgid "ir.exports.line"
-msgstr "ir.linie.exporturi"
+msgstr "ir.exports.line"
#. module: base
#: model:ir.module.category,description:base.module_category_purchase_management
@@ -2125,8 +2126,8 @@ msgid ""
"Access all the fields related to the current object using expressions, i.e. "
"object.partner_id.name "
msgstr ""
-"Acceseaza toate fisierele asociate obiectului actual folosind expresii, de "
-"exemplu obiect.partener_id.nume "
+"Accesează toate câmpurile asociate obiectului actual folosind expresii, de "
+"exemplu object.partner_id.name "
#. module: base
#: model:ir.module.module,shortdesc:base.module_portal_project_issue
@@ -2169,7 +2170,7 @@ msgstr "Gestiunea depozitului"
#. module: base
#: model:ir.model,name:base.model_res_request_link
msgid "res.request.link"
-msgstr "res.link.cerere"
+msgstr "res.request.link"
#. module: base
#: field:ir.actions.wizard,name:0
@@ -2250,7 +2251,7 @@ msgid ""
msgstr ""
"\n"
"Drepturi de acces contabile\n"
-"========================\n"
+"===========================\n"
"Ii ofera utilizatorului Administrator acces la toate caracteristicile "
"contabile, precum elemente ale jurnalului si planul de conturi.\n"
"\n"
@@ -2260,7 +2261,7 @@ msgstr ""
#. module: base
#: view:ir.sequence:0
msgid "Day: %(day)s"
-msgstr "Ziua: %(zi)s"
+msgstr "Ziua: %(day)s"
#. module: base
#: model:ir.module.category,description:base.module_category_point_of_sale
@@ -2299,7 +2300,7 @@ msgstr "Traducere în desfășurare"
#. module: base
#: model:ir.model,name:base.model_ir_rule
msgid "ir.rule"
-msgstr "ir.regula"
+msgstr "ir.rule"
#. module: base
#: selection:ir.cron,interval_type:0
@@ -2444,7 +2445,8 @@ msgstr ""
"\n"
"Sincronizarea inregistrarilor sarcinilor proiectului cu inregistrarile fisei "
"de pontaj.\n"
-"====================================================================\n"
+"============================================================================="
+"==========\n"
"\n"
"Acest modul va permite sa transferati inregistrarile sub sarcini definite "
"pentru Managementul\n"
@@ -2456,7 +2458,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_model_access
msgid "ir.model.access"
-msgstr "ir.model.acces"
+msgstr "ir.model.access"
#. module: base
#: model:ir.module.module,description:base.module_l10n_multilang
@@ -2778,7 +2780,7 @@ msgid ""
msgstr ""
"\n"
"Inregistreaza si valideaza fisele de pontaj si prezenta cu usurinta\n"
-"=====================================================\n"
+"===================================================================\n"
"\n"
"Aceasta aplicatie ofera un ecran nou care va permite sa gestionati atat "
"prezenta (La intrare/La iesire) cat si inregistrare muncii (fisa de pontaj) "
@@ -2874,7 +2876,7 @@ msgid ""
msgstr ""
"\n"
"Permite anonimilor sa Acceseze Portalul.\n"
-"=================================\n"
+"========================================\n"
" "
#. module: base
@@ -2987,7 +2989,7 @@ msgstr "Va fi șters"
#. module: base
#: model:ir.model,name:base.model_ir_sequence
msgid "ir.sequence"
-msgstr "ir.secventa"
+msgstr "ir.sequence"
#. module: base
#: help:ir.actions.server,expression:0
@@ -2996,9 +2998,9 @@ msgid ""
"order in Object, and you can have loop on the sales order line. Expression = "
"`object.order_line`."
msgstr ""
-"Introduceti campul/expresia care va genera lista. De exemplu, selectati "
-"comanda de vanzare in Obiect, si puteti parcurge in bucla pozitiile din "
-"comanda de vanzare. Expresie = `obiect.linie_comanda`."
+"Introduceți câmpul / expresia care sa genereze lista. De exemplu, selectând "
+"comanda de vânzare în Obiecte puteți parcurge în buclă pozițiile din "
+"comandă. Expresie = `object.order_line`."
#. module: base
#: field:ir.mail_server,smtp_debug:0
@@ -3021,7 +3023,7 @@ msgid ""
msgstr ""
"\n"
"Managementul Serviciului de asistenta tehnica.\n"
-"===================================\n"
+"==============================================\n"
"\n"
"La fel ca si inregistrarea si prelucrarea reclamatiilor, Serviciul de "
"Asistenta tehnica este un instrument\n"
@@ -3095,7 +3097,8 @@ msgstr ""
"\n"
"Acesta este modulul de baza pentru gestionarea produselor si a listelor de "
"preturi in OpenERP.\n"
-"========================================================================\n"
+"============================================================================="
+"=================\n"
"\n"
"Produsele accepta variante, diferite metode de stabilire a pretului, "
"informatii referitoare la furnizori,\n"
@@ -3103,7 +3106,7 @@ msgstr ""
"proprietati.\n"
"\n"
"Listele de preturi accepta:\n"
-"--------------------\n"
+"---------------------------\n"
" * Niveluri multiple de reducere (dupa produs, categorie, cantitati)\n"
" * Calculeaza pretul pe baza unor criterii diferite:\n"
" * Alte liste de preturi\n"
@@ -3134,11 +3137,10 @@ msgid ""
msgstr ""
"\n"
"Configureaza valorile implicite pentru conturile dumneavoastra analitice.\n"
-"==============================================\n"
+"=========================================================================\n"
"\n"
"Permite selectarea automata a conturilor analitice pe baza criteriilor:\n"
-"-----------------------------------------------------------------------------"
-"------\n"
+"-----------------------------------------------------------------------\n"
" * Produs \n"
" * Partener\n"
" * Utilizator\n"
@@ -3216,7 +3218,8 @@ msgstr ""
"\n"
"Modulul de baza pentru gestionarea distribuirii analitice si a comenzilor de "
"vanzare.\n"
-"==========================================================================\n"
+"============================================================================="
+"========\n"
"\n"
"Folosind acest modul veti putea lega conturile analitice de comenzile de "
"vanzare.\n"
@@ -3292,7 +3295,7 @@ msgid ""
msgstr ""
"\n"
"Acesta este un sistem complet de gestionare a documentelor.\n"
-"==============================================\n"
+"===========================================================\n"
" * Autentificare Utilizator\n"
" * Indexare Documente:- fisierele .pptx si .docx nu sunt acceptate in "
"platforma Windows.\n"
@@ -3351,8 +3354,8 @@ msgid ""
" "
msgstr ""
"\n"
-"Gestiunea cotarilor si a comenzilor de vanzare\n"
-" ==================================\n"
+"Gestionare cotațiilor și a comenzilor de vânzare\n"
+"================================================\n"
"\n"
"Aceasta aplicatie va permite sa va gestionati obiectivele de vanzari intr-un "
"mod efectiv si eficient, tinand evidenta tuturor comenzilor de vanzare si "
@@ -3363,7 +3366,7 @@ msgstr ""
"* **Cotare** -> **Comanda de vanzare** -> **Factura**\n"
"\n"
"Preferinte (numai daca este instalat si modulul Gestionarea Depozitului)\n"
-"-----------------------------------------------------\n"
+"------------------------------------------------------------------------\n"
"\n"
"Daca ati instalat si Gestionarea Depozitului, puteti efectua urmatoarele:\n"
"\n"
@@ -3382,7 +3385,7 @@ msgstr ""
"\n"
"\n"
"Tabloul de bord pentru Managerul de Vanzari va include\n"
-"------------------------------------------------\n"
+"------------------------------------------------------\n"
"* Cotatiile mele\n"
"* Cifra de afaceri lunara (Grafic)\n"
" "
@@ -3414,7 +3417,7 @@ msgid ""
msgstr ""
"\n"
"Modul pentru atasarea unui document google oricarui model.\n"
-"================================================\n"
+"==========================================================\n"
#. module: base
#: code:addons/base/ir/ir_fields.py:333
@@ -3591,7 +3594,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_actions_act_window_close
msgid "ir.actions.act_window_close"
-msgstr "ir.actiuni.inchide_fereastra_act"
+msgstr "ir.actions.act_window_close"
#. module: base
#: field:ir.server.object.lines,col1:0
@@ -4878,7 +4881,7 @@ msgstr "Jersey"
#. module: base
#: model:ir.model,name:base.model_ir_translation
msgid "ir.translation"
-msgstr "ir.traducere"
+msgstr "ir.translation"
#. module: base
#: view:res.lang:0
@@ -4954,7 +4957,7 @@ msgstr "Reg"
#. module: base
#: model:ir.model,name:base.model_ir_property
msgid "ir.property"
-msgstr "ir.proprietate"
+msgstr "ir.property"
#. module: base
#: selection:ir.actions.act_window,view_type:0
@@ -6083,9 +6086,9 @@ msgid ""
"the same values as those available in the condition field, e.g. `Dear [[ "
"object.partner_id.name ]]`"
msgstr ""
-"Continuturile e-mail-urilor, pot sa contina expresii incluse in paranteze "
-"duble bazate pe aceleasi valori ca si cele disponibile in campul conditie, "
-"de exemplu: `Stimate [[ obiect.id_nume.partener ]]`"
+"Conținuturile e-mail-urilor, pot sa includă expresii incluse în paranteze "
+"duble bazate pe aceleași valori ca și cele disponibile în câmpul condiție, "
+"de exemplu: `Stimate [[ object.partner_id.name ]]`"
#. module: base
#: model:ir.actions.act_window,name:base.action_workflow_form
@@ -6329,7 +6332,7 @@ msgstr "Nume de utilizator optional pentru autentificarea SMTP"
#. module: base
#: model:ir.model,name:base.model_ir_actions_actions
msgid "ir.actions.actions"
-msgstr "ir.actiuni.actiuni"
+msgstr "ir.actions.actions"
#. module: base
#: selection:ir.model.fields,select_level:0
@@ -6364,19 +6367,19 @@ msgid ""
" \n"
"%(country_code)s: the code of the country"
msgstr ""
-"Aici puteti mentiona formatul obisnuit care va fi folosit pentru adresele "
-"care apartin acestei tari.\n"
+"Aici puteți menționa formatul obișnuit care va fi folosit pentru adresele "
+"acestei țări.\n"
"\n"
-"Puteti folosi tiparul in sir stil python cu toate campurile adreselor (de "
-"exemplu, folositi '%(strada)s' pentru a afisa campul 'strada') plus\n"
+"Puteți folosi tiparul in sir stil python cu toate câmpurile adreselor (de "
+"exemplu, folosiți '%(street)s' pentru a afișa câmpul 'strada') plus\n"
" \n"
-"%(nume_stat)s: numele statului\n"
+"%(state_name)s: numele statului (județului)\n"
" \n"
-"%(cod_stat)s: codul statului\n"
+"%(state_code)s: codul statului (județului)\n"
" \n"
-"%(nume_tara)s: numele tarii\n"
+"%(country_name)s: numele țării\n"
" \n"
-"%(cod_tara)s: codul tarii"
+"%(country_code)s: codul țării"
#. module: base
#: model:res.country,name:base.mu
@@ -7194,7 +7197,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_actions_act_window_view
msgid "ir.actions.act_window.view"
-msgstr "ir.actiuni.act_fereastra.vizualizare"
+msgstr "ir.actions.act_window.view"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web
@@ -7278,7 +7281,7 @@ msgstr "Insulele Svalbard si Jan Mayen"
#: model:ir.model,name:base.model_ir_actions_wizard
#: selection:ir.ui.menu,action:0
msgid "ir.actions.wizard"
-msgstr "ir.asistent.actiuni"
+msgstr "ir.actions.wizard"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_kanban
@@ -7567,7 +7570,7 @@ msgstr "Start Flux"
#. module: base
#: model:ir.model,name:base.model_res_partner_title
msgid "res.partner.title"
-msgstr "res.partener.titlu"
+msgstr "res.partner.title"
#. module: base
#: view:res.partner.bank:0
@@ -8097,7 +8100,7 @@ msgstr "Meniuri Create"
#: view:ir.module.module:0
#, python-format
msgid "Uninstall"
-msgstr "Dezinstaleaza"
+msgstr "Dezinstalați"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_budget
@@ -8208,7 +8211,7 @@ msgstr "Curaçao"
#. module: base
#: view:ir.sequence:0
msgid "Current Year without Century: %(y)s"
-msgstr "Anul curent fara Secol: %(y)s"
+msgstr "Anul curent fără secol: %(y)s"
#. module: base
#: model:ir.actions.act_window,name:base.ir_config_list_action
@@ -8490,7 +8493,7 @@ msgstr ""
#. module: base
#: view:ir.sequence:0
msgid "Week of the Year: %(woy)s"
-msgstr "Saptamana din An: %(sda)s"
+msgstr "Săptămâna din an: %(woy)s"
#. module: base
#: field:res.users,id:0
@@ -8601,7 +8604,7 @@ msgstr "Filtre vizibile doar pentru un utilizator"
#. module: base
#: model:ir.model,name:base.model_ir_attachment
msgid "ir.attachment"
-msgstr "ir.atasament"
+msgstr "ir.attachment"
#. module: base
#: code:addons/orm.py:4348
@@ -9154,7 +9157,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_config_parameter
msgid "ir.config_parameter"
-msgstr "ir.configurare_parametru"
+msgstr "ir.config_parameter"
#. module: base
#: model:ir.module.module,description:base.module_project_long_term
@@ -9243,7 +9246,7 @@ msgstr "Compania pentru care acest utilizator lucreaza in prezent."
#. module: base
#: model:ir.model,name:base.model_wizard_ir_model_menu_create
msgid "wizard.ir.model.menu.create"
-msgstr "wizard.ir.creeaza.model.meniu"
+msgstr "wizard.ir.model.menu.create"
#. module: base
#: view:workflow.transition:0
@@ -9981,9 +9984,9 @@ msgid ""
"the same values as those available in the condition field, e.g. `Hello [[ "
"object.partner_id.name ]]`"
msgstr ""
-"Subiectul e-mail-ului poate sa contina expresii intre paranteze duble, "
-"bazate pe aceleasi valori ca si cele disponibile in campul conditie, de ex. "
-"`Buna ziua [[obiect.partener_id.nume]]`"
+"Subiectul e-mail-ului poate să conțină expresii intre paranteze duble, "
+"bazate pe aceleași valori ca și cele disponibile în câmpul condiție, de ex. "
+"`Buna ziua [[ object.partner_id.name ]]`"
#. module: base
#: help:res.partner,image:0
@@ -10209,7 +10212,7 @@ msgstr "Austria - Contabilitate"
#. module: base
#: model:ir.model,name:base.model_ir_ui_menu
msgid "ir.ui.menu"
-msgstr "ir.ui.meniu"
+msgstr "ir.ui.menu"
#. module: base
#: model:ir.module.module,shortdesc:base.module_project
@@ -10219,7 +10222,7 @@ msgstr "Managementul Proiectelor"
#. module: base
#: view:ir.module.module:0
msgid "Cancel Uninstall"
-msgstr "Anulati dezinstalarea"
+msgstr "Anulați dezinstalarea"
#. module: base
#: view:res.bank:0
@@ -10234,7 +10237,7 @@ msgstr "Contabilitate Analitica"
#. module: base
#: model:ir.model,name:base.model_ir_model_constraint
msgid "ir.model.constraint"
-msgstr "ir.restrictie.model"
+msgstr "ir.model.constraint"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_graph
@@ -10260,7 +10263,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_server_object_lines
msgid "ir.server.object.lines"
-msgstr "ir.linii.obiect.server"
+msgstr "ir.server.object.lines"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_be
@@ -10889,7 +10892,7 @@ msgstr "Instalati Actualizare Modul"
#. module: base
#: model:ir.model,name:base.model_ir_actions_configuration_wizard
msgid "ir.actions.configuration.wizard"
-msgstr "ir.wizard.configurare.actiuni"
+msgstr "ir.actions.configuration.wizard"
#. module: base
#: view:res.lang:0
@@ -11835,7 +11838,7 @@ msgstr "Statele Unite - Plan de Conturi"
#: view:res.users:0
#: view:wizard.ir.model.menu.create:0
msgid "Cancel"
-msgstr "Anulati"
+msgstr "Anulați"
#. module: base
#: code:addons/orm.py:1507
@@ -12119,9 +12122,9 @@ msgid ""
"same values as for the condition field.\n"
"Example: object.invoice_address_id.email, or 'me@example.com'"
msgstr ""
-"Expresie care intoarce adresa de e-mail la trimite catre. Poate fi bazata pe "
-"aceleasi valori ca si pentru campul conditie.\n"
-"Exemplu: obiect.id_adresa_factura.e-mail, sau 'me@exemplu.com'"
+"Expresie care întoarce adresa de e-mail în câmpul trimite către. Poate fi "
+"bazată pe aceleași valori ca și pentru câmpul condiție.\n"
+"Exemplu: object.invoice_address_id.email, sau 'me@exemplu.com'"
#. module: base
#: model:ir.module.module,description:base.module_project_issue_sheet
@@ -12326,7 +12329,7 @@ msgid ""
" </p>\n"
" "
msgstr ""
-"<clasa p=\"creeaza_niciuncontinut_vizualizare_oe\">\n"
+"<p class=\"oe_view_nocontent_create\">\n"
" Faceti click pentru a adauga un contact in agenda "
"dumneavoastra.\n"
" </p><p>\n"
@@ -12389,7 +12392,7 @@ msgstr "Cod"
#. module: base
#: model:ir.model,name:base.model_res_config_installer
msgid "res.config.installer"
-msgstr "res.config.program_de_instalare"
+msgstr "res.config.installer"
#. module: base
#: model:res.country,name:base.mc
@@ -12452,7 +12455,7 @@ msgstr ""
#. module: base
#: view:ir.sequence:0
msgid "Current Year with Century: %(year)s"
-msgstr "Anul curent cu Secol: %(an)s"
+msgstr "Anul curent cu secol: %(year)s"
#. module: base
#: field:ir.exports,export_fields:0
@@ -12593,7 +12596,7 @@ msgstr "Chineza (TW) / 正體字"
#. module: base
#: model:ir.model,name:base.model_res_request
msgid "res.request"
-msgstr "res.cerere"
+msgstr "res.request"
#. module: base
#: field:res.partner,image_medium:0
@@ -13120,7 +13123,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_mail_server
msgid "ir.mail_server"
-msgstr "ir.server_e-mail"
+msgstr "ir.mail_server"
#. module: base
#: selection:base.language.install,lang:0
@@ -13689,7 +13692,7 @@ msgstr "Fus orar"
#: model:ir.model,name:base.model_ir_actions_report_xml
#: selection:ir.ui.menu,action:0
msgid "ir.actions.report.xml"
-msgstr "ir.actiuni.raport.xml"
+msgstr "ir.actions.report.xml"
#. module: base
#: model:ir.actions.act_window,name:base.ir_sequence_form
@@ -14248,7 +14251,7 @@ msgstr "Data trimiterii"
#. module: base
#: view:ir.sequence:0
msgid "Month: %(month)s"
-msgstr "Luna: %(luna)s"
+msgstr "Luna: %(month)s"
#. module: base
#: field:ir.actions.act_window.view,sequence:0
@@ -14285,7 +14288,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_fields_converter
msgid "ir.fields.converter"
-msgstr "ir.convertor.campuri"
+msgstr "ir.fields.converter"
#. module: base
#: code:addons/base/res/res_partner.py:439
@@ -14308,12 +14311,12 @@ msgstr "Comore"
#. module: base
#: view:ir.module.module:0
msgid "Cancel Install"
-msgstr "Anulati Instalarea"
+msgstr "Anulați Instalarea"
#. module: base
#: model:ir.model,name:base.model_ir_model_relation
msgid "ir.model.relation"
-msgstr "ir.model.relatie"
+msgstr "ir.model.relation"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_check_writing
@@ -14534,7 +14537,7 @@ msgstr "Planuri Analitice Multiple"
#. module: base
#: model:ir.model,name:base.model_ir_default
msgid "ir.default"
-msgstr "ir.implicit"
+msgstr "ir.default"
#. module: base
#: view:ir.sequence:0
@@ -14633,9 +14636,9 @@ msgstr ""
"*URL:** legatura dumneavoastra moodle, de exemplu: "
"http://openerp.moodle.com\n"
"\n"
-"**AUTENTIFICARE:** ${obiect.nume_de_utilizator_moodle}\n"
+"**AUTENTIFICARE:**${object.moodle_username}\n"
" \n"
-"**PAROLA:** ${obiect.parola_utilizator_moodle}\n"
+"**PAROLA:** ${object.moodle_user_password}\n"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_uk
@@ -15423,7 +15426,7 @@ msgid ""
msgstr ""
"\n"
"Retele Sociale orientate spre afaceri\n"
-"===================================\n"
+"=====================================\n"
"Modulul Retele Sociale furnizeaza un strat de abstractizare unificat de "
"retele sociale, permitand aplicatiilor sa afiseze un istoric\n"
"complet al conversatiilor in documente cu un sistem complet integrat de "
@@ -15537,7 +15540,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_values
msgid "ir.values"
-msgstr "ir.valori"
+msgstr "ir.values"
#. module: base
#: model:ir.model,name:base.model_base_module_update
@@ -16201,7 +16204,7 @@ msgstr "Agenda"
#. module: base
#: model:ir.model,name:base.model_ir_sequence_type
msgid "ir.sequence.type"
-msgstr "ir.tip.secventa"
+msgstr "ir.sequence.type"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_be_hr_payroll_account
@@ -16825,7 +16828,7 @@ msgstr "Nu pot exista doi utilizatori cu acelasi nume de autentificare !"
#. module: base
#: model:ir.model,name:base.model_res_request_history
msgid "res.request.history"
-msgstr "res.istoric.solicitari"
+msgstr "res.request.history"
#. module: base
#: model:ir.model,name:base.model_multi_company_default
@@ -17409,7 +17412,7 @@ msgstr "Uzbekistan"
#: model:ir.model,name:base.model_ir_actions_act_window
#: selection:ir.ui.menu,action:0
msgid "ir.actions.act_window"
-msgstr "ir.actiuni.act_fereastra"
+msgstr "ir.actions.act_window"
#. module: base
#: model:res.country,name:base.vi
@@ -17597,7 +17600,7 @@ msgstr "Germania - Contabilitate"
#. module: base
#: view:ir.sequence:0
msgid "Day of the Year: %(doy)s"
-msgstr "Ziua din An: %(doy)s"
+msgstr "Ziua din an: %(doy)s"
#. module: base
#: field:ir.ui.menu,web_icon:0
@@ -17642,7 +17645,7 @@ msgstr "Model sursa"
#. module: base
#: view:ir.sequence:0
msgid "Day of the Week (0:Monday): %(weekday)s"
-msgstr "Ziua din Saptamana (0:Luni): %(weekday)s"
+msgstr "Ziua din saptămâna (0:Luni): %(weekday)s"
#. module: base
#: code:addons/base/module/wizard/base_module_upgrade.py:84
@@ -17936,7 +17939,7 @@ msgstr ""
#. module: base
#: model:ir.model,name:base.model_ir_model_data
msgid "ir.model.data"
-msgstr "ir.date.model"
+msgstr "ir.model.data"
#. module: base
#: selection:base.language.install,lang:0
@@ -18442,7 +18445,7 @@ msgstr "Grafic"
#: model:ir.model,name:base.model_ir_actions_server
#: selection:ir.ui.menu,action:0
msgid "ir.actions.server"
-msgstr "ir.actiuni.server"
+msgstr "ir.actions.server"
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_ca
@@ -18953,7 +18956,7 @@ msgstr "Note Interne"
#: model:res.partner.title,name:base.res_partner_title_pvt_ltd
#: model:res.partner.title,shortcut:base.res_partner_title_pvt_ltd
msgid "Corp."
-msgstr "Corp."
+msgstr "SA"
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase_requisition
diff --git a/openerp/addons/base/i18n/ru.po b/openerp/addons/base/i18n/ru.po
index 218ef2052c2..59cab185b27 100644
--- a/openerp/addons/base/i18n/ru.po
+++ b/openerp/addons/base/i18n/ru.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:21+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:31+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/sk.po b/openerp/addons/base/i18n/sk.po
index 65765175dc4..a4cb967cdbb 100644
--- a/openerp/addons/base/i18n/sk.po
+++ b/openerp/addons/base/i18n/sk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:22+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:32+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -25,6 +25,10 @@ msgid ""
"================================================\n"
" "
msgstr ""
+"\n"
+"Modul pre vypisovanie a tlač šekov.\n"
+"================================================\n"
+" "
#. module: base
#: model:res.country,name:base.sh
diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po
index b238208dc5c..f86dbc72f64 100644
--- a/openerp/addons/base/i18n/sl.po
+++ b/openerp/addons/base/i18n/sl.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:22+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:32+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/sq.po b/openerp/addons/base/i18n/sq.po
index fe8043c95b3..9fb318a5422 100644
--- a/openerp/addons/base/i18n/sq.po
+++ b/openerp/addons/base/i18n/sq.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:15+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:22+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/sr.po b/openerp/addons/base/i18n/sr.po
index b8d9d13c363..7bae2e9c48a 100644
--- a/openerp/addons/base/i18n/sr.po
+++ b/openerp/addons/base/i18n/sr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:21+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:31+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/sr@latin.po b/openerp/addons/base/i18n/sr@latin.po
index 550424a19f6..f307be9e8b0 100644
--- a/openerp/addons/base/i18n/sr@latin.po
+++ b/openerp/addons/base/i18n/sr@latin.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:26+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:38+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/sv.po b/openerp/addons/base/i18n/sv.po
index a201d6646b8..765f5a23578 100644
--- a/openerp/addons/base/i18n/sv.po
+++ b/openerp/addons/base/i18n/sv.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:22+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:33+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/th.po b/openerp/addons/base/i18n/th.po
index 6f6c5af6d07..afd43cf2210 100644
--- a/openerp/addons/base/i18n/th.po
+++ b/openerp/addons/base/i18n/th.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:33+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -25,6 +25,9 @@ msgid ""
"================================================\n"
" "
msgstr ""
+"\n"
+"โมดูลสำหรับการเขียน และพิมพ์เช็ค\n"
+" "
#. module: base
#: model:res.country,name:base.sh
diff --git a/openerp/addons/base/i18n/tlh.po b/openerp/addons/base/i18n/tlh.po
index be2f66f6e76..877e3c9c0ce 100644
--- a/openerp/addons/base/i18n/tlh.po
+++ b/openerp/addons/base/i18n/tlh.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:33+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/tr.po b/openerp/addons/base/i18n/tr.po
index c9ba314d44c..e18e16a8b2e 100644
--- a/openerp/addons/base/i18n/tr.po
+++ b/openerp/addons/base/i18n/tr.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:34+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/uk.po b/openerp/addons/base/i18n/uk.po
index 3520be8b730..a4c380e217e 100644
--- a/openerp/addons/base/i18n/uk.po
+++ b/openerp/addons/base/i18n/uk.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:34+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/ur.po b/openerp/addons/base/i18n/ur.po
index 83bdf196d78..0907705cd6c 100644
--- a/openerp/addons/base/i18n/ur.po
+++ b/openerp/addons/base/i18n/ur.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:34+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/vi.po b/openerp/addons/base/i18n/vi.po
index 93a7ef61319..a88ebdc9981 100644
--- a/openerp/addons/base/i18n/vi.po
+++ b/openerp/addons/base/i18n/vi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:34+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/zh_CN.po b/openerp/addons/base/i18n/zh_CN.po
index 6913b04af49..e6dc69d2355 100644
--- a/openerp/addons/base/i18n/zh_CN.po
+++ b/openerp/addons/base/i18n/zh_CN.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:37+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/zh_HK.po b/openerp/addons/base/i18n/zh_HK.po
index 1bc226bf240..0d10f810bb9 100644
--- a/openerp/addons/base/i18n/zh_HK.po
+++ b/openerp/addons/base/i18n/zh_HK.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:23+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:35+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/i18n/zh_TW.po b/openerp/addons/base/i18n/zh_TW.po
index 0951a3a2ffa..0b50ad3e1d8 100644
--- a/openerp/addons/base/i18n/zh_TW.po
+++ b/openerp/addons/base/i18n/zh_TW.po
@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2014-01-01 05:25+0000\n"
-"X-Generator: Launchpad (build 16877)\n"
+"X-Launchpad-Export-Date: 2014-02-22 06:37+0000\n"
+"X-Generator: Launchpad (build 16926)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py
index f5e8fcf41a7..b3df5bcbccb 100644
--- a/openerp/addons/base/ir/__init__.py
+++ b/openerp/addons/base/ir/__init__.py
@@ -37,6 +37,7 @@ import ir_config_parameter
import osv_memory_autovacuum
import ir_mail_server
import ir_fields
+import ir_qweb
import ir_http
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py
index fe3e715aba2..9adbf2c608f 100644
--- a/openerp/addons/base/ir/ir_actions.py
+++ b/openerp/addons/base/ir/ir_actions.py
@@ -24,6 +24,8 @@ import logging
import operator
import os
import time
+import datetime
+import dateutil
import openerp
from openerp import SUPERUSER_ID
@@ -268,7 +270,7 @@ class ir_actions_act_window(osv.osv):
'filter': fields.boolean('Filter'),
'auto_search':fields.boolean('Auto Search'),
'search_view' : fields.function(_search_view, type='text', string='Search View'),
- 'multi': fields.boolean('Action on Multiple Doc.', help="If set to true, the action will not be displayed on the right toolbar of a form view"),
+ 'multi': fields.boolean('Restrict to lists', help="If checked and the action is bound to a model, it will only appear in the More menu on list views"),
}
_defaults = {
@@ -550,6 +552,7 @@ class ir_actions_server(osv.osv):
# - uid: current user id
# - context: current context
# - time: Python time module
+# - workflow: Workflow engine
# If you plan to return an action, assign: action = {...}""",
'use_relational_model': 'base',
'use_create': 'new',
@@ -910,11 +913,38 @@ class ir_actions_server(osv.osv):
if action.link_new_record and action.link_field_id:
self.pool[action.model_id.model].write(cr, uid, [context.get('active_id')], {action.link_field_id.name: res_id})
+ def _get_eval_context(self, cr, uid, action, context=None):
+ """ Prepare the context used when evaluating python code, like the
+ condition or code server actions.
+
+ :param action: the current server action
+ :type action: browse record
+ :returns: dict -- evaluation context given to (safe_)eval """
+ user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
+ obj_pool = self.pool[action.model_id.model]
+ obj = None
+ if context.get('active_model') == action.model_id.model and context.get('active_id'):
+ obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
+ return {
+ 'self': obj_pool,
+ 'object': obj,
+ 'obj': obj,
+ 'pool': self.pool,
+ 'time': time,
+ 'datetime': datetime,
+ 'dateutil': dateutil,
+ 'cr': cr,
+ 'uid': uid,
+ 'user': user,
+ 'context': context,
+ 'workflow': workflow
+ }
+
def run(self, cr, uid, ids, context=None):
- """ Run the server action. For each server action, the condition is
- checked. Note that A void (aka False) condition is considered as always
+ """ Runs the server action. For each server action, the condition is
+ checked. Note that a void (``False``) condition is considered as always
valid. If it is verified, the run_action_<STATE> method is called. This
- allows easy inheritance of the server actions.
+ allows easy overriding of the server actions.
:param dict context: context should contain following keys
@@ -932,33 +962,14 @@ class ir_actions_server(osv.osv):
if context is None:
context = {}
res = False
- user = self.pool.get('res.users').browse(cr, uid, uid)
- active_ids = context.get('active_ids', [context.get('active_id')])
for action in self.browse(cr, uid, ids, context):
- obj_pool = self.pool[action.model_id.model]
- obj = None
- if context.get('active_model') == action.model_id.model and context.get('active_id'):
- obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
-
- # evaluation context for python strings to evaluate
- eval_context = {
- 'self': obj_pool,
- 'object': obj,
- 'obj': obj,
- 'pool': self.pool,
- 'time': time,
- 'cr': cr,
- 'uid': uid,
- 'user': user,
- }
+ eval_context = self._get_eval_context(cr, uid, action, context=context)
condition = action.condition
if condition is False:
# Void (aka False) conditions are considered as True
condition = True
if hasattr(self, 'run_action_%s_multi' % action.state):
- # set active_ids in context only needed if one active_id
- run_context = dict(context, active_ids=active_ids)
- eval_context["context"] = run_context
+ run_context = eval_context['context']
expr = eval(str(condition), eval_context)
if not expr:
continue
@@ -968,6 +979,8 @@ class ir_actions_server(osv.osv):
elif hasattr(self, 'run_action_%s' % action.state):
func = getattr(self, 'run_action_%s' % action.state)
+ active_id = context.get('active_id')
+ active_ids = context.get('active_ids', [active_id] if active_id else [])
for active_id in active_ids:
# run context dedicated to a particular active_id
run_context = dict(context, active_ids=[active_id], active_id=active_id)
diff --git a/openerp/addons/base/ir/ir_actions.xml b/openerp/addons/base/ir/ir_actions.xml
index 7e6c1f9be4b..26c08d4f1b0 100644
--- a/openerp/addons/base/ir/ir_actions.xml
+++ b/openerp/addons/base/ir/ir_actions.xml
@@ -180,6 +180,7 @@
<field name="auto_refresh"/>
<field name="auto_search"/>
<field name="filter"/>
+ <field name="multi"/>
</group>
</group>
<group string="Help">
@@ -411,6 +412,7 @@
<li>cr: database cursor</li>
<li>uid: current user id</li>
<li>context: current context</li>
+ <li>workflow: Workflow engine</li>
</ul>
<div>
<p>Example of condition expression using Python</p>
diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py
index d9089a25f96..992ac1b5ff0 100644
--- a/openerp/addons/base/ir/ir_attachment.py
+++ b/openerp/addons/base/ir/ir_attachment.py
@@ -45,6 +45,7 @@ class ir_attachment(osv.osv):
The default implementation is the file:dirname location that stores files
on the local filesystem using name based on their sha1 hash
"""
+ _order = 'id desc'
def _name_get_resname(self, cr, uid, ids, object, method, context):
data = {}
for attachment in self.browse(cr, uid, ids, context=context):
diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py
index e1522123dcf..217ea319d8e 100644
--- a/openerp/addons/base/ir/ir_fields.py
+++ b/openerp/addons/base/ir/ir_fields.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import cStringIO
import datetime
import functools
import operator
@@ -12,6 +13,7 @@ from openerp.osv import orm
from openerp.tools.translate import _
from openerp.tools.misc import DEFAULT_SERVER_DATE_FORMAT,\
DEFAULT_SERVER_DATETIME_FORMAT
+from openerp.tools import html_sanitize
REFERENCING_FIELDS = set([None, 'id', '.id'])
def only_ref_fields(record):
@@ -128,14 +130,17 @@ class ir_fields_converter(orm.Model):
:param column: column object to generate a value for
:type column: :class:`fields._column`
- :param type fromtype: type to convert to something fitting for ``column``
+ :param fromtype: type to convert to something fitting for ``column``
+ :type fromtype: type | str
:param context: openerp request context
:return: a function (fromtype -> column.write_type), if a converter is found
:rtype: Callable | None
"""
+ assert isinstance(fromtype, (type, str))
# FIXME: return None
+ typename = fromtype.__name__ if isinstance(fromtype, type) else fromtype
converter = getattr(
- self, '_%s_to_%s' % (fromtype.__name__, column._type), None)
+ self, '_%s_to_%s' % (typename, column._type), None)
if not converter: return None
return functools.partial(
@@ -184,7 +189,7 @@ class ir_fields_converter(orm.Model):
def _str_id(self, cr, uid, model, column, value, context=None):
return value, []
- _str_to_reference = _str_to_char = _str_to_text = _str_to_binary = _str_id
+ _str_to_reference = _str_to_char = _str_to_text = _str_to_binary = _str_to_html = _str_id
def _str_to_date(self, cr, uid, model, column, value, context=None):
try:
diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py
index 646c34e5bbd..8cc24c88cce 100644
--- a/openerp/addons/base/ir/ir_http.py
+++ b/openerp/addons/base/ir/ir_http.py
@@ -15,9 +15,7 @@ from openerp.osv import osv, orm
_logger = logging.getLogger(__name__)
-
-# FIXME: replace by proxy on request.uid?
-_uid = object()
+UID_PLACEHOLDER = object()
class ModelConverter(werkzeug.routing.BaseConverter):
@@ -29,7 +27,7 @@ class ModelConverter(werkzeug.routing.BaseConverter):
def to_python(self, value):
m = re.match(self.regex, value)
return request.registry[self.model].browse(
- request.cr, _uid, int(m.group(1)), context=request.context)
+ request.cr, UID_PLACEHOLDER, int(m.group(1)), context=request.context)
def to_url(self, value):
return value.id
@@ -43,10 +41,7 @@ class ModelsConverter(werkzeug.routing.BaseConverter):
self.regex = '([0-9,]+)'
def to_python(self, value):
- # TODO:
- # - raise routing.ValidationError() if no browse record can be createdm
- # - support slug
- return request.registry[self.model].browse(request.cr, _uid, [int(i) for i in value.split(',')], context=request.context)
+ return request.registry[self.model].browse(request.cr, UID_PLACEHOLDER, [int(i) for i in value.split(',')], context=request.context)
def to_url(self, value):
return ",".join(i.id for i in value)
@@ -66,15 +61,15 @@ class ir_http(osv.AbstractModel):
if not request.uid:
raise http.SessionExpiredException("Session expired")
- def _auth_method_admin(self):
- if not request.db:
- raise http.SessionExpiredException("No valid database for request %s" % request.httprequest)
- request.uid = openerp.SUPERUSER_ID
-
def _auth_method_none(self):
- request.disable_db = True
request.uid = None
+ def _auth_method_public(self):
+ if not request.session.uid:
+ dummy, request.uid = self.pool['ir.model.data'].get_object_reference(request.cr, openerp.SUPERUSER_ID, 'base', 'public_user')
+ else:
+ request.uid = request.session.uid
+
def _authenticate(self, auth_method='user'):
if request.session.uid:
try:
@@ -88,16 +83,8 @@ class ir_http(osv.AbstractModel):
return auth_method
def _handle_exception(self, exception):
- if isinstance(exception, openerp.exceptions.AccessError):
- code = 403
- else:
- code = getattr(exception, 'code', 500)
-
- fn = getattr(self, '_handle_%d' % code, self._handle_unknown_exception)
- return fn(exception)
-
- def _handle_unknown_exception(self, exception):
- raise exception
+ # If handle exception return something different than None, it will be used as a response
+ raise
def _dispatch(self):
# locate the controller method
@@ -108,17 +95,17 @@ class ir_http(osv.AbstractModel):
# check authentication level
try:
- auth_method = self._authenticate(getattr(func, "auth", None))
+ auth_method = self._authenticate(func.routing["auth"])
except Exception:
# force a Forbidden exception with the original traceback
return self._handle_exception(
convert_exception_to(
werkzeug.exceptions.Forbidden))
- # post process arg to set uid on browse records
- for arg in arguments.itervalues():
- if isinstance(arg, orm.browse_record) and arg._uid is _uid:
- arg._uid = request.uid
+ processing = self._postprocess_args(arguments)
+ if processing:
+ return processing
+
# set and execute handler
try:
@@ -131,6 +118,16 @@ class ir_http(osv.AbstractModel):
return result
+ def _postprocess_args(self, arguments):
+ """ post process arg to set uid on browse records """
+ for arg in arguments.itervalues():
+ if isinstance(arg, orm.browse_record) and arg._uid is UID_PLACEHOLDER:
+ arg._uid = request.uid
+ try:
+ arg[arg._rec_name]
+ except KeyError:
+ return self._handle_exception(werkzeug.exceptions.NotFound())
+
def routing_map(self):
if not hasattr(self, '_routing_map'):
_logger.info("Generating routing map")
@@ -138,7 +135,9 @@ class ir_http(osv.AbstractModel):
m = request.registry.get('ir.module.module')
ids = m.search(cr, openerp.SUPERUSER_ID, [('state', '=', 'installed'), ('name', '!=', 'web')], context=request.context)
installed = set(x['name'] for x in m.read(cr, 1, ids, ['name'], context=request.context))
- mods = ['', "web"] + sorted(installed)
+ if openerp.tools.config['test_enable']:
+ installed.add(openerp.modules.module.current_test)
+ mods = [''] + openerp.conf.server_wide_modules + sorted(installed)
self._routing_map = http.routing_map(mods, False, converters=self._get_converters())
return self._routing_map
diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py
index 61fdb8ab005..d119c0344b4 100644
--- a/openerp/addons/base/ir/ir_model.py
+++ b/openerp/addons/base/ir/ir_model.py
@@ -3,7 +3,7 @@
##############################################################################
#
# OpenERP, Open Source Business Applications
-# Copyright (C) 2004-2012 OpenERP S.A. (<http://openerp.com>).
+# Copyright (C) 2004-2014 OpenERP S.A. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -29,7 +29,7 @@ import openerp.modules.registry
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import fields,osv
-from openerp.osv.orm import Model
+from openerp.osv.orm import Model, browse_null
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools import config
from openerp.tools.translate import _
@@ -737,7 +737,7 @@ class ir_model_access(osv.osv):
msg_params = (model_name,)
_logger.warning('Access Denied by ACLs for operation: %s, uid: %s, model: %s', mode, uid, model_name)
msg = '%s %s' % (msg_heads[mode], msg_tail)
- raise except_orm(_('Access Denied'), msg % msg_params)
+ raise openerp.exceptions.AccessError(msg % msg_params)
return r or False
__cache_clearing_methods = []
@@ -853,24 +853,58 @@ class ir_model_data(osv.osv):
if not cr.fetchone():
cr.execute('CREATE INDEX ir_model_data_module_name_index ON ir_model_data (module, name)')
- @tools.ormcache()
- def _get_id(self, cr, uid, module, xml_id):
- """Returns the id of the ir.model.data record corresponding to a given module and xml_id (cached) or raise a ValueError if not found"""
- ids = self.search(cr, uid, [('module','=',module), ('name','=', xml_id)])
+ # NEW V8 API
+ @tools.ormcache(skiparg=3)
+ def xmlid_lookup(self, cr, uid, xmlid):
+ """Low level xmlid lookup
+ Return (id, res_model, res_id) or raise ValueError if not found
+ """
+ module, name = xmlid.split('.', 1)
+ ids = self.search(cr, uid, [('module','=',module), ('name','=', name)])
if not ids:
- raise ValueError('No such external ID currently defined in the system: %s.%s' % (module, xml_id))
+ raise ValueError('External ID not found in the system: %s' % (xmlid))
# the sql constraints ensure us we have only one result
- return ids[0]
+ res = self.read(cr, uid, ids[0], ['model', 'res_id'])
+ if not res['res_id']:
+ raise ValueError('External ID not found in the system: %s' % (xmlid))
+ return ids[0], res['model'], res['res_id']
+
+ def xmlid_to_res_model_res_id(self, cr, uid, xmlid, raise_if_not_found=False):
+ """ Return (res_model, res_id)"""
+ try:
+ return self.xmlid_lookup(cr, uid, xmlid)[1:3]
+ except ValueError:
+ if raise_if_not_found:
+ raise
+ return (False, False)
+
+ def xmlid_to_res_id(self, cr, uid, xmlid, raise_if_not_found=False):
+ """ Returns res_id """
+ return self.xmlid_to_res_model_res_id(cr, uid, xmlid, raise_if_not_found)[1]
+
+ def xmlid_to_object(self, cr, uid, xmlid, raise_if_not_found=False, context=None):
+ """ Return a browse_record
+ if not found and raise_if_not_found is True return the browse_null
+ """
+ t = self.xmlid_to_res_model_res_id(cr, uid, xmlid, raise_if_not_found)
+ res_model, res_id = t
+
+ if res_model and res_id:
+ record = self.pool[res_model].browse(cr, uid, res_id, context=context)
+ if record.exists():
+ return record
+ if raise_if_not_found:
+ raise ValueError('No record found for unique ID %s. It may have been deleted.' % (xml_id))
+ return browse_null()
+
+ # OLD API
+ def _get_id(self, cr, uid, module, xml_id):
+ """Returns the id of the ir.model.data record corresponding to a given module and xml_id (cached) or raise a ValueError if not found"""
+ return self.xmlid_lookup(cr, uid, "%s.%s" % (module, xml_id))[0]
- @tools.ormcache()
def get_object_reference(self, cr, uid, module, xml_id):
"""Returns (model, res_id) corresponding to a given module and xml_id (cached) or raise ValueError if not found"""
- data_id = self._get_id(cr, uid, module, xml_id)
- #assuming data_id is not False, as it was checked upstream
- res = self.read(cr, uid, data_id, ['model', 'res_id'])
- if not res['res_id']:
- raise ValueError('No such external ID currently defined in the system: %s.%s' % (module, xml_id))
- return res['model'], res['res_id']
+ return self.xmlid_lookup(cr, uid, "%s.%s" % (module, xml_id))[1:3]
def check_object_reference(self, cr, uid, module, xml_id, raise_on_access_error=False):
"""Returns (model, res_id) corresponding to a given module and xml_id (cached), if and only if the user has the necessary access rights
@@ -885,12 +919,11 @@ class ir_model_data(osv.osv):
return model, False
def get_object(self, cr, uid, module, xml_id, context=None):
- """Returns a browsable record for the given module name and xml_id or raise ValueError if not found"""
- res_model, res_id = self.get_object_reference(cr, uid, module, xml_id)
- result = self.pool[res_model].browse(cr, uid, res_id, context=context)
- if not result.exists():
- raise ValueError('No record found for unique ID %s.%s. It may have been deleted.' % (module, xml_id))
- return result
+ """ Returns a browsable record for the given module name and xml_id.
+ If not found, raise a ValueError or return a browse_null, depending
+ on the value of `raise_exception`.
+ """
+ return self.xmlid_to_object(cr, uid, "%s.%s" % (module, xml_id), raise_if_not_found=True, context=context)
def _update_dummy(self,cr, uid, model, module, xml_id=False, store=True):
if not xml_id:
@@ -907,8 +940,7 @@ class ir_model_data(osv.osv):
:returns: itself
"""
- self._get_id.clear_cache(self)
- self.get_object_reference.clear_cache(self)
+ self.xmlid_lookup.clear_cache(self)
return self
def unlink(self, cr, uid, ids, context=None):
@@ -929,15 +961,17 @@ class ir_model_data(osv.osv):
return False
action_id = False
if xml_id:
- cr.execute('''SELECT imd.id, imd.res_id, md.id, imd.model
+ cr.execute('''SELECT imd.id, imd.res_id, md.id, imd.model, imd.noupdate
FROM ir_model_data imd LEFT JOIN %s md ON (imd.res_id = md.id)
WHERE imd.module=%%s AND imd.name=%%s''' % model_obj._table,
(module, xml_id))
results = cr.fetchall()
- for imd_id2,res_id2,real_id2,real_model in results:
+ for imd_id2,res_id2,real_id2,real_model,noupdate_imd in results:
+ # In update mode, do not update a record if it's ir.model.data is flagged as noupdate
+ if mode == 'update' and noupdate_imd:
+ return res_id2
if not real_id2:
- self._get_id.clear_cache(self, uid, module, xml_id)
- self.get_object_reference.clear_cache(self, uid, module, xml_id)
+ self.clear_caches()
cr.execute('delete from ir_model_data where id=%s', (imd_id2,))
res_id = False
else:
diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py
new file mode 100644
index 00000000000..590ce90188f
--- /dev/null
+++ b/openerp/addons/base/ir/ir_qweb.py
@@ -0,0 +1,850 @@
+# -*- coding: utf-8 -*-
+import collections
+import cStringIO
+import datetime
+import json
+import logging
+import math
+import re
+import sys
+import xml # FIXME use lxml and etree
+
+import babel
+import babel.dates
+import werkzeug.utils
+from PIL import Image
+
+import openerp.tools
+from openerp.tools.safe_eval import safe_eval as eval
+from openerp.osv import osv, orm, fields
+from openerp.tools.translate import _
+
+_logger = logging.getLogger(__name__)
+
+#--------------------------------------------------------------------
+# QWeb template engine
+#--------------------------------------------------------------------
+class QWebException(Exception):
+ def __init__(self, message, **kw):
+ Exception.__init__(self, message)
+ self.qweb = dict(kw)
+
+class QWebTemplateNotFound(QWebException):
+ pass
+
+def convert_to_qweb_exception(etype=None, **kw):
+ if etype is None:
+ etype = QWebException
+ orig_type, original, tb = sys.exc_info()
+ try:
+ raise etype, original, tb
+ except etype, e:
+ for k, v in kw.items():
+ e.qweb[k] = v
+ # Will use `raise foo from bar` in python 3 and rename cause to __cause__
+ e.qweb['cause'] = original
+ return e
+
+class QWebContext(dict):
+ def __init__(self, cr, uid, data, loader=None, templates=None, context=None):
+ self.cr = cr
+ self.uid = uid
+ self.loader = loader
+ self.templates = templates or {}
+ self.context = context
+ dic = dict(data)
+ super(QWebContext, self).__init__(dic)
+ self['defined'] = lambda key: key in self
+
+ def safe_eval(self, expr):
+ locals_dict = collections.defaultdict(lambda: None)
+ locals_dict.update(self)
+ locals_dict.pop('cr', None)
+ locals_dict.pop('loader', None)
+ return eval(expr, None, locals_dict, nocopy=True, locals_builtins=True)
+
+ def copy(self):
+ return QWebContext(self.cr, self.uid, dict.copy(self),
+ loader=self.loader,
+ templates=self.templates,
+ context=self.context)
+
+ def __copy__(self):
+ return self.copy()
+
+class QWeb(orm.AbstractModel):
+ """QWeb Xml templating engine
+
+ The templating engine use a very simple syntax based "magic" xml
+ attributes, to produce textual output (even non-xml).
+
+ The core magic attributes are:
+
+ flow attributes:
+ t-if t-foreach t-call
+
+ output attributes:
+ t-att t-raw t-esc t-trim
+
+ assignation attribute:
+ t-set
+
+ QWeb can be extended like any OpenERP model and new attributes can be
+ added.
+
+ If you need to customize t-fields rendering, subclass the ir.qweb.field
+ model (and its sub-models) then override :meth:`~.get_converter_for` to
+ fetch the right field converters for your qweb model.
+
+ Beware that if you need extensions or alterations which could be
+ incompatible with other subsystems, you should create a local object
+ inheriting from ``ir.qweb`` and customize that.
+ """
+
+ _name = 'ir.qweb'
+
+ node = xml.dom.Node
+ _void_elements = frozenset([
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
+ 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'])
+ _format_regex = re.compile(
+ '(?:'
+ # ruby-style pattern
+ '#\{(.+?)\}'
+ ')|(?:'
+ # jinja-style pattern
+ '\{\{(.+?)\}\}'
+ ')')
+
+ def __init__(self, pool, cr):
+ super(QWeb, self).__init__(pool, cr)
+
+ self._render_tag = self.prefixed_methods('render_tag_')
+ self._render_att = self.prefixed_methods('render_att_')
+
+ def prefixed_methods(self, prefix):
+ """ Extracts all methods prefixed by ``prefix``, and returns a mapping
+ of (t-name, method) where the t-name is the method name with prefix
+ removed and underscore converted to dashes
+
+ :param str prefix:
+ :return: dict
+ """
+ n_prefix = len(prefix)
+ return dict(
+ (name[n_prefix:].replace('_', '-'), getattr(type(self), name))
+ for name in dir(self)
+ if name.startswith(prefix)
+ )
+
+ def register_tag(self, tag, func):
+ self._render_tag[tag] = func
+
+ def add_template(self, qwebcontext, name, node):
+ """Add a parsed template in the context. Used to preprocess templates."""
+ qwebcontext.templates[name] = node
+
+ def load_document(self, document, qwebcontext):
+ """
+ Loads an XML document and installs any contained template in the engine
+ """
+ if hasattr(document, 'documentElement'):
+ dom = document
+ elif document.startswith("<?xml"):
+ dom = xml.dom.minidom.parseString(document)
+ else:
+ dom = xml.dom.minidom.parse(document)
+
+ for node in dom.documentElement.childNodes:
+ if node.nodeType == self.node.ELEMENT_NODE and node.getAttribute('t-name'):
+ name = str(node.getAttribute("t-name"))
+ self.add_template(qwebcontext, name, node)
+
+ def get_template(self, name, qwebcontext):
+ origin_template = qwebcontext.get('__caller__') or qwebcontext['__stack__'][0]
+ if qwebcontext.loader and name not in qwebcontext.templates:
+ try:
+ xml_doc = qwebcontext.loader(name)
+ except ValueError:
+ raise convert_to_qweb_exception(QWebTemplateNotFound, message="Loader could not find template %r" % name, template=origin_template)
+ self.load_document(xml_doc, qwebcontext=qwebcontext)
+
+ if name in qwebcontext.templates:
+ return qwebcontext.templates[name]
+
+ raise QWebTemplateNotFound("Template %r not found" % name, template=origin_template)
+
+ def eval(self, expr, qwebcontext):
+ try:
+ return qwebcontext.safe_eval(expr)
+ except Exception:
+ template = qwebcontext.get('__template__')
+ raise convert_to_qweb_exception(message="Could not evaluate expression %r" % expr, expression=expr, template=template)
+
+ def eval_object(self, expr, qwebcontext):
+ return self.eval(expr, qwebcontext)
+
+ def eval_str(self, expr, qwebcontext):
+ if expr == "0":
+ return qwebcontext.get(0, '')
+ val = self.eval(expr, qwebcontext)
+ if isinstance(val, unicode):
+ return val.encode("utf8")
+ if val is False or val is None:
+ return ''
+ return str(val)
+
+ def eval_format(self, expr, qwebcontext):
+ expr, replacements = self._format_regex.subn(
+ lambda m: self.eval_str(m.group(1) or m.group(2), qwebcontext),
+ expr
+ )
+
+ if replacements:
+ return expr
+
+ try:
+ return str(expr % qwebcontext)
+ except Exception:
+ template = qwebcontext.get('__template__')
+ raise convert_to_qweb_exception(message="Format error for expression %r" % expr, expression=expr, template=template)
+
+ def eval_bool(self, expr, qwebcontext):
+ return int(bool(self.eval(expr, qwebcontext)))
+
+ def render(self, cr, uid, id_or_xml_id, qwebcontext=None, loader=None, context=None):
+ if qwebcontext is None:
+ qwebcontext = {}
+
+ if not isinstance(qwebcontext, QWebContext):
+ qwebcontext = QWebContext(cr, uid, qwebcontext, loader=loader, context=context)
+
+ qwebcontext['__template__'] = id_or_xml_id
+ stack = qwebcontext.get('__stack__', [])
+ if stack:
+ qwebcontext['__caller__'] = stack[-1]
+ stack.append(id_or_xml_id)
+ qwebcontext['__stack__'] = stack
+ qwebcontext['xmlid'] = str(stack[0]) # Temporary fix
+ return self.render_node(self.get_template(id_or_xml_id, qwebcontext), qwebcontext)
+
+ def render_node(self, element, qwebcontext):
+ result = ""
+ if element.nodeType == self.node.TEXT_NODE or element.nodeType == self.node.CDATA_SECTION_NODE:
+ result = element.data.encode("utf8")
+ elif element.nodeType == self.node.ELEMENT_NODE:
+ generated_attributes = ""
+ t_render = None
+ template_attributes = {}
+ for (attribute_name, attribute_value) in element.attributes.items():
+ attribute_name = str(attribute_name)
+ if attribute_name == "groups":
+ cr = qwebcontext.get('request') and qwebcontext['request'].cr or None
+ uid = qwebcontext.get('request') and qwebcontext['request'].uid or None
+ can_see = self.user_has_groups(cr, uid, groups=attribute_value)
+ if not can_see:
+ return ''
+ continue
+
+ if isinstance(attribute_value, unicode):
+ attribute_value = attribute_value.encode("utf8")
+ else:
+ attribute_value = attribute_value.nodeValue.encode("utf8")
+
+ if attribute_name.startswith("t-"):
+ for attribute in self._render_att:
+ if attribute_name[2:].startswith(attribute):
+ att, val = self._render_att[attribute](self, element, attribute_name, attribute_value, qwebcontext)
+ generated_attributes += val and ' %s="%s"' % (att, werkzeug.utils.escape(val)) or " "
+ break
+ else:
+ if attribute_name[2:] in self._render_tag:
+ t_render = attribute_name[2:]
+ template_attributes[attribute_name[2:]] = attribute_value
+ else:
+ generated_attributes += ' %s="%s"' % (attribute_name, werkzeug.utils.escape(attribute_value))
+
+ if 'debug' in template_attributes:
+ debugger = template_attributes.get('debug', 'pdb')
+ __import__(debugger).set_trace() # pdb, ipdb, pudb, ...
+ if t_render:
+ result = self._render_tag[t_render](self, element, template_attributes, generated_attributes, qwebcontext)
+ else:
+ result = self.render_element(element, template_attributes, generated_attributes, qwebcontext)
+ if isinstance(result, unicode):
+ return result.encode('utf-8')
+ return result
+
+ def render_element(self, element, template_attributes, generated_attributes, qwebcontext, inner=None):
+ # element: element
+ # template_attributes: t-* attributes
+ # generated_attributes: generated attributes
+ # qwebcontext: values
+ # inner: optional innerXml
+ if inner:
+ g_inner = inner
+ else:
+ g_inner = []
+ for current_node in element.childNodes:
+ try:
+ g_inner.append(self.render_node(current_node, qwebcontext))
+ except QWebException:
+ raise
+ except Exception:
+ template = qwebcontext.get('__template__')
+ raise convert_to_qweb_exception(message="Could not render element %r" % element.nodeName, node=element, template=template)
+ name = str(element.nodeName)
+ inner = "".join(g_inner)
+ trim = template_attributes.get("trim", 0)
+ if trim == 0:
+ pass
+ elif trim == 'left':
+ inner = inner.lstrip()
+ elif trim == 'right':
+ inner = inner.rstrip()
+ elif trim == 'both':
+ inner = inner.strip()
+ if name == "t":
+ return inner
+ elif len(inner) or name not in self._void_elements:
+ return "<%s%s>%s</%s>" % tuple(
+ qwebcontext if isinstance(qwebcontext, str) else qwebcontext.encode('utf-8')
+ for qwebcontext in (name, generated_attributes, inner, name)
+ )
+ else:
+ return "<%s%s/>" % (name, generated_attributes)
+
+ # Attributes
+ def render_att_att(self, element, attribute_name, attribute_value, qwebcontext):
+ if attribute_name.startswith("t-attf-"):
+ att, val = attribute_name[7:], self.eval_format(attribute_value, qwebcontext)
+ elif attribute_name.startswith("t-att-"):
+ att, val = attribute_name[6:], self.eval(attribute_value, qwebcontext)
+ if isinstance(val, unicode):
+ val = val.encode("utf8")
+ else:
+ att, val = self.eval_object(attribute_value, qwebcontext)
+ return att, val
+
+ # Tags
+ def render_tag_raw(self, element, template_attributes, generated_attributes, qwebcontext):
+ inner = self.eval_str(template_attributes["raw"], qwebcontext)
+ return self.render_element(element, template_attributes, generated_attributes, qwebcontext, inner)
+
+ def render_tag_esc(self, element, template_attributes, generated_attributes, qwebcontext):
+ inner = werkzeug.utils.escape(self.eval_str(template_attributes["esc"], qwebcontext))
+ return self.render_element(element, template_attributes, generated_attributes, qwebcontext, inner)
+
+ def render_tag_foreach(self, element, template_attributes, generated_attributes, qwebcontext):
+ expr = template_attributes["foreach"]
+ enum = self.eval_object(expr, qwebcontext)
+ if enum is not None:
+ var = template_attributes.get('as', expr).replace('.', '_')
+ copy_qwebcontext = qwebcontext.copy()
+ size = -1
+ if isinstance(enum, (list, tuple)):
+ size = len(enum)
+ elif hasattr(enum, 'count'):
+ size = enum.count()
+ copy_qwebcontext["%s_size" % var] = size
+ copy_qwebcontext["%s_all" % var] = enum
+ index = 0
+ ru = []
+ for i in enum:
+ copy_qwebcontext["%s_value" % var] = i
+ copy_qwebcontext["%s_index" % var] = index
+ copy_qwebcontext["%s_first" % var] = index == 0
+ copy_qwebcontext["%s_even" % var] = index % 2
+ copy_qwebcontext["%s_odd" % var] = (index + 1) % 2
+ copy_qwebcontext["%s_last" % var] = index + 1 == size
+ if index % 2:
+ copy_qwebcontext["%s_parity" % var] = 'odd'
+ else:
+ copy_qwebcontext["%s_parity" % var] = 'even'
+ if 'as' in template_attributes:
+ copy_qwebcontext[var] = i
+ elif isinstance(i, dict):
+ copy_qwebcontext.update(i)
+ ru.append(self.render_element(element, template_attributes, generated_attributes, copy_qwebcontext))
+ index += 1
+ return "".join(ru)
+ else:
+ template = qwebcontext.get('__template__')
+ raise QWebException("foreach enumerator %r is not defined while rendering template %r" % (expr, template), template=template)
+
+ def render_tag_if(self, element, template_attributes, generated_attributes, qwebcontext):
+ if self.eval_bool(template_attributes["if"], qwebcontext):
+ return self.render_element(element, template_attributes, generated_attributes, qwebcontext)
+ return ""
+
+ def render_tag_call(self, element, template_attributes, generated_attributes, qwebcontext):
+ d = qwebcontext.copy()
+ d[0] = self.render_element(element, template_attributes, generated_attributes, d)
+ cr = d.get('request') and d['request'].cr or None
+ uid = d.get('request') and d['request'].uid or None
+
+ return self.render(cr, uid, self.eval_format(template_attributes["call"], d), d)
+
+ def render_tag_set(self, element, template_attributes, generated_attributes, qwebcontext):
+ if "value" in template_attributes:
+ qwebcontext[template_attributes["set"]] = self.eval_object(template_attributes["value"], qwebcontext)
+ elif "valuef" in template_attributes:
+ qwebcontext[template_attributes["set"]] = self.eval_format(template_attributes["valuef"], qwebcontext)
+ else:
+ qwebcontext[template_attributes["set"]] = self.render_element(element, template_attributes, generated_attributes, qwebcontext)
+ return ""
+
+ def render_tag_field(self, element, template_attributes, generated_attributes, qwebcontext):
+ """ eg: <span t-record="browse_record(res.partner, 1)" t-field="phone">+1 555 555 8069</span>"""
+ node_name = element.nodeName
+ assert node_name not in ("table", "tbody", "thead", "tfoot", "tr", "td",
+ "li", "ul", "ol", "dl", "dt", "dd"),\
+ "RTE widgets do not work correctly on %r elements" % node_name
+ assert node_name != 't',\
+ "t-field can not be used on a t element, provide an actual HTML node"
+
+ record, field_name = template_attributes["field"].rsplit('.', 1)
+ record = self.eval_object(record, qwebcontext)
+
+ column = record._model._all_columns[field_name].column
+ options = json.loads(template_attributes.get('field-options') or '{}')
+ field_type = get_field_type(column, options)
+
+ converter = self.get_converter_for(field_type)
+
+ return converter.to_html(qwebcontext.cr, qwebcontext.uid, field_name, record, options,
+ element, template_attributes, generated_attributes, qwebcontext, context=qwebcontext.context)
+
+ def get_converter_for(self, field_type):
+ return self.pool.get('ir.qweb.field.' + field_type,
+ self.pool['ir.qweb.field'])
+
+#--------------------------------------------------------------------
+# QWeb Fields converters
+#--------------------------------------------------------------------
+
+class FieldConverter(osv.AbstractModel):
+ """ Used to convert a t-field specification into an output HTML field.
+
+ :meth:`~.to_html` is the entry point of this conversion from QWeb, it:
+
+ * converts the record value to html using :meth:`~.record_to_html`
+ * generates the metadata attributes (``data-oe-``) to set on the root
+ result node
+ * generates the root result node itself through :meth:`~.render_element`
+ """
+ _name = 'ir.qweb.field'
+
+ def attributes(self, cr, uid, field_name, record, options,
+ source_element, g_att, t_att, qweb_context,
+ context=None):
+ """
+ Generates the metadata attributes (prefixed by ``data-oe-`` for the
+ root node of the field conversion. Attribute values are escaped by the
+ parent using ``werkzeug.utils.escape``.
+
+ The default attributes are:
+
+ * ``model``, the name of the record's model
+ * ``id`` the id of the record to which the field belongs
+ * ``field`` the name of the converted field
+ * ``type`` the logical field type (widget, may not match the column's
+ ``type``, may not be any _column subclass name)
+ * ``translate``, a boolean flag (``0`` or ``1``) denoting whether the
+ column is translatable
+ * ``expression``, the original expression
+
+ :returns: iterable of (attribute name, attribute value) pairs.
+ """
+ column = record._model._all_columns[field_name].column
+ field_type = get_field_type(column, options)
+ return [
+ ('data-oe-model', record._model._name),
+ ('data-oe-id', record.id),
+ ('data-oe-field', field_name),
+ ('data-oe-type', field_type),
+ ('data-oe-expression', t_att['field']),
+ ]
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ """ Converts a single value to its HTML version/output
+ """
+ if not value: return ''
+ return value
+
+ def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
+ """ Converts the specified field of the browse_record ``record`` to
+ HTML
+ """
+ return self.value_to_html(
+ cr, uid, record[field_name], column, options=options, context=context)
+
+ def to_html(self, cr, uid, field_name, record, options,
+ source_element, t_att, g_att, qweb_context, context=None):
+ """ Converts a ``t-field`` to its HTML output. A ``t-field`` may be
+ extended by a ``t-field-options``, which is a JSON-serialized mapping
+ of configuration values.
+
+ A default configuration key is ``widget`` which can override the
+ field's own ``_type``.
+ """
+ content = None
+ try:
+ content = self.record_to_html(
+ cr, uid, field_name, record,
+ record._model._all_columns[field_name].column,
+ options, context=context)
+ if options.get('html-escape', True):
+ content = werkzeug.utils.escape(content)
+ elif hasattr(content, '__html__'):
+ content = content.__html__()
+ except Exception:
+ _logger.warning("Could not get field %s for model %s",
+ field_name, record._model._name, exc_info=True)
+ content = None
+
+ g_att += ''.join(
+ ' %s="%s"' % (name, werkzeug.utils.escape(value))
+ for name, value in self.attributes(
+ cr, uid, field_name, record, options,
+ source_element, g_att, t_att, qweb_context)
+ )
+
+ return self.render_element(cr, uid, source_element, t_att, g_att,
+ qweb_context, content)
+
+ def qweb_object(self):
+ return self.pool['ir.qweb']
+
+ def render_element(self, cr, uid, source_element, t_att, g_att,
+ qweb_context, content):
+ """ Final rendering hook, by default just calls ir.qweb's ``render_element``
+ """
+ return self.qweb_object().render_element(
+ source_element, t_att, g_att, qweb_context, content or '')
+
+ def user_lang(self, cr, uid, context):
+ """
+ Fetches the res.lang object corresponding to the language code stored
+ in the user's context. Fallbacks to en_US if no lang is present in the
+ context *or the language code is not valid*.
+
+ :returns: res.lang browse_record
+ """
+ if context is None: context = {}
+
+ lang_code = context.get('lang') or 'en_US'
+ Lang = self.pool['res.lang']
+
+ lang_ids = Lang.search(cr, uid, [('code', '=', lang_code)], context=context) \
+ or Lang.search(cr, uid, [('code', '=', 'en_US')], context=context)
+
+ return Lang.browse(cr, uid, lang_ids[0], context=context)
+
+class FloatConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.float'
+ _inherit = 'ir.qweb.field'
+
+ def precision(self, cr, uid, column, options=None, context=None):
+ _, precision = column.digits or (None, None)
+ return precision
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ if context is None:
+ context = {}
+ precision = self.precision(cr, uid, column, options=options, context=context)
+ fmt = '%f' if precision is None else '%.{precision}f'
+
+ lang_code = context.get('lang') or 'en_US'
+ lang = self.pool['res.lang']
+ formatted = lang.format(cr, uid, [lang_code], fmt.format(precision=precision), value, grouping=True)
+
+ # %f does not strip trailing zeroes. %g does but its precision causes
+ # it to switch to scientific notation starting at a million *and* to
+ # strip decimals. So use %f and if no precision was specified manually
+ # strip trailing 0.
+ if not precision:
+ formatted = re.sub(r'(?:(0|\d+?)0+)$', r'\1', formatted)
+ return formatted
+
+class DateConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.date'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ if not value: return ''
+ lang = self.user_lang(cr, uid, context=context)
+ locale = babel.Locale.parse(lang.code)
+
+ if isinstance(value, basestring):
+ value = datetime.datetime.strptime(
+ value, openerp.tools.DEFAULT_SERVER_DATE_FORMAT)
+
+ if options and 'format' in options:
+ pattern = options['format']
+ else:
+ strftime_pattern = lang.date_format
+ pattern = openerp.tools.posix_to_ldml(strftime_pattern, locale=locale)
+
+ return babel.dates.format_datetime(
+ value, format=pattern,
+ locale=locale)
+
+class DateTimeConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.datetime'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ if not value: return ''
+ lang = self.user_lang(cr, uid, context=context)
+ locale = babel.Locale.parse(lang.code)
+
+ if isinstance(value, basestring):
+ value = datetime.datetime.strptime(
+ value, openerp.tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ value = column.context_timestamp(
+ cr, uid, timestamp=value, context=context)
+
+ if options and 'format' in options:
+ pattern = options['format']
+ else:
+ strftime_pattern = (u"%s %s" % (lang.date_format, lang.time_format))
+ pattern = openerp.tools.posix_to_ldml(strftime_pattern, locale=locale)
+
+ return babel.dates.format_datetime(value, format=pattern, locale=locale)
+
+class TextConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.text'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ """
+ Escapes the value and converts newlines to br. This is bullshit.
+ """
+ if not value: return ''
+
+ return nl2br(value, options=options)
+
+class SelectionConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.selection'
+ _inherit = 'ir.qweb.field'
+
+ def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
+ value = record[field_name]
+ if not value: return ''
+ selection = dict(fields.selection.reify(
+ cr, uid, record._model, column))
+ return self.value_to_html(
+ cr, uid, selection[value], column, options=options)
+
+class ManyToOneConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.many2one'
+ _inherit = 'ir.qweb.field'
+
+ def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
+ [read] = record.read([field_name])
+ if not read[field_name]: return ''
+ _, value = read[field_name]
+ return nl2br(value, options=options)
+
+class HTMLConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.html'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ return HTMLSafe(value or '')
+
+class ImageConverter(osv.AbstractModel):
+ """ ``image`` widget rendering, inserts a data:uri-using image tag in the
+ document. May be overridden by e.g. the website module to generate links
+ instead.
+
+ .. todo:: what happens if different output need different converters? e.g.
+ reports may need embedded images or FS links whereas website
+ needs website-aware
+ """
+ _name = 'ir.qweb.field.image'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ try:
+ image = Image.open(cStringIO.StringIO(value.decode('base64')))
+ image.verify()
+ except IOError:
+ raise ValueError("Non-image binary fields can not be converted to HTML")
+ except: # image.verify() throws "suitable exceptions", I have no idea what they are
+ raise ValueError("Invalid image content")
+
+ return HTMLSafe('<img src="data:%s;base64,%s">' % (Image.MIME[image.format], value))
+
+class MonetaryConverter(osv.AbstractModel):
+ """ ``monetary`` converter, has a mandatory option
+ ``display_currency``.
+
+ The currency is used for formatting *and rounding* of the float value. It
+ is assumed that the linked res_currency has a non-empty rounding value and
+ res.currency's ``round`` method is used to perform rounding.
+
+ .. note:: the monetary converter internally adds the qweb context to its
+ options mapping, so that the context is available to callees.
+ It's set under the ``_qweb_context`` key.
+ """
+ _name = 'ir.qweb.field.monetary'
+ _inherit = 'ir.qweb.field'
+
+ def to_html(self, cr, uid, field_name, record, options,
+ source_element, t_att, g_att, qweb_context, context=None):
+ options['_qweb_context'] = qweb_context
+ return super(MonetaryConverter, self).to_html(
+ cr, uid, field_name, record, options,
+ source_element, t_att, g_att, qweb_context, context=context)
+
+ def record_to_html(self, cr, uid, field_name, record, column, options, context=None):
+ if context is None:
+ context = {}
+ Currency = self.pool['res.currency']
+ display = self.display_currency(cr, uid, options)
+
+ # lang.format mandates a sprintf-style format. These formats are non-
+ # minimal (they have a default fixed precision instead), and
+ # lang.format will not set one by default. currency.round will not
+ # provide one either. So we need to generate a precision value
+ # (integer > 0) from the currency's rounding (a float generally < 1.0).
+ #
+ # The log10 of the rounding should be the number of digits involved if
+ # negative, if positive clamp to 0 digits and call it a day.
+ # nb: int() ~ floor(), we want nearest rounding instead
+ precision = int(round(math.log10(display.rounding)))
+ fmt = "%.{0}f".format(-precision if precision < 0 else 0)
+
+ lang_code = context.get('lang') or 'en_US'
+ lang = self.pool['res.lang']
+ formatted_amount = lang.format(cr, uid, [lang_code],
+ fmt, Currency.round(cr, uid, display, record[field_name]),
+ grouping=True, monetary=True)
+
+ pre = post = u''
+ if display.position == 'before':
+ pre = u'{symbol} '
+ else:
+ post = u' {symbol}'
+
+ return HTMLSafe(u'{pre}<span class="oe_currency_value">{0}</span>{post}'.format(
+ formatted_amount,
+ pre=pre, post=post,
+ ).format(
+ symbol=display.symbol,
+ ))
+
+ def display_currency(self, cr, uid, options):
+ return self.qweb_object().eval_object(
+ options['display_currency'], options['_qweb_context'])
+
+TIMEDELTA_UNITS = (
+ ('year', 3600 * 24 * 365),
+ ('month', 3600 * 24 * 30),
+ ('week', 3600 * 24 * 7),
+ ('day', 3600 * 24),
+ ('hour', 3600),
+ ('minute', 60),
+ ('second', 1)
+)
+class DurationConverter(osv.AbstractModel):
+ """ ``duration`` converter, to display integral or fractional values as
+ human-readable time spans (e.g. 1.5 as "1 hour 30 minutes").
+
+ Can be used on any numerical field.
+
+ Has a mandatory option ``unit`` which can be one of ``second``, ``minute``,
+ ``hour``, ``day``, ``week`` or ``year``, used to interpret the numerical
+ field value before converting it.
+
+ Sub-second values will be ignored.
+ """
+ _name = 'ir.qweb.field.duration'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ units = dict(TIMEDELTA_UNITS)
+ if value < 0:
+ raise ValueError(_("Durations can't be negative"))
+ if not options or options.get('unit') not in units:
+ raise ValueError(_("A unit must be provided to duration widgets"))
+
+ locale = babel.Locale.parse(
+ self.user_lang(cr, uid, context=context).code)
+ factor = units[options['unit']]
+
+ sections = []
+ r = value * factor
+ for unit, secs_per_unit in TIMEDELTA_UNITS:
+ v, r = divmod(r, secs_per_unit)
+ if not v: continue
+ section = babel.dates.format_timedelta(
+ v*secs_per_unit, threshold=1, locale=locale)
+ if section:
+ sections.append(section)
+ return u' '.join(sections)
+
+class RelativeDatetimeConverter(osv.AbstractModel):
+ _name = 'ir.qweb.field.relative'
+ _inherit = 'ir.qweb.field'
+
+ def value_to_html(self, cr, uid, value, column, options=None, context=None):
+ parse_format = openerp.tools.DEFAULT_SERVER_DATETIME_FORMAT
+ locale = babel.Locale.parse(
+ self.user_lang(cr, uid, context=context).code)
+
+ if isinstance(value, basestring):
+ value = datetime.datetime.strptime(value, parse_format)
+
+ # value should be a naive datetime in UTC. So is fields.datetime.now()
+ reference = datetime.datetime.strptime(column.now(), parse_format)
+
+ return babel.dates.format_timedelta(
+ value - reference, add_direction=True, locale=locale)
+
+class HTMLSafe(object):
+ """ HTMLSafe string wrapper, Werkzeug's escape() has special handling for
+ objects with a ``__html__`` methods but AFAIK does not provide any such
+ object.
+
+ Wrapping a string in HTML will prevent its escaping
+ """
+ __slots__ = ['string']
+ def __init__(self, string):
+ self.string = string
+ def __html__(self):
+ return self.string
+ def __str__(self):
+ s = self.string
+ if isinstance(s, unicode):
+ return s.encode('utf-8')
+ return s
+ def __unicode__(self):
+ s = self.string
+ if isinstance(s, str):
+ return s.decode('utf-8')
+ return s
+
+def nl2br(string, options=None):
+ """ Converts newlines to HTML linebreaks in ``string``. Automatically
+ escapes content unless options['html-escape'] is set to False, and returns
+ the result wrapped in an HTMLSafe object.
+
+ :param str string:
+ :param dict options:
+ :rtype: HTMLSafe
+ """
+ if options is None: options = {}
+
+ if options.get('html-escape', True):
+ string = werkzeug.utils.escape(string)
+ return HTMLSafe(string.replace('\n', '<br>\n'))
+
+def get_field_type(column, options):
+ """ Gets a t-field's effective type from the field's column and its options
+ """
+ return options.get('widget', column._type)
+
+# vim:et:
diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py
index c9eaa1c53e4..b6a7a722ddb 100644
--- a/openerp/addons/base/ir/ir_translation.py
+++ b/openerp/addons/base/ir/ir_translation.py
@@ -268,13 +268,8 @@ class ir_translation(osv.osv):
return translations
def _set_ids(self, cr, uid, name, tt, lang, ids, value, src=None):
- # clear the caches
- tr = self._get_ids(cr, uid, name, tt, lang, ids)
- for res_id in tr:
- if tr[res_id]:
- self._get_source.clear_cache(self, uid, name, tt, lang, tr[res_id])
- self._get_ids.clear_cache(self, uid, name, tt, lang, res_id)
- self._get_source.clear_cache(self, uid, name, tt, lang)
+ self._get_ids.clear_cache(self)
+ self._get_source.clear_cache(self)
cr.execute('delete from ir_translation '
'where lang=%s '
@@ -294,7 +289,7 @@ class ir_translation(osv.osv):
return len(ids)
@tools.ormcache(skiparg=3)
- def _get_source(self, cr, uid, name, types, lang, source=None):
+ def _get_source(self, cr, uid, name, types, lang, source=None, res_id=None):
"""
Returns the translation for the given combination of name, type, language
and source. All values passed to this method should be unicode (not byte strings),
@@ -304,6 +299,7 @@ class ir_translation(osv.osv):
:param types: single string defining type of term to translate (see ``type`` field on ir.translation), or sequence of allowed types (strings)
:param lang: language code of the desired translation
:param source: optional source term to translate (should be unicode)
+ :param res_id: optional resource id to translate (if used, ``source`` should be set)
:rtype: unicode
:return: the request translation, or an empty unicode string if no translation was
found and `source` was not passed
@@ -321,6 +317,9 @@ class ir_translation(osv.osv):
AND type in %s
AND src=%s"""
params = (lang or '', types, tools.ustr(source))
+ if res_id:
+ query += "AND res_id=%s"
+ params += (res_id,)
if name:
query += " AND name=%s"
params += (tools.ustr(name),)
@@ -342,8 +341,9 @@ class ir_translation(osv.osv):
if context is None:
context = {}
ids = super(ir_translation, self).create(cr, uid, vals, context=context)
- self._get_source.clear_cache(self, uid, vals.get('name',0), vals.get('type',0), vals.get('lang',0), vals.get('src',0))
- self._get_ids.clear_cache(self, uid, vals.get('name',0), vals.get('type',0), vals.get('lang',0), vals.get('res_id',0))
+ self._get_source.clear_cache(self)
+ self._get_ids.clear_cache(self)
+ self.pool['ir.ui.view'].clear_cache()
return ids
def write(self, cursor, user, ids, vals, context=None):
@@ -356,9 +356,9 @@ class ir_translation(osv.osv):
if vals.get('value'):
vals.update({'state':'translated'})
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
- for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
- self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
- self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['res_id'])
+ self._get_source.clear_cache(self)
+ self._get_ids.clear_cache(self)
+ self.pool['ir.ui.view'].clear_cache()
return result
def unlink(self, cursor, user, ids, context=None):
@@ -366,9 +366,9 @@ class ir_translation(osv.osv):
context = {}
if isinstance(ids, (int, long)):
ids = [ids]
- for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
- self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
- self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['res_id'])
+
+ self._get_source.clear_cache(self)
+ self._get_ids.clear_cache(self)
result = super(ir_translation, self).unlink(cursor, user, ids, context=context)
return result
diff --git a/openerp/addons/base/ir/ir_translation_view.xml b/openerp/addons/base/ir/ir_translation_view.xml
index f3f9c4d0fac..4cabab6d1b4 100644
--- a/openerp/addons/base/ir/ir_translation_view.xml
+++ b/openerp/addons/base/ir/ir_translation_view.xml
@@ -14,7 +14,7 @@
domain="[('comments', 'like', 'openerp-web')]"/>
<field name="name" operator="="/>
<field name="lang"/>
- <field name="source"/>
+ <field name="src"/>
<field name="value"/>
</search>
</field>
diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py
index 123b20db15f..d4655bf8b9c 100644
--- a/openerp/addons/base/ir/ir_ui_view.py
+++ b/openerp/addons/base/ir/ir_ui_view.py
@@ -18,20 +18,43 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
-
+import collections
+import copy
+import fnmatch
import logging
from lxml import etree
from operator import itemgetter
import os
+import simplejson
+import werkzeug
+
+import HTMLParser
+import openerp
from openerp import tools
-from openerp.osv import fields,osv
-from openerp.tools import graph
+from openerp.http import request
+from openerp.osv import fields, osv, orm
+from openerp.tools import graph, SKIPPED_ELEMENT_TYPES
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.view_validation import valid_view
+from openerp.tools import misc
+from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
+MOVABLE_BRANDING = ['data-oe-model', 'data-oe-id', 'data-oe-field', 'data-oe-xpath']
+
+def keep_query(*args, **kw):
+ if not args and not kw:
+ args = ('*',)
+ params = kw.copy()
+ query_params = frozenset(werkzeug.url_decode(request.httprequest.query_string).keys())
+ for keep_param in args:
+ for param in fnmatch.filter(query_params, keep_param):
+ if param not in params and param in request.params:
+ params[param] = request.params[param]
+ return werkzeug.urls.url_encode(params)
+
class view_custom(osv.osv):
_name = 'ir.ui.view.custom'
_order = 'create_date desc' # search(limit=1) should return the last customization
@@ -50,59 +73,45 @@ class view_custom(osv.osv):
class view(osv.osv):
_name = 'ir.ui.view'
- def _type_field(self, cr, uid, ids, name, args, context=None):
- result = {}
- for record in self.browse(cr, uid, ids, context):
- # Get the type from the inherited view if any.
- if record.inherit_id:
- result[record.id] = record.inherit_id.type
- else:
- result[record.id] = etree.fromstring(record.arch.encode('utf8')).tag
+ def _get_model_data(self, cr, uid, ids, *args, **kwargs):
+ ir_model_data = self.pool.get('ir.model.data')
+ data_ids = ir_model_data.search(cr, uid, [('model', '=', self._name), ('res_id', 'in', ids)])
+ result = dict(zip(ids, data_ids))
return result
_columns = {
'name': fields.char('View Name', required=True),
- 'model': fields.char('Object', size=64, required=True, select=True),
+ 'model': fields.char('Object', select=True),
'priority': fields.integer('Sequence', required=True),
- 'type': fields.function(_type_field, type='selection', selection=[
+ 'type': fields.selection([
('tree','Tree'),
('form','Form'),
- ('mdx','mdx'),
('graph', 'Graph'),
('calendar', 'Calendar'),
('diagram','Diagram'),
('gantt', 'Gantt'),
('kanban', 'Kanban'),
- ('search','Search')], string='View Type', required=True, select=True, store=True),
+ ('search','Search'),
+ ('qweb', 'QWeb')], string='View Type'),
'arch': fields.text('View Architecture', required=True),
'inherit_id': fields.many2one('ir.ui.view', 'Inherited View', ondelete='cascade', select=True),
- 'field_parent': fields.char('Child Field',size=64),
+ 'inherit_children_ids': fields.one2many('ir.ui.view','inherit_id', 'Inherit Views'),
+ 'field_parent': fields.char('Child Field'),
+ 'model_data_id': fields.function(_get_model_data, type='many2one', relation='ir.model.data', string="Model Data", store=True),
'xml_id': fields.function(osv.osv.get_xml_id, type='char', size=128, string="External ID",
help="ID of the view defined in xml file"),
'groups_id': fields.many2many('res.groups', 'ir_ui_view_group_rel', 'view_id', 'group_id',
string='Groups', help="If this field is empty, the view applies to all users. Otherwise, the view applies to the users of those groups only."),
+ 'model_ids': fields.one2many('ir.model.data', 'res_id', domain=[('model','=','ir.ui.view')], auto_join=True),
}
_defaults = {
- 'arch': '<?xml version="1.0"?>\n<tree string="My view">\n\t<field name="name"/>\n</tree>',
'priority': 16,
- 'type': 'tree',
}
_order = "priority,name"
# Holds the RNG schema
_relaxng_validator = None
- def create(self, cr, uid, values, context=None):
- if 'type' in values:
- _logger.warning("Setting the `type` field is deprecated in the `ir.ui.view` model.")
- if not values.get('name'):
- if values.get('inherit_id'):
- inferred_type = self.browse(cr, uid, values['inherit_id'], context).type
- else:
- inferred_type = etree.fromstring(values['arch'].encode('utf8')).tag
- values['name'] = "%s %s" % (values['model'], inferred_type)
- return super(view, self).create(cr, uid, values, context)
-
def _relaxng(self):
if not self._relaxng_validator:
frng = tools.file_open(os.path.join('base','rng','view.rng'))
@@ -115,59 +124,37 @@ class view(osv.osv):
frng.close()
return self._relaxng_validator
- def _check_render_view(self, cr, uid, view, context=None):
- """Verify that the given view's hierarchy is valid for rendering, along with all the changes applied by
- its inherited views, by rendering it using ``fields_view_get()``.
-
- @param browse_record view: view to validate
- @return: the rendered definition (arch) of the view, always utf-8 bytestring (legacy convention)
- if no error occurred, else False.
- """
- if view.model not in self.pool:
- return False
- try:
- fvg = self.pool[view.model].fields_view_get(cr, uid, view_id=view.id, view_type=view.type, context=context)
- return fvg['arch']
- except Exception:
- _logger.exception('cannot render view %s', view.xml_id)
- return False
-
def _check_xml(self, cr, uid, ids, context=None):
if context is None:
context = {}
- context['check_view_ids'] = ids
-
- for view in self.browse(cr, uid, ids, context):
- # Sanity check: the view should not break anything upon rendering!
- view_arch_utf8 = self._check_render_view(cr, uid, view, context=context)
- # always utf-8 bytestring - legacy convention
- if not view_arch_utf8: return False
-
- # RNG-based validation is not possible anymore with 7.0 forms
- # TODO 7.0: provide alternative assertion-based validation of view_arch_utf8
- view_docs = [etree.fromstring(view_arch_utf8)]
- if view_docs[0].tag == 'data':
- # A <data> element is a wrapper for multiple root nodes
- view_docs = view_docs[0]
- validator = self._relaxng()
- for view_arch in view_docs:
- if (view_arch.get('version') < '7.0') and validator and not validator.validate(view_arch):
- for error in validator.error_log:
- _logger.error(tools.ustr(error))
- return False
- if not valid_view(view_arch):
- return False
- return True
+ context = dict(context, check_view_ids=ids)
- def _check_model(self, cr, uid, ids, context=None):
+ # Sanity checks: the view should not break anything upon rendering!
+ # Any exception raised below will cause a transaction rollback.
for view in self.browse(cr, uid, ids, context):
- if view.model not in self.pool:
- return False
+ view_def = self.read_combined(cr, uid, view.id, None, context=context)
+ view_arch_utf8 = view_def['arch']
+ if view.type != 'qweb':
+ view_doc = etree.fromstring(view_arch_utf8)
+ # verify that all fields used are valid, etc.
+ self.postprocess_and_fields(cr, uid, view.model, view_doc, view.id, context=context)
+ # RNG-based validation is not possible anymore with 7.0 forms
+ view_docs = [view_doc]
+ if view_docs[0].tag == 'data':
+ # A <data> element is a wrapper for multiple root nodes
+ view_docs = view_docs[0]
+ validator = self._relaxng()
+ for view_arch in view_docs:
+ if (view_arch.get('version') < '7.0') and validator and not validator.validate(view_arch):
+ for error in validator.error_log:
+ _logger.error(tools.ustr(error))
+ return False
+ if not valid_view(view_arch):
+ return False
return True
_constraints = [
- (_check_model, 'The model name does not exist.', ['model']),
- (_check_xml, 'The model name does not exist or the view architecture cannot be rendered.', ['arch', 'model']),
+ (_check_xml, 'Invalid view definition', ['arch'])
]
def _auto_init(self, cr, context=None):
@@ -176,6 +163,73 @@ class view(osv.osv):
if not cr.fetchone():
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, inherit_id)')
+ def create(self, cr, uid, values, context=None):
+ if 'type' not in values:
+ if values.get('inherit_id'):
+ values['type'] = self.browse(cr, uid, values['inherit_id'], context).type
+ else:
+ values['type'] = etree.fromstring(values['arch']).tag
+
+ if not values.get('name'):
+ values['name'] = "%s %s" % (values['model'], values['type'])
+
+ self.read_template.clear_cache(self)
+ return super(view, self).create(cr, uid, values, context)
+
+ def write(self, cr, uid, ids, vals, context=None):
+ if not isinstance(ids, (list, tuple)):
+ ids = [ids]
+ if context is None:
+ context = {}
+
+ # drop the corresponding view customizations (used for dashboards for example), otherwise
+ # not all users would see the updated views
+ custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id', 'in', ids)])
+ if custom_view_ids:
+ self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
+
+ self.read_template.clear_cache(self)
+ ret = super(view, self).write(cr, uid, ids, vals, context)
+
+ # if arch is modified views become noupdatable
+ if 'arch' in vals and not context.get('install_mode', False):
+ # TODO: should be doable in a read and a write
+ for view_ in self.browse(cr, uid, ids, context=context):
+ if view_.model_data_id:
+ self.pool.get('ir.model.data').write(cr, openerp.SUPERUSER_ID, view_.model_data_id.id, {'noupdate': True})
+ return ret
+
+ def copy(self, cr, uid, id, default=None, context=None):
+ if not default:
+ default = {}
+ default.update({
+ 'model_ids': [],
+ })
+ return super(view, self).copy(cr, uid, id, default, context=context)
+
+ # default view selection
+ def default_view(self, cr, uid, model, view_type, context=None):
+ """ Fetches the default view for the provided (model, view_type) pair:
+ view with no parent (inherit_id=Fase) with the lowest priority.
+
+ :param str model:
+ :param int view_type:
+ :return: id of the default view of False if none found
+ :rtype: int
+ """
+ domain = [
+ ['model', '=', model],
+ ['type', '=', view_type],
+ ['inherit_id', '=', False],
+ ]
+ ids = self.search(cr, uid, domain, limit=1, order='priority', context=context)
+ if not ids:
+ return False
+ return ids[0]
+
+ #------------------------------------------------------
+ # Inheritance mecanism
+ #------------------------------------------------------
def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None):
"""Retrieves the architecture of views that inherit from the given view, from the sets of
views that should currently be used in the system. During the module upgrade phase it
@@ -185,43 +239,611 @@ class view(osv.osv):
after the module initialization phase is completely finished.
:param int view_id: id of the view whose inheriting views should be retrieved
- :param str model: model identifier of the view's related model (for double-checking)
+ :param str model: model identifier of the inheriting views.
:rtype: list of tuples
:return: [(view_arch,view_id), ...]
"""
user_groups = frozenset(self.pool.get('res.users').browse(cr, 1, uid, context).groups_id)
+
+ check_view_ids = context and context.get('check_view_ids') or (0,)
+ conditions = [['inherit_id', '=', view_id], ['model', '=', model]]
if self.pool._init:
- # Module init currently in progress, only consider views from modules whose code was already loaded
- check_view_ids = context and context.get('check_view_ids') or (0,)
- query = """SELECT v.id FROM ir_ui_view v LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id)
- WHERE v.inherit_id=%s AND v.model=%s AND (md.module in %s OR v.id in %s)
- ORDER BY priority"""
- query_params = (view_id, model, tuple(self.pool._init_modules), tuple(check_view_ids))
- else:
- # Modules fully loaded, consider all views
- query = """SELECT v.id FROM ir_ui_view v
- WHERE v.inherit_id=%s AND v.model=%s
- ORDER BY priority"""
- query_params = (view_id, model)
- cr.execute(query, query_params)
- view_ids = [v[0] for v in cr.fetchall()]
- # filter views based on user groups
+ # Module init currently in progress, only consider views from
+ # modules whose code is already loaded
+ conditions.extend([
+ '|',
+ ['model_ids.module', 'in', tuple(self.pool._init_modules)],
+ ['id', 'in', check_view_ids],
+ ])
+ view_ids = self.search(cr, uid, conditions, context=context)
+
return [(view.arch, view.id)
for view in self.browse(cr, 1, view_ids, context)
if not (view.groups_id and user_groups.isdisjoint(view.groups_id))]
- def write(self, cr, uid, ids, vals, context=None):
- if not isinstance(ids, (list, tuple)):
- ids = [ids]
+ def raise_view_error(self, cr, uid, message, view_id, context=None):
+ view = self.browse(cr, uid, view_id, context)
+ not_avail = _('n/a')
+ message = ("%(msg)s\n\n" +
+ _("Error context:\nView `%(view_name)s`") +
+ "\n[view_id: %(viewid)s, xml_id: %(xmlid)s, "
+ "model: %(model)s, parent_id: %(parent)s]") % \
+ {
+ 'view_name': view.name or not_avail,
+ 'viewid': view_id or not_avail,
+ 'xmlid': view.xml_id or not_avail,
+ 'model': view.model or not_avail,
+ 'parent': view.inherit_id.id or not_avail,
+ 'msg': message,
+ }
+ _logger.error(message)
+ raise AttributeError(message)
+
+ def locate_node(self, arch, spec):
+ """ Locate a node in a source (parent) architecture.
+
+ Given a complete source (parent) architecture (i.e. the field
+ `arch` in a view), and a 'spec' node (a node in an inheriting
+ view that specifies the location in the source view of what
+ should be changed), return (if it exists) the node in the
+ source view matching the specification.
+
+ :param arch: a parent architecture to modify
+ :param spec: a modifying node in an inheriting view
+ :return: a node in the source matching the spec
+ """
+ if spec.tag == 'xpath':
+ nodes = arch.xpath(spec.get('expr'))
+ return nodes[0] if nodes else None
+ elif spec.tag == 'field':
+ # Only compare the field name: a field can be only once in a given view
+ # at a given level (and for multilevel expressions, we should use xpath
+ # inheritance spec anyway).
+ for node in arch.iter('field'):
+ if node.get('name') == spec.get('name'):
+ return node
+ return None
+
+ for node in arch.iter(spec.tag):
+ if isinstance(node, SKIPPED_ELEMENT_TYPES):
+ continue
+ if all(node.get(attr) == spec.get(attr) for attr in spec.attrib
+ if attr not in ('position','version')):
+ # Version spec should match parent's root element's version
+ if spec.get('version') and spec.get('version') != arch.get('version'):
+ return None
+ return node
+ return None
+
+ def inherit_branding(self, specs_tree, view_id, root_id):
+ for node in specs_tree.iterchildren(tag=etree.Element):
+ xpath = node.getroottree().getpath(node)
+ if node.tag == 'data' or node.tag == 'xpath':
+ self.inherit_branding(node, view_id, root_id)
+ else:
+ node.set('data-oe-id', str(view_id))
+ node.set('data-oe-source-id', str(root_id))
+ node.set('data-oe-xpath', xpath)
+ node.set('data-oe-model', 'ir.ui.view')
+ node.set('data-oe-field', 'arch')
+
+ return specs_tree
+
+ def apply_inheritance_specs(self, cr, uid, source, specs_tree, inherit_id, context=None):
+ """ Apply an inheriting view (a descendant of the base view)
+
+ Apply to a source architecture all the spec nodes (i.e. nodes
+ describing where and what changes to apply to some parent
+ architecture) given by an inheriting view.
+
+ :param Element source: a parent architecture to modify
+ :param Elepect specs_tree: a modifying architecture in an inheriting view
+ :param inherit_id: the database id of specs_arch
+ :return: a modified source where the specs are applied
+ :rtype: Element
+ """
+ # Queue of specification nodes (i.e. nodes describing where and
+ # changes to apply to some parent architecture).
+ specs = [specs_tree]
+
+ while len(specs):
+ spec = specs.pop(0)
+ if isinstance(spec, SKIPPED_ELEMENT_TYPES):
+ continue
+ if spec.tag == 'data':
+ specs += [c for c in spec]
+ continue
+ node = self.locate_node(source, spec)
+ if node is not None:
+ pos = spec.get('position', 'inside')
+ if pos == 'replace':
+ if node.getparent() is None:
+ source = copy.deepcopy(spec[0])
+ else:
+ for child in spec:
+ node.addprevious(child)
+ node.getparent().remove(node)
+ elif pos == 'attributes':
+ for child in spec.getiterator('attribute'):
+ attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
+ if attribute[1]:
+ node.set(attribute[0], attribute[1])
+ elif attribute[0] in node.attrib:
+ del node.attrib[attribute[0]]
+ else:
+ sib = node.getnext()
+ for child in spec:
+ if pos == 'inside':
+ node.append(child)
+ elif pos == 'after':
+ if sib is None:
+ node.addnext(child)
+ node = child
+ else:
+ sib.addprevious(child)
+ elif pos == 'before':
+ node.addprevious(child)
+ else:
+ self.raise_view_error(cr, uid, _("Invalid position attribute: '%s'") % pos, inherit_id, context=context)
+ else:
+ attrs = ''.join([
+ ' %s="%s"' % (attr, spec.get(attr))
+ for attr in spec.attrib
+ if attr != 'position'
+ ])
+ tag = "<%s%s>" % (spec.tag, attrs)
+ self.raise_view_error(cr, uid, _("Element '%s' cannot be located in parent view") % tag, inherit_id, context=context)
+
+ return source
+
+ def apply_view_inheritance(self, cr, uid, source, source_id, model, root_id=None, context=None):
+ """ Apply all the (directly and indirectly) inheriting views.
+
+ :param source: a parent architecture to modify (with parent modifications already applied)
+ :param source_id: the database view_id of the parent view
+ :param model: the original model for which we create a view (not
+ necessarily the same as the source's model); only the inheriting
+ views with that specific model will be applied.
+ :return: a modified source where all the modifying architecture are applied
+ """
+ if context is None: context = {}
+ if root_id is None:
+ root_id = source_id
+ sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, uid, source_id, model, context=context)
+ for (specs, view_id) in sql_inherit:
+ specs_tree = etree.fromstring(specs.encode('utf-8'))
+ if context.get('inherit_branding'):
+ self.inherit_branding(specs_tree, view_id, root_id)
+ source = self.apply_inheritance_specs(cr, uid, source, specs_tree, view_id, context=context)
+ source = self.apply_view_inheritance(cr, uid, source, view_id, model, root_id=root_id, context=context)
+ return source
+
+ def read_combined(self, cr, uid, view_id, fields=None, context=None):
+ """
+ Utility function to get a view combined with its inherited views.
- # drop the corresponding view customizations (used for dashboards for example), otherwise
- # not all users would see the updated views
- custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
- if custom_view_ids:
- self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
+ * Gets the top of the view tree if a sub-view is requested
+ * Applies all inherited archs on the root view
+ * Returns the view with all requested fields
+ .. note:: ``arch`` is always added to the fields list even if not
+ requested (similar to ``id``)
+ """
+ if context is None: context = {}
+
+ # if view_id is not a root view, climb back to the top.
+ base = v = self.browse(cr, uid, view_id, context=context)
+ while v.inherit_id:
+ v = v.inherit_id
+ root_id = v.id
+
+ # arch and model fields are always returned
+ if fields:
+ fields = list(set(fields) | set(['arch', 'model']))
+
+ # read the view arch
+ [view] = self.read(cr, uid, [root_id], fields=fields, context=context)
+ arch_tree = etree.fromstring(view['arch'].encode('utf-8'))
+
+ if context.get('inherit_branding'):
+ arch_tree.attrib.update({
+ 'data-oe-model': 'ir.ui.view',
+ 'data-oe-id': str(root_id),
+ 'data-oe-field': 'arch',
+ })
+
+ # and apply inheritance
+ arch = self.apply_view_inheritance(
+ cr, uid, arch_tree, root_id, base.model, context=context)
+
+ return dict(view, arch=etree.tostring(arch, encoding='utf-8'))
+
+ #------------------------------------------------------
+ # Postprocessing: translation, groups and modifiers
+ #------------------------------------------------------
+ # TODO:
+ # - split postprocess so that it can be used instead of translate_qweb
+ # - remove group processing from ir_qweb
+ #------------------------------------------------------
+ def postprocess(self, cr, user, model, node, view_id, in_tree_view, model_fields, context=None):
+ """Return the description of the fields in the node.
+
+ In a normal call to this method, node is a complete view architecture
+ but it is actually possible to give some sub-node (this is used so
+ that the method can call itself recursively).
+
+ Originally, the field descriptions are drawn from the node itself.
+ But there is now some code calling fields_get() in order to merge some
+ of those information in the architecture.
+
+ """
+ if context is None:
+ context = {}
+ result = False
+ fields = {}
+ children = True
+
+ modifiers = {}
+ Model = self.pool.get(model)
+ if not Model:
+ self.raise_view_error(cr, user, _('Model not found: %(model)s') % dict(model=model),
+ view_id, context)
+
+ def encode(s):
+ if isinstance(s, unicode):
+ return s.encode('utf8')
+ return s
+
+ def check_group(node):
+ """Apply group restrictions, may be set at view level or model level::
+ * at view level this means the element should be made invisible to
+ people who are not members
+ * at model level (exclusively for fields, obviously), this means
+ the field should be completely removed from the view, as it is
+ completely unavailable for non-members
+
+ :return: True if field should be included in the result of fields_view_get
+ """
+ if node.tag == 'field' and node.get('name') in Model._all_columns:
+ column = Model._all_columns[node.get('name')].column
+ if column.groups and not self.user_has_groups(
+ cr, user, groups=column.groups, context=context):
+ node.getparent().remove(node)
+ fields.pop(node.get('name'), None)
+ # no point processing view-level ``groups`` anymore, return
+ return False
+ if node.get('groups'):
+ can_see = self.user_has_groups(
+ cr, user, groups=node.get('groups'), context=context)
+ if not can_see:
+ node.set('invisible', '1')
+ modifiers['invisible'] = True
+ if 'attrs' in node.attrib:
+ del(node.attrib['attrs']) #avoid making field visible later
+ del(node.attrib['groups'])
+ return True
+
+ if node.tag in ('field', 'node', 'arrow'):
+ if node.get('object'):
+ attrs = {}
+ views = {}
+ xml = "<form>"
+ for f in node:
+ if f.tag == 'field':
+ xml += etree.tostring(f, encoding="utf-8")
+ xml += "</form>"
+ new_xml = etree.fromstring(encode(xml))
+ ctx = context.copy()
+ ctx['base_model_name'] = model
+ xarch, xfields = self.postprocess_and_fields(cr, user, node.get('object'), new_xml, view_id, ctx)
+ views['form'] = {
+ 'arch': xarch,
+ 'fields': xfields
+ }
+ attrs = {'views': views}
+ fields = xfields
+ if node.get('name'):
+ attrs = {}
+ try:
+ if node.get('name') in Model._columns:
+ column = Model._columns[node.get('name')]
+ else:
+ column = Model._inherit_fields[node.get('name')][2]
+ except Exception:
+ column = False
+
+ if column:
+ children = False
+ views = {}
+ for f in node:
+ if f.tag in ('form', 'tree', 'graph', 'kanban', 'calendar'):
+ node.remove(f)
+ ctx = context.copy()
+ ctx['base_model_name'] = model
+ xarch, xfields = self.postprocess_and_fields(cr, user, column._obj or None, f, view_id, ctx)
+ views[str(f.tag)] = {
+ 'arch': xarch,
+ 'fields': xfields
+ }
+ attrs = {'views': views}
+ fields[node.get('name')] = attrs
+
+ field = model_fields.get(node.get('name'))
+ if field:
+ orm.transfer_field_to_modifiers(field, modifiers)
+
+ elif node.tag in ('form', 'tree'):
+ result = Model.view_header_get(cr, user, False, node.tag, context)
+ if result:
+ node.set('string', result)
+ in_tree_view = node.tag == 'tree'
+
+ elif node.tag == 'calendar':
+ for additional_field in ('date_start', 'date_delay', 'date_stop', 'color', 'all_day', 'attendee'):
+ if node.get(additional_field):
+ fields[node.get(additional_field)] = {}
+
+ if not check_group(node):
+ # node must be removed, no need to proceed further with its children
+ return fields
+
+ # The view architeture overrides the python model.
+ # Get the attrs before they are (possibly) deleted by check_group below
+ orm.transfer_node_to_modifiers(node, modifiers, context, in_tree_view)
+
+ # TODO remove attrs counterpart in modifiers when invisible is true ?
+
+ # translate view
+ if 'lang' in context:
+ Translations = self.pool['ir.translation']
+ if node.text and node.text.strip():
+ trans = Translations._get_source(cr, user, model, 'view', context['lang'], node.text.strip())
+ if trans:
+ node.text = node.text.replace(node.text.strip(), trans)
+ if node.tail and node.tail.strip():
+ trans = Translations._get_source(cr, user, model, 'view', context['lang'], node.tail.strip())
+ if trans:
+ node.tail = node.tail.replace(node.tail.strip(), trans)
+
+ if node.get('string') and not result:
+ trans = Translations._get_source(cr, user, model, 'view', context['lang'], node.get('string'))
+ if trans == node.get('string') and ('base_model_name' in context):
+ # If translation is same as source, perhaps we'd have more luck with the alternative model name
+ # (in case we are in a mixed situation, such as an inherited view where parent_view.model != model
+ trans = Translations._get_source(cr, user, context['base_model_name'], 'view', context['lang'], node.get('string'))
+ if trans:
+ node.set('string', trans)
+
+ for attr_name in ('confirm', 'sum', 'avg', 'help', 'placeholder'):
+ attr_value = node.get(attr_name)
+ if attr_value:
+ trans = Translations._get_source(cr, user, model, 'view', context['lang'], attr_value)
+ if trans:
+ node.set(attr_name, trans)
+
+ for f in node:
+ if children or (node.tag == 'field' and f.tag in ('filter','separator')):
+ fields.update(self.postprocess(cr, user, model, f, view_id, in_tree_view, model_fields, context))
+
+ orm.transfer_modifiers_to_node(modifiers, node)
+ return fields
+
+ def _disable_workflow_buttons(self, cr, user, model, node):
+ """ Set the buttons in node to readonly if the user can't activate them. """
+ if model is None or user == 1:
+ # admin user can always activate workflow buttons
+ return node
+
+ # TODO handle the case of more than one workflow for a model or multiple
+ # transitions with different groups and same signal
+ usersobj = self.pool.get('res.users')
+ buttons = (n for n in node.getiterator('button') if n.get('type') != 'object')
+ for button in buttons:
+ user_groups = usersobj.read(cr, user, [user], ['groups_id'])[0]['groups_id']
+ cr.execute("""SELECT DISTINCT t.group_id
+ FROM wkf
+ INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
+ INNER JOIN wkf_transition t ON (t.act_to = a.id)
+ WHERE wkf.osv = %s
+ AND t.signal = %s
+ AND t.group_id is NOT NULL
+ """, (model, button.get('name')))
+ group_ids = [x[0] for x in cr.fetchall() if x[0]]
+ can_click = not group_ids or bool(set(user_groups).intersection(group_ids))
+ button.set('readonly', str(int(not can_click)))
+ return node
+
+ def postprocess_and_fields(self, cr, user, model, node, view_id, context=None):
+ """ Return an architecture and a description of all the fields.
+
+ The field description combines the result of fields_get() and
+ postprocess().
+
+ :param node: the architecture as as an etree
+ :return: a tuple (arch, fields) where arch is the given node as a
+ string and fields is the description of all the fields.
+
+ """
+ fields = {}
+ Model = self.pool.get(model)
+ if not Model:
+ self.raise_view_error(cr, user, _('Model not found: %(model)s') % dict(model=model), view_id, context)
+
+ if node.tag == 'diagram':
+ if node.getchildren()[0].tag == 'node':
+ node_model = self.pool[node.getchildren()[0].get('object')]
+ node_fields = node_model.fields_get(cr, user, None, context)
+ fields.update(node_fields)
+ if not node.get("create") and not node_model.check_access_rights(cr, user, 'create', raise_exception=False):
+ node.set("create", 'false')
+ if node.getchildren()[1].tag == 'arrow':
+ arrow_fields = self.pool[node.getchildren()[1].get('object')].fields_get(cr, user, None, context)
+ fields.update(arrow_fields)
+ else:
+ fields = Model.fields_get(cr, user, None, context)
+
+ fields_def = self.postprocess(cr, user, model, node, view_id, False, fields, context=context)
+ node = self._disable_workflow_buttons(cr, user, model, node)
+ if node.tag in ('kanban', 'tree', 'form', 'gantt'):
+ for action, operation in (('create', 'create'), ('delete', 'unlink'), ('edit', 'write')):
+ if not node.get(action) and not Model.check_access_rights(cr, user, operation, raise_exception=False):
+ node.set(action, 'false')
+ arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
+ for k in fields.keys():
+ if k not in fields_def:
+ del fields[k]
+ for field in fields_def:
+ if field == 'id':
+ # sometime, the view may contain the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
+ fields['id'] = {'readonly': True, 'type': 'integer', 'string': 'ID'}
+ elif field in fields:
+ fields[field].update(fields_def[field])
+ else:
+ message = _("Field `%(field_name)s` does not exist") % \
+ dict(field_name=field)
+ self.raise_view_error(cr, user, message, view_id, context)
+ return arch, fields
+
+ #------------------------------------------------------
+ # QWeb template views
+ #------------------------------------------------------
+ @tools.ormcache_context(accepted_keys=('lang','inherit_branding', 'editable', 'translatable'))
+ def read_template(self, cr, uid, xml_id, context=None):
+ if '.' not in xml_id:
+ raise ValueError('Invalid template id: %r' % (xml_id,))
+
+ view_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, xml_id, raise_if_not_found=True)
+ arch = self.read_combined(cr, uid, view_id, fields=['arch'], context=context)['arch']
+ arch_tree = etree.fromstring(arch)
+
+ if 'lang' in context:
+ arch_tree = self.translate_qweb(cr, uid, view_id, arch_tree, context['lang'], context)
+
+ self.distribute_branding(arch_tree)
+ root = etree.Element('templates')
+ root.append(arch_tree)
+ arch = etree.tostring(root, encoding='utf-8', xml_declaration=True)
+ return arch
+
+ def clear_cache(self):
+ self.read_template.clear_cache(self)
+
+ def distribute_branding(self, e, branding=None, parent_xpath='',
+ index_map=misc.ConstantMapping(1)):
+ if e.get('t-ignore') or e.tag == 'head':
+ # TODO: find a better name and check if we have a string to boolean helper
+ return
+
+ node_path = e.get('data-oe-xpath')
+ if node_path is None:
+ node_path = "%s/%s[%d]" % (parent_xpath, e.tag, index_map[e.tag])
+ if branding and not (e.get('data-oe-model') or e.get('t-field')):
+ e.attrib.update(branding)
+ e.set('data-oe-xpath', node_path)
+ if not e.get('data-oe-model'): return
+
+ # if a branded element contains branded elements distribute own
+ # branding to children unless it's t-raw, then just remove branding
+ # on current element
+ if e.tag == 't' or 't-raw' in e.attrib or \
+ any(self.is_node_branded(child) for child in e.iterdescendants()):
+ distributed_branding = dict(
+ (attribute, e.attrib.pop(attribute))
+ for attribute in MOVABLE_BRANDING
+ if e.get(attribute))
+
+ if 't-raw' not in e.attrib:
+ # TODO: collections.Counter if remove p2.6 compat
+ # running index by tag type, for XPath query generation
+ indexes = collections.defaultdict(lambda: 0)
+ for child in e.iterchildren(tag=etree.Element):
+ if child.get('data-oe-xpath'):
+ # injected by view inheritance, skip otherwise
+ # generated xpath is incorrect
+ continue
+ indexes[child.tag] += 1
+ self.distribute_branding(child, distributed_branding,
+ parent_xpath=node_path,
+ index_map=indexes)
+
+ def is_node_branded(self, node):
+ """ Finds out whether a node is branded or qweb-active (bears a
+ @data-oe-model or a @t-* *which is not t-field* as t-field does not
+ section out views)
+
+ :param node: an etree-compatible element to test
+ :type node: etree._Element
+ :rtype: boolean
+ """
+ return any(
+ (attr == 'data-oe-model' or (attr != 't-field' and attr.startswith('t-')))
+ for attr in node.attrib
+ )
+
+ def translate_qweb(self, cr, uid, id_, arch, lang, context=None):
+ # TODO: this should be moved in a place before inheritance is applied
+ # but process() is only called on fields_view_get()
+ Translations = self.pool['ir.translation']
+ h = HTMLParser.HTMLParser()
+ def get_trans(text):
+ if not text or not text.strip():
+ return None
+ text = h.unescape(text.strip())
+ if len(text) < 2 or (text.startswith('<!') and text.endswith('>')):
+ return None
+ return Translations._get_source(cr, uid, 'website', 'view', lang, text, id_)
+
+ if arch.tag not in ['script']:
+ text = get_trans(arch.text)
+ if text:
+ arch.text = arch.text.replace(arch.text.strip(), text)
+ tail = get_trans(arch.tail)
+ if tail:
+ arch.tail = arch.tail.replace(arch.tail.strip(), tail)
+
+ for attr_name in ('title', 'alt', 'placeholder'):
+ attr = get_trans(arch.get(attr_name))
+ if attr:
+ arch.set(attr_name, attr)
+ for node in arch.iterchildren("*"):
+ self.translate_qweb(cr, uid, id_, node, lang, context)
+ return arch
+
+ @openerp.tools.ormcache()
+ def get_view_xmlid(self, cr, uid, id):
+ imd = self.pool['ir.model.data']
+ domain = [('model', '=', 'ir.ui.view'), ('res_id', '=', id)]
+ xmlid = imd.search_read(cr, uid, domain, ['module', 'name'])[0]
+ return '%s.%s' % (xmlid['module'], xmlid['name'])
+
+ def render(self, cr, uid, id_or_xml_id, values=None, engine='ir.qweb', context=None):
+ if isinstance(id_or_xml_id, list):
+ id_or_xml_id = id_or_xml_id[0]
+ tname = id_or_xml_id
+ if isinstance(tname, (int, long)):
+ tname = self.get_view_xmlid(cr, uid, tname)
+
+ if not context:
+ context = {}
- return super(view, self).write(cr, uid, ids, vals, context)
+ if values is None:
+ values = dict()
+ qcontext = dict(
+ keep_query=keep_query,
+ request=request,
+ json=simplejson,
+ quote_plus=werkzeug.url_quote_plus,
+ )
+ qcontext.update(values)
+
+ def loader(name):
+ return self.read_template(cr, uid, name, context=context)
+
+ return self.pool[engine].render(cr, uid, tname, qcontext, loader=loader, context=context)
+
+ #------------------------------------------------------
+ # Misc
+ #------------------------------------------------------
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node, label, scale, context=None):
nodes=[]
@@ -305,5 +927,4 @@ class view(osv.osv):
ids = map(itemgetter(0), cr.fetchall())
return self._check_xml(cr, uid, ids)
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
+# vim:et:
diff --git a/openerp/addons/base/ir/ir_ui_view_view.xml b/openerp/addons/base/ir/ir_ui_view_view.xml
index 82a7db2c723..f9f9f211da2 100644
--- a/openerp/addons/base/ir/ir_ui_view_view.xml
+++ b/openerp/addons/base/ir/ir_ui_view_view.xml
@@ -17,6 +17,7 @@
<group>
<field name="field_parent"/>
<field name="inherit_id"/>
+ <field name="model_data_id"/>
<field name="xml_id"/>
</group>
</group>
@@ -49,17 +50,19 @@
<field name="model">ir.ui.view</field>
<field name="arch" type="xml">
<search string="Views">
- <field name="name" filter_domain="['|', ('name','ilike',self), ('model','ilike',self)]" string="View"/>
+ <field name="name" filter_domain="['|', '|', ('name','ilike',self), ('model','ilike',self), ('model_data_id','ilike',self)]" string="View"/>
<filter string="Form" domain="[('type', '=','form')]"/>
<filter string="Tree" domain="[('type', '=', 'tree')]"/>
<filter string="Kanban" domain="[('type', '=', 'kanban')]"/>
<filter string="Search" domain="[('type', '=', 'search')]"/>
+ <filter string="QWeb" domain="[('type', '=', 'qweb')]"/>
<field name="model"/>
<field name="inherit_id"/>
<field name="type"/>
<group expand="0" string="Group By...">
- <filter string="Object" icon="terp-stock_align_left_24" domain="[]" context="{'group_by':'model'}"/>
- <filter string="Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'type'}"/>
+ <filter string="Object" domain="[]" context="{'group_by':'model'}"/>
+ <filter string="Type" domain="[]" context="{'group_by':'type'}"/>
+ <filter string="Inherit" domain="[]" context="{'group_by':'inherit_id'}"/>
</group>
</search>
</field>
diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py
index a21b034d1b0..6af09b7ecbb 100644
--- a/openerp/addons/base/ir/ir_values.py
+++ b/openerp/addons/base/ir/ir_values.py
@@ -394,17 +394,16 @@ class ir_values(osv.osv):
for action in cr.dictfetchall():
if not action['value']:
continue # skip if undefined
- action_model,id = action['value'].split(',')
- fields = [
- field
- for field in self.pool[action_model]._all_columns
- if field not in EXCLUDED_FIELDS]
+ action_model_name, action_id = action['value'].split(',')
+ action_model = self.pool.get(action_model_name)
+ if not action_model:
+ continue # unknow model? skip it
+ fields = [field for field in action_model._all_columns if field not in EXCLUDED_FIELDS]
# FIXME: needs cleanup
try:
- action_def = self.pool[action_model].read(cr, uid, int(id), fields, context)
+ action_def = action_model.read(cr, uid, int(action_id), fields, context)
if action_def:
- if action_model in ('ir.actions.report.xml','ir.actions.act_window',
- 'ir.actions.wizard'):
+ if action_model_name in ('ir.actions.report.xml', 'ir.actions.act_window'):
groups = action_def.get('groups_id')
if groups:
cr.execute('SELECT 1 FROM res_groups_users_rel WHERE gid IN %s AND uid=%s',
diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py
index d55061c3900..6ad74857f39 100644
--- a/openerp/addons/base/module/module.py
+++ b/openerp/addons/base/module/module.py
@@ -41,8 +41,9 @@ except ImportError:
from StringIO import StringIO # NOQA
import openerp
-from openerp import modules, tools, addons
+from openerp import modules, tools
from openerp.modules.db import create_categories
+from openerp.modules import get_module_resource
from openerp.tools.parse_version import parse_version
from openerp.tools.translate import _
from openerp.osv import fields, osv, orm
@@ -154,7 +155,7 @@ class module(osv.osv):
def _get_desc(self, cr, uid, ids, field_name=None, arg=None, context=None):
res = dict.fromkeys(ids, '')
for module in self.browse(cr, uid, ids, context=context):
- path = addons.get_module_resource(module.name, 'static/description/index.html')
+ path = get_module_resource(module.name, 'static/description/index.html')
if path:
with tools.file_open(path, 'rb') as desc_file:
doc = desc_file.read()
@@ -233,7 +234,7 @@ class module(osv.osv):
def _get_icon_image(self, cr, uid, ids, field_name=None, arg=None, context=None):
res = dict.fromkeys(ids, '')
for module in self.browse(cr, uid, ids, context=context):
- path = addons.get_module_resource(module.name, 'static', 'description', 'icon.png')
+ path = get_module_resource(module.name, 'static', 'description', 'icon.png')
if path:
image_file = tools.file_open(path, 'rb')
try:
diff --git a/openerp/addons/base/module/module_data.xml b/openerp/addons/base/module/module_data.xml
index f59de0af973..2b7fd2bdab5 100644
--- a/openerp/addons/base/module/module_data.xml
+++ b/openerp/addons/base/module/module_data.xml
@@ -7,6 +7,7 @@
<field name="visible" eval="0" />
</record>
+
<record model="ir.module.category" id="module_category_localization">
<field name="name">Localization</field>
<field name="visible" eval="0" />
@@ -113,6 +114,11 @@
<field name="sequence">15</field>
</record>
+ <record model="ir.module.category" id="module_category_website">
+ <field name="name">Website</field>
+ <field name="sequence">16</field>
+ </record>
+
<record model="ir.module.category" id="module_category_administration">
<field name="name">Administration</field>
<field name="sequence">100</field>
diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py
index b46492d28d7..ae83aa4f2d1 100644
--- a/openerp/addons/base/res/res_company.py
+++ b/openerp/addons/base/res/res_company.py
@@ -124,7 +124,8 @@ class res_company(osv.osv):
'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports."),
'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True),
'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually. Otherwise it will be filled in automatically."),
- 'font': fields.many2one('res.font', string="Font",help="Set the font into the report header, it will be used as default font in the RML reports of the user company"),
+ 'font': fields.many2one('res.font', string="Font", domain=[('mode', 'in', ('Normal', 'Regular', 'all', 'Book'))],
+ help="Set the font into the report header, it will be used as default font in the RML reports of the user company"),
'logo': fields.related('partner_id', 'image', string="Logo", type="binary"),
'logo_web': fields.function(_get_logo_web, string="Logo Web", type="binary", store={
'res.company': (lambda s, c, u, i, x: i, ['partner_id'], 10),
@@ -141,13 +142,13 @@ class res_company(osv.osv):
'state_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country.state', string="Fed. State", multi='address'),
'bank_ids': fields.one2many('res.partner.bank','company_id', 'Bank Accounts', help='Bank accounts related to this company'),
'country_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country', string="Country", multi='address'),
- 'email': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Email", multi='address'),
- 'phone': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Phone", multi='address'),
+ 'email': fields.related('partner_id', 'email', size=64, type='char', string="Email", store=True),
+ 'phone': fields.related('partner_id', 'phone', size=64, type='char', string="Phone", store=True),
'fax': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Fax", multi='address'),
'website': fields.related('partner_id', 'website', string="Website", type="char", size=64),
'vat': fields.related('partner_id', 'vat', string="Tax ID", type="char", size=32),
'company_registry': fields.char('Company Registry', size=64),
- 'paper_format': fields.selection([('a4', 'A4'), ('us_letter', 'US Letter')], "Paper Format", required=True),
+ 'rml_paper_format': fields.selection([('a4', 'A4'), ('us_letter', 'US Letter')], "Paper Format", required=True, oldname='paper_format'),
}
_sql_constraints = [
('name_uniq', 'unique (name)', 'The company name must be unique !')
@@ -388,8 +389,8 @@ class res_company(osv.osv):
_header_a4 = _header_main % ('21.7cm', '27.7cm', '27.7cm', '27.7cm', '27.8cm', '27.3cm', '25.3cm', '25.0cm', '25.0cm', '24.6cm', '24.6cm', '24.5cm', '24.5cm')
_header_letter = _header_main % ('20cm', '26.0cm', '26.0cm', '26.0cm', '26.1cm', '25.6cm', '23.6cm', '23.3cm', '23.3cm', '22.9cm', '22.9cm', '22.8cm', '22.8cm')
- def onchange_paper_format(self, cr, uid, ids, paper_format, context=None):
- if paper_format == 'us_letter':
+ def onchange_rml_paper_format(self, cr, uid, ids, rml_paper_format, context=None):
+ if rml_paper_format == 'us_letter':
return {'value': {'rml_header': self._header_letter}}
return {'value': {'rml_header': self._header_a4}}
@@ -398,7 +399,7 @@ class res_company(osv.osv):
_defaults = {
'currency_id': _get_euro,
- 'paper_format': 'a4',
+ 'rml_paper_format': 'a4',
'rml_header':_get_header,
'rml_header2': _header2,
'rml_header3': _header3,
diff --git a/openerp/addons/base/res/res_company_view.xml b/openerp/addons/base/res/res_company_view.xml
index c037b0e76ac..5139623031f 100644
--- a/openerp/addons/base/res/res_company_view.xml
+++ b/openerp/addons/base/res/res_company_view.xml
@@ -23,9 +23,6 @@
<div>
<field name="logo" widget="image" class="oe_avatar oe_left"/>
</div>
- <div class="oe_right oe_button_box" name="button_box">
- <button name="%(preview_report)d" string="Preview Header/Footer" type="action"/>
- </div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
@@ -75,36 +72,41 @@
<field name="bank_ids" nolabel="1" context="{'default_company_id': active_id, 'footer_hide': False}"
on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
</group>
- <group string="Report Footer Configuration">
- <field name="paper_format" on_change="onchange_paper_format(paper_format)"/>
+ </page>
+ <page string="Configuration">
+ <group>
+ <group name="account_grp" string="Accounting">
+ <field name="currency_id"/>
+ </group>
+ </group>
+ </page>
+ <page string="Reports Configuration">
+ <group string="Footer Configuration">
<field name="custom_footer" on_change="onchange_footer(custom_footer, phone, fax, email, website, vat, company_registry, bank_ids)"/>
<field name="rml_footer" attrs="{'invisible': [('custom_footer','=',False)]}"/>
<field name="rml_footer_readonly" attrs="{'invisible': [('custom_footer','=',True)]}"/>
</group>
+ <group string="RML Configuration">
+ <field name="rml_paper_format" on_change="onchange_rml_paper_format(rml_paper_format)"/>
+ </group>
<group>
<label for="font" />
<div>
<div>
- <field name="font" class="oe_inline" colspan="2" on_change="onchange_font_name(font, rml_header, rml_header2, rml_header3)" domain="[('mode', 'in', ('normal', 'regular', 'all', 'book'))]" />
+ <field name="font" class="oe_inline" colspan="2" on_change="onchange_font_name(font, rml_header, rml_header2, rml_header3)" />
<button string="(reload fonts)" name="act_discover_fonts" type="object" class="oe_link" colspan="1"/>
</div>
</div>
</group>
- </page>
- <page string="Header/Footer" groups="base.group_no_one">
- <label for="rml_header"/>
- <field name="rml_header"/>
- <label for="rml_header2"/>
- <field name="rml_header2"/>
- <label for="rml_header3"/>
- <field name="rml_header3"/>
- </page>
- <page string="Configuration">
- <group>
- <group name="account_grp" string="Accounting">
- <field name="currency_id"/>
- </group>
- </group>
+ <div class="oe_right oe_button_box" name="button_box" groups="base.group_no_one" >
+ <button name="%(preview_report)d" string="Preview Header/Footer" type="action"/>
+ </div>
+ <label for="rml_header" groups="base.group_no_one" />
+ <field name="rml_header" groups="base.group_no_one" />
+ <label for="rml_header2" groups="base.group_no_one" />
+ <field name="rml_header2" groups="base.group_no_one" />
+ <label for="rml_header3" groups="base.group_no_one" />
+ <field name="rml_header3" groups="base.group_no_one" />
</page>
</notebook>
</sheet>
diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py
index 2a7d7bb7f66..4fe6ff1989e 100644
--- a/openerp/addons/base/res/res_config.py
+++ b/openerp/addons/base/res/res_config.py
@@ -415,6 +415,7 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
* For a boolean field like 'group_XXX', ``execute`` adds/removes 'implied_group'
to/from the implied groups of 'group', depending on the field's value.
By default 'group' is the group Employee. Groups are given by their xml id.
+ The attribute 'group' may contain several xml ids, separated by commas.
* For a boolean field like 'module_XXX', ``execute`` triggers the immediate
installation of the module named 'XXX' if the field has value ``True``.
@@ -437,7 +438,7 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
""" return a dictionary with the fields classified by category::
{ 'default': [('default_foo', 'model', 'foo'), ...],
- 'group': [('group_bar', browse_group, browse_implied_group), ...],
+ 'group': [('group_bar', [browse_group], browse_implied_group), ...],
'module': [('module_baz', browse_module), ...],
'other': ['other_field', ...],
}
@@ -446,15 +447,15 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
ir_module = self.pool['ir.module.module']
def ref(xml_id):
mod, xml = xml_id.split('.', 1)
- return ir_model_data.get_object(cr, uid, mod, xml, context)
+ return ir_model_data.get_object(cr, uid, mod, xml, context=context)
defaults, groups, modules, others = [], [], [], []
for name, field in self._columns.items():
if name.startswith('default_') and hasattr(field, 'default_model'):
defaults.append((name, field.default_model, name[8:]))
elif name.startswith('group_') and isinstance(field, fields.boolean) and hasattr(field, 'implied_group'):
- field_group = getattr(field, 'group', 'base.group_user')
- groups.append((name, ref(field_group), ref(field.implied_group)))
+ field_groups = getattr(field, 'group', 'base.group_user').split(',')
+ groups.append((name, map(ref, field_groups), ref(field.implied_group)))
elif name.startswith('module_') and isinstance(field, fields.boolean):
mod_ids = ir_module.search(cr, uid, [('name', '=', name[7:])])
record = ir_module.browse(cr, uid, mod_ids[0], context) if mod_ids else None
@@ -477,8 +478,8 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
res[name] = value
# groups: which groups are implied by the group Employee
- for name, group, implied_group in classified['group']:
- res[name] = implied_group in group.implied_ids
+ for name, groups, implied_group in classified['group']:
+ res[name] = all(implied_group in group.implied_ids for group in groups)
# modules: which modules are installed/to install
for name, module in classified['module']:
@@ -497,6 +498,7 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
ir_values = self.pool['ir.values']
ir_module = self.pool['ir.module.module']
+ res_groups = self.pool['res.groups']
classified = self._get_classified_fields(cr, uid, context)
@@ -507,12 +509,16 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
ir_values.set_default(cr, SUPERUSER_ID, model, field, config[name])
# group fields: modify group / implied groups
- for name, group, implied_group in classified['group']:
+ for name, groups, implied_group in classified['group']:
+ gids = map(int, groups)
if config[name]:
- group.write({'implied_ids': [(4, implied_group.id)]})
+ res_groups.write(cr, uid, gids, {'implied_ids': [(4, implied_group.id)]}, context=context)
else:
- group.write({'implied_ids': [(3, implied_group.id)]})
- implied_group.write({'users': [(3, u.id) for u in group.users]})
+ res_groups.write(cr, uid, gids, {'implied_ids': [(3, implied_group.id)]}, context=context)
+ uids = set()
+ for group in groups:
+ uids.update(map(int, group.users))
+ implied_group.write({'users': [(3, u) for u in uids]})
# other fields: execute all methods that start with 'set_'
for method in dir(self):
diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py
index 94a5f538b25..1419cc7ccb4 100644
--- a/openerp/addons/base/res/res_currency.py
+++ b/openerp/addons/base/res/res_currency.py
@@ -40,20 +40,21 @@ class res_currency(osv.osv):
if context is None:
context = {}
res = {}
- if 'date' in context:
- date = context['date']
- else:
- date = time.strftime('%Y-%m-%d')
- date = date or time.strftime('%Y-%m-%d')
+
+ date = context.get('date') or time.strftime('%Y-%m-%d')
# Convert False values to None ...
currency_rate_type = context.get('currency_rate_type_id') or None
# ... and use 'is NULL' instead of '= some-id'.
operator = '=' if currency_rate_type else 'is'
for id in ids:
- cr.execute("SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %s AND name <= %s AND currency_rate_type_id " + operator +" %s ORDER BY name desc LIMIT 1" ,(id, date, currency_rate_type))
+ cr.execute('SELECT rate FROM res_currency_rate '
+ 'WHERE currency_id = %s '
+ 'AND name <= %s '
+ 'AND currency_rate_type_id ' + operator + ' %s '
+ 'ORDER BY name desc LIMIT 1',
+ (id, date, currency_rate_type))
if cr.rowcount:
- id, rate = cr.fetchall()[0]
- res[id] = rate
+ res[id] = cr.fetchone()[0]
elif not raise_on_no_rate:
res[id] = 0
else:
diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py
index 160e86fd8d2..11a115ba009 100644
--- a/openerp/addons/base/res/res_lang.py
+++ b/openerp/addons/base/res/res_lang.py
@@ -162,9 +162,13 @@ class lang(osv.osv):
]
@tools.ormcache(skiparg=3)
- def _lang_data_get(self, cr, uid, lang_id, monetary=False):
+ def _lang_data_get(self, cr, uid, lang, monetary=False):
+ if type(lang) in (str, unicode):
+ lang = self.search(cr, uid, [('code', '=', lang)]) or \
+ self.search(cr, uid, [('code', '=', 'en_US')])
+ lang = lang[0]
conv = localeconv()
- lang_obj = self.browse(cr, uid, lang_id)
+ lang_obj = self.browse(cr, uid, lang)
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
decimal_point = lang_obj.decimal_point
grouping = lang_obj.grouping
@@ -192,32 +196,29 @@ class lang(osv.osv):
trans_obj.unlink(cr, uid, trans_ids, context=context)
return super(lang, self).unlink(cr, uid, ids, context=context)
+ #
+ # IDS: can be a list of IDS or a list of XML_IDS
+ #
def format(self, cr, uid, ids, percent, value, grouping=False, monetary=False, context=None):
""" Format() will return the language-specific output for float values"""
-
if percent[0] != '%':
raise ValueError("format() must be given exactly one %char format specifier")
- lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
- eval_lang_grouping = eval(lang_grouping)
-
formatted = percent % value
+
# floats and decimal ints need special action!
- if percent[-1] in 'eEfFgG':
- seps = 0
- parts = formatted.split('.')
-
- if grouping:
- parts[0], seps = intersperse(parts[0], eval_lang_grouping, thousands_sep)
-
- formatted = decimal_point.join(parts)
- while seps:
- sp = formatted.find(' ')
- if sp == -1: break
- formatted = formatted[:sp] + formatted[sp+1:]
- seps -= 1
- elif percent[-1] in 'diu':
- if grouping:
+ if grouping:
+ lang_grouping, thousands_sep, decimal_point = \
+ self._lang_data_get(cr, uid, ids[0], monetary)
+ eval_lang_grouping = eval(lang_grouping)
+
+ if percent[-1] in 'eEfFgG':
+ parts = formatted.split('.')
+ parts[0], _ = intersperse(parts[0], eval_lang_grouping, thousands_sep)
+
+ formatted = decimal_point.join(parts)
+
+ elif percent[-1] in 'diu':
formatted = intersperse(formatted, eval_lang_grouping, thousands_sep)[0]
return formatted
diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py
index 02ceebf5777..e9573088680 100644
--- a/openerp/addons/base/res/res_partner.py
+++ b/openerp/addons/base/res/res_partner.py
@@ -23,14 +23,12 @@ import datetime
from lxml import etree
import math
import pytz
-import re
import openerp
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.osv import osv, fields
from openerp.tools.translate import _
-from openerp.tools.yaml_import import is_comment
class format_address(object):
def fields_view_get_address(self, cr, uid, arch, context={}):
@@ -210,6 +208,8 @@ class res_partner(osv.osv, format_address):
def _display_name_compute(self, cr, uid, ids, name, args, context=None):
context = dict(context or {})
context.pop('show_address', None)
+ context.pop('show_address_only', None)
+ context.pop('show_email', None)
return dict(self.name_get(cr, uid, ids, context=context))
# indirections to avoid passing a copy of the overridable method when declaring the function field
@@ -217,12 +217,12 @@ class res_partner(osv.osv, format_address):
_display_name = lambda self, *args, **kwargs: self._display_name_compute(*args, **kwargs)
_commercial_partner_store_triggers = {
- 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
- ['parent_id', 'is_company'], 10)
+ 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)], context=dict(active_test=False)),
+ ['parent_id', 'is_company'], 10)
}
_display_name_store_triggers = {
- 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)]),
- ['parent_id', 'is_company', 'name'], 10)
+ 'res.partner': (lambda self,cr,uid,ids,context=None: self.search(cr, uid, [('id','child_of',ids)], context=dict(active_test=False)),
+ ['parent_id', 'is_company', 'name'], 10)
}
_order = "display_name"
@@ -232,7 +232,7 @@ class res_partner(osv.osv, format_address):
'date': fields.date('Date', select=1),
'title': fields.many2one('res.partner.title', 'Title'),
'parent_id': fields.many2one('res.partner', 'Related Company'),
- 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override
+ 'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override
'ref': fields.char('Reference', size=64, select=1),
'lang': fields.selection(_lang_get, 'Language',
help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."),
@@ -560,10 +560,12 @@ class res_partner(osv.osv, format_address):
name = record.name
if record.parent_id and not record.is_company:
name = "%s, %s" % (record.parent_id.name, name)
+ if context.get('show_address_only'):
+ name = self._display_address(cr, uid, record, without_company=True, context=context)
if context.get('show_address'):
name = name + "\n" + self._display_address(cr, uid, record, without_company=True, context=context)
- name = name.replace('\n\n','\n')
- name = name.replace('\n\n','\n')
+ name = name.replace('\n\n','\n')
+ name = name.replace('\n\n','\n')
if context.get('show_email') and record.email:
name = "%s <%s>" % (name, record.email)
res.append((record.id, name))
@@ -602,7 +604,8 @@ class res_partner(osv.osv, format_address):
""" Override search() to always show inactive children when searching via ``child_of`` operator. The ORM will
always call search() with a simple domain of the form [('parent_id', 'in', [ids])]. """
# a special ``domain`` is set on the ``child_ids`` o2m to bypass this logic, as it uses similar domain expressions
- if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in'):
+ if len(args) == 1 and len(args[0]) == 3 and args[0][:2] == ('parent_id','in') \
+ and args[0][2] != [False]:
context = dict(context or {}, active_test=False)
return super(res_partner, self)._search(cr, user, args, offset=offset, limit=limit, order=order, context=context,
count=count, access_rights_uid=access_rights_uid)
@@ -611,26 +614,36 @@ class res_partner(osv.osv, format_address):
if not args:
args = []
if name and operator in ('=', 'ilike', '=ilike', 'like', '=like'):
+
+ self.check_access_rights(cr, uid, 'read')
+ where_query = self._where_calc(cr, uid, args, context=context)
+ self._apply_ir_rules(cr, uid, where_query, 'read', context=context)
+ from_clause, where_clause, where_clause_params = where_query.get_sql()
+ where_str = where_clause and (" WHERE %s AND " % where_clause) or ' WHERE '
+
# search on the name of the contacts and of its company
search_name = name
if operator in ('ilike', 'like'):
search_name = '%%%s%%' % name
if operator in ('=ilike', '=like'):
operator = operator[1:]
- query_args = {'name': search_name}
- query = ('''SELECT id FROM res_partner
- WHERE email ''' + operator + ''' %(name)s
- OR display_name ''' + operator + ''' %(name)s
- ORDER BY display_name
- ''')
+
+ query = ('SELECT id FROM res_partner ' +
+ where_str + '(email ' + operator + ''' %s
+ OR display_name ''' + operator + ''' %s)
+ ORDER BY display_name''')
+
+ where_clause_params += [search_name, search_name]
if limit:
- query += ' limit %(limit)s'
- query_args['limit'] = limit
- cr.execute(query, query_args)
+ query += ' limit %s'
+ where_clause_params.append(limit)
+ cr.execute(query, where_clause_params)
ids = map(lambda x: x[0], cr.fetchall())
- ids = self.search(cr, uid, [('id', 'in', ids)] + args, limit=limit, context=context)
+
if ids:
return self.name_get(cr, uid, ids, context)
+ else:
+ return []
return super(res_partner,self).name_search(cr, uid, name, args, operator=operator, context=context, limit=limit)
def find_or_create(self, cr, uid, email, context=None):
diff --git a/openerp/addons/base/res/res_partner_demo.xml b/openerp/addons/base/res/res_partner_demo.xml
index 2ef54fbddc0..cffe87b098b 100644
--- a/openerp/addons/base/res/res_partner_demo.xml
+++ b/openerp/addons/base/res/res_partner_demo.xml
@@ -75,7 +75,7 @@
<field name="zip">106</field>
<field name="country_id" ref="base.tw"/>
<field name="street">31 Hong Kong street</field>
- <field name="email">info@asustek.com</field>
+ <field name="email">asusteK@yourcompany.example.com</field>
<field name="phone">(+886) (02) 4162 2023</field>
<field name="website">www.asustek.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_1-image.jpg"/>
@@ -88,7 +88,7 @@
<field name="zip">1300</field>
<field name="country_id" ref="base.be"/>
<field name="street">69 rue de Namur</field>
- <field name="email">info@agrolait.com</field>
+ <field name="email">agrolait@yourcompany.example.com</field>
<field name="phone">+32 10 588 558</field>
<field name="website">www.agrolait.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_2-image.jpg"/>
@@ -103,7 +103,7 @@
<field model="res.country" name="country_id" search="[('name','=','China')]"/>
<field name="country_id" ref="base.cn"/>
<field name="street">52 Chop Suey street</field>
- <field name="email">info@chinaexport.com</field>
+ <field name="email">chinaexport@yourcompany.example.com</field>
<field name="phone">+86 21 6484 5671</field>
<field name="website">www.chinaexport.com/</field>
<field name="image" type="base64" file="base/static/img/res_partner_3-image.png"/>
@@ -120,7 +120,7 @@
<field name="country_id" ref="base.us"/>
<field model="res.country.state" name="state_id" search="[('code','ilike','ca')]"/>
<field name="street">3661 Station Street</field>
- <field name="email">info@deltapc.com</field>
+ <field name="email">deltapc@yourcompany.example.com</field>
<field name="phone">+1 510 340 2385</field>
<field name="website">www.distribpc.com/</field>
<field name="image" type="base64" file="base/static/img/res_partner_4-image.png"/>
@@ -135,25 +135,25 @@
<field model="res.country.state" name="state_id" search="[('code','ilike','il')]"/>
<field name="zip">60610</field>
<field name="city">Chicago</field>
- <field name="email">epic@tech.info</field>
+ <field name="email">epic@yourcompany.example.com</field>
<field name="phone">+1 312 349 2324</field>
<field name="website">www.epic-tech.info//</field>
<field name="image" type="base64" file="base/static/img/res_partner_5-image.jpg"/>
</record>
<record id="res_partner_6" model="res.partner">
- <field name="name">Elec Import</field>
+ <field name="name">OpenElec Applications</field>
<field eval="[(6, 0, [ref('res_partner_category_12')])]" name="category_id"/>
<field eval="1" name="supplier"/>
<field eval="0" name="customer"/>
<field name="is_company">1</field>
- <field name="city">Chicago</field>
- <field name="zip">60623</field>
+ <field name="zip">90001</field>
+ <field name="city">Los Angeles</field>
<field name="country_id" ref="base.us"/>
- <field model="res.country.state" name="state_id" search="[('code','ilike','il')]"/>
+ <field model="res.country.state" name="state_id" search="[('code','ilike','ca')]"/>
<field name="street">23 Rockwell Lane</field>
- <field name="email">info@elecimport.com</field>
- <field name="phone">+1 773 439 3000</field>
+ <field name="email">openelecapplications@yourcompany.example.com</field>
+ <field name="phone">+1 312 349 2121</field>
<field name="image" type="base64" file="base/static/img/res_partner_6-image.jpg"/>
</record>
@@ -168,7 +168,7 @@
<field name="zip">B46 3AG</field>
<field name="country_id" ref="base.uk"/>
<field name="phone">+44 121 690 4596</field>
- <field name="email">email@wealthyandsons.com</field>
+ <field name="email">wealthyandsons@yourcompany.example.com</field>
<field name="website">www.wealthyandsons.com/</field>
<field name="image" type="base64" file="base/static/img/res_partner_7-image.jpg"/>
</record>
@@ -184,6 +184,7 @@
<field name="zip">80352</field>
<field name="country_id" ref="base.de"/>
<field name="phone">+49 8932 450203 </field>
+ <field name="email">mediapole@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_8-image.jpg"/>
</record>
<record id="res_partner_9" model="res.partner">
@@ -195,7 +196,7 @@
<field name="street">203, Systems Plaza</field>
<field name="city">Mumbai</field>
<field name="country_id" ref="base.in"/>
- <field name="email">info@bestdesigners.in</field>
+ <field name="email">bestdesigners@yourcompany.example.com</field>
<field name="phone">+91 22 3445 0349</field>
<field name="website">www.bestdesigners.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_9-image.jpg"/>
@@ -209,7 +210,7 @@
<field name="zip">33169</field>
<field name="country_id" ref="base.us"/>
<field model="res.country.state" name="state_id" search="[('code','=','FL')]"/>
- <field name="email">contact@jackson.com</field>
+ <field name="email">jackson@yourcompany.example.com</field>
<field name="phone">+1 786 525 0724</field>
<field name="street">3203 Lamberts Branch Road</field>
<field name="image" type="base64" file="base/static/img/res_partner_10-image.jpg"/>
@@ -228,6 +229,7 @@
<field name="zip">08078</field>
<field name="phone">+34 934 340 230</field>
<field name="website">www.lumitech.com</field>
+ <field name="email">luminous@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_11-image.png"/>
</record>
@@ -242,7 +244,7 @@
<field name="phone">+33 4 49 23 44 54</field>
<field name="country_id" ref="base.fr"/>
<field name="street">93, Press Avenue</field>
- <field name="email">info@c2c.com</field>
+ <field name="email">camptocamp@yourcompany.example.com</field>
<field name="website">www.camptocamp.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_12-image.jpg"/>
</record>
@@ -255,7 +257,7 @@
<field name="city">Champs sur Marne</field>
<field name="zip">77420</field>
<field name="country_id" ref="base.fr"/>
- <field name="email">info@axelor.com</field>
+ <field name="email">axelor@yourcompany.example.com</field>
<field name="phone">+33 1 64 61 04 01</field>
<field name="street">12 rue Albert Einstein</field>
<field name="website">www.axelor.com/</field>
@@ -274,7 +276,7 @@
<field name="country_id" ref="base.us"/>
<field model="res.country.state" name="state_id" search="[('code','ilike','mi')]"/>
<field name="street">60, Rosewood Court</field>
- <field name="email">info@chamberworks.com</field>
+ <field name="email">chamberworks@yourcompany.example.com</field>
<field name="phone">+1 313 222 3456</field>
<field name="image" type="base64" file="base/static/img/res_partner_14-image.jpg"/>
</record>
@@ -290,6 +292,7 @@
<field name="country_id" ref="base.uk"/>
<field name="city">London</field>
<field name="phone">+44 20 1294 2193</field>
+ <field name="email">millennium@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_15-image.jpg"/>
</record>
@@ -304,6 +307,7 @@
<field name="phone">+55 11 2402 2045</field>
<field name="country_id" ref="base.br"/>
<field name="is_company">1</field>
+ <field name="email">sparksystems@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_16-image.png"/>
</record>
@@ -313,7 +317,7 @@
<field eval="1" name="customer"/>
<field name="is_company">1</field>
<field name="city">Rosario</field>
- <field name="email">contact@nebula.ar</field>
+ <field name="email">nebula@yourcompany.example.com</field>
<field name="street">34 Westwood Avenue</field>
<field name="street2">Capital Federal</field>
<field name="phone">+54 341 324 9459 </field>
@@ -328,7 +332,7 @@
<field eval="[(6, 0, [ref('res_partner_category_5')])]" name="category_id"/>
<field name="city">Boston</field>
<field name="zip">02203</field>
- <field name="email">info@thinkbig.com</field>
+ <field name="email">thinkbig@yourcompany.example.com</field>
<field name="phone">+1 857 349 3049</field>
<field name="country_id" ref="base.us"/>
<field name="street">One Lincoln Street</field>
@@ -347,7 +351,7 @@
<field name="country_id" ref="base.us"/>
<field model="res.country.state" name="state_id" search="[('code','ilike','ca')]"/>
<field name="street">10200 S. De Anza Blvd</field>
- <field name="email">info@seagate.com</field>
+ <field name="email">seagate@yourcompany.example.com</field>
<field name="phone">+1 800 732 4283</field>
<field name="image" type="base64" file="base/static/img/res_partner_19-image.jpg"/>
</record>
@@ -374,6 +378,7 @@
<field name="city">Liverpool</field>
<field name="country_id" ref="base.uk"/>
<field name="zip">L25 4RL</field>
+ <field name="email">globalsolutions@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_21-image.png"/>
</record>
@@ -390,6 +395,7 @@
<field name="phone">+44 20 1294 2193</field>
<field name="country_id" ref="base.uk"/>
<field name="website">www.vicking-direct.com</field>
+ <field name="email">vickingdirect@yourcompany.example.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_22-image.jpg"/>
</record>
@@ -404,12 +410,136 @@
<field name="street2">Carretera Panamericana, Km 1, Urb. Delgado Chalbaud</field>
<field name="city">Caracas</field>
<field name="zip">1090</field>
- <field name="email">info@vauxoo.com</field>
+ <field name="email">vauxoo@yourcompany.example.com</field>
<field name="phone">+58 212 681 0538</field>
<field name="country_id" ref="base.ve"/>
<field name="website">vauxoo.com</field>
<field name="image" type="base64" file="base/static/img/res_partner_23-image.jpg"/>
</record>
-
+ <record id="res_partner_24" model="res.partner">
+ <field name="name">OpenCorp</field>
+ <field eval="[(6, 0, [ref('base.res_partner_category_7'), ref('base.res_partner_category_9')])]" name="category_id"/>
+ <field name="is_company">1</field>
+ <field name="city">Mortsel</field>
+ <field name="zip">2640</field>
+ <field name="country_id" ref="base.be"/>
+ <field name="street">Avenue Louise 149/24</field>
+ <field name="email">opencorp@yourcompany.example.com</field>
+ <field name="phone">+32 3 450 97 11</field>
+ <field name="website">http://www.opencorp.com</field>
+ </record>
+ <record id="res_partner_25" model="res.partner">
+ <field name="name">Míng</field>
+ <field name="supplier">1</field>
+ <field eval="[(6, 0, [ref('res_partner_category_8'), ref('res_partner_category_14')])]" name="category_id"/>
+ <field name="is_company">1</field>
+ <field name="city">Shanghai</field>
+ <field name="zip">201208</field>
+ <field model="res.country" name="country_id" search="[('name','=','China')]"/>
+ <field name="country_id" ref="base.cn"/>
+ <field name="street">89 Dong Lu Road</field>
+ <field name="email">míng@yourcompany.example.com</field>
+ <field name="phone">+86 215 069 5177</field>
+ <field name="website">http://www.míng.com</field>
+ </record>
+ <record id="res_partner_26" model="res.partner">
+ <field name="name">Federal</field>
+ <field name="supplier">1</field>
+ <field eval="[(6, 0, [ref('res_partner_category_8'), ref('res_partner_category_16')])]" name="category_id"/>
+ <field name="is_company">1</field>
+ <field name="city">Düsseldorf</field>
+ <field name="zip">40227</field>
+ <field name="country_id" ref="base.de"/>
+ <field name="street">Willi-Becker-Allee 10</field>
+ <field name="email">federal@yourcompany.example.com</field>
+ <field name="website">http://www.federal.com</field>
+ </record>
+ <record id="res_partner_address_1" model="res.partner">
+ <field name="name">Tang Tsui</field>
+ <field name="parent_id" eval="ref('res_partner_1')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Service Manager</field>
+ <field name="email">tang@asustek.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_2" model="res.partner">
+ <field name="name">Joseph Walters</field>
+ <field name="parent_id" eval="ref('res_partner_1')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Store Manager</field>
+ <field name="email">joseph.walters@asustek.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_7" model="res.partner">
+ <field name="name">Richard Ellis</field>
+ <field name="parent_id" eval="ref('res_partner_4')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Production Supervisor</field>
+ <field name="email">richard.ellis@deltapc.example.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_8" model="res.partner">
+ <field name="name">Paul Williams</field>
+ <field name="parent_id" eval="ref('res_partner_4')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Line Mechanic</field>
+ <field name="email">paul.williams@deltapc.example.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_9" model="res.partner">
+ <field name="name">Brian Williams</field>
+ <field name="parent_id" eval="ref('res_partner_4')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Computer Technician</field>
+ <field name="email">brian.williams@deltapc.example.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_12" model="res.partner">
+ <field name="name">James Miller</field>
+ <field name="parent_id" eval="ref('res_partner_6')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Electrical Supervisor</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_31" model="res.partner">
+ <field name="name">Edward Foster</field>
+ <field name="parent_id" eval="ref('res_partner_19')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Sales Representative</field>
+ <field name="email">efoster@seagate.com</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_27" model="res.partner">
+ <field name="name">Arthur Gomez</field>
+ <field name="parent_id" eval="ref('res_partner_16')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Software Developer</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_26" model="res.partner">
+ <field name="name">Julia Rivero</field>
+ <field name="parent_id" eval="ref('res_partner_16')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Technical Director</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
+ <record id="res_partner_address_35" model="res.partner">
+ <field name="name">Peter Mitchell</field>
+ <field name="parent_id" eval="ref('res_partner_22')"/>
+ <field name="use_parent_address">1</field>
+ <field name="function">Store Manager</field>
+ <field name="supplier">1</field>
+ <field eval="0" name="customer"/>
+ </record>
</data>
</openerp>
+
diff --git a/openerp/addons/base/res/res_partner_demo.yml b/openerp/addons/base/res/res_partner_demo.yml
index 7b4a94d62b4..10b468a5061 100644
--- a/openerp/addons/base/res/res_partner_demo.yml
+++ b/openerp/addons/base/res/res_partner_demo.yml
@@ -1,242 +1,185 @@
-
- !record {model: 'res.partner', id: base.res_partner_address_1}:
- name: Tang Tsui
- parent_id: base.res_partner_1
- use_parent_address: True
- function: Service Manager
- email: tang@asustek.com
--
- !record {model: 'res.partner', id: base.res_partner_address_2}:
- name: Joseph Walters
- parent_id: base.res_partner_1
- use_parent_address: True
- function: Store Manager
- email: joseph.walters@asustek.com
--
!record {model: 'res.partner', id: base.res_partner_address_3}:
name: Thomas Passot
parent_id: base.res_partner_2
use_parent_address: True
function: Functional Consultant
- email: p.thomas@agrolait.com
+ email: thomas.passot@agrolait.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_4}:
name: Michel Fletcher
parent_id: base.res_partner_2
use_parent_address: True
function: Analyst
- email: m.fletcher@agrolait.com
+ email: michel.fletcher@agrolait.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_5}:
name: Chao Wang
parent_id: base.res_partner_3
use_parent_address: True
function: Marketing Manager
- email: chao_wang@chinaexport.com
+ email: chao.wang@chinaexport.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_6}:
name: Zhi Ch'ang
parent_id: base.res_partner_3
use_parent_address: True
function: Supervisor
- email: zhi_chang@chinaexport.com
--
- !record {model: 'res.partner', id: base.res_partner_address_7}:
- name: Richard Ellis
- parent_id: base.res_partner_4
- use_parent_address: True
- function: Production Supervisor
--
- !record {model: 'res.partner', id: base.res_partner_address_8}:
- name: Paul Williams
- parent_id: base.res_partner_4
- use_parent_address: True
- function: Line Mechanic
- email:
--
- !record {model: 'res.partner', id: base.res_partner_address_9}:
- name: Brian Williams
- parent_id: base.res_partner_4
- use_parent_address: True
- function: Computer Technician
- email:
+ email: zhi.chang@chinaexport.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_10}:
name: David Simpson
parent_id: base.res_partner_5
use_parent_address: True
function: Senior Consultant
- email: david.s@tech.info
+ email: david.simpson@epic.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_11}:
name: John M. Brown
parent_id: base.res_partner_5
use_parent_address: True
function: Director
- email: john.b@tech.info
--
- !record {model: 'res.partner', id: base.res_partner_address_12}:
- name: James Miller
- parent_id: base.res_partner_6
- use_parent_address: True
- function: Electrical Supervisor
+ email: john.brown@epic.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_13}:
name: Charlie Bernard
parent_id: base.res_partner_7
use_parent_address: True
function: Senior Associate
- email: charlie.bernard@wealthyandsons.com
+ email: charlie.bernard@wealthyandsons.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_14}:
name: Jessica Dupont
parent_id: base.res_partner_7
use_parent_address: True
function: Analyst
- email: jessica.dupont@wealthyandsons.com
+ email: jessica.dupont@wealthyandsons.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_15}:
name: Phillipp Miller
parent_id: base.res_partner_8
use_parent_address: True
function: Creative Director
+ email: phillipp.miller@mediapole.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_16}:
name: Ayaan Agarwal
parent_id: base.res_partner_9
use_parent_address: True
function: Director
+ email: ayaan.agarwal@bestdesigners.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_17}:
name: Daniel Jackson
parent_id: base.res_partner_10
use_parent_address: True
function: Managing Partner
- email: daniel@jackson.com
+ email: daniel.jackson@jackson.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_18}:
name: William Thomas
parent_id: base.res_partner_10
use_parent_address: True
function: Senior Consultant
- email: william@jackson.com
+ email: william.jackson@jackson.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_19}:
name: Sergio Pérez
parent_id: base.res_partner_11
use_parent_address: True
function: Accountant
- email:
+ email: sergio.perez@luminous.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_20}:
name: Laura Castro
parent_id: base.res_partner_11
use_parent_address: True
function: Goods Supervisor
- email:
+ email: laura.castro@luminous.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_21}:
name: Luc Maurer
parent_id: base.res_partner_12
use_parent_address: True
function: Director
+ email: luc.maurer@camptocamp.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_22}:
name: Laith Jubair
parent_id: base.res_partner_13
use_parent_address: True
function: Director
+ email: laith.jubair@axelor.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_23}:
name: Angel Cook
parent_id: base.res_partner_14
use_parent_address: True
function: General Manager
- email: angel.cook@chamberworks.com
+ email: angel.cook@chamberworks.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_24}:
name: Robert Anderson
parent_id: base.res_partner_14
use_parent_address: True
function: System Analyst
- email: robert.anderson@chamberworks.com
+ email: robert.anderson@chamberworks.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_25}:
name: Jacob Taylor
parent_id: base.res_partner_15
use_parent_address: True
function: Order Clerk
--
- !record {model: 'res.partner', id: base.res_partner_address_26}:
- name: Arthur Gomez
- parent_id: base.res_partner_16
- use_parent_address: True
- function: Software Developer
- email:
--
- !record {model: 'res.partner', id: base.res_partner_address_27}:
- name: Julia Rivero
- parent_id: base.res_partner_16
- use_parent_address: True
- function: Technical Director
+ email: jacob.taylor@millennium.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_28}:
name: Benjamin Flores
parent_id: base.res_partner_17
use_parent_address: True
function: Business Executive
- email: ben@nebula.ar
+ email: benjamin.flores@nebula.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_29}:
name: George Wilson
parent_id: base.res_partner_18
use_parent_address: True
function: Chief Information Officer (CIO)
- email:
+ email: george.wilson@thinkbig.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_30}:
name: Lucas Jones
parent_id: base.res_partner_18
use_parent_address: True
function: Functional Consultant
- email: jones@thinkbig.com
--
- !record {model: 'res.partner', id: base.res_partner_address_31}:
- name: Edward Foster
- parent_id: base.res_partner_19
- use_parent_address: True
- function: Sales Representative
- email: efoster@seagate.com
+ email: lucas.jones@thinkbig.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_32}:
name: Robin Smith
parent_id: base.res_partner_21
use_parent_address: True
function: Sales Manager
+ email: robin.smith@globalsolutions.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_33}:
name: Morgan Rose
parent_id: base.res_partner_21
use_parent_address: True
function: Financial Manager
+ email: morgan.rose@globalsolutions.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_34}:
name: Kevin Clarke
parent_id: base.res_partner_21
use_parent_address: True
function: Knowledge Manager
--
- !record {model: 'res.partner', id: base.res_partner_address_35}:
- name: Peter Mitchell
- parent_id: base.res_partner_22
- use_parent_address: True
- function: Store Manager
+ email: kevin.clarke@globalsolutions.example.com
-
!record {model: 'res.partner', id: base.res_partner_address_36}:
name: Nhomar Hernandez
parent_id: base.res_partner_23
use_parent_address: True
function: Chief Executive Officer
+ email: nhomar.hernandez@vauxoo.example.com
-
!record {model: 'res.partner', id: base.res_partner_main1}:
name: Mark Davis
@@ -244,7 +187,7 @@
parent_id: base.main_partner
use_parent_address: True
function: Chief Executive Officer (CEO)
- email: mark@yourcompany.com
+ email: mark.davis@yourcompany.example.com
-
!record {model: 'res.partner', id: base.res_partner_main2}:
name: Roger Scott
@@ -252,4 +195,4 @@
parent_id: base.main_partner
use_parent_address: True
function: Chief Operations Officer (COO)
- email: roger@yourcompany.com
+ email: roger.scott@yourcompany.example.com
diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml
index 822c6a36fd2..a0e32ab83bd 100644
--- a/openerp/addons/base/res/res_partner_view.xml
+++ b/openerp/addons/base/res/res_partner_view.xml
@@ -129,7 +129,7 @@
<form string="Partners" version="7.0">
<sheet>
<field name="image" widget='image' class="oe_left oe_avatar" options='{"preview_image": "image_medium", "size": [90, 90]}'/>
- <div class="oe_title">
+ <div class="oe_title oe_left">
<div class="oe_edit_only">
<label for="name"/> (
<field name="is_company" on_change="onchange_type(is_company)" class="oe_inline"/> <label for="is_company" string="Is a Company?"/>)
diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py
index 789f9202cbc..b2aba694078 100644
--- a/openerp/addons/base/res/res_users.py
+++ b/openerp/addons/base/res/res_users.py
@@ -600,6 +600,7 @@ class users_implied(osv.osv):
if groups:
# delegate addition of groups to add implied groups
self.write(cr, uid, [user_id], {'groups_id': groups}, context)
+ self.pool['ir.ui.view'].clear_cache()
return user_id
def write(self, cr, uid, ids, values, context=None):
@@ -612,6 +613,7 @@ class users_implied(osv.osv):
gs = set(concat([g.trans_implied_ids for g in user.groups_id]))
vals = {'groups_id': [(4, g.id) for g in gs]}
super(users_implied, self).write(cr, uid, [user.id], vals, context)
+ self.pool['ir.ui.view'].clear_cache()
return res
#----------------------------------------------------------
@@ -681,8 +683,10 @@ class groups_view(osv.osv):
def update_user_groups_view(self, cr, uid, context=None):
# the view with id 'base.user_groups_view' inherits the user form view,
# and introduces the reified group fields
- view = self.get_user_groups_view(cr, uid, context)
- if view:
+ # we have to try-catch this, because at first init the view does not exist
+ # but we are already creating some basic groups
+ view = self.pool['ir.model.data'].xmlid_to_object(cr, SUPERUSER_ID, 'base.user_groups_view', context=context)
+ if view and view.exists() and view._table_name == 'ir.ui.view':
xml1, xml2 = [], []
xml1.append(E.separator(string=_('Application'), colspan="4"))
for app, kind, gs in self.get_groups_by_application(cr, uid, context):
@@ -707,14 +711,6 @@ class groups_view(osv.osv):
view.write({'arch': xml_content})
return True
- def get_user_groups_view(self, cr, uid, context=None):
- try:
- view = self.pool['ir.model.data'].get_object(cr, SUPERUSER_ID, 'base', 'user_groups_view', context)
- assert view and view._table_name == 'ir.ui.view'
- except Exception:
- view = False
- return view
-
def get_application_groups(self, cr, uid, domain=None, context=None):
return self.search(cr, uid, domain or [])
@@ -910,6 +906,8 @@ class change_password_wizard(osv.TransientModel):
for user in wizard.user_ids:
user_ids.append(user.id)
self.pool.get('change.password.user').change_password_button(cr, uid, user_ids, context=context)
+ # don't keep temporary password copies in the database longer than necessary
+ self.pool.get('change.password.user').unlink(cr, uid, user_ids)
return {
'type': 'ir.actions.act_window_close',
}
diff --git a/openerp/addons/base/res/res_users_view.xml b/openerp/addons/base/res/res_users_view.xml
index 9c84d4326f4..ba603c7a0f0 100644
--- a/openerp/addons/base/res/res_users_view.xml
+++ b/openerp/addons/base/res/res_users_view.xml
@@ -231,7 +231,7 @@
<field name="model">res.users</field>
<field name="arch" type="xml">
<search string="Users">
- <field name="name" filter_domain="['|', '|', ('name','ilike',self), ('login','ilike',self), ('email,'ilike',self)]" string="User"/>
+ <field name="name" filter_domain="['|', '|', ('name','ilike',self), ('login','ilike',self), ('email','ilike',self)]" string="User"/>
<field name="company_ids" string="Company" groups="base.group_multi_company"/>
</search>
</field>
diff --git a/openerp/addons/base/rng/view.rng b/openerp/addons/base/rng/view.rng
index 0f161a91f51..794eade6b89 100644
--- a/openerp/addons/base/rng/view.rng
+++ b/openerp/addons/base/rng/view.rng
@@ -590,6 +590,7 @@
<rng:optional><rng:attribute name="filters"/></rng:optional>
<rng:optional><rng:attribute name="statusbar_visible"/></rng:optional>
<rng:optional><rng:attribute name="statusbar_colors"/></rng:optional>
+ <rng:optional><rng:attribute name="interval" /></rng:optional>
<!-- Widget *static* options defined as an arbitrary JSON dict, with
widget-dependent parameters. To be ignored if widget/client does
not support them. -->
diff --git a/openerp/addons/base/security/base_security.xml b/openerp/addons/base/security/base_security.xml
index 4bd78e353cf..27e55bf24d1 100644
--- a/openerp/addons/base/security/base_security.xml
+++ b/openerp/addons/base/security/base_security.xml
@@ -57,6 +57,16 @@
<field name="domain_force">['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field>
</record>
+ <record model="ir.rule" id="res_partner_portal_public_rule">
+ <field name="name">res_partner: portal/public: read access on my commercial partner</field>
+ <field name="model_id" ref="base.model_res_partner"/>
+ <field name="domain_force">[('id', 'child_of', user.commercial_partner_id.id)]</field>
+ <field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
+ <field name="perm_create" eval="False"/>
+ <field name="perm_unlink" eval="False"/>
+ <field name="perm_write" eval="False"/>
+ </record>
+
<record model="ir.rule" id="multi_company_default_rule">
<field name="name">Multi_company_default company</field>
<field name="model_id" ref="model_multi_company_default"/>
diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv
index cb391a45701..25df6e117d0 100644
--- a/openerp/addons/base/security/ir.model.access.csv
+++ b/openerp/addons/base/security/ir.model.access.csv
@@ -43,8 +43,6 @@
"access_ir_values_group_all","ir_values group_all","model_ir_values",,1,1,1,1
"access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1
"access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0
-"access_res_font_group_erp_manager","res_font group_erp_manager","model_res_font","group_erp_manager",1,1,1,1
-"access_res_font_group_all","res_font group_all","model_res_font",,1,0,0,0
"access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0
"access_res_country_state_group_all","res_country_state group_user_all","model_res_country_state",,1,0,0,0
"access_res_country_group_user","res_country group_user","model_res_country","group_partner_manager",1,1,1,1
@@ -58,6 +56,8 @@
"access_res_groups_group_user","res_groups group_user","model_res_groups",,1,0,0,0
"access_res_lang_group_all","res_lang group_all","model_res_lang",,1,0,0,0
"access_res_lang_group_user","res_lang group_user","model_res_lang","group_system",1,1,1,1
+"access_res_partner_public","res_partner group_public","model_res_partner","group_public",1,0,0,0
+"access_res_partner_portal","res_partner group_portal","model_res_partner","group_portal",1,0,0,0
"access_res_partner_group_partner_manager","res_partner group_partner_manager","model_res_partner","group_partner_manager",1,1,1,1
"access_res_partner_group_user","res_partner group_user","model_res_partner","group_user",1,0,0,0
"access_res_partner_bank_group_user","res_partner_bank group_user","model_res_partner_bank","group_user",1,0,0,0
@@ -111,4 +111,5 @@
"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
"access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1
-
+"access_res_font_all","res_res_font all","model_res_font",,1,0,0,0
+"access_res_font_group_user","res_res_font group_user","model_res_font","group_user",1,1,1,1
diff --git a/openerp/addons/base/static/img/public_user-image.png b/openerp/addons/base/static/img/public_user-image.png
new file mode 100644
index 00000000000..e333176e3e4
--- /dev/null
+++ b/openerp/addons/base/static/img/public_user-image.png
Binary files differ
diff --git a/openerp/addons/base/test/bug_lp541545.xml b/openerp/addons/base/test/bug_lp541545.xml
deleted file mode 100644
index 79c3c05c729..00000000000
--- a/openerp/addons/base/test/bug_lp541545.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <!-- Test count attribute for assertions -->
- <data>
- <assert
- model="res.currency.rate"
- search="[('currency_id', '=', ref('INR'))]"
- count="1"
- string="Rate entries for Indian rupee">
- <test expr="True"/>
- </assert>
- </data>
-
-</openerp>
diff --git a/openerp/addons/base/test/test_context.xml b/openerp/addons/base/test/test_context.xml
deleted file mode 100644
index d308fc3dea8..00000000000
--- a/openerp/addons/base/test/test_context.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <!-- Test context attribute for unit tests -->
- <data context="{'date': '2009-06-01'}">
-<!-- <assert -->
-<!-- model="res.currency"-->
-<!-- id="INR"-->
-<!-- string="Indian rupee rate in 2009">-->
- <!-- date specified in data element's context -->
-<!-- <test expr="str(rate)">65.8287</test>-->
-<!-- </assert> -->
- <assert
- model="res.currency"
- id="INR"
- string="Indian rupee rate in 2002"
- context="{'date': '2010-06-01'}">
- <test expr="rate_ids and str(rate_ids[0].rate)">59.9739</test>
- </assert>
- </data>
-</openerp>
diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py
index 0306839b5d3..2e55989ba19 100644
--- a/openerp/addons/base/tests/__init__.py
+++ b/openerp/addons/base/tests/__init__.py
@@ -1,23 +1,26 @@
+import test_acl
import test_base
+import test_basecase
+import test_db_cursor
import test_expression
+import test_expression
+import test_fields
+import test_func
import test_ir_actions
import test_ir_attachment
+import test_ir_filters
+import test_ir_sequence
import test_ir_values
+import test_mail
import test_menu
+import test_orm
+import test_osv
+import test_qweb
import test_res_config
import test_res_lang
import test_search
+import test_translate
+#import test_uninstall
+import test_view_validation
import test_views
-
-checks = [
- test_base,
- test_expression,
- test_ir_actions,
- test_ir_attachment,
- test_ir_values,
- test_menu,
- test_res_config,
- test_res_lang,
- test_search,
- test_views,
-]
+import test_xmlrpc
diff --git a/openerp/tests/test_acl.py b/openerp/addons/base/tests/test_acl.py
index 44ec677ff6f..f3fa0bb2b1d 100644
--- a/openerp/tests/test_acl.py
+++ b/openerp/addons/base/tests/test_acl.py
@@ -3,8 +3,7 @@ from lxml import etree
import openerp
from openerp.tools.misc import mute_logger
-
-import common
+from openerp.tests import common
# test group that demo user should not have
GROUP_TECHNICAL_FEATURES = 'base.group_no_one'
@@ -17,7 +16,7 @@ class TestACL(common.TransactionCase):
self.res_currency = self.registry('res.currency')
self.res_partner = self.registry('res.partner')
self.res_users = self.registry('res.users')
- self.demo_uid = 3
+ _, self.demo_uid = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, 'base', 'user_demo')
self.tech_group = self.registry('ir.model.data').get_object(self.cr, self.uid,
*(GROUP_TECHNICAL_FEATURES.split('.')))
@@ -104,7 +103,6 @@ class TestACL(common.TransactionCase):
finally:
self.res_partner._columns['email'].groups = False
-
if __name__ == '__main__':
unittest2.main()
diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py
index 4cc54aeaf9d..263cb0adf23 100644
--- a/openerp/addons/base/tests/test_base.py
+++ b/openerp/addons/base/tests/test_base.py
@@ -8,6 +8,7 @@ class test_base(common.TransactionCase):
def setUp(self):
super(test_base,self).setUp()
self.res_partner = self.registry('res.partner')
+ self.res_users = self.registry('res.users')
# samples use effective TLDs from the Mozilla public suffix
# list at http://publicsuffix.org
@@ -39,6 +40,20 @@ class test_base(common.TransactionCase):
new_id2 = self.res_partner.find_or_create(cr, uid, self.samples[2][0])
self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again')
+ def test_15_res_partner_name_search(self):
+ cr,uid = self.cr, self.uid
+ for name, active in [
+ ('"A Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr>', False),
+ ('B Raoul chirurgiens-dentistes.fr', True),
+ ("C Raoul O'hara <!@historicalsociety.museum>", True),
+ ('ryu+giga-Sushi@aizubange.fukushima.jp', True),
+ ]:
+ partner_id, dummy = self.res_partner.name_create(cr, uid, name, context={'default_active': active})
+ partners = self.res_partner.name_search(cr, uid, 'Raoul')
+ self.assertEqual(len(partners), 2, 'Incorrect search number result for name_search')
+ partners = self.res_partner.name_search(cr, uid, 'Raoul', limit=1)
+ self.assertEqual(len(partners), 1, 'Incorrect search number result for name_search with a limit')
+ self.assertEqual(partners[0][1], 'B Raoul chirurgiens-dentistes.fr', 'Incorrect partner returned, should be the first active')
def test_20_res_partner_address_sync(self):
cr, uid = self.cr, self.uid
@@ -268,6 +283,30 @@ class test_base(common.TransactionCase):
p0.refresh()
self.assertEquals(p0.vat, sunhelmvat2, 'Commercial fields must be automatically synced')
+ def test_60_read_group(self):
+ cr, uid = self.cr, self.uid
+ for user_data in [
+ {'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend'},
+ {'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend'},
+ {'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper'},
+ {'name': 'Nab', 'login': 'nab', 'color': 2, 'function': '5$ Wrench'},
+ ]:
+ self.res_users.create(cr, uid, user_data)
+
+ groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve'))], fields=['name', 'color', 'function'], groupby='function')
+ self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field")
+ for group_data in groups_data:
+ self.assertIn('color', group_data, "Aggregated data for the column 'color' is not present in read_group return values")
+ self.assertEqual(group_data['color'], 3, "Incorrect sum for aggregated data for the column 'color'")
+
+ groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve'))], fields=['name', 'color'], groupby='name', orderby='name DESC, color asc')
+ self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field")
+ self.assertEqual([user['name'] for user in groups_data], ['Eve', 'Bob', 'Alice'], 'Incorrect ordering of the list')
+
+ groups_data = self.res_users.read_group(cr, uid, domain=[('login', 'in', ('alice', 'bob', 'eve', 'nab'))], fields=['function', 'color'], groupby='function', orderby='color ASC')
+ self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field")
+ self.assertEqual(groups_data, sorted(groups_data, key=lambda x: x['color']), 'Incorrect ordering of the list')
+
class test_partner_recursion(common.TransactionCase):
def setUp(self):
@@ -345,6 +384,59 @@ class test_translation(common.TransactionCase):
fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_FR'})
self.assertEqual(fr_context_cat.name, 'Clients (copie)', "Did not used default value for translated value")
+test_state = None
+#: Stores state information across multiple test classes
+def setUpModule():
+ global test_state
+ test_state = {}
+def tearDownModule():
+ global test_state
+ test_state = None
+
+class TestPhaseInstall00(unittest2.TestCase):
+ """
+ WARNING: Relies on tests being run in alphabetical order
+ """
+ @classmethod
+ def setUpClass(cls):
+ cls.state = None
+
+ def test_00_setup(self):
+ type(self).state = 'init'
+
+ @common.at_install(False)
+ def test_01_no_install(self):
+ type(self).state = 'error'
+
+ def test_02_check(self):
+ self.assertEqual(
+ self.state, 'init',
+ "Testcase state should not have been transitioned from 00")
+
+class TestPhaseInstall01(unittest2.TestCase):
+ at_install = False
+
+ def test_default_norun(self):
+ self.fail("An unmarket test in a non-at-install case should not run")
+
+ @common.at_install(True)
+ def test_set_run(self):
+ test_state['set_at_install'] = True
+
+class TestPhaseInstall02(unittest2.TestCase):
+ """
+ Can't put the check for test_set_run in the same class: if
+ @common.at_install does not work for test_set_run, it won't work for
+ the other one either. Thus move checking of whether test_set_run has
+ correctly run indeed to a separate class.
+
+ Warning: relies on *classes* being run in alphabetical order in test
+ modules
+ """
+ def test_check_state(self):
+ self.assertTrue(
+ test_state.get('set_at_install'),
+ "The flag should be set if local overriding of runstate")
if __name__ == '__main__':
unittest2.main()
diff --git a/openerp/tests/test_basecase.py b/openerp/addons/base/tests/test_basecase.py
index 376494b571e..8b06eff7858 100644
--- a/openerp/tests/test_basecase.py
+++ b/openerp/addons/base/tests/test_basecase.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import unittest2
-import common
+from openerp.tests import common
class test_single_transaction_case(common.SingleTransactionCase):
"""
diff --git a/openerp/tests/test_db_cursor.py b/openerp/addons/base/tests/test_db_cursor.py
index dba1cf47b64..b3ce36467bb 100644
--- a/openerp/tests/test_db_cursor.py
+++ b/openerp/addons/base/tests/test_db_cursor.py
@@ -4,7 +4,7 @@ import unittest2
import openerp
from openerp.tools.misc import mute_logger
-import common
+from openerp.tests import common
DB = common.DB
ADMIN_USER_ID = common.ADMIN_USER_ID
diff --git a/openerp/addons/base/tests/test_expression.py b/openerp/addons/base/tests/test_expression.py
index 4f533a5e170..a05009b0252 100644
--- a/openerp/addons/base/tests/test_expression.py
+++ b/openerp/addons/base/tests/test_expression.py
@@ -1,8 +1,9 @@
import unittest2
+
+import openerp
from openerp.osv.orm import BaseModel
import openerp.tests.common as common
-
class test_expression(common.TransactionCase):
def _reinit_mock(self):
@@ -439,5 +440,13 @@ class test_expression(common.TransactionCase):
partner_parent_id_col._auto_join = False
state_country_id_col._auto_join = False
+ def test_30_normalize_domain(self):
+ expression = openerp.osv.expression
+ norm_domain = domain = ['&', (1, '=', 1), ('a', '=', 'b')]
+ assert norm_domain == expression.normalize_domain(domain), "Normalized domains should be left untouched"
+ domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')]
+ norm_domain = ['&', '&', '&'] + domain
+ assert norm_domain == expression.normalize_domain(domain), "Non-normalized domains should be properly normalized"
+
if __name__ == '__main__':
unittest2.main()
diff --git a/openerp/tests/test_fields.py b/openerp/addons/base/tests/test_fields.py
index 774bbf41fb2..47ffcd2f5b1 100644
--- a/openerp/tests/test_fields.py
+++ b/openerp/addons/base/tests/test_fields.py
@@ -1,9 +1,8 @@
#
# test cases for fields access, etc.
#
-import common
-
from openerp.osv import fields
+from openerp.tests import common
class TestRelatedField(common.TransactionCase):
@@ -121,4 +120,62 @@ class TestRelatedField(common.TransactionCase):
# restore res.partner fields
self.partner._columns = old_columns
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+
+class TestPropertyField(common.TransactionCase):
+
+ def setUp(self):
+ super(TestPropertyField, self).setUp()
+ self.user = self.registry('res.users')
+ self.partner = self.registry('res.partner')
+ self.company = self.registry('res.company')
+ self.country = self.registry('res.country')
+ self.property = self.registry('ir.property')
+ self.imd = self.registry('ir.model.data')
+
+ def test_1_property_multicompany(self):
+ cr, uid = self.cr, self.uid
+
+ parent_company_id = self.imd.get_object_reference(cr, uid, 'base', 'main_company')[1]
+ country_be = self.imd.get_object_reference(cr, uid, 'base', 'be')[1]
+ country_fr = self.imd.get_object_reference(cr, uid, 'base', 'fr')[1]
+ group_partner_manager = self.imd.get_object_reference(cr, uid, 'base', 'group_partner_manager')[1]
+ group_multi_company = self.imd.get_object_reference(cr, uid, 'base', 'group_multi_company')[1]
+
+ sub_company = self.company.create(cr, uid, {'name': 'MegaCorp', 'parent_id': parent_company_id})
+ alice = self.user.create(cr, uid, {'name': 'Alice',
+ 'login':'alice',
+ 'email':'alice@youcompany.com',
+ 'company_id':parent_company_id,
+ 'company_ids':[(6, 0, [parent_company_id, sub_company])],
+ 'country_id':country_be,
+ 'groups_id': [(6, 0, [group_partner_manager, group_multi_company])]
+ })
+ bob = self.user.create(cr, uid, {'name': 'Bob',
+ 'login':'bob',
+ 'email':'bob@megacorp.com',
+ 'company_id':sub_company,
+ 'company_ids':[(6, 0, [parent_company_id, sub_company])],
+ 'country_id':country_fr,
+ 'groups_id': [(6, 0, [group_partner_manager, group_multi_company])]
+ })
+
+ self.partner._columns = dict(self.partner._columns)
+ self.partner._columns.update({
+ 'property_country': fields.property(type='many2one', relation="res.country", string="Country by company"),
+ })
+ self.partner._all_columns.update({
+ 'property_country': fields.column_info('property_country', self.partner._columns['property_country'], None, None, None),
+ })
+ self.partner._field_create(cr)
+
+ partner_id = self.partner.create(cr, alice, {
+ 'name': 'An International Partner',
+ 'email': 'partner@example.com',
+ 'company_id': parent_company_id,
+ })
+ self.partner.write(cr, bob, [partner_id], {'property_country': country_fr})
+ self.assertEqual(self.partner.browse(cr, bob, partner_id).property_country.id, country_fr, "Bob does not see the value he has set on the property field")
+
+ self.partner.write(cr, alice, [partner_id], {'property_country': country_be})
+ self.assertEqual(self.partner.browse(cr, alice, partner_id).property_country.id, country_be, "Alice does not see the value he has set on the property field")
+ self.assertEqual(self.partner.browse(cr, bob, partner_id).property_country.id, country_fr, "Changes made by Alice have overwritten Bob's value")
diff --git a/openerp/addons/base/tests/test_func.py b/openerp/addons/base/tests/test_func.py
new file mode 100644
index 00000000000..e6dfab20825
--- /dev/null
+++ b/openerp/addons/base/tests/test_func.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+import functools
+import unittest2
+
+from openerp.tools.func import compose
+
+class TestCompose(unittest2.TestCase):
+ def test_basic(self):
+ str_add = compose(str, lambda a, b: a + b)
+ self.assertEqual(
+ str_add(1, 2),
+ "3")
+
+ def test_decorator(self):
+ """ ensure compose() can be partially applied as a decorator
+ """
+ @functools.partial(compose, unicode)
+ def mul(a, b):
+ return a * b
+
+ self.assertEqual(mul(5, 42), u"210")
+
diff --git a/openerp/addons/base/tests/test_ir_actions.py b/openerp/addons/base/tests/test_ir_actions.py
index 04f67617ad6..baea8299f9e 100644
--- a/openerp/addons/base/tests/test_ir_actions.py
+++ b/openerp/addons/base/tests/test_ir_actions.py
@@ -97,7 +97,8 @@ class TestServerActions(TestServerActionsBase):
self.ir_actions_server.write(cr, uid, self.act_id, {
'state': 'code',
'code': """partner_name = obj.name + '_code'
-self.pool["res.partner"].create(cr, uid, {"name": partner_name}, context=context)"""
+self.pool["res.partner"].create(cr, uid, {"name": partner_name}, context=context)
+workflow"""
})
run_res = self.ir_actions_server.run(cr, uid, [self.act_id], context=self.context)
self.assertFalse(run_res, 'ir_actions_server: code server action correctly finished should return False')
diff --git a/openerp/tests/test_ir_filters.py b/openerp/addons/base/tests/test_ir_filters.py
index daf58a380e1..04ecca74525 100644
--- a/openerp/tests/test_ir_filters.py
+++ b/openerp/addons/base/tests/test_ir_filters.py
@@ -2,23 +2,7 @@
import functools
from openerp import exceptions
-from . import common
-
-class Fixtures(object):
- def __init__(self, *args):
- self.fixtures = args
-
- def __call__(self, fn):
- @functools.wraps(fn)
- def wrapper(case):
- for model, vars in self.fixtures:
- case.registry(model).create(
- case.cr, common.ADMIN_USER_ID, vars, {})
-
- fn(case)
- return wrapper
-def fixtures(*args):
- return Fixtures(*args)
+from openerp.tests import common
def noid(d):
""" Removes `id` key from a dict so we don't have to keep these things
@@ -27,17 +11,26 @@ def noid(d):
if 'id' in d: del d['id']
return d
-class TestGetFilters(common.TransactionCase):
- USER_ID = 3
- USER = (3, u'Demo User')
+class FiltersCase(common.TransactionCase):
+ def build(self, model, *args):
+ Model = self.registry(model)
+ for vars in args:
+ Model.create(self.cr, common.ADMIN_USER_ID, vars, {})
+
+class TestGetFilters(FiltersCase):
+ def setUp(self):
+ super(TestGetFilters, self).setUp()
+ self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
+ self.USER_ID = self.USER[0]
- @fixtures(
- ('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='b', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='c', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='d', user_id=USER_ID, model_id='ir.filters')),
- )
def test_own_filters(self):
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='b', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='c', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='d', user_id=self.USER_ID, model_id='ir.filters'))
+
filters = self.registry('ir.filters').get_filters(
self.cr, self.USER_ID, 'ir.filters')
@@ -48,13 +41,15 @@ class TestGetFilters(common.TransactionCase):
dict(name='d', is_default=False, user_id=self.USER, domain='[]', context='{}'),
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='c', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='d', user_id=False, model_id='ir.filters')),
- )
def test_global_filters(self):
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', user_id=False, model_id='ir.filters'),
+ dict(name='c', user_id=False, model_id='ir.filters'),
+ dict(name='d', user_id=False, model_id='ir.filters'),
+ )
+
filters = self.registry('ir.filters').get_filters(
self.cr, self.USER_ID, 'ir.filters')
@@ -65,13 +60,14 @@ class TestGetFilters(common.TransactionCase):
dict(name='d', is_default=False, user_id=False, domain='[]', context='{}'),
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', user_id=common.ADMIN_USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='c', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='d', user_id=common.ADMIN_USER_ID, model_id='ir.filters')),
- )
def test_no_third_party_filters(self):
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', user_id=common.ADMIN_USER_ID, model_id='ir.filters'),
+ dict(name='c', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='d', user_id=common.ADMIN_USER_ID, model_id='ir.filters') )
+
filters = self.registry('ir.filters').get_filters(
self.cr, self.USER_ID, 'ir.filters')
@@ -80,9 +76,11 @@ class TestGetFilters(common.TransactionCase):
dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}'),
])
-class TestOwnDefaults(common.TransactionCase):
- USER_ID = 3
- USER = (3, u'Demo User')
+class TestOwnDefaults(FiltersCase):
+ def setUp(self):
+ super(TestOwnDefaults, self).setUp()
+ self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
+ self.USER_ID = self.USER[0]
def test_new_no_filter(self):
"""
@@ -103,15 +101,17 @@ class TestOwnDefaults(common.TransactionCase):
domain='[]', context='{}')
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='b', user_id=USER_ID, model_id='ir.filters')),
- )
def test_new_filter_not_default(self):
"""
When creating a @is_default filter with existing non-default filters,
the new filter gets the flag
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='b', user_id=self.USER_ID, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
Filters.create_or_replace(self.cr, self.USER_ID, {
'name': 'c',
@@ -127,15 +127,17 @@ class TestOwnDefaults(common.TransactionCase):
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}'),
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='b', is_default=True, user_id=USER_ID, model_id='ir.filters')),
- )
def test_new_filter_existing_default(self):
"""
When creating a @is_default filter where an existing filter is already
@is_default, the flag should be *moved* from the old to the new filter
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
Filters.create_or_replace(self.cr, self.USER_ID, {
'name': 'c',
@@ -151,15 +153,17 @@ class TestOwnDefaults(common.TransactionCase):
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}'),
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
- ('ir.filters', dict(name='b', is_default=True, user_id=USER_ID, model_id='ir.filters')),
- )
def test_update_filter_set_default(self):
"""
When updating an existing filter to @is_default, if an other filter
already has the flag the flag should be moved
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=self.USER_ID, model_id='ir.filters'),
+ dict(name='b', is_default=True, user_id=self.USER_ID, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
Filters.create_or_replace(self.cr, self.USER_ID, {
'name': 'a',
@@ -174,18 +178,23 @@ class TestOwnDefaults(common.TransactionCase):
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}'),
])
-class TestGlobalDefaults(common.TransactionCase):
- USER_ID = 3
+class TestGlobalDefaults(FiltersCase):
+ def setUp(self):
+ super(TestGlobalDefaults, self).setUp()
+ self.USER = self.registry('res.users').name_search(self.cr, self.uid, 'demo')[0]
+ self.USER_ID = self.USER[0]
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', user_id=False, model_id='ir.filters')),
- )
def test_new_filter_not_default(self):
"""
When creating a @is_default filter with existing non-default filters,
the new filter gets the flag
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', user_id=False, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
Filters.create_or_replace(self.cr, self.USER_ID, {
'name': 'c',
@@ -201,15 +210,17 @@ class TestGlobalDefaults(common.TransactionCase):
dict(name='c', user_id=False, is_default=True, domain='[]', context='{}'),
])
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
- )
def test_new_filter_existing_default(self):
"""
When creating a @is_default filter where an existing filter is already
@is_default, an error should be generated
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
with self.assertRaises(exceptions.Warning):
Filters.create_or_replace(self.cr, self.USER_ID, {
@@ -219,15 +230,17 @@ class TestGlobalDefaults(common.TransactionCase):
'is_default': True,
})
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
- )
def test_update_filter_set_default(self):
"""
When updating an existing filter to @is_default, if an other filter
already has the flag an error should be generated
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
with self.assertRaises(exceptions.Warning):
@@ -238,14 +251,16 @@ class TestGlobalDefaults(common.TransactionCase):
'is_default': True,
})
- @fixtures(
- ('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
- ('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
- )
def test_update_default_filter(self):
"""
Replacing the current default global filter should not generate any error
"""
+ self.build(
+ 'ir.filters',
+ dict(name='a', user_id=False, model_id='ir.filters'),
+ dict(name='b', is_default=True, user_id=False, model_id='ir.filters'),
+ )
+
Filters = self.registry('ir.filters')
context_value = "{'some_key': True}"
Filters.create_or_replace(self.cr, self.USER_ID, {
diff --git a/openerp/tests/test_ir_sequence.py b/openerp/addons/base/tests/test_ir_sequence.py
index cbb1a347038..bc428d7f647 100644
--- a/openerp/tests/test_ir_sequence.py
+++ b/openerp/addons/base/tests/test_ir_sequence.py
@@ -11,7 +11,7 @@ import psycopg2
import unittest2
import openerp
-import common
+from openerp.tests import common
DB = common.DB
ADMIN_USER_ID = common.ADMIN_USER_ID
diff --git a/openerp/tests/test_mail.py b/openerp/addons/base/tests/test_mail.py
index 3ddd3439899..4ebec837c6d 100755..100644
--- a/openerp/tests/test_mail.py
+++ b/openerp/addons/base/tests/test_mail.py
@@ -22,18 +22,22 @@
#
##############################################################################
-from lxml import etree
import unittest2
-from . import test_mail_examples
+
+from lxml import etree
+
from openerp.tools import html_sanitize, html_email_clean, append_content_to_html, plaintext2html, email_split
+import test_mail_examples
+
+
class TestSanitizer(unittest2.TestCase):
""" Test the html sanitizer that filters html to remove unwanted attributes """
def test_basic_sanitizer(self):
cases = [
("yop", "<p>yop</p>"), # simple
- ("lala<p>yop</p>xxx", "<div><p>lala</p><p>yop</p>xxx</div>"), # trailing text
+ ("lala<p>yop</p>xxx", "<p>lala</p><p>yop</p>xxx"), # trailing text
("Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci",
u"<p>Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci</p>"), # unicode
]
@@ -276,6 +280,40 @@ class TestCleaner(unittest2.TestCase):
for ext in test_mail_examples.THUNDERBIRD_1_OUT:
self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
+ def test_70_read_more_and_shorten(self):
+ expand_options = {
+ 'oe_expand_container_class': 'span_class',
+ 'oe_expand_container_content': 'Herbert Einstein',
+ 'oe_expand_separator_node': 'br_lapin',
+ 'oe_expand_a_class': 'a_class',
+ 'oe_expand_a_content': 'read mee',
+ }
+ new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_1, remove=True, shorten=True, max_length=100, expand_options=expand_options)
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_1_IN:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content')
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_1_OUT:
+ self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content')
+ for ext in ['<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>']:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options')
+
+ new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=False)
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content')
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT:
+ self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content')
+ for ext in ['<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>']:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options')
+
+ new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=True)
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content')
+ for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT:
+ self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content')
+ for ext in [
+ '<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>',
+ 'tasks using the gantt chart and control deadlines']:
+ self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options')
+
def test_70_read_more(self):
new_html = html_email_clean(test_mail_examples.BUG1, remove=True, shorten=True, max_length=100)
for ext in test_mail_examples.BUG_1_IN:
diff --git a/openerp/tests/test_mail_examples.py b/openerp/addons/base/tests/test_mail_examples.py
index 54671106334..6886ce86baa 100644
--- a/openerp/tests/test_mail_examples.py
+++ b/openerp/addons/base/tests/test_mail_examples.py
@@ -60,6 +60,154 @@ EDI_LIKE_HTML_SOURCE = """<div style="font-family: 'Lucica Grande', Ubuntu, Aria
</div>
</div></body></html>"""
+OERP_WEBSITE_HTML_1 = """
+<div>
+ <div class="container">
+ <div class="row">
+ <div class="col-md-12 text-center mt16 mb16" data-snippet-id="colmd">
+ <h2>OpenERP HR Features</h2>
+ <h3 class="text-muted">Manage your company most important asset: People</h3>
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg">
+ <h4 class="mt16">Streamline Recruitments</h4>
+ <p>Post job offers and keep track of each application received. Follow applicants in your recruitment process with the smart kanban view.</p>
+ <p>Save time by automating some communications with email templates. Resumes are indexed automatically, allowing you to easily find for specific profiles.</p>
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg">
+ <h4 class="mt16">Enterprise Social Network</h4>
+ <p>Break down information silos. Share knowledge and best practices amongst all employees. Follow specific people or documents and join groups of interests to share expertise and documents.</p>
+ <p>Interact with your collegues in real time with live chat.</p>
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg">
+ <h4 class="mt16">Leaves Management</h4>
+ <p>Keep track of the vacation days accrued by each employee. Employees enter their requests (paid holidays, sick leave, etc), for managers to approve and validate. It's all done in just a few clicks. The agenda of each employee is updated accordingly.</p>
+ </div>
+ </div>
+ </div>
+</div>"""
+
+OERP_WEBSITE_HTML_1_IN = [
+ 'Manage your company most important asset: People',
+ 'img class="img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg"',
+]
+OERP_WEBSITE_HTML_1_OUT = [
+ 'Break down information silos.',
+ 'Keep track of the vacation days accrued by each employee',
+ 'img class="img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg',
+]
+
+OERP_WEBSITE_HTML_2 = """
+<div class="mt16 cke_widget_editable cke_widget_element oe_editable oe_dirty" data-oe-model="blog.post" data-oe-id="6" data-oe-field="content" data-oe-type="html" data-oe-translate="0" data-oe-expression="blog_post.content" data-cke-widget-data="{}" data-cke-widget-keep-attr="0" data-widget="oeref" contenteditable="true" data-cke-widget-editable="text">
+ <section class="mt16 mb16" data-snippet-id="text-block">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-12 text-center mt16 mb32" data-snippet-id="colmd">
+ <h2>
+ OpenERP Project Management
+ </h2>
+ <h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
+ </div>
+ <div class="col-md-12 mb16 mt16" data-snippet-id="colmd">
+ <p>
+ OpenERP's <b>collaborative and realtime</b> project
+ management helps your team get work done. Keep
+ track of everything, from the big picture to the
+ minute details, from the customer contract to the
+ billing.
+ </p><p>
+ Organize projects around <b>your own processes</b>. Work
+ on tasks and issues using the kanban view, schedule
+ tasks using the gantt chart and control deadlines
+ in the calendar view. Every project may have it's
+ own stages allowing teams to optimize their job.
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+ <section class="" data-snippet-id="image-text">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-6 mt16 mb16" data-snippet-id="colmd">
+ <img class="img-responsive shadow" src="/website/static/src/img/image_text.jpg">
+ </div>
+ <div class="col-md-6 mt32" data-snippet-id="colmd">
+ <h3>Manage Your Shops</h3>
+ <p>
+ OpenERP's Point of Sale introduces a super clean
+ interface with no installation required that runs
+ online and offline on modern hardwares.
+ </p><p>
+ It's full integration with the company inventory
+ and accounting, gives you real time statistics and
+ consolidations amongst all shops without the hassle
+ of integrating several applications.
+ </p>
+ </div>
+ </div>
+ </div>
+ </section>
+ <section class="" data-snippet-id="text-image">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-6 mt32" data-snippet-id="colmd">
+ <h3>Enterprise Social Network</h3>
+ <p>
+ Make every employee feel more connected and engaged
+ with twitter-like features for your own company. Follow
+ people, share best practices, 'like' top ideas, etc.
+ </p><p>
+ Connect with experts, follow what interests you, share
+ documents and promote best practices with OpenERP
+ Social application. Get work done with effective
+ collaboration across departments, geographies
+ and business applications.
+ </p>
+ </div>
+ <div class="col-md-6 mt16 mb16" data-snippet-id="colmd">
+ <img class="img-responsive shadow" src="/website/static/src/img/text_image.png">
+ </div>
+ </div>
+ </div>
+ </section><section class="" data-snippet-id="portfolio">
+ <div class="container">
+ <div class="row">
+ <div class="col-md-12 text-center mt16 mb32" data-snippet-id="colmd">
+ <h2>Our Porfolio</h2>
+ <h4 class="text-muted">More than 500 successful projects</h4>
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/deers.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/desert.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/china.jpg">
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/desert.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/china.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/deers.jpg">
+ </div>
+ <div class="col-md-4" data-snippet-id="colmd">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/landscape.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/china.jpg">
+ <img class="img-thumbnail img-responsive" src="/website/static/src/img/desert.jpg">
+ </div>
+ </div>
+ </div>
+ </section>
+</div>
+"""
+
+OERP_WEBSITE_HTML_2_IN = [
+ 'management helps your team get work done',
+]
+OERP_WEBSITE_HTML_2_OUT = [
+ 'Make every employee feel more connected',
+ 'img class="img-responsive shadow" src="/website/static/src/img/text_image.png',
+]
+
TEXT_1 = """I contact you about our meeting tomorrow. Here is the schedule I propose:
9 AM: brainstorming about our new amazing business app
9.45 AM: summary
diff --git a/openerp/tests/test_misc.py b/openerp/addons/base/tests/test_misc.py
index 9540c0222f3..11cc3f49638 100644
--- a/openerp/tests/test_misc.py
+++ b/openerp/addons/base/tests/test_misc.py
@@ -1,8 +1,6 @@
-# This test can be run stand-alone with something like:
-# > PYTHONPATH=. python2 openerp/tests/test_misc.py
-
import unittest2
-from ..tools import misc
+
+from openerp.tools import misc
class test_countingstream(unittest2.TestCase):
diff --git a/openerp/tests/test_orm.py b/openerp/addons/base/tests/test_orm.py
index 9e2a9c4a65f..fcd81965b8c 100644
--- a/openerp/tests/test_orm.py
+++ b/openerp/addons/base/tests/test_orm.py
@@ -1,6 +1,6 @@
from collections import defaultdict
from openerp.tools import mute_logger
-import common
+from openerp.tests import common
UID = common.ADMIN_USER_ID
DB = common.DB
@@ -131,26 +131,15 @@ class TestORM(common.TransactionCase):
else:
domain = main_domain
- display_format, groupby_format = {
- 'year': ('YYYY', 'yyyy'),
- 'month': ('YYYY-MM', 'yyyy-mm'),
- 'day': ('yyyy-MM-dd', 'yyyy-mm-dd'),
- }[interval]
-
- datetime_format = {
- 'date': dict(interval=interval, display_format=display_format, groupby_format=groupby_format)
- }
- context = dict(datetime_format=datetime_format)
-
- rg = self.partner.read_group(self.cr, self.uid, domain, ['date'], 'date', context=context)
+ rg = self.partner.read_group(self.cr, self.uid, domain, ['date'], 'date' + ':' + interval)
result = {}
for r in rg:
result[r['date']] = set(self.partner.search(self.cr, self.uid, r['__domain']))
return result
- self.assertDictEqual(read_group('day'), partners_by_day)
- self.assertDictEqual(read_group('month'), partners_by_month)
- self.assertDictEqual(read_group('year'), partners_by_year)
+ self.assertEqual(len(read_group('day')), len(partners_by_day))
+ self.assertEqual(len(read_group('month')), len(partners_by_month))
+ self.assertEqual(len(read_group('year')), len(partners_by_year))
class TestInherits(common.TransactionCase):
diff --git a/openerp/tests/test_osv.py b/openerp/addons/base/tests/test_osv.py
index e36495fc7c6..e36495fc7c6 100644
--- a/openerp/tests/test_osv.py
+++ b/openerp/addons/base/tests/test_osv.py
diff --git a/openerp/addons/base/tests/test_qweb.py b/openerp/addons/base/tests/test_qweb.py
new file mode 100644
index 00000000000..71beaab605a
--- /dev/null
+++ b/openerp/addons/base/tests/test_qweb.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+import cgi
+from xml.dom import minidom as dom
+
+from openerp.tests import common
+from openerp.addons.base.ir import ir_qweb
+
+impl = dom.getDOMImplementation()
+document = impl.createDocument(None, None, None)
+
+class TestQWebTField(common.TransactionCase):
+ def setUp(self):
+ super(TestQWebTField, self).setUp()
+ self.engine = self.registry('ir.qweb')
+
+ def context(self, values):
+ return ir_qweb.QWebContext(self.cr, self.uid, values)
+
+ def test_trivial(self):
+ field = document.createElement('span')
+ field.setAttribute('t-field', u'company.name')
+
+ Companies = self.registry('res.company')
+ company_id = Companies.create(self.cr, self.uid, {
+ 'name': "My Test Company"
+ })
+ result = self.engine.render_node(field, self.context({
+ 'company': Companies.browse(self.cr, self.uid, company_id),
+ }))
+
+ self.assertEqual(
+ result,
+ '<span data-oe-model="res.company" data-oe-id="%d" '
+ 'data-oe-field="name" data-oe-type="char" '
+ 'data-oe-expression="company.name">%s</span>' % (
+ company_id,
+ "My Test Company",))
+
+ def test_i18n(self):
+ field = document.createElement('span')
+ field.setAttribute('t-field', u'company.name')
+
+ Companies = self.registry('res.company')
+ s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!"
+ company_id = Companies.create(self.cr, self.uid, {
+ 'name': s,
+ })
+ result = self.engine.render_node(field, self.context({
+ 'company': Companies.browse(self.cr, self.uid, company_id),
+ }))
+
+ self.assertEqual(
+ result,
+ '<span data-oe-model="res.company" data-oe-id="%d" '
+ 'data-oe-field="name" data-oe-type="char" '
+ 'data-oe-expression="company.name">%s</span>' % (
+ company_id,
+ cgi.escape(s.encode('utf-8')),))
+
+ def test_reject_crummy_tags(self):
+ field = document.createElement('td')
+ field.setAttribute('t-field', u'company.name')
+
+ with self.assertRaisesRegexp(
+ AssertionError,
+ r'^RTE widgets do not work correctly'):
+ self.engine.render_node(field, self.context({
+ 'company': None
+ }))
+
+ def test_reject_t_tag(self):
+ field = document.createElement('t')
+ field.setAttribute('t-field', u'company.name')
+
+ with self.assertRaisesRegexp(
+ AssertionError,
+ r'^t-field can not be used on a t element'):
+ self.engine.render_node(field, self.context({
+ 'company': None
+ }))
diff --git a/openerp/tests/test_translate.py b/openerp/addons/base/tests/test_translate.py
index d9f771b69fb..d9f771b69fb 100644
--- a/openerp/tests/test_translate.py
+++ b/openerp/addons/base/tests/test_translate.py
diff --git a/openerp/tests/test_uninstall.py b/openerp/addons/base/tests/test_uninstall.py
index 6f6a623f6a9..2425249afa4 100644
--- a/openerp/tests/test_uninstall.py
+++ b/openerp/addons/base/tests/test_uninstall.py
@@ -15,9 +15,9 @@ def registry(model):
def cursor():
return openerp.modules.registry.RegistryManager.get(DB).db.cursor()
-def model_exists(model_name):
+def get_module(module_name):
registry = openerp.modules.registry.RegistryManager.get(DB)
- return model_name in registry
+ return registry.get(module_name)
def reload_registry():
openerp.modules.registry.RegistryManager.new(
@@ -61,7 +61,7 @@ class test_uninstall(unittest2.TestCase):
def test_01_install(self):
""" Check a few things showing the module is installed. """
install_module('test_uninstall')
- assert model_exists('test_uninstall.model')
+ assert get_module('test_uninstall.model')
assert search_registry('ir.model.data',
[('module', '=', 'test_uninstall')])
@@ -72,7 +72,7 @@ class test_uninstall(unittest2.TestCase):
def test_02_uninstall(self):
""" Check a few things showing the module is uninstalled. """
uninstall_module('test_uninstall')
- assert not model_exists('test_uninstall.model')
+ assert not get_module('test_uninstall.model')
assert not search_registry('ir.model.data',
[('module', '=', 'test_uninstall')])
diff --git a/openerp/tests/test_view_validation.py b/openerp/addons/base/tests/test_view_validation.py
index 362bdc5d851..4cd8b95bbaa 100644
--- a/openerp/tests/test_view_validation.py
+++ b/openerp/addons/base/tests/test_view_validation.py
@@ -4,7 +4,10 @@ from lxml import etree
from StringIO import StringIO
import unittest2
-from openerp.tools.view_validation import *
+from openerp.tools.view_validation import (valid_page_in_book, valid_att_in_form, valid_type_in_colspan,
+ valid_type_in_col, valid_att_in_field, valid_att_in_label,
+ valid_field_in_graph, valid_field_in_tree
+ )
invalid_form = etree.parse(StringIO('''\
<form>
@@ -79,7 +82,7 @@ invalid_tree = etree.parse(StringIO('''\
</tree>
''')).getroot()
-valid_tree= etree.parse(StringIO('''\
+valid_tree = etree.parse(StringIO('''\
<tree string="">
<field name=""></field>
<field name=""></field>
@@ -97,15 +100,14 @@ class test_view_validation(unittest2.TestCase):
assert valid_page_in_book(valid_form)
def test_all_field_validation(self):
- assert not valid_att_in_field(invalid_form)
- assert valid_att_in_field(valid_form)
+ assert not valid_att_in_field(invalid_form)
+ assert valid_att_in_field(valid_form)
def test_all_label_validation(self):
- assert not valid_att_in_label(invalid_form)
- assert valid_att_in_label(valid_form)
+ assert not valid_att_in_label(invalid_form)
+ assert valid_att_in_label(valid_form)
def test_form_string_validation(self):
- assert not valid_att_in_form(invalid_form)
assert valid_att_in_form(valid_form)
def test_graph_validation(self):
diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py
index 8ad5e5c8b73..6780996ed6e 100644
--- a/openerp/addons/base/tests/test_views.py
+++ b/openerp/addons/base/tests/test_views.py
@@ -1,47 +1,479 @@
+# -*- encoding: utf-8 -*-
from functools import partial
-import unittest2
-import lxml.etree
+from lxml import etree as ET
from lxml.builder import E
-import openerp.tests.common as common
-from openerp.osv.orm import except_orm
-from openerp.tools import mute_logger
+from openerp.tests import common
-class test_views(common.TransactionCase):
+Field = E.field
+
+class TestNodeLocator(common.BaseCase):
+ """
+ The node locator returns None when it can not find a node, and the first
+ match when it finds something (no jquery-style node sets)
+ """
+ def setUp(self):
+ super(TestNodeLocator, self).setUp()
+ self.Views = self.registry('ir.ui.view')
+
+ def test_no_match_xpath(self):
+ """
+ xpath simply uses the provided @expr pattern to find a node
+ """
+ node = self.Views.locate_node(
+ E.root(E.foo(), E.bar(), E.baz()),
+ E.xpath(expr="//qux"))
+ self.assertIsNone(node)
+
+ def test_match_xpath(self):
+ bar = E.bar()
+ node = self.Views.locate_node(
+ E.root(E.foo(), bar, E.baz()),
+ E.xpath(expr="//bar"))
+ self.assertIs(node, bar)
+
+
+ def test_no_match_field(self):
+ """
+ A field spec will match by @name against all fields of the view
+ """
+ node = self.Views.locate_node(
+ E.root(E.foo(), E.bar(), E.baz()),
+ Field(name="qux"))
+ self.assertIsNone(node)
+
+ node = self.Views.locate_node(
+ E.root(Field(name="foo"), Field(name="bar"), Field(name="baz")),
+ Field(name="qux"))
+ self.assertIsNone(node)
+
+ def test_match_field(self):
+ bar = Field(name="bar")
+ node = self.Views.locate_node(
+ E.root(Field(name="foo"), bar, Field(name="baz")),
+ Field(name="bar"))
+ self.assertIs(node, bar)
+
+
+ def test_no_match_other(self):
+ """
+ Non-xpath non-fields are matched by node name first
+ """
+ node = self.Views.locate_node(
+ E.root(E.foo(), E.bar(), E.baz()),
+ E.qux())
+ self.assertIsNone(node)
+
+ def test_match_other(self):
+ bar = E.bar()
+ node = self.Views.locate_node(
+ E.root(E.foo(), bar, E.baz()),
+ E.bar())
+ self.assertIs(bar, node)
+
+ def test_attribute_mismatch(self):
+ """
+ Non-xpath non-field are filtered by matching attributes on spec and
+ matched nodes
+ """
+ node = self.Views.locate_node(
+ E.root(E.foo(attr='1'), E.bar(attr='2'), E.baz(attr='3')),
+ E.bar(attr='5'))
+ self.assertIsNone(node)
+
+ def test_attribute_filter(self):
+ match = E.bar(attr='2')
+ node = self.Views.locate_node(
+ E.root(E.bar(attr='1'), match, E.root(E.bar(attr='3'))),
+ E.bar(attr='2'))
+ self.assertIs(node, match)
+
+ def test_version_mismatch(self):
+ """
+ A @version on the spec will be matched against the view's version
+ """
+ node = self.Views.locate_node(
+ E.root(E.foo(attr='1'), version='4'),
+ E.foo(attr='1', version='3'))
+ self.assertIsNone(node)
+
+class TestViewInheritance(common.TransactionCase):
+ def arch_for(self, name, view_type='form', parent=None):
+ """ Generates a trivial view of the specified ``view_type``.
+
+ The generated view is empty but ``name`` is set as its root's ``@string``.
+
+ If ``parent`` is not falsy, generates an extension view (instead of
+ a root view) replacing the parent's ``@string`` by ``name``
+
+ :param str name: ``@string`` value for the view root
+ :param str view_type:
+ :param bool parent:
+ :return: generated arch
+ :rtype: str
+ """
+ if not parent:
+ element = E(view_type, string=name)
+ else:
+ element = E(view_type,
+ E.attribute(name, name='string'),
+ position='attributes'
+ )
+ return ET.tostring(element)
+
+ def makeView(self, name, parent=None, arch=None):
+ """ Generates a basic ir.ui.view with the provided name, parent and arch.
+
+ If no parent is provided, the view is top-level.
+
+ If no arch is provided, generates one by calling :meth:`~.arch_for`.
+
+ :param str name:
+ :param int parent: id of the parent view, if any
+ :param str arch:
+ :returns: the created view's id.
+ :rtype: int
+ """
+ view_id = self.View.create(self.cr, self.uid, {
+ 'model': self.model,
+ 'name': name,
+ 'arch': arch or self.arch_for(name, parent=parent),
+ 'inherit_id': parent,
+ 'priority': 5, # higher than default views
+ })
+ self.ids[name] = view_id
+ return view_id
+
+ def setUp(self):
+ super(TestViewInheritance, self).setUp()
+
+ self.model = 'ir.ui.view.custom'
+ self.View = self.registry('ir.ui.view')
+ self._init = self.View.pool._init
+ self.View.pool._init = False
+ self.ids = {}
+
+ a = self.makeView("A")
+ a1 = self.makeView("A1", a)
+ a11 = self.makeView("A11", a1)
+ self.makeView("A111", a11)
+ self.makeView("A12", a1)
+ a2 = self.makeView("A2", a)
+ self.makeView("A21", a2)
+ a22 = self.makeView("A22", a2)
+ self.makeView("A221", a22)
+
+ b = self.makeView('B', arch=self.arch_for("B", 'tree'))
+ self.makeView('B1', b, arch=self.arch_for("B1", 'tree', parent=b))
+ c = self.makeView('C', arch=self.arch_for("C", 'tree'))
+ self.View.write(self.cr, self.uid, c, {'priority': 1})
+
+ def tearDown(self):
+ self.View.pool._init = self._init
+ super(TestViewInheritance, self).tearDown()
+
+ def test_get_inheriting_views_arch(self):
+ self.assertEqual(self.View.get_inheriting_views_arch(
+ self.cr, self.uid, self.ids['A'], self.model), [
+ (self.arch_for('A1', parent=True), self.ids['A1']),
+ (self.arch_for('A2', parent=True), self.ids['A2']),
+ ])
+
+ self.assertEqual(self.View.get_inheriting_views_arch(
+ self.cr, self.uid, self.ids['A21'], self.model),
+ [])
+
+ self.assertEqual(self.View.get_inheriting_views_arch(
+ self.cr, self.uid, self.ids['A11'], self.model),
+ [(self.arch_for('A111', parent=True), self.ids['A111'])])
+
+ def test_default_view(self):
+ default = self.View.default_view(
+ self.cr, self.uid, model=self.model, view_type='form')
+ self.assertEqual(default, self.ids['A'])
+
+ default_tree = self.View.default_view(
+ self.cr, self.uid, model=self.model, view_type='tree')
+ self.assertEqual(default_tree, self.ids['C'])
+
+ def test_no_default_view(self):
+ self.assertFalse(
+ self.View.default_view(
+ self.cr, self.uid, model='does.not.exist', view_type='form'))
+
+ self.assertFalse(
+ self.View.default_view(
+ self.cr, self.uid, model=self.model, view_type='graph'))
+
+class TestApplyInheritanceSpecs(common.TransactionCase):
+ """ Applies a sequence of inheritance specification nodes to a base
+ architecture. IO state parameters (cr, uid, model, context) are used for
+ error reporting
+
+ The base architecture is altered in-place.
+ """
+ def setUp(self):
+ super(TestApplyInheritanceSpecs, self).setUp()
+ self.View = self.registry('ir.ui.view')
+ self.base_arch = E.form(
+ Field(name="target"),
+ string="Title")
+
+ def test_replace(self):
+ spec = Field(
+ Field(name="replacement"),
+ name="target", position="replace")
+
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(Field(name="replacement"), string="Title")))
+
+ def test_delete(self):
+ spec = Field(name="target", position="replace")
+
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(string="Title")))
+
+ def test_insert_after(self):
+ spec = Field(
+ Field(name="inserted"),
+ name="target", position="after")
+
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(
+ Field(name="target"),
+ Field(name="inserted"),
+ string="Title"
+ )))
+
+ def test_insert_before(self):
+ spec = Field(
+ Field(name="inserted"),
+ name="target", position="before")
- @mute_logger('openerp.osv.orm', 'openerp.addons.base.ir.ir_ui_view')
- def test_whatever(self):
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(
+ Field(name="inserted"),
+ Field(name="target"),
+ string="Title")))
+
+ def test_insert_inside(self):
+ default = Field(Field(name="inserted"), name="target")
+ spec = Field(Field(name="inserted 2"), name="target", position='inside')
+
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ default, None)
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(
+ Field(
+ Field(name="inserted"),
+ Field(name="inserted 2"),
+ name="target"),
+ string="Title")))
+
+ def test_unpack_data(self):
+ spec = E.data(
+ Field(Field(name="inserted 0"), name="target"),
+ Field(Field(name="inserted 1"), name="target"),
+ Field(Field(name="inserted 2"), name="target"),
+ Field(Field(name="inserted 3"), name="target"),
+ )
+
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ self.assertEqual(
+ ET.tostring(self.base_arch),
+ ET.tostring(E.form(
+ Field(
+ Field(name="inserted 0"),
+ Field(name="inserted 1"),
+ Field(name="inserted 2"),
+ Field(name="inserted 3"),
+ name="target"),
+ string="Title")))
+
+ def test_invalid_position(self):
+ spec = Field(
+ Field(name="whoops"),
+ name="target", position="serious_series")
+
+ with self.assertRaises(AttributeError):
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+ def test_incorrect_version(self):
+ # Version ignored on //field elements, so use something else
+ arch = E.form(E.element(foo="42"))
+ spec = E.element(
+ Field(name="placeholder"),
+ foo="42", version="7.0")
+
+ with self.assertRaises(AttributeError):
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ arch,
+ spec, None)
+
+ def test_target_not_found(self):
+ spec = Field(name="targut")
+
+ with self.assertRaises(AttributeError):
+ self.View.apply_inheritance_specs(self.cr, self.uid,
+ self.base_arch,
+ spec, None)
+
+class TestApplyInheritedArchs(common.TransactionCase):
+ """ Applies a sequence of modificator archs to a base view
+ """
+
+class TestViewCombined(common.TransactionCase):
+ """
+ Test fallback operations of View.read_combined:
+ * defaults mapping
+ * ?
+ """
+
+class TestNoModel(common.TransactionCase):
+ def test_create_view_nomodel(self):
+ View = self.registry('ir.ui.view')
+ view_id = View.create(self.cr, self.uid, {
+ 'name': 'dummy',
+ 'arch': '<template name="foo"/>',
+ 'inherit_id': False,
+ 'type': 'qweb',
+ })
+ fields = ['name', 'arch', 'type', 'priority', 'inherit_id', 'model']
+ [view] = View.read(self.cr, self.uid, [view_id], fields)
+ self.assertEqual(view, {
+ 'id': view_id,
+ 'name': 'dummy',
+ 'arch': '<template name="foo"/>',
+ 'type': 'qweb',
+ 'priority': 16,
+ 'inherit_id': False,
+ 'model': False,
+ })
+
+ text_para = E.p("", {'class': 'legalese'})
+ arch = E.body(
+ E.div(
+ E.h1("Title"),
+ id="header"),
+ E.p("Welcome!"),
+ E.div(
+ E.hr(),
+ text_para,
+ id="footer"),
+ {'class': "index"},)
+
+ def test_qweb_translation(self):
+ """
+ Test if translations work correctly without a model
+ """
+ View = self.registry('ir.ui.view')
+ self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
+ orig_text = "Copyright copyrighter"
+ translated_text = u"Copyrighter, tous droits réservés"
+ self.text_para.text = orig_text
+ self.registry('ir.translation').create(self.cr, self.uid, {
+ 'name': 'website',
+ 'type': 'view',
+ 'lang': 'fr_FR',
+ 'src': orig_text,
+ 'value': translated_text,
+ })
+ sarch = View.translate_qweb(self.cr, self.uid, None, self.arch, 'fr_FR')
+
+ self.text_para.text = translated_text
+ self.assertEqual(
+ ET.tostring(sarch, encoding='utf-8'),
+ ET.tostring(self.arch, encoding='utf-8'))
+
+class TestTemplating(common.TransactionCase):
+ def setUp(self):
+ import openerp.modules
+ super(TestTemplating, self).setUp()
+ self._pool = openerp.modules.registry.RegistryManager.get(common.DB)
+ self._init = self._pool._init
+ # fuck off
+ self._pool._init = False
+
+ def tearDown(self):
+ self._pool._init = self._init
+ super(TestTemplating, self).tearDown()
+
+ def test_branding_inherit(self):
Views = self.registry('ir.ui.view')
+ id = Views.create(self.cr, self.uid, {
+ 'name': "Base view",
+ 'type': 'qweb',
+ 'arch': """<root>
+ <item order="1"/>
+ </root>
+ """
+ })
+ id2 = Views.create(self.cr, self.uid, {
+ 'name': "Extension",
+ 'type': 'qweb',
+ 'inherit_id': id,
+ 'arch': """<xpath expr="//item" position="before">
+ <item order="2"/>
+ </xpath>
+ """
+ })
- self.assertTrue(Views.pool._init)
-
- error_msg = "The model name does not exist or the view architecture cannot be rendered"
- # test arch check is call for views without xmlid during registry initialization
- with self.assertRaisesRegexp(except_orm, error_msg):
- Views.create(self.cr, self.uid, {
- 'name': 'Test View #1',
- 'model': 'ir.ui.view',
- 'arch': """<?xml version="1.0"?>
- <tree>
- <field name="test_1"/>
- </tree>
- """,
- })
+ arch_string = Views.read_combined(
+ self.cr, self.uid, id, fields=['arch'],
+ context={'inherit_branding': True})['arch']
- # same for inherited views
- with self.assertRaisesRegexp(except_orm, error_msg):
- # Views.pudb = True
- Views.create(self.cr, self.uid, {
- 'name': 'Test View #2',
- 'model': 'ir.ui.view',
- 'inherit_id': self.browse_ref('base.view_view_tree').id,
- 'arch': """<?xml version="1.0"?>
- <xpath expr="//field[@name='name']" position="after">
- <field name="test_2"/>
- </xpath>
- """,
- })
+ arch = ET.fromstring(arch_string)
+ Views.distribute_branding(arch)
+
+ [initial] = arch.xpath('//item[@order=1]')
+ self.assertEqual(
+ str(id),
+ initial.get('data-oe-id'),
+ "initial should come from the root view")
+ self.assertEqual(
+ '/root[1]/item[1]',
+ initial.get('data-oe-xpath'),
+ "initial's xpath should be within the root view only")
+
+ [second] = arch.xpath('//item[@order=2]')
+ self.assertEqual(
+ str(id2),
+ second.get('data-oe-id'),
+ "second should come from the extension view")
+
+class test_views(common.TransactionCase):
def test_nonexistent_attribute_removal(self):
Views = self.registry('ir.ui.view')
@@ -75,47 +507,32 @@ class test_views(common.TransactionCase):
validate = partial(Views._validate_custom_views, self.cr, self.uid, model)
# validation of a single view
- vid = self._insert_view(**{
- 'name': 'base view',
- 'model': model,
- 'priority': 1,
- 'arch': """<?xml version="1.0"?>
+ vid = self._insert_view(
+ name='base view',
+ model=model,
+ priority=1,
+ arch="""<?xml version="1.0"?>
<tree string="view">
<field name="url"/>
</tree>
""",
- })
+ )
self.assertTrue(validate()) # single view
# validation of a inherited view
- self._insert_view(**{
- 'name': 'inherited view',
- 'model': model,
- 'priority': 1,
- 'inherit_id': vid,
- 'arch': """<?xml version="1.0"?>
+ self._insert_view(
+ name='inherited view',
+ model=model,
+ priority=1,
+ inherit_id=vid,
+ arch="""<?xml version="1.0"?>
<xpath expr="//field[@name='url']" position="before">
<field name="name"/>
</xpath>
""",
- })
+ )
self.assertTrue(validate()) # inherited view
- # validation of a bad inherited view
- self._insert_view(**{
- 'name': 'bad inherited view',
- 'model': model,
- 'priority': 2,
- 'inherit_id': vid,
- 'arch': """<?xml version="1.0"?>
- <xpath expr="//field[@name='url']" position="after">
- <field name="bad"/>
- </xpath>
- """,
- })
- with mute_logger('openerp.osv.orm', 'openerp.addons.base.ir.ir_ui_view'):
- self.assertFalse(validate()) # bad inherited view
-
def test_view_inheritance(self):
Views = self.registry('ir.ui.view')
@@ -172,9 +589,9 @@ class test_views(common.TransactionCase):
})
self.assertEqual(view['type'], 'form')
self.assertEqual(
- lxml.etree.tostring(lxml.etree.fromstring(
+ ET.tostring(ET.fromstring(
view['arch'],
- parser=lxml.etree.XMLParser(remove_blank_text=True)
+ parser=ET.XMLParser(remove_blank_text=True)
)),
'<form string="Replacement title" version="7.0">'
'<p>Replacement data</p>'
@@ -239,9 +656,9 @@ class test_views(common.TransactionCase):
})
self.assertEqual(view['type'], 'form')
self.assertEqual(
- lxml.etree.tostring(lxml.etree.fromstring(
+ ET.tostring(ET.fromstring(
view['arch'],
- parser=lxml.etree.XMLParser(remove_blank_text=True)
+ parser=ET.XMLParser(remove_blank_text=True)
)),
'<form string="Replacement title" version="7.0">'
'<p>Replacement data</p>'
@@ -250,5 +667,3 @@ class test_views(common.TransactionCase):
'</footer>'
'</form>')
-if __name__ == '__main__':
- unittest2.main()
diff --git a/openerp/addons/base/tests/test_xmlrpc.py b/openerp/addons/base/tests/test_xmlrpc.py
new file mode 100644
index 00000000000..854e345078a
--- /dev/null
+++ b/openerp/addons/base/tests/test_xmlrpc.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+import time
+import unittest2
+import xmlrpclib
+
+import openerp
+
+DB = openerp.tests.common.DB
+
+class test_xmlrpc(openerp.tests.common.HttpCase):
+
+ def test_01_xmlrpc_login(self):
+ """ Try to login on the common service. """
+ uid = self.xmlrpc_common.login(DB, 'admin', 'admin')
+ self.assertTrue(uid == 1)
+
+ def test_xmlrpc_ir_model_search(self):
+ """ Try a search on the object service. """
+ o = self.xmlrpc_object
+ ids = o.execute(DB, 1, 'admin', 'ir.model', 'search', [])
+ self.assertIsInstance(ids, list)
+ ids = o.execute(DB, 1, 'admin', 'ir.model', 'search', [], {})
+ self.assertIsInstance(ids, list)
+
+ # This test was written to test the creation of a new RPC endpoint, not
+ # really for the EDI itself.
+ #def test_xmlrpc_import_edi_document(self):
+ # """ Try to call an EDI method. """
+ # msg_re = 'EDI Document is empty!'
+ # with self.assertRaisesRegexp(Exception, msg_re):
+ # self.proxy.edi_60.import_edi_document(DB, ADMIN_USER_ID, ADMIN_PASSWORD, {})
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/test_convert/__init__.py b/openerp/addons/test_convert/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/openerp/addons/test_convert/__init__.py
diff --git a/openerp/addons/test_convert/__openerp__.py b/openerp/addons/test_convert/__openerp__.py
new file mode 100644
index 00000000000..40d9eb3a87f
--- /dev/null
+++ b/openerp/addons/test_convert/__openerp__.py
@@ -0,0 +1,5 @@
+{
+ 'name': 'test_convert',
+ 'description': "Data for xml conversion tests",
+ 'version': '0.0.1',
+}
diff --git a/openerp/addons/test_convert/test_file.txt b/openerp/addons/test_convert/test_file.txt
new file mode 100644
index 00000000000..e69b2e08d55
--- /dev/null
+++ b/openerp/addons/test_convert/test_file.txt
@@ -0,0 +1 @@
+nothing to see here, move along
diff --git a/openerp/addons/test_convert/tests/__init__.py b/openerp/addons/test_convert/tests/__init__.py
new file mode 100644
index 00000000000..002a0a18d1a
--- /dev/null
+++ b/openerp/addons/test_convert/tests/__init__.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from . import test_convert
+
+checks = [
+ test_convert
+]
diff --git a/openerp/addons/test_convert/tests/test_convert.py b/openerp/addons/test_convert/tests/test_convert.py
new file mode 100644
index 00000000000..50d7df4b665
--- /dev/null
+++ b/openerp/addons/test_convert/tests/test_convert.py
@@ -0,0 +1,83 @@
+import collections
+import unittest2
+from lxml import etree as ET
+from lxml.builder import E
+
+from openerp.tests import common
+
+from openerp.tools.convert import _eval_xml
+
+Field = E.field
+Value = E.value
+class TestEvalXML(common.TransactionCase):
+ def eval_xml(self, node, obj=None, idref=None):
+ return _eval_xml(obj, node, pool=None, cr=self.cr, uid=self.uid,
+ idref=idref, context=None)
+
+ def test_char(self):
+ self.assertEqual(
+ self.eval_xml(Field("foo")),
+ "foo")
+ self.assertEqual(
+ self.eval_xml(Field("None")),
+ "None")
+
+ def test_int(self):
+ self.assertIsNone(
+ self.eval_xml(Field("None", type='int')),
+ "what the fuck?")
+ self.assertEqual(
+ self.eval_xml(Field(" 42 ", type="int")),
+ 42)
+
+ with self.assertRaises(ValueError):
+ self.eval_xml(Field("4.82", type="int"))
+
+ with self.assertRaises(ValueError):
+ self.eval_xml(Field("Whelp", type="int"))
+
+ def test_float(self):
+ self.assertEqual(
+ self.eval_xml(Field("4.78", type="float")),
+ 4.78)
+
+ with self.assertRaises(ValueError):
+ self.eval_xml(Field("None", type="float"))
+
+ with self.assertRaises(ValueError):
+ self.eval_xml(Field("Foo", type="float"))
+
+ def test_list(self):
+ self.assertEqual(
+ self.eval_xml(Field(type="list")),
+ [])
+
+ self.assertEqual(
+ self.eval_xml(Field(
+ Value("foo"),
+ Value("5", type="int"),
+ Value("4.76", type="float"),
+ Value("None", type="int"),
+ type="list"
+ )),
+ ["foo", 5, 4.76, None])
+
+ def test_file(self):
+ Obj = collections.namedtuple('Obj', 'module')
+ obj = Obj('test_convert')
+ self.assertEqual(
+ self.eval_xml(Field('test_file.txt', type='file'), obj),
+ 'test_convert,test_file.txt')
+
+ with self.assertRaises(IOError):
+ self.eval_xml(Field('test_nofile.txt', type='file'), obj)
+
+ @unittest2.skip("not tested")
+ def test_xml(self):
+ pass
+
+ @unittest2.skip("not tested")
+ def test_html(self):
+ pass
+
+
diff --git a/openerp/addons/test_converter/__init__.py b/openerp/addons/test_converter/__init__.py
new file mode 100644
index 00000000000..89d26e2f597
--- /dev/null
+++ b/openerp/addons/test_converter/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+import models
diff --git a/openerp/addons/test_converter/__openerp__.py b/openerp/addons/test_converter/__openerp__.py
new file mode 100644
index 00000000000..c76b1fec875
--- /dev/null
+++ b/openerp/addons/test_converter/__openerp__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': 'test-field-converter',
+ 'version': '0.1',
+ 'category': 'Tests',
+ 'description': """Tests of field conversions""",
+ 'author': 'OpenERP SA',
+ 'maintainer': 'OpenERP SA',
+ 'website': 'http://www.openerp.com',
+ 'depends': ['base'],
+ 'data': ['ir.model.access.csv'],
+ 'installable': True,
+ 'auto_install': False,
+}
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/test_converter/ir.model.access.csv b/openerp/addons/test_converter/ir.model.access.csv
new file mode 100644
index 00000000000..ff4ac975996
--- /dev/null
+++ b/openerp/addons/test_converter/ir.model.access.csv
@@ -0,0 +1,4 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_converter_model,access_converter_model,model_test_converter_test_model,,1,1,1,1
+access_test_converter_test_model_sub,access_test_converter_test_model_sub,model_test_converter_test_model_sub,,1,1,1,1
+access_test_converter_monetary,access_test_converter_monetary,model_test_converter_monetary,,1,1,1,1
diff --git a/openerp/addons/test_converter/models.py b/openerp/addons/test_converter/models.py
new file mode 100644
index 00000000000..9074ba8178f
--- /dev/null
+++ b/openerp/addons/test_converter/models.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+from openerp.osv import orm, fields
+
+class test_model(orm.Model):
+ _name = 'test_converter.test_model'
+
+ _columns = {
+ 'char': fields.char(),
+ 'integer': fields.integer(),
+ 'float': fields.float(),
+ 'numeric': fields.float(digits=(16, 2)),
+ 'many2one': fields.many2one('test_converter.test_model.sub'),
+ 'binary': fields.binary(),
+ 'date': fields.date(),
+ 'datetime': fields.datetime(),
+ 'selection': fields.selection([
+ (1, "réponse A"),
+ (2, "réponse B"),
+ (3, "réponse C"),
+ (4, "réponse D"),
+ ]),
+ 'selection_str': fields.selection([
+ ('A', "Qu'il n'est pas arrivé à Toronto"),
+ ('B', "Qu'il était supposé arriver à Toronto"),
+ ('C', "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?"),
+ ('D', "La réponse D"),
+ ], string="Lorsqu'un pancake prend l'avion à destination de Toronto et "
+ "qu'il fait une escale technique à St Claude, on dit:"),
+ 'html': fields.html(),
+ 'text': fields.text(),
+ }
+
+class test_model_sub(orm.Model):
+ _name = 'test_converter.test_model.sub'
+
+ _columns = {
+ 'name': fields.char()
+ }
+
+
+class test_model_monetary(orm.Model):
+ _name = 'test_converter.monetary'
+
+ _columns = {
+ 'value': fields.float(digits=(16, 55)),
+ }
diff --git a/openerp/addons/test_converter/tests/__init__.py b/openerp/addons/test_converter/tests/__init__.py
new file mode 100644
index 00000000000..493b164d44a
--- /dev/null
+++ b/openerp/addons/test_converter/tests/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+
+from . import test_html
+
+fast_suite = [
+]
+
+checks = [
+ test_html
+]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/test_converter/tests/test_html.py b/openerp/addons/test_converter/tests/test_html.py
new file mode 100644
index 00000000000..2f0896990ea
--- /dev/null
+++ b/openerp/addons/test_converter/tests/test_html.py
@@ -0,0 +1,387 @@
+# -*- encoding: utf-8 -*-
+import json
+import os
+import xml.dom.minidom
+import datetime
+
+from werkzeug.utils import escape as e
+
+from openerp.tests import common
+from openerp.addons.base.ir import ir_qweb
+
+directory = os.path.dirname(__file__)
+
+impl = xml.dom.minidom.getDOMImplementation()
+doc = impl.createDocument(None, None, None)
+
+class TestExport(common.TransactionCase):
+ _model = None
+
+ def setUp(self):
+ super(TestExport, self).setUp()
+ self.Model = self.registry(self._model)
+ self.columns = self.Model._all_columns
+
+ def get_column(self, name):
+ return self.Model._all_columns[name].column
+
+ def get_converter(self, name, type=None):
+ column = self.get_column(name)
+
+ for postfix in type, column._type, '':
+ fs = ['ir', 'qweb', 'field']
+ if postfix is None: continue
+ if postfix: fs.append(postfix)
+
+ try:
+ model = self.registry('.'.join(fs))
+ break
+ except KeyError: pass
+
+ return lambda value, options=None, context=None: e(model.value_to_html(
+ self.cr, self.uid, value, column, options=options, context=context))
+
+class TestBasicExport(TestExport):
+ _model = 'test_converter.test_model'
+
+class TestCharExport(TestBasicExport):
+ def test_char(self):
+ converter = self.get_converter('char')
+
+ value = converter('foo')
+ self.assertEqual(value, 'foo')
+
+ value = converter("foo<bar>")
+ self.assertEqual(value, "foo&lt;bar&gt;")
+
+class TestIntegerExport(TestBasicExport):
+ def test_integer(self):
+ converter = self.get_converter('integer')
+
+ value = converter(42)
+ self.assertEqual(value, "42")
+
+class TestFloatExport(TestBasicExport):
+ def setUp(self):
+ super(TestFloatExport, self).setUp()
+ self.registry('res.lang').write(self.cr, self.uid, [1], {
+ 'grouping': '[3,0]'
+ })
+
+ def test_float(self):
+ converter = self.get_converter('float')
+
+ value = converter(42.0)
+ self.assertEqual(value, "42.0")
+
+ value = converter(42.0100)
+ self.assertEqual(value, "42.01")
+
+ value = converter(42.01234)
+ self.assertEqual(value, "42.01234")
+
+ value = converter(1234567.89)
+ self.assertEqual(value, '1,234,567.89')
+
+ def test_numeric(self):
+ converter = self.get_converter('numeric')
+
+ value = converter(42.0)
+ self.assertEqual(value, '42.00')
+
+ value = converter(42.01234)
+ self.assertEqual(value, '42.01')
+
+class TestCurrencyExport(TestExport):
+ _model = 'test_converter.monetary'
+
+ def setUp(self):
+ super(TestCurrencyExport, self).setUp()
+ self.Currency = self.registry('res.currency')
+ self.base = self.create(self.Currency, name="Source", symbol=u'source')
+
+ def create(self, model, context=None, **values):
+ return model.browse(
+ self.cr, self.uid,
+ model.create(self.cr, self.uid, values, context=context),
+ context=context)
+
+ def convert(self, obj, dest):
+ converter = self.registry('ir.qweb.field.monetary')
+ options = {
+ 'widget': 'monetary',
+ 'display_currency': 'c2'
+ }
+ converted = converter.to_html(
+ self.cr, self.uid, 'value', obj, options,
+ doc.createElement('span'),
+ {'field': 'obj.value', 'field-options': json.dumps(options)},
+ '', ir_qweb.QWebContext(self.cr, self.uid, {'obj': obj, 'c2': dest, }))
+ return converted
+
+ def test_currency_post(self):
+ currency = self.create(self.Currency, name="Test", symbol=u"test")
+ obj = self.create(self.Model, value=0.12)
+
+ converted = self.convert(obj, dest=currency)
+
+ self.assertEqual(
+ converted,
+ '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
+ 'data-oe-field="value" data-oe-type="monetary" '
+ 'data-oe-expression="obj.value">'
+ '<span class="oe_currency_value">0.12</span>'
+ ' {symbol}</span>'.format(
+ obj=obj,
+ symbol=currency.symbol.encode('utf-8')
+ ),)
+
+ def test_currency_pre(self):
+ currency = self.create(
+ self.Currency, name="Test", symbol=u"test", position='before')
+ obj = self.create(self.Model, value=0.12)
+
+ converted = self.convert(obj, dest=currency)
+
+ self.assertEqual(
+ converted,
+ '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
+ 'data-oe-field="value" data-oe-type="monetary" '
+ 'data-oe-expression="obj.value">'
+ '{symbol} '
+ '<span class="oe_currency_value">0.12</span>'
+ '</span>'.format(
+ obj=obj,
+ symbol=currency.symbol.encode('utf-8')
+ ),)
+
+ def test_currency_precision(self):
+ """ Precision should be the currency's, not the float field's
+ """
+ currency = self.create(self.Currency, name="Test", symbol=u"test",)
+ obj = self.create(self.Model, value=0.1234567)
+
+ converted = self.convert(obj, dest=currency)
+
+ self.assertEqual(
+ converted,
+ '<span data-oe-model="{obj._model._name}" data-oe-id="{obj.id}" '
+ 'data-oe-field="value" data-oe-type="monetary" '
+ 'data-oe-expression="obj.value">'
+ '<span class="oe_currency_value">0.12</span>'
+ ' {symbol}</span>'.format(
+ obj=obj,
+ symbol=currency.symbol.encode('utf-8')
+ ),)
+
+class TestTextExport(TestBasicExport):
+ def test_text(self):
+ converter = self.get_converter('text')
+
+ value = converter("This is my text-kai")
+ self.assertEqual(value, "This is my text-kai")
+
+ value = converter("""
+ . The current line (address) in the buffer.
+ $ The last line in the buffer.
+ n The nth, line in the buffer where n is a number in the range [0,$].
+ $ The last line in the buffer.
+ - The previous line. This is equivalent to -1 and may be repeated with cumulative effect.
+ -n The nth previous line, where n is a non-negative number.
+ + The next line. This is equivalent to +1 and may be repeated with cumulative effect.
+ """)
+ self.assertEqual(value, """<br>
+ . The current line (address) in the buffer.<br>
+ $ The last line in the buffer.<br>
+ n The nth, line in the buffer where n is a number in the range [0,$].<br>
+ $ The last line in the buffer.<br>
+ - The previous line. This is equivalent to -1 and may be repeated with cumulative effect.<br>
+ -n The nth previous line, where n is a non-negative number.<br>
+ + The next line. This is equivalent to +1 and may be repeated with cumulative effect.<br>
+ """)
+
+ value = converter("""
+ fgdkls;hjas;lj <b>fdslkj</b> d;lasjfa lkdja <a href=http://spam.com>lfks</a>
+ fldkjsfhs <i style="color: red"><a href="http://spamspam.com">fldskjh</a></i>
+ """)
+ self.assertEqual(value, """<br>
+ fgdkls;hjas;lj &lt;b&gt;fdslkj&lt;/b&gt; d;lasjfa lkdja &lt;a href=http://spam.com&gt;lfks&lt;/a&gt;<br>
+ fldkjsfhs &lt;i style=&quot;color: red&quot;&gt;&lt;a href=&quot;http://spamspam.com&quot;&gt;fldskjh&lt;/a&gt;&lt;/i&gt;<br>
+ """)
+
+class TestMany2OneExport(TestBasicExport):
+ def test_many2one(self):
+ Sub = self.registry('test_converter.test_model.sub')
+
+
+ id0 = self.Model.create(self.cr, self.uid, {
+ 'many2one': Sub.create(self.cr, self.uid, {'name': "Foo"})
+ })
+ id1 = self.Model.create(self.cr, self.uid, {
+ 'many2one': Sub.create(self.cr, self.uid, {'name': "Fo<b>o</b>"})
+ })
+
+ def converter(record):
+ column = self.get_column('many2one')
+ model = self.registry('ir.qweb.field.many2one')
+
+ return e(model.record_to_html(
+ self.cr, self.uid, 'many2one', record, column))
+
+ value = converter(self.Model.browse(self.cr, self.uid, id0))
+ self.assertEqual(value, "Foo")
+
+ value = converter(self.Model.browse(self.cr, self.uid, id1))
+ self.assertEqual(value, "Fo&lt;b&gt;o&lt;/b&gt;")
+
+class TestBinaryExport(TestBasicExport):
+ def test_image(self):
+ column = self.get_column('binary')
+ converter = self.registry('ir.qweb.field.image')
+
+ with open(os.path.join(directory, 'test_vectors', 'image'), 'rb') as f:
+ content = f.read()
+
+ encoded_content = content.encode('base64')
+ value = e(converter.value_to_html(
+ self.cr, self.uid, encoded_content, column))
+ self.assertEqual(
+ value, '<img src="data:image/jpeg;base64,%s">' % (
+ encoded_content
+ ))
+
+ with open(os.path.join(directory, 'test_vectors', 'pdf'), 'rb') as f:
+ content = f.read()
+
+ with self.assertRaises(ValueError):
+ e(converter.value_to_html(
+ self.cr, self.uid, 'binary', content.encode('base64'), column))
+
+ with open(os.path.join(directory, 'test_vectors', 'pptx'), 'rb') as f:
+ content = f.read()
+
+ with self.assertRaises(ValueError):
+ e(converter.value_to_html(
+ self.cr, self.uid, 'binary', content.encode('base64'), column))
+
+class TestSelectionExport(TestBasicExport):
+ def test_selection(self):
+ [record] = self.Model.browse(self.cr, self.uid, [self.Model.create(self.cr, self.uid, {
+ 'selection': 2,
+ 'selection_str': 'C',
+ })])
+
+ column_name = 'selection'
+ column = self.get_column(column_name)
+ converter = self.registry('ir.qweb.field.selection')
+
+ value = converter.record_to_html(
+ self.cr, self.uid, column_name, record, column)
+ self.assertEqual(value, "réponse B")
+
+ column_name = 'selection_str'
+ column = self.get_column(column_name)
+ value = converter.record_to_html(
+ self.cr, self.uid, column_name, record, column)
+ self.assertEqual(value, "Qu'est-ce qu'il fout ce maudit pancake, tabernacle ?")
+
+class TestHTMLExport(TestBasicExport):
+ def test_html(self):
+ converter = self.get_converter('html')
+
+ input = '<span>span</span>'
+ value = converter(input)
+ self.assertEqual(value, input)
+
+class TestDatetimeExport(TestBasicExport):
+ def setUp(self):
+ super(TestDatetimeExport, self).setUp()
+ # set user tz to known value
+ Users = self.registry('res.users')
+ Users.write(self.cr, self.uid, self.uid, {
+ 'tz': 'Pacific/Niue'
+ }, context=None)
+
+ def test_date(self):
+ converter = self.get_converter('date')
+
+ value = converter('2011-05-03')
+
+ # default lang/format is US
+ self.assertEqual(value, '05/03/2011')
+
+ def test_datetime(self):
+ converter = self.get_converter('datetime')
+
+ value = converter('2011-05-03 11:12:13')
+
+ # default lang/format is US
+ self.assertEqual(value, '05/03/2011 00:12:13')
+
+ def test_custom_format(self):
+ converter = self.get_converter('datetime')
+ converter2 = self.get_converter('date')
+ opts = {'format': 'MMMM d'}
+
+ value = converter('2011-03-02 11:12:13', options=opts)
+ value2 = converter2('2001-03-02', options=opts)
+ self.assertEqual(
+ value,
+ 'March 2'
+ )
+ self.assertEqual(
+ value2,
+ 'March 2'
+ )
+
+class TestDurationExport(TestBasicExport):
+ def setUp(self):
+ super(TestDurationExport, self).setUp()
+ # needs to have lang installed otherwise falls back on en_US
+ self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
+
+ def test_negative(self):
+ converter = self.get_converter('float', 'duration')
+
+ with self.assertRaises(ValueError):
+ converter(-4)
+
+ def test_missing_unit(self):
+ converter = self.get_converter('float', 'duration')
+
+ with self.assertRaises(ValueError):
+ converter(4)
+
+ def test_basic(self):
+ converter = self.get_converter('float', 'duration')
+
+ result = converter(4, {'unit': 'hour'}, {'lang': 'fr_FR'})
+ self.assertEqual(result, u'4 heures')
+
+ result = converter(50, {'unit': 'second'}, {'lang': 'fr_FR'})
+ self.assertEqual(result, u'50 secondes')
+
+ def test_multiple(self):
+ converter = self.get_converter('float', 'duration')
+
+ result = converter(1.5, {'unit': 'hour'}, {'lang': 'fr_FR'})
+ self.assertEqual(result, u"1 heure 30 minutes")
+
+ result = converter(72, {'unit': 'second'}, {'lang': 'fr_FR'})
+ self.assertEqual(result, u"1 minute 12 secondes")
+
+class TestRelativeDatetime(TestBasicExport):
+ # not sure how a test based on "current time" should be tested. Even less
+ # so as it would mostly be a test of babel...
+
+ def setUp(self):
+ super(TestRelativeDatetime, self).setUp()
+ # needs to have lang installed otherwise falls back on en_US
+ self.registry('res.lang').load_lang(self.cr, self.uid, 'fr_FR')
+
+ def test_basic(self):
+ converter = self.get_converter('datetime', 'relative')
+ t = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
+
+ result = converter(t, context={'lang': 'fr_FR'})
+ self.assertEqual(result, u"il y a 1 heure")
diff --git a/openerp/addons/test_converter/tests/test_vectors/image b/openerp/addons/test_converter/tests/test_vectors/image
new file mode 100644
index 00000000000..889c9051721
--- /dev/null
+++ b/openerp/addons/test_converter/tests/test_vectors/image
Binary files differ
diff --git a/openerp/addons/test_converter/tests/test_vectors/pdf b/openerp/addons/test_converter/tests/test_vectors/pdf
new file mode 100644
index 00000000000..6ae543d29d4
--- /dev/null
+++ b/openerp/addons/test_converter/tests/test_vectors/pdf
Binary files differ
diff --git a/openerp/addons/test_converter/tests/test_vectors/pptx b/openerp/addons/test_converter/tests/test_vectors/pptx
new file mode 100644
index 00000000000..f798aca350b
--- /dev/null
+++ b/openerp/addons/test_converter/tests/test_vectors/pptx
Binary files differ
diff --git a/openerp/tests/addons/test_exceptions/__init__.py b/openerp/addons/test_exceptions/__init__.py
index fe4487156b1..fe4487156b1 100644
--- a/openerp/tests/addons/test_exceptions/__init__.py
+++ b/openerp/addons/test_exceptions/__init__.py
diff --git a/openerp/tests/addons/test_exceptions/__openerp__.py b/openerp/addons/test_exceptions/__openerp__.py
index fc104f13a12..fc104f13a12 100644
--- a/openerp/tests/addons/test_exceptions/__openerp__.py
+++ b/openerp/addons/test_exceptions/__openerp__.py
diff --git a/openerp/tests/addons/test_exceptions/ir.model.access.csv b/openerp/addons/test_exceptions/ir.model.access.csv
index 56f99efd729..56f99efd729 100644
--- a/openerp/tests/addons/test_exceptions/ir.model.access.csv
+++ b/openerp/addons/test_exceptions/ir.model.access.csv
diff --git a/openerp/tests/addons/test_exceptions/models.py b/openerp/addons/test_exceptions/models.py
index a22c6ea7d77..a22c6ea7d77 100644
--- a/openerp/tests/addons/test_exceptions/models.py
+++ b/openerp/addons/test_exceptions/models.py
diff --git a/openerp/tests/addons/test_exceptions/view.xml b/openerp/addons/test_exceptions/view.xml
index 4d8e820d456..4d8e820d456 100644
--- a/openerp/tests/addons/test_exceptions/view.xml
+++ b/openerp/addons/test_exceptions/view.xml
diff --git a/openerp/tests/addons/test_impex/__init__.py b/openerp/addons/test_impex/__init__.py
index bff786c0885..bff786c0885 100644
--- a/openerp/tests/addons/test_impex/__init__.py
+++ b/openerp/addons/test_impex/__init__.py
diff --git a/openerp/tests/addons/test_impex/__openerp__.py b/openerp/addons/test_impex/__openerp__.py
index 2b52b6ad5fa..2b52b6ad5fa 100644
--- a/openerp/tests/addons/test_impex/__openerp__.py
+++ b/openerp/addons/test_impex/__openerp__.py
diff --git a/openerp/tests/addons/test_impex/ir.model.access.csv b/openerp/addons/test_impex/ir.model.access.csv
index fd0f7370c67..fd0f7370c67 100644
--- a/openerp/tests/addons/test_impex/ir.model.access.csv
+++ b/openerp/addons/test_impex/ir.model.access.csv
diff --git a/openerp/tests/addons/test_impex/models.py b/openerp/addons/test_impex/models.py
index 8c76850d628..8c76850d628 100644
--- a/openerp/tests/addons/test_impex/models.py
+++ b/openerp/addons/test_impex/models.py
diff --git a/openerp/tests/addons/test_impex/tests/__init__.py b/openerp/addons/test_impex/tests/__init__.py
index 8cab56fcc9a..8cab56fcc9a 100644
--- a/openerp/tests/addons/test_impex/tests/__init__.py
+++ b/openerp/addons/test_impex/tests/__init__.py
diff --git a/openerp/tests/addons/test_impex/tests/contacts.json b/openerp/addons/test_impex/tests/contacts.json
index 4f065037188..4f065037188 100644
--- a/openerp/tests/addons/test_impex/tests/contacts.json
+++ b/openerp/addons/test_impex/tests/contacts.json
diff --git a/openerp/tests/addons/test_impex/tests/contacts_big.json b/openerp/addons/test_impex/tests/contacts_big.json
index 5dfe77ec04b..5dfe77ec04b 100644
--- a/openerp/tests/addons/test_impex/tests/contacts_big.json
+++ b/openerp/addons/test_impex/tests/contacts_big.json
diff --git a/openerp/tests/addons/test_impex/tests/test_export.py b/openerp/addons/test_impex/tests/test_export.py
index 26219b36d3b..26219b36d3b 100644
--- a/openerp/tests/addons/test_impex/tests/test_export.py
+++ b/openerp/addons/test_impex/tests/test_export.py
diff --git a/openerp/tests/addons/test_impex/tests/test_import.py b/openerp/addons/test_impex/tests/test_import.py
index e4e8a6a9774..e4e8a6a9774 100644
--- a/openerp/tests/addons/test_impex/tests/test_import.py
+++ b/openerp/addons/test_impex/tests/test_import.py
diff --git a/openerp/tests/addons/test_impex/tests/test_load.py b/openerp/addons/test_impex/tests/test_load.py
index 260492229a5..260492229a5 100644
--- a/openerp/tests/addons/test_impex/tests/test_load.py
+++ b/openerp/addons/test_impex/tests/test_load.py
diff --git a/openerp/tests/addons/test_limits/__init__.py b/openerp/addons/test_limits/__init__.py
index fe4487156b1..fe4487156b1 100644
--- a/openerp/tests/addons/test_limits/__init__.py
+++ b/openerp/addons/test_limits/__init__.py
diff --git a/openerp/tests/addons/test_limits/__openerp__.py b/openerp/addons/test_limits/__openerp__.py
index 59972e60e36..59972e60e36 100644
--- a/openerp/tests/addons/test_limits/__openerp__.py
+++ b/openerp/addons/test_limits/__openerp__.py
diff --git a/openerp/tests/addons/test_limits/ir.model.access.csv b/openerp/addons/test_limits/ir.model.access.csv
index 02f18639a73..02f18639a73 100644
--- a/openerp/tests/addons/test_limits/ir.model.access.csv
+++ b/openerp/addons/test_limits/ir.model.access.csv
diff --git a/openerp/tests/addons/test_limits/models.py b/openerp/addons/test_limits/models.py
index 32e2a9a16f4..32e2a9a16f4 100644
--- a/openerp/tests/addons/test_limits/models.py
+++ b/openerp/addons/test_limits/models.py
diff --git a/openerp/tests/addons/test_uninstall/__init__.py b/openerp/addons/test_uninstall/__init__.py
index fe4487156b1..fe4487156b1 100644
--- a/openerp/tests/addons/test_uninstall/__init__.py
+++ b/openerp/addons/test_uninstall/__init__.py
diff --git a/openerp/tests/addons/test_uninstall/__openerp__.py b/openerp/addons/test_uninstall/__openerp__.py
index 0015d5a52d4..0015d5a52d4 100644
--- a/openerp/tests/addons/test_uninstall/__openerp__.py
+++ b/openerp/addons/test_uninstall/__openerp__.py
diff --git a/openerp/tests/addons/test_uninstall/ir.model.access.csv b/openerp/addons/test_uninstall/ir.model.access.csv
index f5b5b1f8f4d..f5b5b1f8f4d 100644
--- a/openerp/tests/addons/test_uninstall/ir.model.access.csv
+++ b/openerp/addons/test_uninstall/ir.model.access.csv
diff --git a/openerp/tests/addons/test_uninstall/models.py b/openerp/addons/test_uninstall/models.py
index 96a5800917d..96a5800917d 100644
--- a/openerp/tests/addons/test_uninstall/models.py
+++ b/openerp/addons/test_uninstall/models.py
diff --git a/openerp/tests/addons/test_workflow/__init__.py b/openerp/addons/test_workflow/__init__.py
index fe4487156b1..fe4487156b1 100644
--- a/openerp/tests/addons/test_workflow/__init__.py
+++ b/openerp/addons/test_workflow/__init__.py
diff --git a/openerp/tests/addons/test_workflow/__openerp__.py b/openerp/addons/test_workflow/__openerp__.py
index 12cafa274e8..12cafa274e8 100644
--- a/openerp/tests/addons/test_workflow/__openerp__.py
+++ b/openerp/addons/test_workflow/__openerp__.py
diff --git a/openerp/tests/addons/test_workflow/data.xml b/openerp/addons/test_workflow/data.xml
index 6299baa77ea..6299baa77ea 100644
--- a/openerp/tests/addons/test_workflow/data.xml
+++ b/openerp/addons/test_workflow/data.xml
diff --git a/openerp/tests/addons/test_workflow/ir.model.access.csv b/openerp/addons/test_workflow/ir.model.access.csv
index 6fb5a7ae274..6fb5a7ae274 100644
--- a/openerp/tests/addons/test_workflow/ir.model.access.csv
+++ b/openerp/addons/test_workflow/ir.model.access.csv
diff --git a/openerp/tests/addons/test_workflow/models.py b/openerp/addons/test_workflow/models.py
index f7a5ef23b1a..f7a5ef23b1a 100644
--- a/openerp/tests/addons/test_workflow/models.py
+++ b/openerp/addons/test_workflow/models.py
diff --git a/openerp/tests/addons/test_workflow/tests/__init__.py b/openerp/addons/test_workflow/tests/__init__.py
index a09d09fe74a..a09d09fe74a 100644
--- a/openerp/tests/addons/test_workflow/tests/__init__.py
+++ b/openerp/addons/test_workflow/tests/__init__.py
diff --git a/openerp/tests/addons/test_workflow/tests/test_workflow.py b/openerp/addons/test_workflow/tests/test_workflow.py
index e9ff7b9cd1e..e9ff7b9cd1e 100644
--- a/openerp/tests/addons/test_workflow/tests/test_workflow.py
+++ b/openerp/addons/test_workflow/tests/test_workflow.py
diff --git a/openerp/cli/server.py b/openerp/cli/server.py
index 7041d7a4c3c..42d920da9aa 100644
--- a/openerp/cli/server.py
+++ b/openerp/cli/server.py
@@ -89,29 +89,6 @@ def setup_pid_file():
pidtext = "%d" % (os.getpid())
fd.write(pidtext)
-def preload_registry(dbname):
- """ Preload a registry, and start the cron."""
- try:
- update_module = True if openerp.tools.config['init'] or openerp.tools.config['update'] else False
- registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=update_module)
- except Exception:
- _logger.exception('Failed to initialize database `%s`.', dbname)
- return False
- return registry._assertion_report.failures == 0
-
-def run_test_file(dbname, test_file):
- """ Preload a registry, possibly run a test file, and start the cron."""
- try:
- config = openerp.tools.config
- registry = openerp.modules.registry.RegistryManager.new(dbname, update_module=config['init'] or config['update'])
- cr = registry.db.cursor()
- _logger.info('loading test file %s', test_file)
- openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
- cr.rollback()
- cr.close()
- except Exception:
- _logger.exception('Failed to initialize database `%s` and run test file `%s`.', dbname, test_file)
-
def export_translation():
config = openerp.tools.config
dbname = config['db_name']
@@ -156,8 +133,7 @@ def main(args):
config = openerp.tools.config
if config["test_file"]:
- run_test_file(config['db_name'], config['test_file'])
- sys.exit(0)
+ config["test_enable"] = True
if config["translate_out"]:
export_translation()
@@ -172,23 +148,17 @@ def main(args):
if config['workers']:
openerp.multi_process = True
- # preload registries, needed for -u --stop_after_init
- rc = 0
+ preload = []
if config['db_name']:
- for dbname in config['db_name'].split(','):
- if not preload_registry(dbname):
- rc += 1
-
- if not config["stop_after_init"]:
- setup_pid_file()
- openerp.service.server.start()
- if config['pidfile']:
- os.unlink(config['pidfile'])
- else:
- sys.exit(rc)
+ preload = config['db_name'].split(',')
- _logger.info('OpenERP server is running, waiting for connections...')
- quit_on_signals()
+ stop = config["stop_after_init"]
+
+ setup_pid_file()
+ rc = openerp.service.server.start(preload=preload, stop=stop)
+ if config['pidfile']:
+ os.unlink(config['pidfile'])
+ sys.exit(rc)
class Server(Command):
def run(self, args):
diff --git a/openerp/http.py b/openerp/http.py
index 2bd0f48565f..eef096faa3e 100644
--- a/openerp/http.py
+++ b/openerp/http.py
@@ -35,6 +35,7 @@ import werkzeug.wsgi
import openerp
from openerp.service import security, model as service_model
+import openerp.tools
_logger = logging.getLogger(__name__)
@@ -49,6 +50,28 @@ request = _request_stack()
A global proxy that always redirect to the current request object.
"""
+def local_redirect(path, query=None, keep_hash=False, forward_debug=True, code=303):
+ url = path
+ if not query:
+ query = {}
+ if forward_debug and request and request.debug:
+ query['debug'] = None
+ if query:
+ url += '?' + werkzeug.url_encode(query)
+ if keep_hash:
+ return redirect_with_hash(url, code)
+ else:
+ return werkzeug.utils.redirect(url, code)
+
+def redirect_with_hash(url, code=303):
+ # Most IE and Safari versions decided not to preserve location.hash upon
+ # redirect. And even if IE10 pretends to support it, it still fails
+ # inexplicably in case of multiple redirects (and we do have some).
+ # See extensive test page at http://greenbytes.de/tech/tc/httpredirects/
+ if request.httprequest.user_agent.browser in ('firefox',):
+ return werkzeug.utils.redirect(url, code)
+ return "<html><head><script>window.location = '%s' + location.hash;</script></head></html>" % url
+
class WebRequest(object):
""" Parent class for all OpenERP Web request types, mostly deals with
initialization and setup of the request object (the dispatching itself has
@@ -145,7 +168,10 @@ class WebRequest(object):
"""
# some magic to lazy create the cr
if not self._cr:
- self._cr = self.registry.db.cursor()
+ # Test cursors
+ self._cr = openerp.tests.common.acquire_test_cursor(self.session_id)
+ if not self._cr:
+ self._cr = self.registry.db.cursor()
return self._cr
def __enter__(self):
@@ -154,10 +180,13 @@ class WebRequest(object):
def __exit__(self, exc_type, exc_value, traceback):
_request_stack.pop()
+
if self._cr:
- if exc_type is None:
- self._cr.commit()
- self._cr.close()
+ # Dont commit test cursors
+ if not openerp.tests.common.release_test_cursor(self.session_id):
+ if exc_type is None:
+ self._cr.commit()
+ self._cr.close()
# just to be sure no one tries to re-use the request
self.disable_db = True
self.uid = None
@@ -168,7 +197,7 @@ class WebRequest(object):
if not k.startswith("_ignored_"))
self.func = func
- self.func_request_type = func.exposed
+ self.func_request_type = func.routing['type']
self.func_arguments = arguments
self.auth_method = auth
@@ -181,11 +210,11 @@ class WebRequest(object):
kwargs.update(self.func_arguments)
# Backward for 7.0
- if getattr(self.func, '_first_arg_is_req', False):
+ if getattr(self.func.method, '_first_arg_is_req', False):
args = (request,) + args
# Correct exception handling and concurency retry
@service_model.check
- def checked_call(dbname, *a, **kw):
+ def checked_call(___dbname, *a, **kw):
return self.func(*a, **kw)
# FIXME: code and rollback management could be cleaned
@@ -207,7 +236,7 @@ class WebRequest(object):
warnings.warn('please use request.registry and request.cr directly', DeprecationWarning)
yield (self.registry, self.cr)
-def route(route, type="http", auth="user", methods=None):
+def route(route=None, **kw):
"""
Decorator marking the decorated method as being a handler for requests. The method must be part of a subclass
of ``Controller``.
@@ -225,17 +254,18 @@ def route(route, type="http", auth="user", methods=None):
authentication modules. There request code will not have any facilities to access the database nor have any
configuration indicating the current database nor the current user.
:param methods: A sequence of http methods this route applies to. If not specified, all methods are allowed.
+ :param cors: The Access-Control-Allow-Origin cors directive value.
"""
- assert type in ["http", "json"]
+ routing = kw.copy()
+ assert not 'type' in routing or routing['type'] in ("http", "json")
def decorator(f):
- if isinstance(route, list):
- f.routes = route
- else:
- f.routes = [route]
- f.methods = methods
- f.exposed = type
- if getattr(f, "auth", None) is None:
- f.auth = auth
+ if route:
+ if isinstance(route, list):
+ routes = route
+ else:
+ routes = [route]
+ routing['routes'] = routes
+ f.routing = routing
return f
return decorator
@@ -306,7 +336,7 @@ class JsonRequest(WebRequest):
# Read POST content or POST Form Data named "request"
self.jsonrequest = simplejson.loads(request)
self.params = dict(self.jsonrequest.get("params", {}))
- self.context = self.params.pop('context', self.session.context)
+ self.context = self.params.pop('context', dict(self.session.context))
def dispatch(self):
""" Calls the method asked for by the JSON-RPC2 or JSONP request
@@ -388,11 +418,10 @@ def jsonrequest(f):
Use the ``route()`` decorator instead.
"""
- f.combine = True
base = f.__name__.lstrip('/')
if f.__name__ == "index":
base = ""
- return route([base, base + "/<path:_ignored_path>"], type="json", auth="user")(f)
+ return route([base, base + "/<path:_ignored_path>"], type="json", auth="user", combine=True)(f)
class HttpRequest(WebRequest):
""" Regular GET/POST request
@@ -401,13 +430,27 @@ class HttpRequest(WebRequest):
def __init__(self, *args):
super(HttpRequest, self).__init__(*args)
- params = dict(self.httprequest.args)
- params.update(self.httprequest.form)
- params.update(self.httprequest.files)
+ params = self.httprequest.args.to_dict()
+ params.update(self.httprequest.form.to_dict())
+ params.update(self.httprequest.files.to_dict())
params.pop('session_id', None)
self.params = params
def dispatch(self):
+ # TODO: refactor this correctly. This is a quick fix for pos demo.
+ if request.httprequest.method == 'OPTIONS' and request.func and request.func.routing.get('cors'):
+ response = werkzeug.wrappers.Response(status=200)
+ response.headers.set('Access-Control-Allow-Origin', request.func.routing['cors'])
+ methods = 'GET, POST'
+ if request.func_request_type == 'json':
+ methods = 'POST'
+ elif request.func.routing.get('methods'):
+ methods = ', '.join(request.func.routing['methods'])
+ response.headers.set('Access-Control-Allow-Methods', methods)
+ response.headers.set('Access-Control-Max-Age',60*60*24)
+ response.headers.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
+ return response
+
r = self._call_function(**self.params)
if not r:
r = werkzeug.wrappers.Response(status=204) # no content
@@ -444,11 +487,10 @@ def httprequest(f):
Use the ``route()`` decorator instead.
"""
- f.combine = True
base = f.__name__.lstrip('/')
if f.__name__ == "index":
base = ""
- return route([base, base + "/<path:_ignored_path>"], type="http", auth="user")(f)
+ return route([base, base + "/<path:_ignored_path>"], type="http", auth="user", combine=True)(f)
#----------------------------------------------------------
# Controller and route registration
@@ -485,6 +527,13 @@ class ControllerType(type):
class Controller(object):
__metaclass__ = ControllerType
+class EndPoint(object):
+ def __init__(self, method, routing):
+ self.method = method
+ self.routing = routing
+ def __call__(self, *args, **kw):
+ return self.method(*args, **kw)
+
def routing_map(modules, nodb_only, converters=None):
routing_map = werkzeug.routing.Map(strict_slashes=False, converters=converters)
for module in modules:
@@ -501,13 +550,25 @@ def routing_map(modules, nodb_only, converters=None):
o = cls()
members = inspect.getmembers(o)
for mk, mv in members:
- if inspect.ismethod(mv) and getattr(mv, 'exposed', False) and (not nodb_only or nodb_only == (mv.auth == "none")):
- for url in mv.routes:
- if getattr(mv, "combine", False):
- url = o._cp_path.rstrip('/') + '/' + url.lstrip('/')
- if url.endswith("/") and len(url) > 1:
- url = url[: -1]
- routing_map.add(werkzeug.routing.Rule(url, endpoint=mv, methods=mv.methods))
+ if inspect.ismethod(mv) and hasattr(mv, 'routing'):
+ routing = dict(type='http', auth='user', methods=None, routes=None)
+ methods_done = list()
+ for claz in reversed(mv.im_class.mro()):
+ fn = getattr(claz, mv.func_name, None)
+ if fn and hasattr(fn, 'routing') and fn not in methods_done:
+ methods_done.append(fn)
+ routing.update(fn.routing)
+ if not nodb_only or nodb_only == (routing['auth'] == "none"):
+ assert routing['routes'], "Method %r has not route defined" % mv
+ endpoint = EndPoint(mv, routing)
+ for url in routing['routes']:
+ if routing.get("combine", False):
+ # deprecated
+ url = o._cp_path.rstrip('/') + '/' + url.lstrip('/')
+ if url.endswith("/") and len(url) > 1:
+ url = url[: -1]
+
+ routing_map.add(werkzeug.routing.Rule(url, endpoint=endpoint, methods=routing['methods']))
return routing_map
#----------------------------------------------------------
@@ -537,7 +598,7 @@ class Service(object):
class Model(object):
"""
.. deprecated:: 8.0
- Use the resistry and cursor in ``openerp.addons.web.http.request`` instead.
+ Use the resistry and cursor in ``openerp.http.request`` instead.
"""
def __init__(self, session, model):
self.session = session
@@ -626,9 +687,10 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
raise SessionExpiredException("Session expired")
security.check(self.db, self.uid, self.password)
- def logout(self):
+ def logout(self, keep_db=False):
for k in self.keys():
- del self[k]
+ if not (keep_db and k == 'db'):
+ del self[k]
self._default_values()
def _default_values(self):
@@ -776,6 +838,40 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
return Model(self, model)
+ def save_action(self, action):
+ """
+ This method store an action object in the session and returns an integer
+ identifying that action. The method get_action() can be used to get
+ back the action.
+
+ :param the_action: The action to save in the session.
+ :type the_action: anything
+ :return: A key identifying the saved action.
+ :rtype: integer
+ """
+ saved_actions = self.setdefault('saved_actions', {"next": 1, "actions": {}})
+ # we don't allow more than 10 stored actions
+ if len(saved_actions["actions"]) >= 10:
+ del saved_actions["actions"][min(saved_actions["actions"])]
+ key = saved_actions["next"]
+ saved_actions["actions"][key] = action
+ saved_actions["next"] = key + 1
+ self.modified = True
+ return key
+
+ def get_action(self, key):
+ """
+ Gets back a previously saved action. This method can return None if the action
+ was saved since too much time (this case should be handled in a smart way).
+
+ :param key: The key given by save_action()
+ :type key: integer
+ :return: The saved action or None.
+ :rtype: anything
+ """
+ saved_actions = self.get('saved_actions', {})
+ return saved_actions.get("actions", {}).get(key)
+
def session_gc(session_store):
if random.random() < 0.001:
# we keep session one week
@@ -800,8 +896,10 @@ class LazyResponse(werkzeug.wrappers.Response):
""" Lazy werkzeug response.
API not yet frozen"""
- def __init__(self, callback, **kwargs):
+ def __init__(self, callback, status_code=None, **kwargs):
super(LazyResponse, self).__init__(mimetype='text/html')
+ if status_code:
+ self.status_code = status_code
self.callback = callback
self.params = kwargs
def process(self):
@@ -844,7 +942,7 @@ class Root(object):
self.load_addons()
_logger.info("Generating nondb routing")
- self.nodb_routing_map = routing_map(['', "web"], True)
+ self.nodb_routing_map = routing_map([''] + openerp.conf.server_wide_modules, True)
def __call__(self, environ, start_response):
""" Handle a WSGI request
@@ -892,8 +990,16 @@ class Root(object):
return explicit_session
def setup_db(self, httprequest):
- if not httprequest.session.db:
- # allow "admin" routes to works without being logged in when in monodb.
+ db = httprequest.session.db
+ # Check if session.db is legit
+ if db:
+ if db not in db_filter([db], httprequest=httprequest):
+ _logger.warn("Logged into database '%s', but dbfilter "
+ "rejects it; logging session out.", db)
+ httprequest.session.logout()
+ db = None
+
+ if not db:
httprequest.session.db = db_monodb(httprequest)
def setup_lang(self, httprequest):
@@ -916,7 +1022,10 @@ class Root(object):
try:
result.process()
except(Exception), e:
- result = request.registry['ir.http']._handle_exception(e)
+ if request.db:
+ result = request.registry['ir.http']._handle_exception(e)
+ else:
+ raise
if isinstance(result, basestring):
response = werkzeug.wrappers.Response(result, mimetype='text/html')
@@ -934,6 +1043,16 @@ class Root(object):
if not explicit_session and hasattr(response, 'set_cookie'):
response.set_cookie('session_id', httprequest.session.sid, max_age=90 * 24 * 60 * 60)
+ # Support for Cross-Origin Resource Sharing
+ if request.func and 'cors' in request.func.routing:
+ response.headers.set('Access-Control-Allow-Origin', request.func.routing['cors'])
+ methods = 'GET, POST'
+ if request.func_request_type == 'json':
+ methods = 'POST'
+ elif request.func.routing.get('methods'):
+ methods = ', '.join(request.func.routing['methods'])
+ response.headers.set('Access-Control-Allow-Methods', methods)
+
return response
def dispatch(self, environ, start_response):
@@ -942,7 +1061,6 @@ class Root(object):
"""
try:
httprequest = werkzeug.wrappers.Request(environ)
- httprequest.parameter_storage_class = werkzeug.datastructures.ImmutableDict
httprequest.app = self
explicit_session = self.setup_session(httprequest)
@@ -962,10 +1080,12 @@ class Root(object):
if db:
openerp.modules.registry.RegistryManager.check_registry_signaling(db)
try:
- ir_http = request.registry['ir.http']
+ with openerp.tools.mute_logger('openerp.sql_db'):
+ ir_http = request.registry['ir.http']
except psycopg2.OperationalError:
- # psycopg2 error. At this point, that's mean the database does not exists
- # anymore. We unlog the user and failback in nodb mode
+ # psycopg2 error. At this point, that means the
+ # database probably does not exists anymore. Log the
+ # user out and fall back to nodb
request.session.logout()
result = _dispatch_nodb()
else:
@@ -986,8 +1106,11 @@ class Root(object):
return request.registry['ir.http'].routing_map()
def db_list(force=False, httprequest=None):
- httprequest = httprequest or request.httprequest
dbs = openerp.netsvc.dispatch_rpc("db", "list", [force])
+ return db_filter(dbs, httprequest=httprequest)
+
+def db_filter(dbs, httprequest=None):
+ httprequest = httprequest or request.httprequest
h = httprequest.environ['HTTP_HOST'].split(':')[0]
d = h.split('.')[0]
r = openerp.tools.config['dbfilter'].replace('%h', h).replace('%d', d)
@@ -1006,8 +1129,6 @@ def db_monodb(httprequest=None):
Returns ``None`` if the magic is not magic enough.
"""
httprequest = httprequest or request.httprequest
- db = None
- redirect = None
dbs = db_list(True, httprequest)
@@ -1042,6 +1163,6 @@ root = None
def wsgi_postload():
global root
root = Root()
- openerp.wsgi.register_wsgi_handler(root)
+ openerp.service.wsgi_server.register_wsgi_handler(root)
# vim:et:ts=4:sw=4:
diff --git a/openerp/import_xml.rng b/openerp/import_xml.rng
index a79b7775f3f..04922268e27 100644
--- a/openerp/import_xml.rng
+++ b/openerp/import_xml.rng
@@ -207,6 +207,33 @@
</rng:element>
</rng:define>
+ <rng:define name="template">
+ <rng:element name="template">
+ <rng:optional><rng:attribute name="id"/></rng:optional>
+ <rng:optional><rng:attribute name="t-name"/></rng:optional>
+ <rng:optional><rng:attribute name="name"/></rng:optional>
+ <rng:optional><rng:attribute name="forcecreate"/></rng:optional>
+ <rng:optional><rng:attribute name="context"/></rng:optional>
+ <rng:optional><rng:attribute name="priority"/></rng:optional>
+ <rng:choice>
+ <rng:group>
+ <rng:optional><rng:attribute name="inherit_id"/></rng:optional>
+ <rng:optional><rng:attribute name="inherit_option_id"/></rng:optional>
+ <rng:optional><rng:attribute name="groups"/></rng:optional>
+ </rng:group>
+ <rng:optional>
+ <rng:attribute name="page"><rng:value>True</rng:value></rng:attribute>
+ </rng:optional>
+ </rng:choice>
+ <rng:zeroOrMore>
+ <rng:choice>
+ <rng:text/>
+ <rng:ref name="any"/>
+ </rng:choice>
+ </rng:zeroOrMore>
+ </rng:element>
+ </rng:define>
+
<rng:define name="delete">
<rng:element name="delete">
<rng:attribute name="model" />
@@ -285,6 +312,7 @@
<rng:text/>
<rng:ref name="menuitem" />
<rng:ref name="record" />
+ <rng:ref name="template" />
<rng:ref name="delete" />
<rng:ref name="wizard" />
<rng:ref name="act_window" />
diff --git a/openerp/modules/__init__.py b/openerp/modules/__init__.py
index feaf014f568..55eeefaaa19 100644
--- a/openerp/modules/__init__.py
+++ b/openerp/modules/__init__.py
@@ -26,16 +26,10 @@
from . import db, graph, loading, migration, module, registry
-# TODO temporarily expose those things
-from openerp.modules.module import \
- get_modules, get_modules_with_version, \
- load_information_from_description_file, \
- get_module_resource, zip_directory, \
- get_module_path, initialize_sys_path, \
- load_openerp_module, init_module_models, \
- adapt_version
-
from openerp.modules.loading import load_modules
+from openerp.modules.module import get_modules, get_modules_with_version, \
+ load_information_from_description_file, get_module_resource, get_module_path, \
+ initialize_sys_path, load_openerp_module, init_module_models, adapt_version
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py
index 48c5c5adab5..7ca0a6785d6 100644
--- a/openerp/modules/loading.py
+++ b/openerp/modules/loading.py
@@ -70,6 +70,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
cr.commit()
else:
cr.rollback()
+ # avoid keeping stale xml_id, etc. in cache
+ openerp.modules.registry.RegistryManager.clear_caches(cr.dbname)
+
def _get_files_of_kind(kind):
if kind == 'demo':
@@ -179,18 +182,12 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
migrations.migrate_module(package, 'post')
if has_demo:
- # launch tests only in demo mode, as most tests will depend
- # on demo data. Other tests can be added into the regular
- # 'data' section, but should probably not alter the data,
- # as there is no rollback.
+ # launch tests only in demo mode, allowing tests to use demo data.
if tools.config.options['test_enable']:
+ # Yamel test
report.record_result(load_test(module_name, idref, mode))
-
- # Run the `fast_suite` and `checks` tests given by the module.
- if module_name == 'base':
- # Also run the core tests after the database is created.
- report.record_result(openerp.modules.module.run_unit_tests('openerp'))
- report.record_result(openerp.modules.module.run_unit_tests(module_name))
+ # Python tests
+ report.record_result(openerp.modules.module.run_unit_tests(module_name, cr.dbname))
processed_modules.append(package.name)
@@ -244,7 +241,6 @@ def load_marked_modules(cr, graph, states, force, progressdict, report, loaded_m
if not processed: break
return processed_modules
-
def load_modules(db, force_demo=False, status=None, update_module=False):
# TODO status['progress'] reporting is broken: used twice (and reset each
# time to zero) in load_module_graph, not fine-grained enough.
diff --git a/openerp/modules/module.py b/openerp/modules/module.py
index 98511234b75..554b38f06cf 100644
--- a/openerp/modules/module.py
+++ b/openerp/modules/module.py
@@ -20,38 +20,32 @@
#
##############################################################################
+import functools
import imp
import itertools
+import logging
import os
-from os.path import join as opj
+import re
import sys
-import types
-import zipimport
+import unittest
+from os.path import join as opj
-import openerp.tools as tools
-import openerp.tools.osutil as osutil
-from openerp.tools.safe_eval import safe_eval as eval
+import unittest2
-import zipfile
+import openerp
+import openerp.tools as tools
import openerp.release as release
-
-import re
-import base64
-from zipfile import PyZipFile, ZIP_DEFLATED
-from cStringIO import StringIO
-
-import logging
+from openerp.tools.safe_eval import safe_eval as eval
_logger = logging.getLogger(__name__)
_test_logger = logging.getLogger('openerp.tests')
+# addons path as a list
ad_paths = []
# Modules already loaded
loaded = []
-_logger = logging.getLogger(__name__)
-
class AddonsImportHook(object):
"""
Import hook to load OpenERP addons from multiple paths.
@@ -70,13 +64,10 @@ class AddonsImportHook(object):
return self # We act as a loader too.
def load_module(self, module_name):
+ if module_name in sys.modules:
+ return sys.modules[module_name]
- module_parts = module_name.split('.')
- if len(module_parts) == 3 and module_name.startswith('openerp.addons.'):
- module_part = module_parts[2]
- if module_name in sys.modules:
- return sys.modules[module_name]
-
+ _1, _2, module_part = module_name.split('.')
# Note: we don't support circular import.
f, path, descr = imp.find_module(module_part, ad_paths)
mod = imp.load_module('openerp.addons.' + module_part, f, path, descr)
@@ -124,7 +115,6 @@ def get_module_path(module, downloaded=False, display_warning=True):
_logger.warning('module %s: module not found', module)
return False
-
def get_module_filetree(module, dir='.'):
path = get_module_path(module)
if not path:
@@ -136,12 +126,7 @@ def get_module_filetree(module, dir='.'):
if dir.startswith('..') or (dir and dir[0] == '/'):
raise Exception('Cannot access file outside the module')
- if not os.path.isdir(path):
- # zipmodule
- zip = zipfile.ZipFile(path + ".zip")
- files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()]
- else:
- files = osutil.listdir(path, True)
+ files = openerp.tools.osutil.listdir(path, True)
tree = {}
for f in files:
@@ -158,68 +143,6 @@ def get_module_filetree(module, dir='.'):
return tree
-def zip_directory(directory, b64enc=True, src=True):
- """Compress a directory
-
- @param directory: The directory to compress
- @param base64enc: if True the function will encode the zip file with base64
- @param src: Integrate the source files
-
- @return: a string containing the zip file
- """
-
- RE_exclude = re.compile('(?:^\..+\.swp$)|(?:\.py[oc]$)|(?:\.bak$)|(?:\.~.~$)', re.I)
-
- def _zippy(archive, path, src=True):
- path = os.path.abspath(path)
- base = os.path.basename(path)
- for f in osutil.listdir(path, True):
- bf = os.path.basename(f)
- if not RE_exclude.search(bf) and (src or bf == '__openerp__.py' or not bf.endswith('.py')):
- archive.write(os.path.join(path, f), os.path.join(base, f))
-
- archname = StringIO()
- archive = PyZipFile(archname, "w", ZIP_DEFLATED)
-
- # for Python 2.5, ZipFile.write() still expects 8-bit strings (2.6 converts to utf-8)
- directory = tools.ustr(directory).encode('utf-8')
-
- archive.writepy(directory)
- _zippy(archive, directory, src=src)
- archive.close()
- archive_data = archname.getvalue()
- archname.close()
-
- if b64enc:
- return base64.encodestring(archive_data)
-
- return archive_data
-
-def get_module_as_zip(modulename, b64enc=True, src=True):
- """Generate a module as zip file with the source or not and can do a base64 encoding
-
- @param modulename: The module name
- @param b64enc: if True the function will encode the zip file with base64
- @param src: Integrate the source files
-
- @return: a stream to store in a file-like object
- """
-
- ap = get_module_path(str(modulename))
- if not ap:
- raise Exception('Unable to find path for module %s' % modulename)
-
- ap = ap.encode('utf8')
- if os.path.isfile(ap + '.zip'):
- val = file(ap + '.zip', 'rb').read()
- if b64enc:
- val = base64.encodestring(val)
- else:
- val = zip_directory(ap, b64enc, src)
-
- return val
-
-
def get_module_resource(module, *args):
"""Return the full path of a resource of the given module.
@@ -239,12 +162,6 @@ def get_module_resource(module, *args):
# the module is a directory - ignore zip behavior
if os.path.exists(resource_path):
return resource_path
- elif zipfile.is_zipfile(mod_path + '.zip'):
- zip = zipfile.ZipFile( mod_path + ".zip")
- files = ['/'.join(f.split('/')[1:]) for f in zip.namelist()]
- resource_path = '/'.join(args)
- if resource_path in files:
- return opj(mod_path, resource_path)
return False
def get_module_icon(module):
@@ -262,7 +179,7 @@ def load_information_from_description_file(module):
mod_path = get_module_path(module)
if terp_file:
info = {}
- if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path+'.zip'):
+ if os.path.isfile(terp_file):
# default values for descriptor
info = {
'application': False,
@@ -304,7 +221,6 @@ def load_information_from_description_file(module):
_logger.debug('module %s: no __openerp__.py file found.', module)
return {}
-
def init_module_models(cr, module_name, obj_list):
""" Initialize a list of models.
@@ -346,12 +262,7 @@ def load_openerp_module(module_name):
initialize_sys_path()
try:
mod_path = get_module_path(module_name)
- zip_mod_path = '' if not mod_path else mod_path + '.zip'
- if not os.path.isfile(zip_mod_path):
- __import__('openerp.addons.' + module_name)
- else:
- zimp = zipimport.zipimporter(zip_mod_path)
- zimp.load_module(module_name)
+ __import__('openerp.addons.' + module_name)
# Call the module's post-load hook. This can done before any model or
# data has been initialized. This is ok as the post-load hook is for
@@ -361,8 +272,7 @@ def load_openerp_module(module_name):
getattr(sys.modules['openerp.addons.' + module_name], info['post_load'])()
except Exception, e:
- mt = isinstance(e, zipimport.ZipImportError) and 'zip ' or ''
- msg = "Couldn't load %smodule %s" % (mt, module_name)
+ msg = "Couldn't load module %s" % (module_name)
_logger.critical(msg)
_logger.critical(e)
raise
@@ -382,7 +292,7 @@ def get_modules():
def is_really_module(name):
manifest_name = opj(dir, name, '__openerp__.py')
zipfile_name = opj(dir, name)
- return os.path.isfile(manifest_name) or zipfile.is_zipfile(zipfile_name)
+ return os.path.isfile(manifest_name)
return map(clean, filter(is_really_module, os.listdir(dir)))
plist = []
@@ -391,7 +301,6 @@ def get_modules():
plist.extend(listdir(ad))
return list(set(plist))
-
def get_modules_with_version():
modules = get_modules()
res = dict.fromkeys(modules, adapt_version('1.0'))
@@ -409,126 +318,108 @@ def adapt_version(version):
version = '%s.%s' % (serie, version)
return version
-
-def get_test_modules(module, submodule, explode):
- """
- Return a list of submodules containing tests.
- `submodule` can be:
- - None
- - the name of a submodule
- - '__fast_suite__'
- - '__sanity_checks__'
- """
- # Turn command-line module, submodule into importable names.
- if module is None:
- pass
- elif module == 'openerp':
- module = 'openerp.tests'
- else:
- module = 'openerp.addons.' + module + '.tests'
-
+def get_test_modules(module):
+ """ Return a list of module for the addons potentialy containing tests to
+ feed unittest2.TestLoader.loadTestsFromModule() """
# Try to import the module
+ module = 'openerp.addons.' + module + '.tests'
try:
__import__(module)
except Exception, e:
- if explode:
- print 'Can not `import %s`.' % module
- import logging
- logging.exception('')
- sys.exit(1)
- else:
- if str(e) == 'No module named tests':
- # It seems the module has no `tests` sub-module, no problem.
- pass
- else:
- _logger.exception('Can not `import %s`.', module)
- return []
-
- # Discover available test sub-modules.
- m = sys.modules[module]
- submodule_names = sorted([x for x in dir(m) \
- if x.startswith('test_') and \
- isinstance(getattr(m, x), types.ModuleType)])
- submodules = [getattr(m, x) for x in submodule_names]
-
- def show_submodules_and_exit():
- if submodule_names:
- print 'Available submodules are:'
- for x in submodule_names:
- print ' ', x
- sys.exit(1)
-
- if submodule is None:
- # Use auto-discovered sub-modules.
- ms = submodules
- elif submodule == '__fast_suite__':
- # Obtain the explicit test sub-modules list.
- ms = getattr(sys.modules[module], 'fast_suite', None)
- # `suite` was used before the 6.1 release instead of `fast_suite`.
- ms = ms if ms else getattr(sys.modules[module], 'suite', None)
- if ms is None:
- if explode:
- print 'The module `%s` has no defined test suite.' % (module,)
- show_submodules_and_exit()
- else:
- ms = []
- elif submodule == '__sanity_checks__':
- ms = getattr(sys.modules[module], 'checks', None)
- if ms is None:
- if explode:
- print 'The module `%s` has no defined sanity checks.' % (module,)
- show_submodules_and_exit()
- else:
- ms = []
- else:
- # Pick the command-line-specified test sub-module.
- m = getattr(sys.modules[module], submodule, None)
- ms = [m]
-
- if m is None:
- if explode:
- print 'The module `%s` has no submodule named `%s`.' % \
- (module, submodule)
- show_submodules_and_exit()
- else:
- ms = []
-
- return ms
-
-def run_unit_tests(module_name):
+ # If module has no `tests` sub-module, no problem.
+ if str(e) != 'No module named tests':
+ _logger.exception('Can not `import %s`.', module)
+ return []
+
+ # include submodules too
+ result = [mod_obj for name, mod_obj in sys.modules.iteritems()
+ if mod_obj # mod_obj can be None
+ if name.startswith(module)
+ if re.search(r'test_\w+$', name)]
+ return result
+
+# Use a custom stream object to log the test executions.
+class TestStream(object):
+ def __init__(self):
+ self.r = re.compile(r'^-*$|^ *... *$|^ok$')
+ def flush(self):
+ pass
+ def write(self, s):
+ if self.r.match(s):
+ return
+ first = True
+ for c in s.split('\n'):
+ if not first:
+ c = '` ' + c
+ first = False
+ _test_logger.info(c)
+
+current_test = None
+
+def run_unit_tests(module_name, dbname):
+ """
+ :returns: ``True`` if all of ``module_name``'s tests succeeded, ``False``
+ if any of them failed.
+ :rtype: bool
"""
- Return True or False if some tests were found and succeeded or failed.
- Return None if no test was found.
+ global current_test
+ current_test = module_name
+ mods = get_test_modules(module_name)
+ r = True
+ for m in mods:
+ tests = unwrap_suite(unittest2.TestLoader().loadTestsFromModule(m))
+ suite = unittest2.TestSuite(itertools.ifilter(runs_at_install, tests))
+ _logger.info('module %s: running test %s.', module_name, m.__name__)
+
+ result = unittest2.TextTestRunner(verbosity=2, stream=TestStream()).run(suite)
+
+ if not result.wasSuccessful():
+ r = False
+ _logger.error("Module %s: %d failures, %d errors",
+ module_name, len(result.failures), len(result.errors))
+ current_test = None
+ return r
+
+def runs_at(test, hook, default):
+ # by default, tests do not run post install
+ test_runs = getattr(test, hook, default)
+
+ # for a test suite, we're done
+ if not isinstance(test, unittest.TestCase):
+ return test_runs
+
+ # otherwise check the current test method to see it's been set to a
+ # different state
+ method = getattr(test, test._testMethodName)
+ return getattr(method, hook, test_runs)
+
+runs_at_install = functools.partial(runs_at, hook='at_install', default=True)
+runs_post_install = functools.partial(runs_at, hook='post_install', default=False)
+
+def unwrap_suite(test):
"""
- import unittest2
- ms = get_test_modules(module_name, '__fast_suite__', explode=False)
- # TODO: No need to try again if the above call failed because of e.g. a syntax error.
- ms.extend(get_test_modules(module_name, '__sanity_checks__', explode=False))
- suite = unittest2.TestSuite()
- for m in ms:
- suite.addTests(unittest2.TestLoader().loadTestsFromModule(m))
- if ms:
- _test_logger.info('module %s: executing %s `fast_suite` and/or `checks` sub-modules', module_name, len(ms))
- # Use a custom stream object to log the test executions.
- class MyStream(object):
- def __init__(self):
- self.r = re.compile(r'^-*$|^ *... *$|^ok$')
- def flush(self):
- pass
- def write(self, s):
- if self.r.match(s):
- return
- first = True
- for c in s.split('\n'):
- if not first:
- c = '` ' + c
- first = False
- _test_logger.info(c)
- result = unittest2.TextTestRunner(verbosity=2, stream=MyStream()).run(suite)
- if result.wasSuccessful():
- return True
- else:
- _logger.error('module %s: at least one error occurred in a test', module_name)
- return False
+ Attempts to unpack testsuites (holding suites or cases) in order to
+ generate a single stream of terminals (either test cases or customized
+ test suites). These can then be checked for run/skip attributes
+ individually.
+
+ An alternative would be to use a variant of @unittest2.skipIf with a state
+ flag of some sort e.g. @unittest2.skipIf(common.runstate != 'at_install'),
+ but then things become weird with post_install as tests should *not* run
+ by default there
+ """
+ if isinstance(test, unittest.TestCase):
+ yield test
+ return
+
+ subtests = list(test)
+ # custom test suite (no test cases)
+ if not len(subtests):
+ yield test
+ return
+
+ for item in itertools.chain.from_iterable(
+ itertools.imap(unwrap_suite, subtests)):
+ yield item
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py
index 5929924b118..78b7e5caeab 100644
--- a/openerp/modules/registry.py
+++ b/openerp/modules/registry.py
@@ -68,8 +68,8 @@ class Registry(Mapping):
# must be reloaded.
# The `base_cache_signaling sequence` indicates all caches must be
# invalidated (i.e. cleared).
- self.base_registry_signaling_sequence = 1
- self.base_cache_signaling_sequence = 1
+ self.base_registry_signaling_sequence = None
+ self.base_cache_signaling_sequence = None
# Flag indicating if at least one model cache has been cleared.
# Useful only in a multi-process context.
@@ -159,7 +159,7 @@ class Registry(Mapping):
@classmethod
def setup_multi_process_signaling(cls, cr):
if not openerp.multi_process:
- return
+ return None, None
# Inter-process signaling:
# The `base_registry_signaling` sequence indicates the whole registry
@@ -172,6 +172,16 @@ class Registry(Mapping):
cr.execute("""SELECT nextval('base_registry_signaling')""")
cr.execute("""CREATE SEQUENCE base_cache_signaling INCREMENT BY 1 START WITH 1""")
cr.execute("""SELECT nextval('base_cache_signaling')""")
+
+ cr.execute("""
+ SELECT base_registry_signaling.last_value,
+ base_cache_signaling.last_value
+ FROM base_registry_signaling, base_cache_signaling""")
+ r, c = cr.fetchone()
+ _logger.debug("Multiprocess load registry signaling: [Registry: # %s] "\
+ "[Cache: # %s]",
+ r, c)
+ return r, c
@contextmanager
def cursor(self, auto_commit=True):
@@ -183,6 +193,21 @@ class Registry(Mapping):
finally:
cr.close()
+class TestRLock(object):
+ def __init__(self):
+ self._lock = threading.RLock()
+ def acquire(self):
+ if openerp.tools.config['test_enable']:
+ return
+ return self._lock.acquire()
+ def release(self):
+ if openerp.tools.config['test_enable']:
+ return
+ return self._lock.release()
+ def __enter__(self):
+ self.acquire()
+ def __exit__(self, type, value, traceback):
+ self.release()
class RegistryManager(object):
""" Model registries manager.
@@ -194,7 +219,7 @@ class RegistryManager(object):
# Mapping between db name and model registry.
# Accessed through the methods below.
registries = {}
- registries_lock = threading.RLock()
+ registries_lock = TestRLock()
@classmethod
def get(cls, db_name, force_demo=False, status=None, update_module=False):
@@ -229,6 +254,10 @@ class RegistryManager(object):
cls.delete(db_name)
cls.registries[db_name] = registry
try:
+ with registry.cursor() as cr:
+ seq_registry, seq_cache = Registry.setup_multi_process_signaling(cr)
+ registry.base_registry_signaling_sequence = seq_registry
+ registry.base_cache_signaling_sequence = seq_cache
# This should be a method on Registry
openerp.modules.load_modules(registry.db, force_demo, status, update_module)
except Exception:
@@ -242,7 +271,6 @@ class RegistryManager(object):
cr = registry.db.cursor()
try:
- Registry.setup_multi_process_signaling(cr)
registry.do_parent_store(cr)
cr.commit()
finally:
@@ -304,16 +332,20 @@ class RegistryManager(object):
base_cache_signaling.last_value
FROM base_registry_signaling, base_cache_signaling""")
r, c = cr.fetchone()
+ _logger.debug("Multiprocess signaling check: [Registry - old# %s new# %s] "\
+ "[Cache - old# %s new# %s]",
+ registry.base_registry_signaling_sequence, r,
+ registry.base_cache_signaling_sequence, c)
# Check if the model registry must be reloaded (e.g. after the
# database has been updated by another process).
- if registry.base_registry_signaling_sequence > 1 and registry.base_registry_signaling_sequence != r:
+ if registry.base_registry_signaling_sequence is not None and registry.base_registry_signaling_sequence != r:
changed = True
_logger.info("Reloading the model registry after database signaling.")
registry = cls.new(db_name)
# Check if the model caches must be invalidated (e.g. after a write
# occured on another process). Don't clear right after a registry
# has been reload.
- elif registry.base_cache_signaling_sequence > 1 and registry.base_cache_signaling_sequence != c:
+ elif registry.base_cache_signaling_sequence is not None and registry.base_cache_signaling_sequence != c:
changed = True
_logger.info("Invalidating all model caches after database signaling.")
registry.clear_caches()
@@ -352,6 +384,7 @@ class RegistryManager(object):
@classmethod
def signal_registry_change(cls, db_name):
if openerp.multi_process and db_name in cls.registries:
+ _logger.info("Registry changed, signaling through the database")
registry = cls.get(db_name)
cr = registry.db.cursor()
r = 1
diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py
index 08d93947698..648a8447292 100644
--- a/openerp/osv/expression.py
+++ b/openerp/osv/expression.py
@@ -1018,7 +1018,7 @@ class expression(object):
right += ' 23:59:59'
push(create_substitution_leaf(leaf, (left, operator, right), working_model))
- elif field.translate:
+ elif field.translate and right:
need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike')
sql_operator = {'=like': 'like', '=ilike': 'ilike'}.get(operator, operator)
if need_wildcard:
diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py
index cbb63be154f..478f982cd69 100644
--- a/openerp/osv/fields.py
+++ b/openerp/osv/fields.py
@@ -37,6 +37,7 @@
import base64
import datetime as DT
+import functools
import logging
import pytz
import re
@@ -451,6 +452,39 @@ class selection(_column):
_column.__init__(self, string=string, **args)
self.selection = selection
+ @classmethod
+ def reify(cls, cr, uid, model, field, context=None):
+ """ Munges the field's ``selection`` attribute as necessary to get
+ something useable out of it: calls it if it's a function, applies
+ translations to labels if it's not.
+
+ A callable ``selection`` is considered translated on its own.
+
+ :param orm.Model model:
+ :param _column field:
+ """
+ if callable(field.selection):
+ return field.selection(model, cr, uid, context)
+
+ if not (context and 'lang' in context):
+ return field.selection
+
+ # field_to_dict isn't given a field name, only a field object, we
+ # need to get the name back in order to perform the translation lookup
+ field_name = next(
+ name for name, column in model._columns.iteritems()
+ if column == field)
+
+ translation_filter = "%s,%s" % (model._name, field_name)
+ translate = functools.partial(
+ model.pool['ir.translation']._get_source,
+ cr, uid, translation_filter, 'selection', context['lang'])
+
+ return [
+ (value, translate(label))
+ for value, label in field.selection
+ ]
+
# ---------------------------------------------------------
# Relationals fields
# ---------------------------------------------------------
@@ -567,9 +601,12 @@ class one2many(_column):
domain = self._domain(obj) if callable(self._domain) else self._domain
model = obj.pool[self._obj]
ids2 = model.search(cr, user, domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
- for r in model._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
- if r[self._fields_id] in res:
- res[r[self._fields_id]].append(r['id'])
+ if len(ids) != 1:
+ for r in model._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
+ if r[self._fields_id] in res:
+ res[r[self._fields_id]].append(r['id'])
+ else:
+ res[ids[0]] = ids2
return res
def set(self, cr, obj, id, field, values, user=None, context=None):
@@ -1424,11 +1461,9 @@ class property(function):
def _get_by_id(self, obj, cr, uid, prop_name, ids, context=None):
prop = obj.pool.get('ir.property')
vids = [obj._name + ',' + str(oid) for oid in ids]
- def_id = self._field_get(cr, uid, obj._name, prop_name[0])
- company = obj.pool.get('res.company')
- cid = company._company_default_get(cr, uid, obj._name, def_id, context=context)
- domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name), ('company_id', '=', cid)]
- #domain = prop._get_domain(cr, uid, prop_name, obj._name, context)
+ domain = [('fields_id.model', '=', obj._name), ('fields_id.name', 'in', prop_name)]
+ if context and context.get('company_id'):
+ domain += [('company_id', '=', context.get('company_id'))]
if vids:
domain = [('res_id', 'in', vids)] + domain
return prop.search(cr, uid, domain, context=context)
@@ -1438,7 +1473,12 @@ class property(function):
if context is None:
context = {}
- nids = self._get_by_id(obj, cr, uid, [prop_name], [id], context)
+ def_id = self._field_get(cr, uid, obj._name, prop_name)
+ company = obj.pool.get('res.company')
+ cid = company._company_default_get(cr, uid, obj._name, def_id, context=context)
+ # TODO for trunk: add new parameter company_id to _get_by_id method
+ context_company = dict(context, company_id=cid)
+ nids = self._get_by_id(obj, cr, uid, [prop_name], [id], context_company)
if nids:
cr.execute('DELETE FROM ir_property WHERE id IN %s', (tuple(nids),))
@@ -1452,10 +1492,6 @@ class property(function):
property_create = True
if property_create:
- def_id = self._field_get(cr, uid, obj._name, prop_name)
- company = obj.pool.get('res.company')
- cid = company._company_default_get(cr, uid, obj._name, def_id,
- context=context)
propdef = obj.pool.get('ir.model.fields').browse(cr, uid, def_id,
context=context)
prop = obj.pool.get('ir.property')
@@ -1562,11 +1598,7 @@ def field_to_dict(model, cr, user, field, context=None):
res[arg] = getattr(field, arg)
if hasattr(field, 'selection'):
- if isinstance(field.selection, (tuple, list)):
- res['selection'] = field.selection
- else:
- # call the 'dynamic selection' function
- res['selection'] = field.selection(model, cr, user, context)
+ res['selection'] = selection.reify(cr, user, model, field, context=context)
if res['type'] in ('one2many', 'many2many', 'many2one'):
res['relation'] = field._obj
res['domain'] = field._domain(model) if callable(field._domain) else field._domain
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 1f15eee93c0..3126507608f 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -47,6 +47,7 @@ import itertools
import logging
import operator
import pickle
+import pytz
import re
import simplejson
import time
@@ -62,7 +63,7 @@ import fields
import openerp
import openerp.tools as tools
from openerp.tools.config import config
-from openerp.tools.misc import CountingStream
+from openerp.tools.misc import CountingStream, DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
from openerp import SUPERUSER_ID
@@ -515,7 +516,7 @@ class browse_record(object):
return self._id
def __str__(self):
- return "browse_record(%s, %d)" % (self._table_name, self._id)
+ return "browse_record(%s, %s)" % (self._table_name, self._id)
def __eq__(self, other):
if not isinstance(other, browse_record):
@@ -769,8 +770,6 @@ class BaseModel(object):
(name_id, context['module'], 'ir.model', model_id)
)
- cr.commit()
-
cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,))
cols = {}
for rec in cr.dictfetchall():
@@ -837,7 +836,6 @@ class BaseModel(object):
for key, val in vals.items():
if cols[k][key] != vals[key]:
cr.execute('update ir_model_fields set field_description=%s where model=%s and name=%s', (vals['field_description'], vals['model'], vals['name']))
- cr.commit()
cr.execute("""UPDATE ir_model_fields SET
model_id=%s, field_description=%s, ttype=%s, relation=%s,
select_level=%s, readonly=%s ,required=%s, selectable=%s, relation_field=%s, translate=%s, serialization_field_id=%s
@@ -848,7 +846,6 @@ class BaseModel(object):
vals['select_level'], bool(vals['readonly']), bool(vals['required']), bool(vals['selectable']), vals['relation_field'], bool(vals['translate']), vals['serialization_field_id'], vals['model'], vals['name']
))
break
- cr.commit()
#
# Goal: try to apply inheritance at the instanciation level and
@@ -899,11 +896,6 @@ class BaseModel(object):
for c in new.keys():
if new[c].manual:
del new[c]
- # Duplicate float fields because they have a .digits
- # cache (which must be per-registry, not server-wide).
- for c in new.keys():
- if new[c]._type == 'float':
- new[c] = copy.copy(new[c])
if hasattr(new, 'update'):
new.update(cls.__dict__.get(s, {}))
elif s=='_constraints':
@@ -939,6 +931,13 @@ class BaseModel(object):
if not getattr(cls, '_original_module', None):
cls._original_module = cls._module
obj = object.__new__(cls)
+
+ if hasattr(obj, '_columns'):
+ # float fields are registry-dependent (digit attribute). Duplicate them to avoid issues.
+ for c, f in obj._columns.items():
+ if f._type == 'float':
+ obj._columns[c] = copy.copy(f)
+
obj.__init__(pool, cr)
return obj
@@ -1541,9 +1540,16 @@ class BaseModel(object):
error_msgs = []
for constraint in self._constraints:
fun, msg, fields = constraint
- # We don't pass around the context here: validation code
- # must always yield the same results.
- if not fun(self, cr, uid, ids):
+ try:
+ # We don't pass around the context here: validation code
+ # must always yield the same results.
+ valid = fun(self, cr, uid, ids)
+ extra_error = None
+ except Exception, e:
+ _logger.debug('Exception while validating constraint', exc_info=True)
+ valid = False
+ extra_error = tools.ustr(e)
+ if not valid:
# Check presence of __call__ directly instead of using
# callable() because it will be deprecated as of Python 3.0
if hasattr(msg, '__call__'):
@@ -1555,6 +1561,8 @@ class BaseModel(object):
translated_msg = tmp_msg
else:
translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, msg)
+ if extra_error:
+ translated_msg += "\n\n%s\n%s" % (_('Error details:'), extra_error)
error_msgs.append(
_("The field(s) `%s` failed against a constraint: %s") % (', '.join(fields), translated_msg)
)
@@ -1696,265 +1704,6 @@ class BaseModel(object):
return any([self.pool.get('res.users').has_group(cr, uid, group_ext_id)
for group_ext_id in groups.split(',')])
- def __view_look_dom(self, cr, user, node, view_id, in_tree_view, model_fields, context=None):
- """Return the description of the fields in the node.
-
- In a normal call to this method, node is a complete view architecture
- but it is actually possible to give some sub-node (this is used so
- that the method can call itself recursively).
-
- Originally, the field descriptions are drawn from the node itself.
- But there is now some code calling fields_get() in order to merge some
- of those information in the architecture.
-
- """
- if context is None:
- context = {}
- result = False
- fields = {}
- children = True
-
- modifiers = {}
-
- def encode(s):
- if isinstance(s, unicode):
- return s.encode('utf8')
- return s
-
- def check_group(node):
- """Apply group restrictions, may be set at view level or model level::
- * at view level this means the element should be made invisible to
- people who are not members
- * at model level (exclusively for fields, obviously), this means
- the field should be completely removed from the view, as it is
- completely unavailable for non-members
-
- :return: True if field should be included in the result of fields_view_get
- """
- if node.tag == 'field' and node.get('name') in self._all_columns:
- column = self._all_columns[node.get('name')].column
- if column.groups and not self.user_has_groups(cr, user,
- groups=column.groups,
- context=context):
- node.getparent().remove(node)
- fields.pop(node.get('name'), None)
- # no point processing view-level ``groups`` anymore, return
- return False
- if node.get('groups'):
- can_see = self.user_has_groups(cr, user,
- groups=node.get('groups'),
- context=context)
- if not can_see:
- node.set('invisible', '1')
- modifiers['invisible'] = True
- if 'attrs' in node.attrib:
- del(node.attrib['attrs']) #avoid making field visible later
- del(node.attrib['groups'])
- return True
-
- if node.tag in ('field', 'node', 'arrow'):
- if node.get('object'):
- attrs = {}
- views = {}
- xml = "<form>"
- for f in node:
- if f.tag == 'field':
- xml += etree.tostring(f, encoding="utf-8")
- xml += "</form>"
- new_xml = etree.fromstring(encode(xml))
- ctx = context.copy()
- ctx['base_model_name'] = self._name
- xarch, xfields = self.pool[node.get('object')].__view_look_dom_arch(cr, user, new_xml, view_id, ctx)
- views['form'] = {
- 'arch': xarch,
- 'fields': xfields
- }
- attrs = {'views': views}
- fields = xfields
- if node.get('name'):
- attrs = {}
- try:
- if node.get('name') in self._columns:
- column = self._columns[node.get('name')]
- else:
- column = self._inherit_fields[node.get('name')][2]
- except Exception:
- column = False
-
- if column:
- relation = self.pool[column._obj] if column._obj else None
-
- children = False
- views = {}
- for f in node:
- if f.tag in ('form', 'tree', 'graph', 'kanban', 'calendar'):
- node.remove(f)
- ctx = context.copy()
- ctx['base_model_name'] = self._name
- xarch, xfields = relation.__view_look_dom_arch(cr, user, f, view_id, ctx)
- views[str(f.tag)] = {
- 'arch': xarch,
- 'fields': xfields
- }
- attrs = {'views': views}
- if node.get('widget') and node.get('widget') == 'selection':
- # Prepare the cached selection list for the client. This needs to be
- # done even when the field is invisible to the current user, because
- # other events could need to change its value to any of the selectable ones
- # (such as on_change events, refreshes, etc.)
-
- # If domain and context are strings, we keep them for client-side, otherwise
- # we evaluate them server-side to consider them when generating the list of
- # possible values
- # TODO: find a way to remove this hack, by allow dynamic domains
- dom = []
- if column._domain and not isinstance(column._domain, basestring):
- 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):
- search_context.update(column._context)
- attrs['selection'] = relation._name_search(cr, user, '', dom, context=search_context, limit=None, name_get_uid=1)
- if (node.get('required') and not int(node.get('required'))) or not column.required:
- attrs['selection'].append((False, ''))
- fields[node.get('name')] = attrs
-
- field = model_fields.get(node.get('name'))
- if field:
- transfer_field_to_modifiers(field, modifiers)
-
-
- elif node.tag in ('form', 'tree'):
- result = self.view_header_get(cr, user, False, node.tag, context)
- if result:
- node.set('string', result)
- in_tree_view = node.tag == 'tree'
-
- elif node.tag == 'calendar':
- for additional_field in ('date_start', 'date_delay', 'date_stop', 'color', 'all_day','attendee'):
- if node.get(additional_field):
- fields[node.get(additional_field)] = {}
-
- if not check_group(node):
- # node must be removed, no need to proceed further with its children
- return fields
-
- # The view architeture overrides the python model.
- # Get the attrs before they are (possibly) deleted by check_group below
- transfer_node_to_modifiers(node, modifiers, context, in_tree_view)
-
- # TODO remove attrs couterpart in modifiers when invisible is true ?
-
- # translate view
- if 'lang' in context:
- if node.text and node.text.strip():
- trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.text.strip())
- if trans:
- node.text = node.text.replace(node.text.strip(), trans)
- if node.tail and node.tail.strip():
- trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.tail.strip())
- if trans:
- node.tail = node.tail.replace(node.tail.strip(), trans)
-
- if node.get('string') and not result:
- trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.get('string'))
- if trans == node.get('string') and ('base_model_name' in context):
- # If translation is same as source, perhaps we'd have more luck with the alternative model name
- # (in case we are in a mixed situation, such as an inherited view where parent_view.model != model
- trans = self.pool.get('ir.translation')._get_source(cr, user, context['base_model_name'], 'view', context['lang'], node.get('string'))
- if trans:
- node.set('string', trans)
-
- for attr_name in ('confirm', 'sum', 'avg', 'help', 'placeholder'):
- attr_value = node.get(attr_name)
- if attr_value:
- trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], attr_value)
- if trans:
- node.set(attr_name, trans)
-
- for f in node:
- if children or (node.tag == 'field' and f.tag in ('filter','separator')):
- fields.update(self.__view_look_dom(cr, user, f, view_id, in_tree_view, model_fields, context))
-
- transfer_modifiers_to_node(modifiers, node)
- return fields
-
- def _disable_workflow_buttons(self, cr, user, node):
- """ Set the buttons in node to readonly if the user can't activate them. """
- if user == 1:
- # admin user can always activate workflow buttons
- return node
-
- # TODO handle the case of more than one workflow for a model or multiple
- # transitions with different groups and same signal
- usersobj = self.pool.get('res.users')
- buttons = (n for n in node.getiterator('button') if n.get('type') != 'object')
- for button in buttons:
- user_groups = usersobj.read(cr, user, [user], ['groups_id'])[0]['groups_id']
- cr.execute("""SELECT DISTINCT t.group_id
- FROM wkf
- INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
- INNER JOIN wkf_transition t ON (t.act_to = a.id)
- WHERE wkf.osv = %s
- AND t.signal = %s
- AND t.group_id is NOT NULL
- """, (self._name, button.get('name')))
- group_ids = [x[0] for x in cr.fetchall() if x[0]]
- can_click = not group_ids or bool(set(user_groups).intersection(group_ids))
- button.set('readonly', str(int(not can_click)))
- return node
-
- def __view_look_dom_arch(self, cr, user, node, view_id, context=None):
- """ Return an architecture and a description of all the fields.
-
- The field description combines the result of fields_get() and
- __view_look_dom().
-
- :param node: the architecture as as an etree
- :return: a tuple (arch, fields) where arch is the given node as a
- string and fields is the description of all the fields.
-
- """
- fields = {}
- if node.tag == 'diagram':
- if node.getchildren()[0].tag == 'node':
- node_model = self.pool[node.getchildren()[0].get('object')]
- node_fields = node_model.fields_get(cr, user, None, context)
- fields.update(node_fields)
- if not node.get("create") and not node_model.check_access_rights(cr, user, 'create', raise_exception=False):
- node.set("create", 'false')
- if node.getchildren()[1].tag == 'arrow':
- arrow_fields = self.pool[node.getchildren()[1].get('object')].fields_get(cr, user, None, context)
- fields.update(arrow_fields)
- else:
- fields = self.fields_get(cr, user, None, context)
- fields_def = self.__view_look_dom(cr, user, node, view_id, False, fields, context=context)
- node = self._disable_workflow_buttons(cr, user, node)
- if node.tag in ('kanban', 'tree', 'form', 'gantt'):
- for action, operation in (('create', 'create'), ('delete', 'unlink'), ('edit', 'write')):
- if not node.get(action) and not self.check_access_rights(cr, user, operation, raise_exception=False):
- node.set(action, 'false')
- arch = etree.tostring(node, encoding="utf-8").replace('\t', '')
- for k in fields.keys():
- if k not in fields_def:
- del fields[k]
- for field in fields_def:
- if field == 'id':
- # sometime, the view may contain the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
- fields['id'] = {'readonly': True, 'type': 'integer', 'string': 'ID'}
- elif field in fields:
- fields[field].update(fields_def[field])
- else:
- cr.execute('select name, model from ir_ui_view where (id=%s or inherit_id=%s) and arch like %s', (view_id, view_id, '%%%s%%' % field))
- res = cr.fetchall()[:]
- model = res[0][1]
- res.insert(0, ("Can't find field '%s' in the following view parts composing the view of object model '%s':" % (field, model), None))
- msg = "\n * ".join([r[0] for r in res])
- msg += "\n\nEither you wrongly customized this view, or some modules bringing those views are not compatible with your current data model"
- _logger.error(msg)
- raise except_orm('View error', msg)
- return arch, fields
-
def _get_default_form_view(self, cr, user, context=None):
""" Generates a default single-line form view using all fields
of the current model except the m2m and o2m ones.
@@ -2052,18 +1801,12 @@ class BaseModel(object):
return view
- #
- # if view_id, view_type is not required
- #
- def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
+ def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
"""
Get the detailed composition of the requested view like fields, model, view architecture
- :param cr: database cursor
- :param user: current user id
:param view_id: id of the view or None
:param view_type: type of the view to return if view_id is None ('form', tree', ...)
- :param context: context arguments, like lang, time zone
:param toolbar: true to include contextual actions
:param submenu: deprecated
:return: dictionary describing the composition of the requested view (including inherited views and extensions)
@@ -2071,156 +1814,22 @@ class BaseModel(object):
* if the inherited view has unknown position to work with other than 'before', 'after', 'inside', 'replace'
* if some tag other than 'position' is found in parent view
:raise Invalid ArchitectureError: if there is view type other than form, tree, calendar, search etc defined on the structure
-
"""
if context is None:
context = {}
-
- def encode(s):
- if isinstance(s, unicode):
- return s.encode('utf8')
- return s
-
- def raise_view_error(error_msg, child_view_id):
- view, child_view = self.pool.get('ir.ui.view').browse(cr, user, [view_id, child_view_id], context)
- error_msg = error_msg % {'parent_xml_id': view.xml_id}
- raise AttributeError("View definition error for inherited view '%s' on model '%s': %s"
- % (child_view.xml_id, self._name, error_msg))
-
- def locate(source, spec):
- """ Locate a node in a source (parent) architecture.
-
- Given a complete source (parent) architecture (i.e. the field
- `arch` in a view), and a 'spec' node (a node in an inheriting
- view that specifies the location in the source view of what
- should be changed), return (if it exists) the node in the
- source view matching the specification.
-
- :param source: a parent architecture to modify
- :param spec: a modifying node in an inheriting view
- :return: a node in the source matching the spec
-
- """
- if spec.tag == 'xpath':
- nodes = source.xpath(spec.get('expr'))
- return nodes[0] if nodes else None
- elif spec.tag == 'field':
- # Only compare the field name: a field can be only once in a given view
- # at a given level (and for multilevel expressions, we should use xpath
- # inheritance spec anyway).
- for node in source.getiterator('field'):
- if node.get('name') == spec.get('name'):
- return node
- return None
-
- for node in source.getiterator(spec.tag):
- if isinstance(node, SKIPPED_ELEMENT_TYPES):
- continue
- if all(node.get(attr) == spec.get(attr) \
- for attr in spec.attrib
- if attr not in ('position','version')):
- # Version spec should match parent's root element's version
- if spec.get('version') and spec.get('version') != source.get('version'):
- return None
- return node
- return None
-
- def apply_inheritance_specs(source, specs_arch, inherit_id=None):
- """ Apply an inheriting view.
-
- Apply to a source architecture all the spec nodes (i.e. nodes
- describing where and what changes to apply to some parent
- architecture) given by an inheriting view.
-
- :param source: a parent architecture to modify
- :param specs_arch: a modifying architecture in an inheriting view
- :param inherit_id: the database id of the inheriting view
- :return: a modified source where the specs are applied
-
- """
- specs_tree = etree.fromstring(encode(specs_arch))
- # Queue of specification nodes (i.e. nodes describing where and
- # changes to apply to some parent architecture).
- specs = [specs_tree]
-
- while len(specs):
- spec = specs.pop(0)
- if isinstance(spec, SKIPPED_ELEMENT_TYPES):
- continue
- if spec.tag == 'data':
- specs += [ c for c in specs_tree ]
- continue
- node = locate(source, spec)
- if node is not None:
- pos = spec.get('position', 'inside')
- if pos == 'replace':
- if node.getparent() is None:
- source = copy.deepcopy(spec[0])
- else:
- for child in spec:
- node.addprevious(child)
- node.getparent().remove(node)
- elif pos == 'attributes':
- for child in spec.getiterator('attribute'):
- attribute = (child.get('name'), child.text and child.text.encode('utf8') or None)
- if attribute[1]:
- node.set(attribute[0], attribute[1])
- elif attribute[0] in node.attrib:
- del node.attrib[attribute[0]]
- else:
- sib = node.getnext()
- for child in spec:
- if pos == 'inside':
- node.append(child)
- elif pos == 'after':
- if sib is None:
- node.addnext(child)
- node = child
- else:
- sib.addprevious(child)
- elif pos == 'before':
- node.addprevious(child)
- else:
- raise_view_error("Invalid position value: '%s'" % pos, inherit_id)
- else:
- attrs = ''.join([
- ' %s="%s"' % (attr, spec.get(attr))
- for attr in spec.attrib
- if attr != 'position'
- ])
- tag = "<%s%s>" % (spec.tag, attrs)
- if spec.get('version') and spec.get('version') != source.get('version'):
- raise_view_error("Mismatching view API version for element '%s': %r vs %r in parent view '%%(parent_xml_id)s'" % \
- (tag, spec.get('version'), source.get('version')), inherit_id)
- raise_view_error("Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, inherit_id)
-
- return source
-
- def apply_view_inheritance(cr, user, source, inherit_id):
- """ Apply all the (directly and indirectly) inheriting views.
-
- :param source: a parent architecture to modify (with parent
- modifications already applied)
- :param inherit_id: the database view_id of the parent view
- :return: a modified source where all the modifying architecture
- are applied
-
- """
- sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name, context=context)
- for (view_arch, view_id) in sql_inherit:
- source = apply_inheritance_specs(source, view_arch, view_id)
- source = apply_view_inheritance(cr, user, source, view_id)
- return source
-
- result = {'type': view_type, 'model': self._name}
-
- sql_res = False
- parent_view_model = None
- view_ref_key = view_type + '_view_ref'
- view_ref = context.get(view_ref_key)
- # Search for a root (i.e. without any parent) view.
- while True:
- if view_ref and not view_id:
+ View = self.pool['ir.ui.view']
+
+ result = {
+ 'model': self._name,
+ 'field_parent': False,
+ }
+
+ # try to find a view_id if none provided
+ if not view_id:
+ # <view_type>_view_ref in context can be used to overrride the default view
+ view_ref_key = view_type + '_view_ref'
+ view_ref = context.get(view_ref_key)
+ if view_ref:
if '.' in view_ref:
module, view_ref = view_ref.split('.', 1)
cr.execute("SELECT res_id FROM ir_model_data WHERE model='ir.ui.view' AND module=%s AND name=%s", (module, view_ref))
@@ -2232,82 +1841,53 @@ class BaseModel(object):
'Please use the complete `module.view_id` form instead.', view_ref_key, view_ref,
self._name)
- if view_id:
- cr.execute("""SELECT arch,name,field_parent,id,type,inherit_id,model
- FROM ir_ui_view
- WHERE id=%s""", (view_id,))
- else:
- cr.execute("""SELECT arch,name,field_parent,id,type,inherit_id,model
- FROM ir_ui_view
- WHERE model=%s AND type=%s AND inherit_id IS NULL
- ORDER BY priority""", (self._name, view_type))
- sql_res = cr.dictfetchone()
-
- if not sql_res:
- break
-
- view_id = sql_res['inherit_id'] or sql_res['id']
- parent_view_model = sql_res['model']
- if not sql_res['inherit_id']:
- break
-
- # if a view was found
- if sql_res:
- source = etree.fromstring(encode(sql_res['arch']))
- result.update(
- arch=apply_view_inheritance(cr, user, source, sql_res['id']),
- type=sql_res['type'],
- view_id=sql_res['id'],
- name=sql_res['name'],
- field_parent=sql_res['field_parent'] or False)
+ if not view_id:
+ # otherwise try to find the lowest priority matching ir.ui.view
+ view_id = View.default_view(cr, uid, self._name, view_type, context=context)
+
+ # context for post-processing might be overriden
+ ctx = context
+ if view_id:
+ # read the view with inherited views applied
+ root_view = View.read_combined(cr, uid, view_id, fields=['id', 'name', 'field_parent', 'type', 'model', 'arch'], context=context)
+ result['arch'] = root_view['arch']
+ result['name'] = root_view['name']
+ result['type'] = root_view['type']
+ result['view_id'] = root_view['id']
+ result['field_parent'] = root_view['field_parent']
+ # override context fro postprocessing
+ if root_view.get('model') != self._name:
+ ctx = dict(context, base_model_name=root_view.get('model'))
else:
- # otherwise, build some kind of default view
+ # fallback on default views methods if no ir.ui.view could be found
try:
- view = getattr(self, '_get_default_%s_view' % view_type)(
- cr, user, context)
+ get_func = getattr(self, '_get_default_%s_view' % view_type)
+ arch_etree = get_func(cr, uid, context)
+ result['arch'] = etree.tostring(arch_etree, encoding='utf-8')
+ result['type'] = view_type
+ result['name'] = 'default'
except AttributeError:
- # what happens here, graph case?
- raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type)
-
- result.update(
- arch=view,
- name='default',
- field_parent=False,
- view_id=0)
-
- if parent_view_model != self._name:
- ctx = context.copy()
- ctx['base_model_name'] = parent_view_model
- else:
- ctx = context
- xarch, xfields = self.__view_look_dom_arch(cr, user, result['arch'], view_id, context=ctx)
+ raise except_orm(_('Invalid Architecture!'), _("No default view of type '%s' could be found !") % view_type)
+
+ # Apply post processing, groups and modifiers etc...
+ xarch, xfields = View.postprocess_and_fields(cr, uid, self._name, etree.fromstring(result['arch']), view_id, context=ctx)
result['arch'] = xarch
result['fields'] = xfields
+ # Add related action information if aksed
if toolbar:
+ toclean = ('report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml', 'report_sxw_content_data', 'report_rml_content_data')
def clean(x):
x = x[2]
- for key in ('report_sxw_content', 'report_rml_content',
- 'report_sxw', 'report_rml',
- 'report_sxw_content_data', 'report_rml_content_data'):
- if key in x:
- del x[key]
+ for key in toclean:
+ x.pop(key, None)
return x
ir_values_obj = self.pool.get('ir.values')
- resprint = ir_values_obj.get(cr, user, 'action',
- 'client_print_multi', [(self._name, False)], False,
- context)
- resaction = ir_values_obj.get(cr, user, 'action',
- 'client_action_multi', [(self._name, False)], False,
- context)
-
- resrelate = ir_values_obj.get(cr, user, 'action',
- 'client_action_relate', [(self._name, False)], False,
- context)
- resaction = [clean(action) for action in resaction
- if view_type == 'tree' or not action[2].get('multi')]
- resprint = [clean(print_) for print_ in resprint
- if view_type == 'tree' or not print_[2].get('multi')]
+ resprint = ir_values_obj.get(cr, uid, 'action', 'client_print_multi', [(self._name, False)], False, context)
+ resaction = ir_values_obj.get(cr, uid, 'action', 'client_action_multi', [(self._name, False)], False, context)
+ resrelate = ir_values_obj.get(cr, uid, 'action', 'client_action_relate', [(self._name, False)], False, context)
+ resaction = [clean(action) for action in resaction if view_type == 'tree' or not action[2].get('multi')]
+ resprint = [clean(print_) for print_ in resprint if view_type == 'tree' or not print_[2].get('multi')]
#When multi="True" set it will display only in More of the list view
resrelate = [clean(action) for action in resrelate
if (action[2].get('multi') and view_type == 'tree') or (not action[2].get('multi') and view_type == 'form')]
@@ -2322,11 +1902,11 @@ class BaseModel(object):
}
return result
- _view_look_dom_arch = __view_look_dom_arch
+ def _view_look_dom_arch(self, cr, uid, node, view_id, context=None):
+ return self['ir.ui.view'].postprocess_and_fields(
+ cr, uid, self._name, node, view_id, context=context)
def search_count(self, cr, user, args, context=None):
- if not context:
- context = {}
res = self.search(cr, user, args, context=context, count=True)
if isinstance(res, list):
return len(res)
@@ -2605,6 +2185,37 @@ class BaseModel(object):
r['__fold'] = folded.get(r[groupby] and r[groupby][0], False)
return result
+ def _read_group_generate_order_by(self, orderby, aggregated_fields, groupby, query):
+ """
+ Generates the ORDER BY sql clause for the read group method. Adds the missing JOIN clause
+ to the query if order should be computed against m2o field.
+ :param orderby: the orderby definition in the form "%(field)s %(order)s"
+ :param aggregated_fields: list of aggregated fields in the query
+ :param groupby: the current groupby field name
+ :param query: the query object used to construct the query afterwards
+ """
+ orderby_list = []
+ ob = []
+ for order_splits in orderby.split(','):
+ order_split = order_splits.split()
+ orderby_field = order_split[0]
+ fields = openerp.osv.fields
+ if isinstance(self._all_columns[orderby_field].column, (fields.date, fields.datetime)):
+ continue
+ orderby_dir = len(order_split) == 2 and order_split[1].upper() == 'ASC' and 'ASC' or 'DESC'
+ if orderby_field == groupby:
+ orderby_item = self._generate_order_by(order_splits, query).replace('ORDER BY ', '')
+ if orderby_item:
+ orderby_list.append(orderby_item)
+ ob += [obi.split()[0] for obi in orderby_item.split(',')]
+ elif orderby_field in aggregated_fields:
+ orderby_list.append('%s %s' % (orderby_field,orderby_dir))
+
+ if orderby_list:
+ return ' ORDER BY %s' % (','.join(orderby_list)), ob and ','.join(ob) or ''
+ else:
+ return '', ''
+
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
"""
Get the list of records in list view grouped by the given ``groupby`` fields
@@ -2613,21 +2224,14 @@ class BaseModel(object):
:param uid: current user id
:param domain: list specifying search criteria [['field_name', 'operator', 'value'], ...]
:param list fields: list of fields present in the list view specified on the object
- :param list groupby: fields by which the records will be grouped
+ :param list groupby: list of groupby descriptions by which the records will be grouped.
+ A groupby description is either a field (then it will be grouped by that field)
+ or a string 'field:groupby_function'. Right now, the only functions supported
+ are 'day', 'week', 'month', 'quarter' or 'year', and they only make sense for
+ date/datetime fields.
:param int offset: optional number of records to skip
:param int limit: optional max number of records to return
- :param dict context: context arguments, like lang, time zone. A special
- context key exist for datetime fields : ``datetime_format``.
- context[``datetime_format``] = {
- 'field_name': {
- groupby_format: format for to_char (default: yyyy-mm)
- display_format: format for displaying the value
- in the result (default: MMM yyyy)
- interval: day, month or year; used for begin
- and end date of group_by intervals
- computation (default: month)
- }
- }
+ :param dict context: context arguments, like lang, time zone.
:param list orderby: optional ``order by`` specification, for
overriding the natural sort ordering of the
groups, see also :py:meth:`~osv.osv.osv.search`
@@ -2656,6 +2260,12 @@ class BaseModel(object):
if groupby:
if isinstance(groupby, list):
groupby = groupby[0]
+ splitted_groupby = groupby.split(':')
+ if len(splitted_groupby) == 2:
+ groupby = splitted_groupby[0]
+ groupby_function = splitted_groupby[1]
+ else:
+ groupby_function = False
qualified_groupby_field = self._inherits_join_calc(groupby, query)
if groupby:
@@ -2672,21 +2282,29 @@ class BaseModel(object):
if fget.get(groupby):
groupby_type = fget[groupby]['type']
if groupby_type in ('date', 'datetime'):
- if context.get('datetime_format') and isinstance(context['datetime_format'], dict) \
- and context['datetime_format'].get(groupby) and isinstance(context['datetime_format'][groupby], dict):
- groupby_format = context['datetime_format'][groupby].get('groupby_format', 'yyyy-mm')
- display_format = context['datetime_format'][groupby].get('display_format', 'MMMM yyyy')
- interval = context['datetime_format'][groupby].get('interval', 'month')
+ if groupby_function:
+ interval = groupby_function
else:
- groupby_format = 'yyyy-mm'
- display_format = 'MMMM yyyy'
interval = 'month'
- group_by_params = {
- 'groupby_format': groupby_format,
- 'display_format': display_format,
- 'interval': interval,
- }
- qualified_groupby_field = "to_char(%s,%%s)" % qualified_groupby_field
+
+ if interval == 'day':
+ display_format = 'dd MMM YYYY'
+ elif interval == 'week':
+ display_format = "'W'w YYYY"
+ elif interval == 'month':
+ display_format = 'MMMM YYYY'
+ elif interval == 'quarter':
+ display_format = 'QQQ YYYY'
+ elif interval == 'year':
+ display_format = 'YYYY'
+
+ if groupby_type == 'datetime' and context.get('tz') in pytz.all_timezones:
+ # Convert groupby result to user TZ to avoid confusion!
+ # PostgreSQL is compatible with all pytz timezone names, so we can use them
+ # directly for conversion, starting with timestamps stored in UTC.
+ timezone = context.get('tz', 'UTC')
+ qualified_groupby_field = "timezone('%s', timezone('UTC',%s))" % (timezone, qualified_groupby_field)
+ qualified_groupby_field = "date_trunc('%s', %s)" % (interval, qualified_groupby_field)
flist = "%s as %s " % (qualified_groupby_field, groupby)
elif groupby_type == 'boolean':
qualified_groupby_field = "coalesce(%s,false)" % qualified_groupby_field
@@ -2702,38 +2320,43 @@ class BaseModel(object):
f for f in fields
if f not in ('id', 'sequence')
if fget[f]['type'] in ('integer', 'float')
- if (f in self._columns and getattr(self._columns[f], '_classic_write'))]
+ if (f in self._all_columns and getattr(self._all_columns[f].column, '_classic_write'))]
for f in aggregated_fields:
group_operator = fget[f].get('group_operator', 'sum')
if flist:
flist += ', '
- qualified_field = '"%s"."%s"' % (self._table, f)
+ qualified_field = self._inherits_join_calc(f, query)
flist += "%s(%s) AS %s" % (group_operator, qualified_field, f)
+ order = orderby or groupby
+ orderby_clause = ''
+ ob = ''
+ if order:
+ orderby_clause, ob = self._read_group_generate_order_by(order, aggregated_fields, groupby, query)
+
gb = groupby and (' GROUP BY ' + qualified_groupby_field) or ''
from_clause, where_clause, where_clause_params = query.get_sql()
- if group_by_params and group_by_params.get('groupby_format'):
- where_clause_params = [group_by_params['groupby_format']] + where_clause_params + [group_by_params['groupby_format']]
where_clause = where_clause and ' WHERE ' + where_clause
limit_str = limit and ' limit %d' % limit or ''
offset_str = offset and ' offset %d' % offset or ''
if len(groupby_list) < 2 and context.get('group_by_no_leaf'):
group_count = '_'
- cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + limit_str + offset_str, where_clause_params)
+ cr.execute('SELECT min(%s.id) AS id, count(%s.id) AS %s_count' % (self._table, self._table, group_count) + (flist and ',') + flist + ' FROM ' + from_clause + where_clause + gb + (ob and ',') + ob + orderby_clause + limit_str + offset_str, where_clause_params)
alldata = {}
groupby = group_by
- for r in cr.dictfetchall():
+
+ fetched_data = cr.dictfetchall()
+
+ data_ids = []
+ for r in fetched_data:
for fld, val in r.items():
if val is None: r[fld] = False
alldata[r['id']] = r
+ data_ids.append(r['id'])
del r['id']
- order = orderby or groupby
- data_ids = self.search(cr, uid, [('id', 'in', alldata.keys())], order=order, context=context)
- # the IDs of records that have groupby field value = False or '' should be included too
- data_ids += set(alldata.keys()).difference(data_ids)
if groupby:
data = self.read(cr, uid, data_ids, [groupby], context=context)
@@ -2750,22 +2373,36 @@ class BaseModel(object):
if groupby or not context.get('group_by_no_leaf', False):
d['__context'] = {'group_by': groupby_list[1:]}
if groupby and groupby in fget:
- if d[groupby] and fget[groupby]['type'] in ('date', 'datetime'):
- _default = datetime.datetime(1970, 1, 1) # force starts of month
- groupby_datetime = dateutil.parser.parse(alldata[d['id']][groupby], default=_default)
+ groupby_type = fget[groupby]['type']
+ if d[groupby] and groupby_type in ('date', 'datetime'):
+ groupby_datetime = alldata[d['id']][groupby]
+ if isinstance(groupby_datetime, basestring):
+ _default = datetime.datetime(1970, 1, 1) # force starts of month
+ groupby_datetime = dateutil.parser.parse(groupby_datetime, default=_default)
+ tz_convert = groupby_type == 'datetime' and context.get('tz') in pytz.all_timezones
+ if tz_convert:
+ groupby_datetime = pytz.timezone(context['tz']).localize(groupby_datetime)
d[groupby] = babel.dates.format_date(
- groupby_datetime, format=group_by_params.get('display_format', 'MMMM yyyy'), locale=context.get('lang', 'en_US'))
- if group_by_params.get('interval') == 'month':
- days = calendar.monthrange(groupby_datetime.year, groupby_datetime.month)[1]
- domain_dt_begin = groupby_datetime.replace(day=1)
- domain_dt_end = groupby_datetime.replace(day=days)
- elif group_by_params.get('interval') == 'day':
- domain_dt_begin = groupby_datetime.replace(hour=0, minute=0)
- domain_dt_end = groupby_datetime.replace(hour=23, minute=59, second=59)
+ groupby_datetime, format=display_format, locale=context.get('lang', 'en_US'))
+ domain_dt_begin = groupby_datetime
+ if interval == 'quarter':
+ domain_dt_end = groupby_datetime + dateutil.relativedelta.relativedelta(months=3)
+ elif interval == 'month':
+ domain_dt_end = groupby_datetime + dateutil.relativedelta.relativedelta(months=1)
+ elif interval == 'week':
+ domain_dt_end = groupby_datetime + datetime.timedelta(days=7)
+ elif interval == 'day':
+ domain_dt_end = groupby_datetime + datetime.timedelta(days=1)
else:
- domain_dt_begin = groupby_datetime.replace(month=1, day=1)
- domain_dt_end = groupby_datetime.replace(month=12, day=31)
- d['__domain'] = [(groupby, '>=', domain_dt_begin.strftime('%Y-%m-%d')), (groupby, '<=', domain_dt_end.strftime('%Y-%m-%d'))] + domain
+ domain_dt_end = groupby_datetime + dateutil.relativedelta.relativedelta(years=1)
+ if tz_convert:
+ # the time boundaries were all computed in the apparent TZ of the user,
+ # so we need to convert them to UTC to have proper server-side values.
+ domain_dt_begin = domain_dt_begin.astimezone(pytz.utc)
+ domain_dt_end = domain_dt_end.astimezone(pytz.utc)
+ dt_format = DEFAULT_SERVER_DATETIME_FORMAT if groupby_type == 'datetime' else DEFAULT_SERVER_DATE_FORMAT
+ d['__domain'] = [(groupby, '>=', domain_dt_begin.strftime(dt_format)),
+ (groupby, '<', domain_dt_end.strftime(dt_format))] + domain
del alldata[d['id']][groupby]
d.update(alldata[d['id']])
del d['id']
@@ -3091,7 +2728,7 @@ class BaseModel(object):
f_pg_notnull = res['attnotnull']
if isinstance(f, fields.function) and not f.store and\
not getattr(f, 'nodrop', False):
- _logger.info('column %s (%s) in table %s removed: converted to a function !\n',
+ _logger.info('column %s (%s) converted to a function, removed from table %s',
k, f.string, self._table)
cr.execute('ALTER TABLE "%s" DROP COLUMN "%s" CASCADE' % (self._table, k))
cr.commit()
@@ -3113,10 +2750,16 @@ class BaseModel(object):
('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
]
if f_pg_type == 'varchar' and f._type == 'char' and ((f.size is None and f_pg_size) or f_pg_size < f.size):
- cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
- cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, pg_varchar(f.size)))
- cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, pg_varchar(f.size)))
- cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
+ try:
+ with cr.savepoint():
+ cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" TYPE %s' % (self._table, k, pg_varchar(f.size)))
+ except psycopg2.NotSupportedError:
+ # In place alter table cannot be done because a view is depending of this field.
+ # Do a manual copy. This will drop the view (that will be recreated later)
+ cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
+ cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, pg_varchar(f.size)))
+ cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, pg_varchar(f.size)))
+ cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
cr.commit()
_schema.debug("Table '%s': column '%s' (type varchar) changed size from %s to %s",
self._table, k, f_pg_size or 'unlimited', f.size or 'unlimited')
@@ -3124,10 +2767,10 @@ class BaseModel(object):
if (f_pg_type==c[0]) and (f._type==c[1]):
if f_pg_type != f_obj_type:
ok = True
- cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
+ cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO __temp_type_cast' % (self._table, k))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, c[2]))
- cr.execute(('UPDATE "%s" SET "%s"=temp_change_size'+c[3]) % (self._table, k))
- cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
+ cr.execute(('UPDATE "%s" SET "%s"= __temp_type_cast'+c[3]) % (self._table, k))
+ cr.execute('ALTER TABLE "%s" DROP COLUMN __temp_type_cast CASCADE' % (self._table,))
cr.commit()
_schema.debug("Table '%s': column '%s' changed type from %s to %s",
self._table, k, c[0], c[1])
@@ -3515,31 +3158,6 @@ class BaseModel(object):
self._columns[field_name].required = True
self._columns[field_name].ondelete = "cascade"
- #def __getattr__(self, name):
- # """
- # Proxies attribute accesses to the `inherits` parent so we can call methods defined on the inherited parent
- # (though inherits doesn't use Python inheritance).
- # Handles translating between local ids and remote ids.
- # Known issue: doesn't work correctly when using python's own super(), don't involve inherit-based inheritance
- # when you have inherits.
- # """
- # for model, field in self._inherits.iteritems():
- # proxy = self.pool.get(model)
- # if hasattr(proxy, name):
- # attribute = getattr(proxy, name)
- # if not hasattr(attribute, '__call__'):
- # return attribute
- # break
- # else:
- # return super(orm, self).__getattr__(name)
-
- # def _proxy(cr, uid, ids, *args, **kwargs):
- # objects = self.browse(cr, uid, ids, kwargs.get('context', None))
- # lst = [obj[field].id for obj in objects if obj[field]]
- # return getattr(proxy, name)(cr, uid, lst, *args, **kwargs)
-
- # return _proxy
-
def fields_get(self, cr, user, allfields=None, context=None, write_access=True):
""" Return the definition of each field.
@@ -3588,16 +3206,6 @@ class BaseModel(object):
help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context['lang'])
if help_trans:
res[f]['help'] = help_trans
- if 'selection' in res[f]:
- if isinstance(field.selection, (tuple, list)):
- sel = field.selection
- sel2 = []
- for key, val in sel:
- val2 = None
- if val:
- val2 = translation_obj._get_source(cr, user, self._name + ',' + f, 'selection', context['lang'], val)
- sel2.append((key, val2 or val))
- res[f]['selection'] = sel2
return res
@@ -4325,7 +3933,7 @@ class BaseModel(object):
for (parent_pright, parent_id) in parents:
if parent_id == id:
break
- position = parent_pright + 1
+ position = parent_pright and parent_pright + 1 or 1
# It's the first node of the parent
if not position:
@@ -5054,24 +4662,22 @@ class BaseModel(object):
blacklist_given_fields(self)
- fields_to_read = [f for f in self.check_field_access_rights(cr, uid, 'read', None)
- if f not in blacklist]
- data = self.read(cr, uid, [id], fields_to_read, context=context)
+
+ fields_to_copy = dict((f,fi) for f, fi in self._all_columns.iteritems()
+ if f not in default
+ if f not in blacklist
+ if not isinstance(fi.column, fields.function))
+
+ data = self.read(cr, uid, [id], fields_to_copy.keys(), context=context)
if data:
data = data[0]
else:
- raise IndexError(_("Record #%d of %s not found, cannot copy!") % (id, self._name))
+ raise IndexError( _("Record #%d of %s not found, cannot copy!") %( id, self._name))
res = dict(default)
- for f, colinfo in self._all_columns.items():
+ for f, colinfo in fields_to_copy.iteritems():
field = colinfo.column
- if f in default:
- pass
- elif f in blacklist:
- pass
- elif isinstance(field, fields.function):
- pass
- elif field._type == 'many2one':
+ if field._type == 'many2one':
res[f] = data[f] and data[f][0]
elif field._type == 'one2many':
other = self.pool[field._obj]
@@ -5449,17 +5055,21 @@ class BaseModel(object):
:rtype: List of dictionaries.
"""
- record_ids = self.search(cr, uid, domain or [], offset, limit or False, order or False, context or {})
+ record_ids = self.search(cr, uid, domain or [], offset=offset, limit=limit, order=order, context=context)
if not record_ids:
return []
- result = self.read(cr, uid, record_ids, fields or [], context or {})
+
+ if fields and fields == ['id']:
+ # shortcut read if we only want the ids
+ return [{'id': id} for id in record_ids]
+
+ result = self.read(cr, uid, record_ids, fields, context=context)
+ if len(result) <= 1:
+ return result
+
# reorder read
- if len(result) >= 1:
- index = {}
- for r in result:
- index[r['id']] = r
- result = [index[x] for x in record_ids if x in index]
- return result
+ index = dict((r['id'], r) for r in result)
+ return [index[x] for x in record_ids if x in index]
def _register_hook(self, cr):
""" stuff to do right after the registry is built """
@@ -5530,12 +5140,12 @@ def itemgetter_tuple(items):
if len(items) == 1:
return lambda gettable: (gettable[items[0]],)
return operator.itemgetter(*items)
+
class ImportWarning(Warning):
""" Used to send warnings upwards the stack during the import process
"""
pass
-
def convert_pgerror_23502(model, fields, info, e):
m = re.match(r'^null value in column "(?P<field>\w+)" violates '
r'not-null constraint\n',
@@ -5551,6 +5161,7 @@ def convert_pgerror_23502(model, fields, info, e):
'message': message,
'field': field_name,
}
+
def convert_pgerror_23505(model, fields, info, e):
m = re.match(r'^duplicate key (?P<field>\w+) violates unique constraint',
str(e))
diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py
index ad1ff656e1d..aaed9ddf4c6 100644
--- a/openerp/report/render/rml2pdf/trml2pdf.py
+++ b/openerp/report/render/rml2pdf/trml2pdf.py
@@ -982,7 +982,7 @@ class _rml_template(object):
}
pageSize = A4
if self.localcontext.get('company'):
- pageSize = pagesize_map.get(self.localcontext.get('company').paper_format, A4)
+ pageSize = pagesize_map.get(self.localcontext.get('company').rml_paper_format, A4)
if node.get('pageSize'):
ps = map(lambda x:x.strip(), node.get('pageSize').replace(')', '').replace('(', '').split(','))
pageSize = ( utils.unit_get(ps[0]),utils.unit_get(ps[1]) )
diff --git a/openerp/report/report_sxw.py b/openerp/report/report_sxw.py
index 03bc0ffa03f..1c31c5ec3ae 100644
--- a/openerp/report/report_sxw.py
+++ b/openerp/report/report_sxw.py
@@ -255,9 +255,7 @@ class rml_parse(object):
d = DEFAULT_DIGITS = 2
if dp:
decimal_precision_obj = self.pool['decimal.precision']
- ids = decimal_precision_obj.search(self.cr, self.uid, [('name', '=', dp)])
- if ids:
- d = decimal_precision_obj.browse(self.cr, self.uid, ids)[0].digits
+ d = decimal_precision_obj.precision_get(self.cr, self.uid, dp)
elif obj and f:
res_digits = getattr(obj._columns[f], 'digits', lambda x: ((16, DEFAULT_DIGITS)))
if isinstance(res_digits, tuple):
diff --git a/openerp/service/db.py b/openerp/service/db.py
index acdb8fe2ed9..f48a1e6e91b 100644
--- a/openerp/service/db.py
+++ b/openerp/service/db.py
@@ -145,7 +145,7 @@ def exp_get_progress(id):
raise Exception, e
def exp_drop(db_name):
- if not exp_db_exist(db_name):
+ if db_name not in exp_list(True):
return False
openerp.modules.registry.RegistryManager.delete(db_name)
openerp.sql_db.close_db(db_name)
@@ -306,7 +306,7 @@ def exp_list(document=False):
cr.execute("select datname from pg_database where datdba=(select usesysid from pg_user where usename=%s) and datname not in %s order by datname", (db_user, templates_list))
else:
cr.execute("select datname from pg_database where datname not in %s order by datname", (templates_list,))
- res = [str(name) for (name,) in cr.fetchall()]
+ res = [openerp.tools.ustr(name) for (name,) in cr.fetchall()]
except Exception:
res = []
res.sort()
diff --git a/openerp/service/model.py b/openerp/service/model.py
index a2c2dff90c5..a637e234295 100644
--- a/openerp/service/model.py
+++ b/openerp/service/model.py
@@ -40,9 +40,10 @@ def dispatch(method, params):
def check(f):
@wraps(f)
- def wrapper(dbname, *args, **kwargs):
+ def wrapper(___dbname, *args, **kwargs):
""" Wraps around OSV functions and normalises a few exceptions
"""
+ dbname = ___dbname # NOTE: this forbid to use "___dbname" as arguments in http routes
def tr(src, ttype):
# We try to do the same as the _(), but without the frame
@@ -107,7 +108,7 @@ def check(f):
tries = 0
while True:
try:
- if openerp.registry(dbname)._init:
+ if openerp.registry(dbname)._init and not openerp.tools.config['test_enable']:
raise openerp.exceptions.Warning('Currently, this database is not fully loaded and can not be used.')
return f(dbname, *args, **kwargs)
except OperationalError, e:
diff --git a/openerp/service/server.py b/openerp/service/server.py
index e7fcb610152..b3d16bc8ab2 100644
--- a/openerp/service/server.py
+++ b/openerp/service/server.py
@@ -17,6 +17,7 @@ import subprocess
import sys
import threading
import time
+import unittest2
import werkzeug.serving
@@ -30,15 +31,14 @@ except ImportError:
setproctitle = lambda x: None
import openerp
-import openerp.tools.config as config
+from openerp.modules.registry import RegistryManager
from openerp.release import nt_service_name
+import openerp.tools.config as config
from openerp.tools.misc import stripped_sys_argv, dumpstacks
-import wsgi_server
-
_logger = logging.getLogger(__name__)
-SLEEP_INTERVAL = 60 # 1 min
+SLEEP_INTERVAL = 60 # 1 min
#----------------------------------------------------------
# Werkzeug WSGI servers patched
@@ -123,7 +123,7 @@ class AutoReload(object):
if len(right) < 2:
continue
module = right[0]
- self.modules[module]=1
+ self.modules[module] = 1
if self.modules:
_logger.info('autoreload: xml change detected, autoreload activated')
restart()
@@ -143,7 +143,7 @@ class AutoReload(object):
if py_errors:
_logger.info('autoreload: python code change detected, errors found')
for i in py_errors:
- _logger.info('autoreload: SyntaxError %s',i)
+ _logger.info('autoreload: SyntaxError %s', i)
else:
_logger.info('autoreload: python code updated, autoreload activated')
restart()
@@ -181,7 +181,6 @@ class CommonServer(object):
# runtime
self.pid = os.getpid()
-
def close_socket(self, sock):
""" Closes a socket instance cleanly
:param sock: the network socket to close
@@ -211,7 +210,7 @@ class ThreadedServer(CommonServer):
self.httpd = None
def signal_handler(self, sig, frame):
- if sig in [signal.SIGINT,signal.SIGTERM]:
+ if sig in [signal.SIGINT, signal.SIGTERM]:
# shutdown on kill -INT or -TERM
self.quit_signals_received += 1
if self.quit_signals_received > 1:
@@ -225,7 +224,7 @@ class ThreadedServer(CommonServer):
def cron_thread(self, number):
while True:
- time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style
+ time.sleep(SLEEP_INTERVAL + number) # Steve Reich timing style
registries = openerp.modules.registry.RegistryManager.registries
_logger.debug('cron%d polling for jobs', number)
for db_name, registry in registries.items():
@@ -255,13 +254,15 @@ class ThreadedServer(CommonServer):
_logger.debug("cron%d started!" % i)
def http_thread(self):
- def app(e,s):
- return self.app(e,s)
+ def app(e, s):
+ return self.app(e, s)
self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, app)
self.httpd.serve_forever()
def http_spawn(self):
- threading.Thread(target=self.http_thread).start()
+ t = threading.Thread(target=self.http_thread, name="openerp.service.httpd")
+ t.setDaemon(True)
+ t.start()
_logger.info('HTTP service (werkzeug) running on %s:%s', self.interface, self.port)
def start(self):
@@ -274,7 +275,7 @@ class ThreadedServer(CommonServer):
signal.signal(signal.SIGQUIT, dumpstacks)
elif os.name == 'nt':
import win32api
- win32api.SetConsoleCtrlHandler(lambda sig: signal_handler(sig, None), 1)
+ win32api.SetConsoleCtrlHandler(lambda sig: self.signal_handler(sig, None), 1)
self.cron_spawn()
self.http_spawn()
@@ -306,7 +307,7 @@ class ThreadedServer(CommonServer):
openerp.modules.registry.RegistryManager.delete_all()
logging.shutdown()
- def run(self):
+ def run(self, preload=None, stop=False):
""" Start the http server and the cron thread then wait for a signal.
The first SIGINT or SIGTERM signal will initiate a graceful shutdown while
@@ -314,6 +315,12 @@ class ThreadedServer(CommonServer):
"""
self.start()
+ rc = preload_registries(preload)
+
+ if stop:
+ self.stop()
+ return rc
+
# Wait for a first signal to be handled. (time.sleep will be interrupted
# by the signal handler.) The try/except is for the win32 case.
try:
@@ -362,7 +369,7 @@ class GeventServer(CommonServer):
self.httpd.stop()
gevent.shutdown()
- def run(self):
+ def run(self, preload, stop):
self.start()
self.stop()
@@ -429,7 +436,7 @@ class PreforkServer(CommonServer):
sys.exit(0)
def long_polling_spawn(self):
- nargs = stripped_sys_argv('--pidfile','--workers')
+ nargs = stripped_sys_argv('--pidfile', '--workers')
cmd = nargs[0]
cmd = os.path.join(os.path.dirname(cmd), "openerp-gevent")
nargs[0] = cmd
@@ -438,10 +445,10 @@ class PreforkServer(CommonServer):
def worker_pop(self, pid):
if pid in self.workers:
- _logger.debug("Worker (%s) unregistered",pid)
+ _logger.debug("Worker (%s) unregistered", pid)
try:
- self.workers_http.pop(pid,None)
- self.workers_cron.pop(pid,None)
+ self.workers_http.pop(pid, None)
+ self.workers_cron.pop(pid, None)
u = self.workers.pop(pid)
u.close()
except OSError:
@@ -457,7 +464,7 @@ class PreforkServer(CommonServer):
def process_signals(self):
while len(self.queue):
sig = self.queue.pop(0)
- if sig in [signal.SIGINT,signal.SIGTERM]:
+ if sig in [signal.SIGINT, signal.SIGTERM]:
raise KeyboardInterrupt
elif sig == signal.SIGHUP:
# restart on kill -HUP
@@ -493,8 +500,8 @@ class PreforkServer(CommonServer):
def process_timeout(self):
now = time.time()
for (pid, worker) in self.workers.items():
- if (worker.watchdog_timeout is not None) and \
- (now - worker.watchdog_time >= worker.watchdog_timeout):
+ if worker.watchdog_timeout is not None and \
+ (now - worker.watchdog_time) >= worker.watchdog_timeout:
_logger.error("Worker (%s) timeout", pid)
self.worker_kill(pid, signal.SIGKILL)
@@ -509,7 +516,7 @@ class PreforkServer(CommonServer):
def sleep(self):
try:
# map of fd -> worker
- fds = dict([(w.watchdog_pipe[0],w) for k,w in self.workers.items()])
+ fds = dict([(w.watchdog_pipe[0], w) for k, w in self.workers.items()])
fd_in = fds.keys() + [self.pipe[0]]
# check for ping or internal wakeups
ready = select.select(fd_in, [], [], self.beat)
@@ -529,6 +536,8 @@ class PreforkServer(CommonServer):
raise
def start(self):
+ # Empty the cursor pool, we dont want them to be shared among forked workers.
+ openerp.sql_db.close_all()
# wakeup pipe, python doesnt throw EINTR when a syscall is interrupted
# by a signal simulating a pseudo SA_RESTART. We write to a pipe in the
# signal handler to overcome this behaviour
@@ -547,11 +556,12 @@ class PreforkServer(CommonServer):
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.setblocking(0)
self.socket.bind(self.address)
- self.socket.listen(8*self.population)
+ self.socket.listen(8 * self.population)
def stop(self, graceful=True):
if self.long_polling_pid is not None:
- self.worker_kill(self.long_polling_pid, signal.SIGKILL) # FIXME make longpolling process handle SIGTERM correctly
+ # FIXME make longpolling process handle SIGTERM correctly
+ self.worker_kill(self.long_polling_pid, signal.SIGKILL)
self.long_polling_pid = None
if graceful:
_logger.info("Stopping gracefully")
@@ -567,8 +577,15 @@ class PreforkServer(CommonServer):
self.worker_kill(pid, signal.SIGTERM)
self.socket.close()
- def run(self):
+ def run(self, preload, stop):
self.start()
+
+ rc = preload_registries(preload)
+
+ if stop:
+ self.stop()
+ return rc
+
_logger.debug("Multiprocess starting")
while 1:
try:
@@ -582,10 +599,10 @@ class PreforkServer(CommonServer):
_logger.debug("Multiprocess clean stop")
self.stop()
break
- except Exception,e:
+ except Exception, e:
_logger.exception(e)
self.stop(False)
- sys.exit(-1)
+ return -1
class Worker(object):
""" Workers """
@@ -614,7 +631,7 @@ class Worker(object):
def sleep(self):
try:
- ret = select.select([self.multi.socket], [], [], self.multi.beat)
+ select.select([self.multi.socket], [], [], self.multi.beat)
except select.error, e:
if e[0] not in [errno.EINTR]:
raise
@@ -632,7 +649,7 @@ class Worker(object):
rss, vms = psutil.Process(os.getpid()).get_memory_info()
if vms > config['limit_memory_soft']:
_logger.info('Worker (%d) virtual memory limit (%s) reached.', self.pid, vms)
- self.alive = False # Commit suicide after the request.
+ self.alive = False # Commit suicide after the request.
# VMS and RLIMIT_AS are the same thing: virtual memory, a.k.a. address space
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
@@ -680,7 +697,7 @@ class Worker(object):
self.process_work()
_logger.info("Worker (%s) exiting. request_count: %s.", self.pid, self.request_count)
self.stop()
- except Exception,e:
+ except Exception:
_logger.exception("Worker (%s) Exception occured, exiting..." % self.pid)
# should we use 3 to abort everything ?
sys.exit(1)
@@ -698,7 +715,7 @@ class WorkerHTTP(Worker):
# tolerate broken pipe when the http client closes the socket before
# receiving the full reply
try:
- self.server.process_request(client,addr)
+ self.server.process_request(client, addr)
except IOError, e:
if e.errno != errno.EPIPE:
raise
@@ -729,7 +746,7 @@ class WorkerCron(Worker):
def sleep(self):
# Really sleep once all the databases have been processed.
if self.db_index == 0:
- interval = SLEEP_INTERVAL + self.pid % 10 # chorus effect
+ interval = SLEEP_INTERVAL + self.pid % 10 # chorus effect
time.sleep(interval)
def _db_list(self):
@@ -751,7 +768,7 @@ class WorkerCron(Worker):
if rpc_request_flag:
start_time = time.time()
start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info()
-
+
import openerp.addons.base as base
base.ir.ir_cron.ir_cron._acquire_job(db_name)
openerp.modules.registry.RegistryManager.delete(db_name)
@@ -760,16 +777,18 @@ class WorkerCron(Worker):
if len(db_names) > 1:
openerp.sql_db.close_db(db_name)
if rpc_request_flag:
- end_time = time.time()
+ run_time = time.time() - start_time
end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info()
- logline = '%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (db_name, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024)
+ vms_diff = (end_vms - start_vms) / 1024
+ logline = '%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % \
+ (db_name, run_time, start_vms / 1024, end_vms / 1024, vms_diff)
_logger.debug("WorkerCron (%s) %s", self.pid, logline)
self.request_count += 1
if self.request_count >= self.request_max and self.request_max < len(db_names):
_logger.error("There are more dabatases to process than allowed "
- "by the `limit_request` configuration variable: %s more.",
- len(db_names) - self.request_max)
+ "by the `limit_request` configuration variable: %s more.",
+ len(db_names) - self.request_max)
else:
self.db_index = 0
@@ -802,12 +821,61 @@ def _reexec(updated_modules=None):
subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True)
exe = os.path.basename(sys.executable)
args = stripped_sys_argv()
- args += ["-u", ','.join(updated_modules)]
+ args += ["-u", ','.join(updated_modules)]
if not args or args[0] != exe:
args.insert(0, exe)
os.execv(sys.executable, args)
-def start():
+def load_test_file_yml(registry, test_file):
+ with registry.cursor() as cr:
+ openerp.tools.convert_yaml_import(cr, 'base', file(test_file), 'test', {}, 'test', True)
+ cr.rollback()
+
+def load_test_file_py(registry, test_file):
+ # Locate python module based on its filename and run the tests
+ test_path, _ = os.path.splitext(os.path.abspath(test_file))
+ for mod_name, mod_mod in sys.modules.items():
+ if mod_mod:
+ mod_path, _ = os.path.splitext(getattr(mod_mod, '__file__', ''))
+ if test_path == mod_path:
+ suite = unittest2.TestSuite()
+ for t in unittest2.TestLoader().loadTestsFromModule(mod_mod):
+ suite.addTest(t)
+ _logger.log(logging.INFO, 'running tests %s.', mod_mod.__name__)
+ stream = openerp.modules.module.TestStream()
+ result = unittest2.TextTestRunner(verbosity=2, stream=stream).run(suite)
+ success = result.wasSuccessful()
+ registry._assertion_report.report_result(success)
+ if not success:
+ _logger.error('%s: at least one error occurred in a test', test_file)
+
+def preload_registries(dbnames):
+ """ Preload a registries, possibly run a test file."""
+ # TODO: move all config checks to args dont check tools.config here
+ config = openerp.tools.config
+ test_file = config['test_file']
+ dbnames = dbnames or []
+ rc = 0
+ for dbname in dbnames:
+ try:
+ update_module = config['init'] or config['update']
+ registry = RegistryManager.new(dbname, update_module=update_module)
+ # run test_file if provided
+ if test_file:
+ _logger.info('loading test file %s', test_file)
+ if test_file.endswith('yml'):
+ load_test_file_yml(registry, test_file)
+ elif test_file.endswith('py'):
+ load_test_file_py(registry, test_file)
+
+ if registry._assertion_report.failures:
+ rc += 1
+ except Exception:
+ _logger.critical('Failed to initialize database `%s`.', dbname, exc_info=True)
+ return -1
+ return rc
+
+def start(preload=None, stop=False):
""" Start the openerp http server and cron processor.
"""
global server
@@ -823,7 +891,7 @@ def start():
autoreload = AutoReload(server)
autoreload.run()
- server.run()
+ rc = server.run(preload, stop)
# like the legend of the phoenix, all ends with beginnings
if getattr(openerp, 'phoenix', False):
@@ -831,7 +899,8 @@ def start():
if config['auto_reload']:
modules = autoreload.modules.keys()
_reexec(modules)
- sys.exit(0)
+
+ return rc if rc else 0
def restart():
""" Restart the server
diff --git a/openerp/sql_db.py b/openerp/sql_db.py
index 7a58a5fc515..694ae02b3d9 100644
--- a/openerp/sql_db.py
+++ b/openerp/sql_db.py
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
-# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
+# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -27,11 +27,11 @@ the database, *not* a database abstraction toolkit. Database abstraction is what
the ORM does, in fact.
"""
-
-__all__ = ['db_connect', 'close_db']
-
+from contextlib import contextmanager
from functools import wraps
import logging
+import time
+import uuid
import psycopg2.extensions
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
from psycopg2.pool import PoolError
@@ -347,6 +347,19 @@ class Cursor(object):
"""
return self._cnx.rollback()
+ @contextmanager
+ @check
+ def savepoint(self):
+ """context manager entering in a new savepoint"""
+ name = uuid.uuid1().hex
+ self.execute('SAVEPOINT "%s"' % name)
+ try:
+ yield
+ self.execute('RELEASE SAVEPOINT "%s"' % name)
+ except:
+ self.execute('ROLLBACK TO SAVEPOINT "%s"' % name)
+ raise
+
@check
def __getattr__(self, name):
return getattr(self._obj, name)
@@ -457,10 +470,10 @@ class ConnectionPool(object):
raise PoolError('This connection does not below to the pool')
@locked
- def close_all(self, dsn):
+ def close_all(self, dsn=None):
_logger.info('%r: Close all connections to %r', self, dsn)
for i, (cnx, used) in tools.reverse_enumerate(self._connections):
- if dsn_are_equals(cnx.dsn, dsn):
+ if dsn is None or dsn_are_equals(cnx.dsn, dsn):
cnx.close()
self._connections.pop(i)
@@ -522,6 +535,11 @@ def close_db(db_name):
if _Pool:
_Pool.close_all(dsn(db_name))
+def close_all():
+ global _Pool
+ if _Pool:
+ _Pool.close_all()
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py
index e6a2eacf386..bdf699e6467 100644
--- a/openerp/tests/__init__.py
+++ b/openerp/tests/__init__.py
@@ -1,47 +1,2 @@
-# -*- coding: utf-8 -*-
-"""
-Tests for the OpenERP library.
-
-This module groups a few sub-modules containing unittest2 test cases.
-
-Tests can be explicitely added to the `fast_suite` or `checks` lists or not.
-See the :ref:`test-framework` section in the :ref:`features` list.
-"""
-
-import test_acl
-import test_basecase
-import test_db_cursor
-import test_expression
-import test_fields
-import test_ir_filters
-import test_ir_sequence
-import test_mail
-import test_misc
-import test_orm
-import test_osv
-import test_translate
-import test_uninstall
-import test_view_validation
-# This need a change in `oe run-tests` to only run fast_suite + checks by default.
-# import test_xmlrpc
-
-fast_suite = [
- test_ir_sequence,
- test_ir_filters
-]
-
-checks = [
- test_acl,
- test_expression,
- test_mail,
- test_db_cursor,
- test_orm,
- test_fields,
- test_basecase,
- test_view_validation,
- test_misc,
- test_osv,
- test_translate,
-]
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+import common
+from common import *
diff --git a/openerp/tests/common.py b/openerp/tests/common.py
index 7bd8bf76cc9..b68bbfe20df 100644
--- a/openerp/tests/common.py
+++ b/openerp/tests/common.py
@@ -1,8 +1,15 @@
# -*- coding: utf-8 -*-
"""
-The module :mod:`openerp.tests.common` provides a few helpers and classes to write
-tests.
+The module :mod:`openerp.tests.common` provides unittest2 test cases and a few
+helpers and classes to write tests.
+
"""
+import errno
+import json
+import logging
+import os
+import select
+import subprocess
import threading
import time
import unittest2
@@ -10,37 +17,64 @@ import xmlrpclib
import openerp
+_logger = logging.getLogger(__name__)
+
# The openerp library is supposed already configured.
+ADDONS_PATH = openerp.tools.config['addons_path']
+HOST = '127.0.0.1'
PORT = openerp.tools.config['xmlrpc_port']
DB = openerp.tools.config['db_name']
-
# If the database name is not provided on the command-line,
# use the one on the thread (which means if it is provided on
# the command-line, this will break when installing another
# database from XML-RPC).
if not DB and hasattr(threading.current_thread(), 'dbname'):
DB = threading.current_thread().dbname
+# Useless constant, tests are aware of the content of demo data
+ADMIN_USER_ID = openerp.SUPERUSER_ID
-HOST = '127.0.0.1'
+# Magic session_id, unfortunately we have to serialize access to the cursors to
+# serialize requests. We first tried to duplicate the database for each tests
+# but this proved too slow. Any idea to improve this is welcome.
+HTTP_SESSION = {}
-ADMIN_USER = 'admin'
-ADMIN_USER_ID = openerp.SUPERUSER_ID
-ADMIN_PASSWORD = 'admin'
+def acquire_test_cursor(session_id):
+ if openerp.tools.config['test_enable']:
+ cr = HTTP_SESSION.get(session_id)
+ if cr:
+ cr._test_lock.acquire()
+ return cr
-def start_openerp():
- """
- Start the OpenERP server similary to the openerp-server script.
- """
- openerp.service.start_services()
+def release_test_cursor(session_id):
+ if openerp.tools.config['test_enable']:
+ cr = HTTP_SESSION.get(session_id)
+ if cr:
+ cr._test_lock.release()
+ return True
+ return False
- # Ugly way to ensure the server is listening.
- time.sleep(2)
+def at_install(flag):
+ """ Sets the at-install state of a test, the flag is a boolean specifying
+ whether the test should (``True``) or should not (``False``) run during
+ module installation.
-def stop_openerp():
+ By default, tests are run at install.
"""
- Shutdown the OpenERP server similarly to a single ctrl-c.
+ def decorator(obj):
+ obj.at_install = flag
+ return obj
+ return decorator
+def post_install(flag):
+ """ Sets the post-install state of a test. The flag is a boolean
+ specifying whether the test should or should not run after a set of
+ module installations.
+
+ By default, tests are *not* run after installation.
"""
- openerp.service.stop_services()
+ def decorator(obj):
+ obj.post_install = flag
+ return obj
+ return decorator
class BaseCase(unittest2.TestCase):
"""
@@ -115,37 +149,144 @@ class SingleTransactionCase(BaseCase):
cls.cr.close()
-class RpcCase(unittest2.TestCase):
- """
- Subclass of TestCase with a few XML-RPC proxies.
+class HttpCase(TransactionCase):
+ """ Transactionnal HTTP TestCase with a phantomjs helper.
"""
def __init__(self, methodName='runTest'):
- super(RpcCase, self).__init__(methodName)
+ super(HttpCase, self).__init__(methodName)
+ # v8 api with correct xmlrpc exception handling.
+ self.xmlrpc_url = url_8 = 'http://%s:%d/xmlrpc/2/' % (HOST, PORT)
+ self.xmlrpc_common = xmlrpclib.ServerProxy(url_8 + 'common')
+ self.xmlrpc_db = xmlrpclib.ServerProxy(url_8 + 'db')
+ self.xmlrpc_object = xmlrpclib.ServerProxy(url_8 + 'object')
+
+ def setUp(self):
+ super(HttpCase, self).setUp()
+ # setup a magic session_id that will be rollbacked
+ self.session = openerp.http.root.session_store.new()
+ self.session_id = self.session.sid
+ self.session.db = DB
+ openerp.http.root.session_store.save(self.session)
+ self.cr._test_lock = threading.RLock()
+ HTTP_SESSION[self.session_id] = self.cr
+
- class A(object):
- pass
- self.proxy = A()
+ def tearDown(self):
+ del HTTP_SESSION[self.session_id]
+ super(HttpCase, self).tearDown()
- # Use the old (pre 6.1) API.
- self.proxy.url_60 = url_60 = 'http://%s:%d/xmlrpc/' % (HOST, PORT)
- self.proxy.common_60 = xmlrpclib.ServerProxy(url_60 + 'common')
- self.proxy.db_60 = xmlrpclib.ServerProxy(url_60 + 'db')
- self.proxy.object_60 = xmlrpclib.ServerProxy(url_60 + 'object')
- #self.proxy.edi_60 = xmlrpclib.ServerProxy(url_60 + 'edi')
+ def phantom_poll(self, phantom, timeout):
+ """ Phantomjs Test protocol.
- # Use the new (8) API.
- self.proxy.url_8 = url_8 = 'http://%s:%d/xmlrpc/2/' % (HOST, PORT)
- self.proxy.common_8 = xmlrpclib.ServerProxy(url_8 + 'common')
- self.proxy.db_8 = xmlrpclib.ServerProxy(url_8 + 'db')
- self.proxy.object_8 = xmlrpclib.ServerProxy(url_8 + 'object')
+ Use console.log in phantomjs to output test results:
+
+ - for a success: console.log("ok")
+ - for an error: console.log("error")
+
+ Other lines are relayed to the test log.
+
+ """
+ t0 = time.time()
+ buf = bytearray()
+ while True:
+ # timeout
+ self.assertLess(time.time(), t0 + timeout,
+ "PhantomJS tests should take less than %s seconds" % timeout)
+
+ # read a byte
+ try:
+ ready, _, _ = select.select([phantom.stdout], [], [], 0.5)
+ except select.error, e:
+ # In Python 2, select.error has no relation to IOError or
+ # OSError, and no errno/strerror/filename, only a pair of
+ # unnamed arguments (matching errno and strerror)
+ err, _ = e.args
+ if err == errno.EINTR: continue
+ raise
+
+ if ready:
+ s = phantom.stdout.read(1)
+ if not s:
+ break
+ buf.append(s)
+
+ # process lines
+ if '\n' in buf:
+ line, buf = buf.split('\n', 1)
+
+ line = str(line)
+ if 'CoreText' in line:
+ continue
+ if line == "ok":
+ break
+ if line.startswith("error"):
+ line_ = line[6:]
+ try: line_ = json.loads(line_)
+ except ValueError: pass
+ self.fail(line_ or "phantomjs test failed")
+
+ try: line = json.loads(line)
+ except ValueError: pass
+ _logger.info("phantomjs: %s", line)
+
+ def phantom_run(self, cmd, timeout):
+ _logger.debug('executing `%s`', ' '.join(cmd))
+ try:
+ phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ except OSError:
+ raise unittest2.SkipTest("PhantomJS not found")
+ try:
+ self.phantom_poll(phantom, timeout)
+ finally:
+ # kill phantomjs if phantom.exit() wasn't called in the test
+ if phantom.poll() is None:
+ phantom.terminate()
+
+ def phantom_jsfile(self, jsfile, timeout=30, **kw):
+ options = {
+ 'timeout' : timeout,
+ 'port': PORT,
+ 'db': DB,
+ 'session_id': self.session_id,
+ }
+ options.update(kw)
+ phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
+ # phantom.args[0] == phantomtest path
+ # phantom.args[1] == options
+ cmd = ['phantomjs', jsfile, phantomtest, json.dumps(options)]
+ self.phantom_run(cmd, timeout)
+
+ def phantom_js(self, url_path, code, ready="window", login=None, timeout=30, **kw):
+ """ Test js code running in the browser
+ - optionnally log as 'login'
+ - load page given by url_path
+ - wait for ready object to be available
+ - eval(code) inside the page
+
+ To signal success test do:
+ console.log('ok')
+
+ To signal failure do:
+ console.log('error')
+
+ If neither are done before timeout test fails.
+ """
+ options = {
+ 'port': PORT,
+ 'db': DB,
+ 'url_path': url_path,
+ 'code': code,
+ 'ready': ready,
+ 'timeout' : timeout,
+ 'login' : login,
+ 'session_id': self.session_id,
+ }
+ options.update(kw)
+ options.setdefault('password', options.get('login'))
+ phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
+ cmd = ['phantomjs', phantomtest, json.dumps(options)]
+ self.phantom_run(cmd, timeout)
- @classmethod
- def generate_database_name(cls):
- if hasattr(cls, '_database_id'):
- cls._database_id += 1
- else:
- cls._database_id = 0
- return '_fresh_name_' + str(cls._database_id) + '_'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/phantomtest.js b/openerp/tests/phantomtest.js
new file mode 100644
index 00000000000..1cdfeabce76
--- /dev/null
+++ b/openerp/tests/phantomtest.js
@@ -0,0 +1,145 @@
+// Phantomjs openerp helper
+
+function waitFor (ready, callback, timeout, timeoutMessageCallback) {
+ timeout = timeout || 10000;
+ var start = new Date().getTime();
+ var condition = ready();
+ var interval = setInterval(function() {
+ if ((new Date().getTime() - start < timeout) && !condition ) {
+ condition = ready();
+ } else {
+ if(!condition) {
+ var message = timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms";
+ console.log("Waiting for " + ready);
+ error(message);
+ } else {
+ clearInterval(interval);
+ callback();
+ }
+ }
+ }, 250);
+}
+
+function error(message) {
+ console.log('error', message);
+ phantom.exit(1);
+}
+function PhantomTest() {
+ var self = this;
+ this.options = JSON.parse(phantom.args[phantom.args.length-1]);
+ this.inject = this.options.inject || [];
+ this.timeout = this.options.timeout ? Math.round(parseFloat(this.options.timeout)*1000 - 5000) : 10000;
+ this.origin = 'http://localhost';
+ this.origin += this.options.port ? ':' + this.options.port : '';
+
+ // ----------------------------------------------------
+ // configure phantom and page
+ // ----------------------------------------------------
+ phantom.addCookie({
+ 'domain': 'localhost',
+ 'name': 'session_id',
+ 'value': this.options.session_id,
+ });
+ this.page = require('webpage').create();
+ this.page.viewportSize = { width: 1366, height: 768 };
+ this.page.onError = function(message, trace) {
+ var msg = [message];
+ if (trace && trace.length) {
+ msg.push.apply(msg, trace.map(function (frame) {
+ var result = [' at ', frame.file, ':', frame.line];
+ if (frame.function) {
+ result.push(' (in ', frame.function, ')');
+ }
+ return result.join('');
+ }));
+ msg.push('(leaf frame on top)')
+ }
+ error(JSON.stringify(msg.join('\n')));
+ };
+ this.page.onAlert = function(message) {
+ error(message);
+ };
+ this.page.onConsoleMessage = function(message) {
+ console.log(message);
+ };
+ this.page.onLoadFinished = function(status) {
+ if (status === "success") {
+ for (var k in self.inject) {
+ var found = false;
+ var v = self.inject[k];
+ var need = v;
+ var src = v;
+ if (v[0]) {
+ need = v[0];
+ src = v[1];
+ found = self.page.evaluate(function(code) {
+ try {
+ return !!eval(code);
+ } catch (e) {
+ return false;
+ }
+ }, need);
+ }
+ if(!found) {
+ console.log('Injecting', src, 'needed for', need);
+ if(!self.page.injectJs(src)) {
+ error("Cannot inject " + src);
+ }
+ }
+ }
+ }
+ };
+ setTimeout(function () {
+ self.page.evaluate(function () {
+ var message = ("Timeout\nhref: " + window.location.href
+ + "\nreferrer: " + document.referrer
+ + "\n\n" + document.body.innerHTML).replace(/[^a-z0-9\s~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "*");
+ error(message);
+ });
+ }, self.timeout);
+
+ // ----------------------------------------------------
+ // run test
+ // ----------------------------------------------------
+ this.run = function(url_path, code, ready) {
+ if(self.options.login) {
+ qp = [];
+ qp.push('db=' + self.options.db);
+ qp.push('login=' + self.options.login);
+ qp.push('key=' + self.options.password);
+ qp.push('redirect=' + encodeURIComponent(url_path));
+ var url_path = "/login?" + qp.join('&');
+ }
+ var url = self.origin + url_path;
+ self.page.open(url, function(status) {
+ if (status !== 'success') {
+ error("failed to load " + url)
+ } else {
+ console.log('loaded', url, status);
+ // process ready
+ waitFor(function() {
+ return self.page.evaluate(function (ready) {
+ var r = false;
+ try {
+ r = !!eval(ready);
+ } catch(ex) {
+ console.log("waiting for " + ready);
+ }
+ return r;
+ }, ready);
+ // run test
+ }, function() {
+ self.page.evaluate(function (code) { return eval(code); }, code);
+ });
+ }
+ });
+ };
+}
+
+// js mode or jsfile mode
+if(phantom.args.length === 1) {
+ pt = new PhantomTest();
+ pt.run(pt.options.url_path, pt.options.code, pt.options.ready);
+}
+
+// vim:et:
diff --git a/openerp/tests/test_expression.py b/openerp/tests/test_expression.py
deleted file mode 100644
index 1c5678becf1..00000000000
--- a/openerp/tests/test_expression.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import unittest2
-
-import openerp
-
-
-class test_domain_normalization(unittest2.TestCase):
- def test_normalize_domain(self):
- expression = openerp.osv.expression
- norm_domain = domain = ['&', (1, '=', 1), ('a', '=', 'b')]
- assert norm_domain == expression.normalize_domain(domain), "Normalized domains should be left untouched"
- domain = [('x', 'in', ['y', 'z']), ('a.v', '=', 'e'), '|', '|', ('a', '=', 'b'), '!', ('c', '>', 'd'), ('e', '!=', 'f'), ('g', '=', 'h')]
- norm_domain = ['&', '&', '&'] + domain
- assert norm_domain == expression.normalize_domain(domain), "Non-normalized domains should be properly normalized"
diff --git a/openerp/tests/test_xmlrpc.py b/openerp/tests/test_xmlrpc.py
deleted file mode 100644
index 12bc828cb29..00000000000
--- a/openerp/tests/test_xmlrpc.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- coding: utf-8 -*-
-# Run with one of these commands:
-# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \
-# OPENERP_DATABASE=yy PYTHONPATH=. python tests/test_xmlrpc.py
-# > OPENERP_ADDONS_PATH='../../addons/trunk' OPENERP_PORT=8069 \
-# OPENERP_DATABASE=yy nosetests tests/test_xmlrpc.py
-# > OPENERP_ADDONS_PATH='../../../addons/trunk' OPENERP_PORT=8069 \
-# OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_xmlrpc
-import time
-import unittest2
-import xmlrpclib
-
-import common
-
-DB = None
-ADMIN_USER = common.ADMIN_USER
-ADMIN_USER_ID = common.ADMIN_USER_ID
-ADMIN_PASSWORD = common.ADMIN_PASSWORD
-
-def setUpModule():
- common.start_openerp()
- global DB
- DB = common.RpcCase.generate_database_name()
-
-tearDownModule = common.stop_openerp
-
-class test_xmlrpc(common.RpcCase):
-
- def test_00_xmlrpc_create_database_polling(self):
- """
- Simulate a OpenERP client requesting the creation of a database and
- polling the server until the creation is complete.
- """
- progress_id = self.proxy.db_60.create(ADMIN_PASSWORD,DB, True, False,
- ADMIN_PASSWORD)
- while True:
- time.sleep(1)
- progress, users = self.proxy.db_60.get_progress(ADMIN_PASSWORD,
- progress_id)
- if progress == 1.0:
- break
-
- def test_xmlrpc_login(self):
- """ Try to login on the common service. """
- uid = self.proxy.common_60.login(DB, ADMIN_USER, ADMIN_PASSWORD)
- assert uid == ADMIN_USER_ID
-
- def test_xmlrpc_ir_model_search(self):
- """ Try a search on the object service. """
- o = self.proxy.object_60
- ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [])
- assert ids
- ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {})
- assert ids
-
- def test_xmlrpc_8_ir_model_search(self):
- """ Try a search on the object service. """
- o = self.proxy.object_8
- ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [])
- assert ids
- ids = o.execute(DB, ADMIN_USER_ID, ADMIN_PASSWORD, 'ir.model', 'search', [], {})
- assert ids
-
- # This test was written to test the creation of a new RPC endpoint, not
- # really for the EDI itself.
- #def test_xmlrpc_import_edi_document(self):
- # """ Try to call an EDI method. """
- # msg_re = 'EDI Document is empty!'
- # with self.assertRaisesRegexp(Exception, msg_re):
- # self.proxy.edi_60.import_edi_document(DB, ADMIN_USER_ID, ADMIN_PASSWORD, {})
-
- def test_zz_xmlrpc_drop_database(self):
- """
- Simulate a OpenERP client requesting the deletion of a database.
- """
- assert self.proxy.db_60.drop(ADMIN_PASSWORD, DB) is True
-
-if __name__ == '__main__':
- unittest2.main()
-
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tools/cache.py b/openerp/tools/cache.py
index 4b4dcea9b8e..a23641a9f4b 100644
--- a/openerp/tools/cache.py
+++ b/openerp/tools/cache.py
@@ -1,4 +1,7 @@
import lru
+import logging
+
+logger = logging.getLogger(__name__)
class ormcache(object):
""" LRU cache decorator for orm methods,
@@ -14,8 +17,8 @@ class ormcache(object):
def __call__(self,m):
self.method = m
- def lookup(self2, cr, *args):
- r = self.lookup(self2, cr, *args)
+ def lookup(self2, cr, *args, **argv):
+ r = self.lookup(self2, cr, *args, **argv)
return r
lookup.clear_cache = self.clear
return lookup
@@ -34,7 +37,7 @@ class ormcache(object):
d = ormcache[self.method] = lru.LRU(self.size)
return d
- def lookup(self, self2, cr, *args):
+ def lookup(self, self2, cr, *args, **argv):
d = self.lru(self2)
key = args[self.skiparg-2:]
try:
@@ -54,22 +57,45 @@ class ormcache(object):
"""
d = self.lru(self2)
if args:
- try:
- key = args[self.skiparg-2:]
- del d[key]
- self2.pool._any_cache_cleared = True
- except KeyError:
- pass
- else:
- d.clear()
- self2.pool._any_cache_cleared = True
+ logger.warn("ormcache.clear arguments are deprecated and ignored "
+ "(while clearing caches on (%s).%s)",
+ self2._name, self.method.__name__)
+ d.clear()
+ self2.pool._any_cache_cleared = True
+
+class ormcache_context(ormcache):
+ def __init__(self, skiparg=2, size=8192, accepted_keys=()):
+ super(ormcache_context,self).__init__(skiparg,size)
+ self.accepted_keys = accepted_keys
+
+ def lookup(self, self2, cr, *args, **argv):
+ d = self.lru(self2)
+
+ context = argv.get('context', {})
+ ckey = filter(lambda x: x[0] in self.accepted_keys, context.items())
+ ckey.sort()
+
+ d = self.lru(self2)
+ key = args[self.skiparg-2:]+tuple(ckey)
+ try:
+ r = d[key]
+ self.stat_hit += 1
+ return r
+ except KeyError:
+ self.stat_miss += 1
+ value = d[key] = self.method(self2, cr, *args, **argv)
+ return value
+ except TypeError:
+ self.stat_err += 1
+ return self.method(self2, cr, *args, **argv)
+
class ormcache_multi(ormcache):
def __init__(self, skiparg=2, size=8192, multi=3):
super(ormcache_multi,self).__init__(skiparg,size)
self.multi = multi - 2
- def lookup(self, self2, cr, *args):
+ def lookup(self, self2, cr, *args, **argv):
d = self.lru(self2)
args = list(args)
multi = self.multi
@@ -130,6 +156,7 @@ if __name__ == '__main__':
print r
for i in a._ormcache:
print a._ormcache[i].d
+ a.m.clear_cache()
a.n.clear_cache(a,1,1)
r=a.n("cr",1,[1,2])
print r
diff --git a/openerp/tools/config.py b/openerp/tools/config.py
index 90013cfedd0..abd46ce7f67 100644
--- a/openerp/tools/config.py
+++ b/openerp/tools/config.py
@@ -164,7 +164,7 @@ class configmanager(object):
# Testing Group
group = optparse.OptionGroup(parser, "Testing Configuration")
group.add_option("--test-file", dest="test_file", my_default=False,
- help="Launch a YML test file.")
+ help="Launch a python or YML test file.")
group.add_option("--test-report-directory", dest="test_report_directory", my_default=False,
help="If set, will save sample of all reports in this directory.")
group.add_option("--test-enable", action="store_true", dest="test_enable",
@@ -279,10 +279,10 @@ class configmanager(object):
group.add_option("--workers", dest="workers", my_default=0,
help="Specify the number of workers, 0 disable prefork mode.",
type="int")
- group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default=640 * 1024 * 1024,
+ group.add_option("--limit-memory-soft", dest="limit_memory_soft", my_default=2048 * 1024 * 1024,
help="Maximum allowed virtual memory per worker, when reached the worker be reset after the current request (default 671088640 aka 640MB).",
type="int")
- group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default=768 * 1024 * 1024,
+ group.add_option("--limit-memory-hard", dest="limit_memory_hard", my_default=2560 * 1024 * 1024,
help="Maximum allowed virtual memory per worker, when reached, any memory allocation will fail (default 805306368 aka 768MB).",
type="int")
group.add_option("--limit-time-cpu", dest="limit_time_cpu", my_default=60,
diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py
index cb2c414788e..43ee96660bd 100644
--- a/openerp/tools/convert.py
+++ b/openerp/tools/convert.py
@@ -50,7 +50,7 @@ except:
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
-from lxml import etree
+from lxml import etree, builder
import misc
from config import config
from translate import _
@@ -854,6 +854,48 @@ form: module.record_id""" % (xml_id,)
cr.commit()
return rec_model, id
+ def _tag_template(self, cr, el, data_node=None):
+ # This helper transforms a <template> element into a <record> and forwards it
+ tpl_id = el.get('id', el.get('t-name', '')).encode('ascii')
+ module = self.module
+ if '.' in tpl_id:
+ module, tpl_id = tpl_id.split('.', 1)
+ # set the full template name for qweb <module>.<id>
+ if not (el.get('inherit_id') or el.get('inherit_option_id')):
+ el.set('t-name', '%s.%s' % (module, tpl_id))
+ el.tag = 't'
+ else:
+ el.tag = 'data'
+ el.attrib.pop('id', None)
+
+ record_attrs = {
+ 'id': tpl_id,
+ 'model': 'ir.ui.view',
+ }
+ for att in ['forcecreate', 'context']:
+ if att in el.keys():
+ record_attrs[att] = el.attrib.pop(att)
+
+ Field = builder.E.field
+ name = el.get('name', tpl_id)
+
+ record = etree.Element('record', attrib=record_attrs)
+ record.append(Field(name, name='name'))
+ record.append(Field("qweb", name='type'))
+ record.append(Field(el.get('priority', "16"), name='priority'))
+ record.append(Field(el, name="arch", type="xml"))
+ for field_name in ('inherit_id','inherit_option_id'):
+ value = el.attrib.pop(field_name, None)
+ if value: record.append(Field(name=field_name, ref=value))
+ groups = el.attrib.pop('groups', None)
+ if groups:
+ grp_lst = map(lambda x: "ref('%s')" % x, groups.split(','))
+ record.append(Field(name="groups_id", eval="[(6, 0, ["+', '.join(grp_lst)+"])]"))
+ if el.attrib.pop('page', None) == 'True':
+ record.append(Field(name="page", eval="True"))
+
+ return self._tag_record(cr, record, data_node)
+
def id_get(self, cr, id_str):
if id_str in self.idref:
return self.idref[id_str]
@@ -898,6 +940,7 @@ form: module.record_id""" % (xml_id,)
self._tags = {
'menuitem': self._tag_menuitem,
'record': self._tag_record,
+ 'template': self._tag_template,
'assert': self._tag_assert,
'report': self._tag_report,
'wizard': self._tag_wizard,
diff --git a/openerp/tools/func.py b/openerp/tools/func.py
index 4728d971c69..ca8bba6bd49 100644
--- a/openerp/tools/func.py
+++ b/openerp/tools/func.py
@@ -57,4 +57,19 @@ def frame_codeinfo(fframe, back=0):
except Exception:
return "<unknown>", ''
+def compose(a, b):
+ """ Composes the callables ``a`` and ``b``. ``compose(a, b)(*args)`` is
+ equivalent to ``a(b(*args))``.
+
+ Can be used as a decorator by partially applying ``a``::
+
+ @partial(compose, a)
+ def b():
+ ...
+ """
+ @wraps(b)
+ def wrapper(*args, **kwargs):
+ return a(b(*args, **kwargs))
+ return wrapper
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tools/image.py b/openerp/tools/image.py
index 5e5055f252d..196ace2da60 100644
--- a/openerp/tools/image.py
+++ b/openerp/tools/image.py
@@ -25,7 +25,7 @@ except ImportError:
import StringIO
from PIL import Image
-from PIL import ImageOps
+from PIL import ImageEnhance
from random import randint
# ----------------------------------------
@@ -81,8 +81,13 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file
return base64_source
if image.size != size:
- # If you need faster thumbnails you may use use Image.NEAREST
- image = ImageOps.fit(image, size, Image.ANTIALIAS)
+ # create a thumbnail: will resize and keep ratios, then sharpen for better looking result
+ image.thumbnail(size, Image.ANTIALIAS)
+ sharpener = ImageEnhance.Sharpness(image.convert('RGBA'))
+ resized_image = sharpener.enhance(2.0)
+ # create a transparent image for background and paste the image on it
+ image = Image.new('RGBA', size, (255, 255, 255, 0))
+ image.paste(resized_image, ((size[0] - resized_image.size[0]) / 2, (size[1] - resized_image.size[1]) / 2))
if image.mode not in ["1", "L", "P", "RGB", "RGBA"]:
image = image.convert("RGB")
diff --git a/openerp/tools/mail.py b/openerp/tools/mail.py
index 673d1beb0ac..85dcfd368fe 100644
--- a/openerp/tools/mail.py
+++ b/openerp/tools/mail.py
@@ -2,7 +2,7 @@
##############################################################################
#
# OpenERP, Open Source Business Applications
-# Copyright (C) 2012-2013 OpenERP S.A. (<http://openerp.com>).
+# Copyright (C) 2012-TODAY OpenERP S.A. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -45,10 +45,15 @@ tags_to_kill = ["script", "head", "meta", "title", "link", "style", "frame", "if
tags_to_remove = ['html', 'body', 'font']
# allow new semantic HTML5 tags
-allowed_tags = clean.defs.tags | frozenset('article section header footer hgroup nav aside figure'.split())
-safe_attrs = clean.defs.safe_attrs | frozenset(['style'])
+allowed_tags = clean.defs.tags | frozenset('article section header footer hgroup nav aside figure main'.split())
+safe_attrs = clean.defs.safe_attrs | frozenset(
+ ['style',
+ 'data-oe-model', 'data-oe-id', 'data-oe-field', 'data-oe-type', 'data-oe-expression', 'data-oe-translate', 'data-oe-nodeid',
+ 'data-snippet-id', 'data-publish', 'data-id', 'data-res_id', 'data-member_id', 'data-view-id'
+ ])
-def html_sanitize(src, silent=True):
+
+def html_sanitize(src, silent=True, strict=False):
if not src:
return src
src = ustr(src, errors='replace')
@@ -75,22 +80,31 @@ def html_sanitize(src, silent=True):
else:
kwargs['remove_tags'] = tags_to_kill + tags_to_remove
- if etree.LXML_VERSION >= (3, 1, 0):
- kwargs.update({
- 'safe_attrs_only': True,
- 'safe_attrs': safe_attrs,
- })
+ if strict:
+ if etree.LXML_VERSION >= (3, 1, 0):
+ # lxml < 3.1.0 does not allow to specify safe_attrs. We keep all attributes in order to keep "style"
+ kwargs.update({
+ 'safe_attrs_only': True,
+ 'safe_attrs': safe_attrs,
+ })
else:
- # lxml < 3.1.0 does not allow to specify safe_attrs. We keep all attributes in order to keep "style"
- kwargs['safe_attrs_only'] = False
+ kwargs['safe_attrs_only'] = False # keep oe-data attributes + style
+ kwargs['frames'] = False, # do not remove frames (embbed video in CMS blogs)
try:
# some corner cases make the parser crash (such as <SCRIPT/XSS SRC=\"http://ha.ckers.org/xss.js\"></SCRIPT> in test_mail)
cleaner = clean.Cleaner(**kwargs)
cleaned = cleaner.clean_html(src)
+ # MAKO compatibility: $, { and } inside quotes are escaped, preventing correct mako execution
+ cleaned = cleaned.replace('%24', '$')
+ cleaned = cleaned.replace('%7B', '{')
+ cleaned = cleaned.replace('%7D', '}')
+ cleaned = cleaned.replace('%20', ' ')
+ cleaned = cleaned.replace('%5B', '[')
+ cleaned = cleaned.replace('%5D', ']')
except etree.ParserError, e:
- if 'empty' in str(e):
- return ""
+ if 'empty' in str(e):
+ return ""
if not silent:
raise
logger.warning('ParserError obtained when sanitizing %r', src, exc_info=True)
@@ -100,6 +114,11 @@ def html_sanitize(src, silent=True):
raise
logger.warning('unknown error obtained when sanitizing %r', src, exc_info=True)
cleaned = '<p>Unknown error when sanitizing</p>'
+
+ # this is ugly, but lxml/etree tostring want to put everything in a 'div' that breaks the editor -> remove that
+ if cleaned.startswith('<div>') and cleaned.endswith('</div>'):
+ cleaned = cleaned[5:-6]
+
return cleaned
@@ -107,7 +126,8 @@ def html_sanitize(src, silent=True):
# HTML Cleaner
#----------------------------------------------------------
-def html_email_clean(html, remove=False, shorten=False, max_length=300):
+def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_options=None,
+ protect_sections=False):
""" html_email_clean: clean the html by doing the following steps:
- try to strip email quotes, by removing blockquotes or having some client-
@@ -132,6 +152,32 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
be flagged as to remove
:param int max_length: if shortening, maximum number of characters before
shortening
+ :param dict expand_options: options for the read more link when shortening
+ the content.The used keys are the following:
+
+ - oe_expand_container_tag: class applied to the
+ container of the whole read more link
+ - oe_expand_container_class: class applied to the
+ link container (default: oe_mail_expand)
+ - oe_expand_container_content: content of the
+ container (default: ...)
+ - oe_expand_separator_node: optional separator, like
+ adding ... <br /><br /> <a ...>read more</a> (default: void)
+ - oe_expand_a_href: href of the read more link itself
+ (default: #)
+ - oe_expand_a_class: class applied to the <a> containing
+ the link itself (default: oe_mail_expand)
+ - oe_expand_a_content: content of the <a> (default: read more)
+
+ The formatted read more link is the following:
+ <cont_tag class="oe_expand_container_class">
+ oe_expand_container_content
+ if expand_options.get('oe_expand_separator_node'):
+ <oe_expand_separator_node/>
+ <a href="oe_expand_a_href" class="oe_expand_a_class">
+ oe_expand_a_content
+ </a>
+ </span>
"""
def _replace_matching_regex(regex, source, replace=''):
""" Replace all matching expressions in source by replace """
@@ -212,8 +258,29 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
node.text = innertext
# create <span> ... <a href="#">read more</a></span> node
- read_more_node = _create_node('span', ' ... ', None, {'class': 'oe_mail_expand'})
- read_more_link_node = _create_node('a', 'read more', None, {'href': '#', 'class': 'oe_mail_expand'})
+ read_more_node = _create_node(
+ expand_options.get('oe_expand_container_tag', 'span'),
+ expand_options.get('oe_expand_container_content', ' ... '),
+ None,
+ {'class': expand_options.get('oe_expand_container_class', 'oe_mail_expand')}
+ )
+ if expand_options.get('oe_expand_separator_node'):
+ read_more_separator_node = _create_node(
+ expand_options.get('oe_expand_separator_node'),
+ '',
+ None,
+ {}
+ )
+ read_more_node.append(read_more_separator_node)
+ read_more_link_node = _create_node(
+ 'a',
+ expand_options.get('oe_expand_a_content', 'read more'),
+ None,
+ {
+ 'href': expand_options.get('oe_expand_a_href', '#'),
+ 'class': expand_options.get('oe_expand_a_class', 'oe_mail_expand'),
+ }
+ )
read_more_node.append(read_more_link_node)
# create outertext node
overtext_node = _create_node('span', outertext)
@@ -223,6 +290,9 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
node.append(read_more_node)
node.append(overtext_node)
+ if expand_options is None:
+ expand_options = {}
+
if not html or not isinstance(html, basestring):
return html
html = ustr(html)
@@ -265,6 +335,8 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
# signature_begin = False # try dynamic signature recognition
quote_begin = False
overlength = False
+ overlength_section_id = None
+ overlength_section_count = 0
cur_char_nbr = 0
for node in root.iter():
# do not take into account multiple spaces that are displayed as max 1 space in html
@@ -276,14 +348,22 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
if 'SkyDrivePlaceholder' in node.get('class', '') or 'SkyDrivePlaceholder' in node.get('id', ''):
root.set('hotmail', '1')
+ # protect sections by tagging section limits and blocks contained inside sections, using an increasing id to re-find them later
+ if node.tag == 'section':
+ overlength_section_count += 1
+ node.set('section_closure', str(overlength_section_count))
+ if node.getparent() is not None and (node.getparent().get('section_closure') or node.getparent().get('section_inner')):
+ node.set('section_inner', str(overlength_section_count))
+
# state of the parsing: flag quotes and tails to remove
if quote_begin:
node.set('in_quote', '1')
node.set('tail_remove', '1')
- # state of the parsing: flag when being in over-length content
+ # state of the parsing: flag when being in over-length content, depending on section content if defined (only when having protect_sections)
if overlength:
- node.set('in_overlength', '1')
- node.set('tail_remove', '1')
+ if not overlength_section_id or int(node.get('section_inner', overlength_section_count + 1)) > overlength_section_count:
+ node.set('in_overlength', '1')
+ node.set('tail_remove', '1')
# find quote in msoffice / hotmail / blockquote / text quote and signatures
if root.get('msoffice') and node.tag == 'div' and 'border-top:solid' in node.get('style', ''):
@@ -298,13 +378,25 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
node.set('in_quote', '1')
# shorten:
- # 1/ truncate the text at the next available space
- # 2/ create a 'read more' node, next to current node
- # 3/ add the truncated text in a new node, next to 'read more' node
+ # if protect section:
+ # 1/ find the first parent not being inside a section
+ # 2/ add the read more link
+ # else:
+ # 1/ truncate the text at the next available space
+ # 2/ create a 'read more' node, next to current node
+ # 3/ add the truncated text in a new node, next to 'read more' node
+ node_text = (node.text or '').strip().strip('\n').strip()
if shorten and not overlength and cur_char_nbr + len(node_text) > max_length:
node_to_truncate = node
- while node_to_truncate.get('in_quote') and node_to_truncate.getparent() is not None:
- node_to_truncate = node_to_truncate.getparent()
+ while node_to_truncate.getparent() is not None:
+ if node_to_truncate.get('in_quote'):
+ node_to_truncate = node_to_truncate.getparent()
+ elif protect_sections and (node_to_truncate.getparent().get('section_inner') or node_to_truncate.getparent().get('section_closure')):
+ node_to_truncate = node_to_truncate.getparent()
+ overlength_section_id = node_to_truncate.get('section_closure')
+ else:
+ break
+
overlength = True
node_to_truncate.set('truncate', '1')
if node_to_truncate == node:
@@ -340,7 +432,7 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300):
if remove:
node.getparent().remove(node)
else:
- if not 'oe_mail_expand' in node.get('class', ''): # trick: read more link should be displayed even if it's in overlength
+ if not expand_options.get('oe_expand_a_class', 'oe_mail_expand') in node.get('class', ''): # trick: read more link should be displayed even if it's in overlength
node_class = node.get('class', '') + ' oe_mail_cleaned'
node.set('class', node_class)
diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py
index 20cb510d956..251905137c0 100644
--- a/openerp/tools/misc.py
+++ b/openerp/tools/misc.py
@@ -35,7 +35,7 @@ import sys
import threading
import time
import zipfile
-from collections import defaultdict
+from collections import defaultdict, Mapping
from datetime import datetime
from itertools import islice, izip, groupby
from lxml import etree
@@ -822,6 +822,76 @@ DATETIME_FORMATS_MAP = {
'%Z': '',
}
+POSIX_TO_LDML = {
+ 'a': 'E',
+ 'A': 'EEEE',
+ 'b': 'MMM',
+ 'B': 'MMMM',
+ #'c': '',
+ 'd': 'dd',
+ 'H': 'HH',
+ 'I': 'hh',
+ 'j': 'DDD',
+ 'm': 'MM',
+ 'M': 'mm',
+ 'p': 'a',
+ 'S': 'ss',
+ 'U': 'w',
+ 'w': 'e',
+ 'W': 'w',
+ 'y': 'yy',
+ 'Y': 'yyyy',
+ # see comments above, and babel's format_datetime assumes an UTC timezone
+ # for naive datetime objects
+ #'z': 'Z',
+ #'Z': 'z',
+}
+
+def posix_to_ldml(fmt, locale):
+ """ Converts a posix/strftime pattern into an LDML date format pattern.
+
+ :param fmt: non-extended C89/C90 strftime pattern
+ :param locale: babel locale used for locale-specific conversions (e.g. %x and %X)
+ :return: unicode
+ """
+ buf = []
+ pc = False
+ quoted = []
+
+ for c in fmt:
+ # LDML date format patterns uses letters, so letters must be quoted
+ if not pc and c.isalpha():
+ quoted.append(c if c != "'" else "''")
+ continue
+ if quoted:
+ buf.append("'")
+ buf.append(''.join(quoted))
+ buf.append("'")
+ quoted = []
+
+ if pc:
+ if c == '%': # escaped percent
+ buf.append('%')
+ elif c == 'x': # date format, short seems to match
+ buf.append(locale.date_formats['short'].pattern)
+ elif c == 'X': # time format, seems to include seconds. short does not
+ buf.append(locale.time_formats['medium'].pattern)
+ else: # look up format char in static mapping
+ buf.append(POSIX_TO_LDML[c])
+ pc = False
+ elif c == '%':
+ pc = True
+ else:
+ buf.append(c)
+
+ # flush anything remaining in quoted buffer
+ if quoted:
+ buf.append("'")
+ buf.append(''.join(quoted))
+ buf.append("'")
+
+ return ''.join(buf)
+
def server_to_local_timestamp(src_tstamp_str, src_format, dst_format, dst_tz_name,
tz_offset=True, ignore_unparsable_time=True):
"""
@@ -1005,6 +1075,8 @@ class mute_logger(object):
def __enter__(self):
for logger in self.loggers:
+ assert isinstance(logger, basestring),\
+ "A logger name must be a string, got %s" % type(logger)
logging.getLogger(logger).addFilter(self)
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
@@ -1070,6 +1142,34 @@ def stripped_sys_argv(*strip_args):
return [x for i, x in enumerate(args) if not strip(args, i)]
+class ConstantMapping(Mapping):
+ """
+ An immutable mapping returning the provided value for every single key.
+
+ Useful for default value to methods
+ """
+ __slots__ = ['_value']
+ def __init__(self, val):
+ self._value = val
+
+ def __len__(self):
+ """
+ defaultdict updates its length for each individually requested key, is
+ that really useful?
+ """
+ return 0
+
+ def __iter__(self):
+ """
+ same as len, defaultdict udpates its iterable keyset with each key
+ requested, is there a point for this?
+ """
+ return iter([])
+
+ def __getitem__(self, item):
+ return self._value
+
+
def dumpstacks(sig, frame):
""" Signal handler: dump a stack trace for each existing thread."""
code = []
@@ -1107,4 +1207,5 @@ def dumpstacks(sig, frame):
_logger.info("\n".join(code))
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tools/safe_eval.py b/openerp/tools/safe_eval.py
index a18d0a83fae..b64b401a71c 100644
--- a/openerp/tools/safe_eval.py
+++ b/openerp/tools/safe_eval.py
@@ -67,7 +67,8 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR',
'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'DELETE_NAME',
'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE',
- 'MAKE_FUNCTION', 'SLICE+0', 'SLICE+1', 'SLICE+2', 'SLICE+3',
+ 'MAKE_FUNCTION', 'SLICE+0', 'SLICE+1', 'SLICE+2', 'SLICE+3', 'BREAK_LOOP',
+ 'CONTINUE_LOOP', 'RAISE_VARARGS',
# New in Python 2.7 - http://bugs.python.org/issue4715 :
'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE',
'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'END_FINALLY'
@@ -174,7 +175,7 @@ def _import(name, globals=None, locals=None, fromlist=None, level=-1):
return __import__(name, globals, locals, level)
raise ImportError(name)
-def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=False):
+def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=False, locals_builtins=False):
"""safe_eval(expression[, globals[, locals[, mode[, nocopy]]]]) -> result
System-restricted Python expression evaluation
@@ -218,29 +219,37 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal
locals_dict = dict(locals_dict)
globals_dict.update(
- __builtins__ = {
- '__import__': _import,
- 'True': True,
- 'False': False,
- 'None': None,
- 'str': str,
- 'globals': locals,
- 'locals': locals,
- 'bool': bool,
- 'dict': dict,
- 'list': list,
- 'tuple': tuple,
- 'map': map,
- 'abs': abs,
- 'min': min,
- 'max': max,
- 'reduce': reduce,
- 'filter': filter,
- 'round': round,
- 'len': len,
- 'set' : set
- }
+ __builtins__={
+ '__import__': _import,
+ 'True': True,
+ 'False': False,
+ 'None': None,
+ 'str': str,
+ 'globals': locals,
+ 'locals': locals,
+ 'bool': bool,
+ 'dict': dict,
+ 'list': list,
+ 'tuple': tuple,
+ 'map': map,
+ 'abs': abs,
+ 'min': min,
+ 'max': max,
+ 'reduce': reduce,
+ 'filter': filter,
+ 'round': round,
+ 'len': len,
+ 'set': set,
+ 'repr': repr,
+ 'int': int,
+ 'float': float,
+ 'range': range,
+ }
)
+ if locals_builtins:
+ if locals_dict is None:
+ locals_dict = {}
+ locals_dict.update(globals_dict.get('__builtins__'))
c = test_expr(expr, _SAFE_OPCODES, mode=mode)
try:
return eval(c, globals_dict, locals_dict)
diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py
index c99d10373a0..6f5b22f4f53 100644
--- a/openerp/tools/translate.py
+++ b/openerp/tools/translate.py
@@ -172,7 +172,7 @@ class GettextAlias(object):
cr = getattr(s, 'cr', None)
if not cr and allow_create:
db = self._get_db()
- if db:
+ if db is not None:
cr = db.cursor()
is_new_cr = True
return cr, is_new_cr
diff --git a/openerp/tools/view_validation.py b/openerp/tools/view_validation.py
index 7e710d55816..9101d10064e 100644
--- a/openerp/tools/view_validation.py
+++ b/openerp/tools/view_validation.py
@@ -41,8 +41,7 @@ def valid_att_in_label(arch):
def valid_att_in_form(arch):
- """A `string` attribute must be on a `form` node."""
- return not arch.xpath('//form[not (@string)]')
+ return True
def valid_type_in_colspan(arch):
@@ -67,8 +66,8 @@ def valid_type_in_col(arch):
def valid_view(arch):
if arch.tag == 'form':
- for pred in [valid_page_in_book, valid_att_in_form, valid_type_in_colspan,\
- valid_type_in_col, valid_att_in_field, valid_att_in_label]:
+ for pred in [valid_page_in_book, valid_att_in_form, valid_type_in_colspan,
+ valid_type_in_col, valid_att_in_field, valid_att_in_label]:
if not pred(arch):
_logger.error('Invalid XML: %s', pred.__doc__)
return False
diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py
index a418cb9f841..060d261ef18 100644
--- a/openerp/tools/yaml_import.py
+++ b/openerp/tools/yaml_import.py
@@ -321,14 +321,13 @@ class YamlInterpreter(object):
view_info = model.fields_view_get(self.cr, SUPERUSER_ID, varg, 'form', context)
record_dict = self._create_record(model, fields, view_info, default=default)
- _logger.debug("RECORD_DICT %s" % record_dict)
id = self.pool['ir.model.data']._update(self.cr, SUPERUSER_ID, record.model, \
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode, context=context)
self.id_map[record.id] = int(id)
if config.get('import_partial'):
self.cr.commit()
- def _create_record(self, model, fields, view_info=False, parent={}, default=True):
+ def _create_record(self, model, fields, view_info=None, parent={}, default=True):
"""This function processes the !record tag in yalm files. It simulates the record creation through an xml
view (either specified on the !record tag or the default one for this object), including the calls to
on_change() functions, and sending only values for fields that aren't set as readonly.
@@ -447,7 +446,13 @@ class YamlInterpreter(object):
args = map(lambda x: eval(x, ctx), match.group(2).split(','))
result = getattr(model, match.group(1))(self.cr, SUPERUSER_ID, [], *args)
for key, val in (result or {}).get('value', {}).items():
- assert key in fg, "The returning field '%s' from your on_change call '%s' does not exist either on the object '%s', either in the view '%s' used for the creation" % (key, match.group(1), model._name, view_info['name'])
+ assert key in fg, (
+ "The field %r returned from the onchange call %r "
+ "does not exist in the source view %r (of object "
+ "%r). This field will be ignored (and thus not "
+ "populated) when clients saves the new record" % (
+ key, match.group(1), view_info.get('name', '?'), model._name
+ ))
if key not in fields:
# do not shadow values explicitly set in yaml.
record_dict[key] = process_val(key, val)
@@ -925,7 +930,7 @@ class YamlInterpreter(object):
def yaml_import(cr, module, yamlfile, kind, idref=None, mode='init', noupdate=False, report=None):
if idref is None:
idref = {}
- loglevel = logging.INFO if kind == 'test' else logging.DEBUG
+ loglevel = logging.DEBUG
yaml_string = yamlfile.read()
yaml_interpreter = YamlInterpreter(cr, module, idref, mode, filename=yamlfile.name, report=report, noupdate=noupdate, loglevel=loglevel)
yaml_interpreter.process(yaml_string)
diff --git a/openerp/workflow/instance.py b/openerp/workflow/instance.py
index 8ae633b5ba1..fd15eee6243 100644
--- a/openerp/workflow/instance.py
+++ b/openerp/workflow/instance.py
@@ -106,7 +106,7 @@ class WorkflowInstance(object):
for cur_instance_id, cur_model_name, cur_record_id in cr.fetchall():
cur_record = Record(cur_model_name, cur_record_id)
for act_name in act_names:
- WorkflowInstance(self.session, cur_record, {'id':cur_instance_id}).validate('subflow.{}'.format(act_name[0]))
+ WorkflowInstance(self.session, cur_record, {'id':cur_instance_id}).validate('subflow.%s' % act_name[0])
return ok
diff --git a/openerpcommand/__init__.py b/openerpcommand/__init__.py
index 9d5e81f0327..b7131913e1e 100644
--- a/openerpcommand/__init__.py
+++ b/openerpcommand/__init__.py
@@ -14,14 +14,13 @@ from . import initialize
from . import model
from . import module
from . import read
-from . import run_tests
from . import scaffold
from . import uninstall
from . import update
from . import web
from . import grunt_tests
-command_list_server = (conf, cron, drop, initialize, model, module, read, run_tests,
+command_list_server = (conf, cron, drop, initialize, model, module, read,
scaffold, uninstall, update, web, grunt_tests, )
command_list_client = (Call, Open, Show, ConsumeNothing, ConsumeMemory,
diff --git a/openerpcommand/common.py b/openerpcommand/common.py
index 9209f8e1eb6..7572bb4efa6 100644
--- a/openerpcommand/common.py
+++ b/openerpcommand/common.py
@@ -57,11 +57,11 @@ def required_or_default(name, h):
a mandatory argument.
"""
if os.environ.get('OPENERP_' + name.upper()):
- d = {'default': os.environ['OPENERP_' + name.upper()]}
+ d = {'default': os.environ['OPENERP_' + name.upper()]}
else:
- d = {'required': True}
+ d = {'required': True}
d['help'] = h + '. The environment variable OPENERP_' + \
- name.upper() + ' can be used instead.'
+ name.upper() + ' can be used instead.'
return d
class Command(object):
@@ -77,7 +77,7 @@ class Command(object):
self.parser = parser = subparsers.add_parser(self.command_name,
description=self.__class__.__doc__)
else:
- self.parser = parser = argparse.ArgumentParser(
+ self.parser = parser = argparse.ArgumentParser(
description=self.__class__.__doc__)
parser.add_argument('-d', '--database', metavar='DATABASE',
diff --git a/openerpcommand/initialize.py b/openerpcommand/initialize.py
index 6261312de7e..cf4e54bfb82 100644
--- a/openerpcommand/initialize.py
+++ b/openerpcommand/initialize.py
@@ -9,24 +9,6 @@ import time
import common
-def install_openerp(database_name, create_database_flag, module_names, install_demo_data):
- import openerp
- config = openerp.tools.config
-
- if create_database_flag:
- with lock_file('/tmp/global_openerp_create_database.lock'):
- create_database(database_name)
-
- config['init'] = dict.fromkeys(module_names, 1)
-
- # Install the import hook, to import openerp.addons.<module>.
- openerp.modules.module.initialize_sys_path()
-
- registry = openerp.modules.registry.RegistryManager.get(
- database_name, update_module=True, force_demo=install_demo_data)
-
- return registry
-
# From http://code.activestate.com/recipes/576572/
@contextlib.contextmanager
def lock_file(path, wait_delay=.1, max_try=600):
@@ -50,21 +32,6 @@ def lock_file(path, wait_delay=.1, max_try=600):
os.close(fd)
os.unlink(path)
-# TODO turn template1 in a parameter
-# This should be exposed from openerp (currently in
-# openerp/service/web_services.py).
-def create_database(database_name):
- import openerp
- db = openerp.sql_db.db_connect('template1')
- cr = db.cursor() # TODO `with db as cr:`
- try:
- cr.autocommit(True)
- cr.execute("""CREATE DATABASE "%s"
- ENCODING 'unicode' TEMPLATE "template1" """ \
- % (database_name,))
- finally:
- cr.close()
-
def run(args):
assert args.database
assert not (args.module and args.all_modules)
@@ -72,11 +39,14 @@ def run(args):
import openerp
config = openerp.tools.config
+ config['db_name'] = args.database
if args.tests:
config['log_handler'] = [':INFO']
config['test_enable'] = True
config['without_demo'] = False
+ if args.port:
+ config['xmlrpc_port'] = int(args.port)
else:
config['log_handler'] = [':CRITICAL']
config['test_enable'] = False
@@ -94,6 +64,7 @@ def run(args):
module_names = args.module
else:
module_names = ['base']
+ config['init'] = dict.fromkeys(module_names, 1)
if args.coverage:
import coverage
@@ -102,17 +73,22 @@ def run(args):
cov = coverage.coverage(branch=True, include='*.py')
cov.start()
openerp.netsvc.init_logger()
- registry = install_openerp(args.database, not args.no_create, module_names, not config['without_demo'])
+
+ if not args.no_create:
+ with lock_file('/tmp/global_openerp_create_database.lock'):
+ openerp.service.db._create_empty_database(args.database)
+
+ config['workers'] = False
+
+ rc = openerp.service.server.start(preload=[args.database], stop=True)
+
if args.coverage:
cov.stop()
cov.html_report(directory='coverage')
# If we wanted the report on stdout:
# cov.report()
- # The `_assertion_report` attribute was added on the registry during the
- # OpenERP 7.0 development.
- if hasattr(registry, '_assertion_report'):
- sys.exit(1 if registry._assertion_report.failures else 0)
+ sys.exit(rc)
def add_parser(subparsers):
parser = subparsers.add_parser('initialize',
@@ -120,6 +96,8 @@ def add_parser(subparsers):
parser.add_argument('-d', '--database', metavar='DATABASE',
**common.required_or_default('DATABASE', 'the database to create'))
common.add_addons_argument(parser)
+ parser.add_argument('-P', '--port', metavar='PORT',
+ **common.required_or_default('PORT', 'the server port'))
parser.add_argument('--module', metavar='MODULE', action='append',
help='specify a module to install'
' (this option can be repeated)')
diff --git a/openerpcommand/run_tests.py b/openerpcommand/run_tests.py
deleted file mode 100644
index 4000b227b90..00000000000
--- a/openerpcommand/run_tests.py
+++ /dev/null
@@ -1,201 +0,0 @@
-"""
-Execute the unittest2 tests available in OpenERP addons.
-"""
-
-import os
-import sys
-import types
-
-import common
-
-def get_test_modules(module, submodule, explode):
- """
- Return a list of submodules containing tests.
- `submodule` can be:
- - None
- - the name of a submodule
- - '__fast_suite__'
- - '__sanity_checks__'
- """
- # Turn command-line module, submodule into importable names.
- if module is None:
- pass
- elif module == 'openerp':
- module = 'openerp.tests'
- else:
- module = 'openerp.addons.' + module + '.tests'
-
- # Try to import the module
- try:
- __import__(module)
- except Exception, e:
- if explode:
- print 'Can not `import %s`.' % module
- import logging
- logging.exception('')
- sys.exit(1)
- else:
- if str(e) == 'No module named tests':
- # It seems the module has no `tests` sub-module, no problem.
- pass
- else:
- print 'Can not `import %s`.' % module
- return []
-
- # Discover available test sub-modules.
- m = sys.modules[module]
- submodule_names = sorted([x for x in dir(m) \
- if x.startswith('test_') and \
- isinstance(getattr(m, x), types.ModuleType)])
- submodules = [getattr(m, x) for x in submodule_names]
-
- def show_submodules_and_exit():
- if submodule_names:
- print 'Available submodules are:'
- for x in submodule_names:
- print ' ', x
- sys.exit(1)
-
- if submodule is None:
- # Use auto-discovered sub-modules.
- ms = submodules
- elif submodule == '__fast_suite__':
- # Obtain the explicit test sub-modules list.
- ms = getattr(sys.modules[module], 'fast_suite', None)
- # `suite` was used before the 6.1 release instead of `fast_suite`.
- ms = ms if ms else getattr(sys.modules[module], 'suite', None)
- if ms is None:
- if explode:
- print 'The module `%s` has no defined test suite.' % (module,)
- show_submodules_and_exit()
- else:
- ms = []
- elif submodule == '__sanity_checks__':
- ms = getattr(sys.modules[module], 'checks', None)
- if ms is None:
- if explode:
- print 'The module `%s` has no defined sanity checks.' % (module,)
- show_submodules_and_exit()
- else:
- ms = []
- else:
- # Pick the command-line-specified test sub-module.
- m = getattr(sys.modules[module], submodule, None)
- ms = [m]
-
- if m is None:
- if explode:
- print 'The module `%s` has no submodule named `%s`.' % \
- (module, submodule)
- show_submodules_and_exit()
- else:
- ms = []
-
- return ms
-
-def run(args):
- import unittest2
-
- import openerp
-
- config = openerp.tools.config
- config['db_name'] = args.database
- if args.port:
- config['xmlrpc_port'] = int(args.port)
- config['admin_passwd'] = 'admin'
- config['db_password'] = 'a2aevl8w' # TODO from .openerpserverrc
- config['addons_path'] = args.addons.replace(':',',')
- if args.addons:
- args.addons = args.addons.split(':')
- else:
- args.addons = []
- if args.sanity_checks and args.fast_suite:
- print 'Only at most one of `--sanity-checks` and `--fast-suite` ' \
- 'can be specified.'
- sys.exit(1)
-
- import logging
- openerp.netsvc.init_alternative_logger()
- logging.getLogger('openerp').setLevel(logging.CRITICAL)
-
- # Install the import hook, to import openerp.addons.<module>.
- openerp.modules.module.initialize_sys_path()
-
- # Extract module, submodule from the command-line args.
- if args.module is None:
- module, submodule = None, None
- else:
- splitted = args.module.split('.')
- if len(splitted) == 1:
- module, submodule = splitted[0], None
- elif len(splitted) == 2:
- module, submodule = splitted
- else:
- print 'The `module` argument must have the form ' \
- '`module[.submodule]`.'
- sys.exit(1)
-
- # Import the necessary modules and get the corresponding suite.
- if module is None:
- # TODO
- modules = common.get_addons_from_paths(args.addons, []) # TODO openerp.addons.base is not included ?
- test_modules = []
- for module in ['openerp'] + modules:
- if args.fast_suite:
- submodule = '__fast_suite__'
- if args.sanity_checks:
- submodule = '__sanity_checks__'
- test_modules.extend(get_test_modules(module,
- submodule, explode=False))
- else:
- if submodule and args.fast_suite:
- print "Submodule name `%s` given, ignoring `--fast-suite`." % (submodule,)
- if submodule and args.sanity_checks:
- print "Submodule name `%s` given, ignoring `--sanity-checks`." % (submodule,)
- if not submodule and args.fast_suite:
- submodule = '__fast_suite__'
- if not submodule and args.sanity_checks:
- submodule = '__sanity_checks__'
- test_modules = get_test_modules(module,
- submodule, explode=True)
-
- # Run the test suite.
- if not args.dry_run:
- suite = unittest2.TestSuite()
- for test_module in test_modules:
- suite.addTests(unittest2.TestLoader().loadTestsFromModule(test_module))
- r = unittest2.TextTestRunner(verbosity=2).run(suite)
- if r.errors or r.failures:
- sys.exit(1)
- else:
- print 'Test modules:'
- for test_module in test_modules:
- print ' ', test_module.__name__
-
-def add_parser(subparsers):
- parser = subparsers.add_parser('run-tests',
- description='Run the OpenERP server and/or addons tests.')
- parser.add_argument('-d', '--database', metavar='DATABASE', required=True,
- help='the database to test. Depending on the test suites, the '
- 'database must already exist or not.')
- parser.add_argument('-p', '--port', metavar='PORT',
- help='the port used for WML-RPC tests')
- common.add_addons_argument(parser)
- parser.add_argument('-m', '--module', metavar='MODULE',
- default=None,
- help='the module to test in `module[.submodule]` notation. '
- 'Use `openerp` for the core OpenERP tests. '
- 'Leave empty to run every declared tests. '
- 'Give a module but no submodule to run all the module\'s declared '
- 'tests. If both the module and the submodule are given, '
- 'the sub-module can be run even if it is not declared in the module.')
- parser.add_argument('--fast-suite', action='store_true',
- help='run only the tests explicitely declared in the fast suite (this '
- 'makes sense only with the bare `module` notation or no module at '
- 'all).')
- parser.add_argument('--sanity-checks', action='store_true',
- help='run only the sanity check tests')
- parser.add_argument('--dry-run', action='store_true',
- help='do not run the tests')
-
- parser.set_defaults(run=run)