diff --git a/debian/control b/debian/control index 91ff36e34c9..7f7786ee98d 100644 --- a/debian/control +++ b/debian/control @@ -35,6 +35,7 @@ Depends: python-pydot, python-pyparsing, python-reportlab, + python-requests, python-simplejson, python-tz, python-unittest2, diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 3c3c290f986..3d0d3e4dda4 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -57,6 +57,8 @@ The kernel of OpenERP, needed for all installation. 'ir/ir_values_view.xml', 'ir/osv_memory_autovacuum.xml', 'ir/ir_model_report.xml', + 'ir/ir_logging_view.xml', + 'ir/ir_qweb.xml', 'workflow/workflow_view.xml', 'module/module_view.xml', 'module/module_data.xml', diff --git a/openerp/addons/base/i18n/ab.po b/openerp/addons/base/i18n/ab.po index 62a7450b7ac..43085686f85 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:26+0000\n" +"X-Generator: Launchpad (build 16967)\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 ea79c793e40..8b72134a932 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:26+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/am.po b/openerp/addons/base/i18n/am.po index a787d963761..8da3ddda48b 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/ar.po b/openerp/addons/base/i18n/ar.po index 443c5f9b027..bfec4b6175c 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\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 41b86bf9de9..8ef295ab110 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-03-04 05:59+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\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 56b2bc70a5b..31ddf58c503 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-03-04 05:59+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\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 c343f0c527a..0260f5f1721 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-03-04 05:59+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\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 91d10c6e60a..d3ee26f8aaa 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-03-04 05:59+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\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 2f66120919d..6f5180c287d 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-03-04 06:00+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\n" "X-Poedit-Language: Czech\n" #. module: base @@ -64,7 +64,7 @@ msgstr "Zobrazení architektury" #. module: base #: model:ir.module.module,summary:base.module_sale_stock msgid "Quotation, Sale Orders, Delivery & Invoicing Control" -msgstr "Nabídky, zakázky, řízení dopravy a fakturace" +msgstr "Nabídky, zakázky, řízení dodávek a fakturace" #. module: base #: selection:ir.sequence,implementation:0 @@ -87,8 +87,7 @@ msgid "" "Helps you manage your projects and tasks by tracking them, generating " "plannings, etc..." msgstr "" -"Pomůže vám spravovat projekty a úkoly jejich sledováním, generováním plánů, " -"apod." +"Pomůže vám řídit projekty a úkoly jejich sledováním, generováním plánů, aj." #. module: base #: model:ir.module.module,summary:base.module_point_of_sale @@ -158,7 +157,7 @@ msgstr "" #. module: base #: help:res.partner,employee:0 msgid "Check this box if this contact is an Employee." -msgstr "Zaškrtněte toto pole, pokud je kontakt zaměstnanec." +msgstr "Zaškrtněte toto pole, pokud je kontakt zaměstnancem." #. module: base #: help:ir.model.fields,domain:0 @@ -11056,7 +11055,7 @@ msgstr "Úkoly" #. module: base #: model:ir.module.module,shortdesc:base.module_product_visible_discount msgid "Prices Visible Discounts" -msgstr "" +msgstr "Zobrazení slevy u ceny" #. module: base #: field:ir.attachment,datas:0 diff --git a/openerp/addons/base/i18n/da.po b/openerp/addons/base/i18n/da.po index bf43d7574a4..09df3428d98 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-03-04 06:00+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\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 2e662191b9a..e5bd8df5bee 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-03-04 06:02+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:30+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/el.po b/openerp/addons/base/i18n/el.po index 1d0c013b663..e3519923b06 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-03-04 06:03+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:30+0000\n" +"X-Generator: Launchpad (build 16967)\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 91729acef84..8f9c671d7fd 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-03-04 06:13+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\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 933fcfc62ab..71e1a37e6cb 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-03-04 06:10+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:36+0000\n" +"X-Generator: Launchpad (build 16967)\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 2ba523bbae8..b9fc7e6a6ae 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-03-04 06:13+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:38+0000\n" +"X-Generator: Launchpad (build 16967)\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 2a5ec16a919..8fbeef6945c 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-03-04 06:14+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\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 c7af368f07c..ee7a13a95ce 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-03-04 06:14+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\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 20829b9b9ba..adc1071c93f 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-03-04 06:15+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:40+0000\n" +"X-Generator: Launchpad (build 16967)\n" "Language: \n" #. module: base diff --git a/openerp/addons/base/i18n/es_DO.po b/openerp/addons/base/i18n/es_DO.po index 715f2b3dd7d..38db01a388e 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-03-04 06:13+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\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 acd1e756205..7254e6a5ff5 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-03-04 06:16+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:41+0000\n" +"X-Generator: Launchpad (build 16967)\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 b89ada14216..c3eb28cb10e 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-03-04 06:15+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:40+0000\n" +"X-Generator: Launchpad (build 16967)\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 b7303b7cbb6..0e551a5aa64 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-03-04 06:16+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:41+0000\n" +"X-Generator: Launchpad (build 16967)\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 a19f76163b0..4ef92878788 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-03-04 06:13+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:38+0000\n" +"X-Generator: Launchpad (build 16967)\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 7900ab0471e..c517ae44f2c 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-03-04 06:01+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:29+0000\n" +"X-Generator: Launchpad (build 16967)\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 b0631ea17c5..d16bce3efde 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-03-04 05:59+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\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 fdaface74b7..0bfe683b714 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-03-04 06:07+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:34+0000\n" +"X-Generator: Launchpad (build 16967)\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 308ab0e88a4..e1d9cdb945a 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-03-04 06:16+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:41+0000\n" +"X-Generator: Launchpad (build 16967)\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 98cfd3020ec..723867d301d 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-03-04 06:01+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:29+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/fr.po b/openerp/addons/base/i18n/fr.po index 0067da733b4..9e75eb74b87 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-03-04 06:02+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:29+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -9951,7 +9951,7 @@ msgid "" msgstr "" "\n" "Le noyau d'OpenERP, nécessaire pour toute installation.\n" -"===================================================\n" +"=======================================================\n" #. module: base #: model:ir.model,name:base.model_ir_server_object_lines diff --git a/openerp/addons/base/i18n/fr_CA.po b/openerp/addons/base/i18n/fr_CA.po index 67772af5635..4a6a61ac48f 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-03-04 06:14+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -29,7 +29,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sh msgid "Saint Helena" -msgstr "" +msgstr "Sainte Hélène" #. module: base #: view:ir.actions.report.xml:0 @@ -39,7 +39,7 @@ msgstr "" #. module: base #: selection:ir.property,type:0 msgid "DateTime" -msgstr "" +msgstr "Date et heure" #. module: base #: code:addons/fields.py:652 @@ -68,7 +68,7 @@ msgstr "" #. module: base #: selection:base.language.install,lang:0 msgid "Hungarian / Magyar" -msgstr "" +msgstr "Hongrois / Magyar" #. module: base #: selection:base.language.install,lang:0 @@ -81,6 +81,8 @@ msgid "" "Helps you manage your projects and tasks by tracking them, generating " "plannings, etc..." msgstr "" +"Vous aide à gérer vos projets et tâches, en assurant leur suivi, en générant " +"des planifications, etc." #. module: base #: model:ir.module.module,summary:base.module_point_of_sale @@ -221,7 +223,7 @@ msgstr "" #. module: base #: model:res.country,name:base.sz msgid "Swaziland" -msgstr "" +msgstr "Swaziland" #. module: base #: code:addons/orm.py:4485 @@ -352,7 +354,7 @@ msgstr "" #. module: base #: model:ir.module.category,name:base.module_category_customer_relationship_management msgid "Customer Relationship Management" -msgstr "" +msgstr "Gestion de la relation client (CRM)" #. module: base #: model:ir.module.module,description:base.module_delivery @@ -389,14 +391,14 @@ msgstr "" #. module: base #: field:res.partner,credit_limit:0 msgid "Credit Limit" -msgstr "" +msgstr "Limite de crédit" #. module: base #: field:ir.model.constraint,date_update:0 #: field:ir.model.data,date_update:0 #: field:ir.model.relation,date_update:0 msgid "Update Date" -msgstr "" +msgstr "Mettre à jour la date" #. module: base #: model:ir.module.module,shortdesc:base.module_base_action_rule @@ -407,12 +409,12 @@ msgstr "" #: view:ir.attachment:0 #: field:ir.attachment,create_uid:0 msgid "Owner" -msgstr "" +msgstr "Propriétaire" #. module: base #: view:ir.actions.act_window:0 msgid "Source Object" -msgstr "" +msgstr "Objet source" #. module: base #: model:res.partner.bank.type,format_layout:base.bank_normal @@ -434,7 +436,7 @@ msgstr "" #: field:ir.model.access,group_id:0 #: view:res.groups:0 msgid "Group" -msgstr "" +msgstr "Groupe" #. module: base #: constraint:res.lang:0 @@ -442,6 +444,9 @@ msgid "" "Invalid date/time format directive specified. Please refer to the list of " "allowed directives, displayed when you edit a language." msgstr "" +"Vous avez spécifié une directive de format date/temps non valide. Veuillez " +"vous référer à la liste des directives autorisées, qui s'affiche lorsque " +"vous modifiez une langue." #. module: base #: code:addons/orm.py:4153 @@ -555,6 +560,19 @@ msgid "" "* Use emails to automatically confirm and send acknowledgements for any " "event registration\n" msgstr "" +"\n" +"Gestion et organisation d'événements\n" +"====================================\n" +"\n" +"Le module 'Événement' vous permet d'organiser efficacement des événements et " +"toutes les tâches liées : planification, suivi des inscriptions, des " +"présences, etc.\n" +"\n" +"Fonctionnalités clés\n" +"--------------------\n" +"* Gestion des événements et des inscriptions\n" +"* Utilisation d'e-mails pour automatiquement confirmer et envoyer des " +"accusés de réception pour chaque inscription à un événement\n" #. module: base #: selection:base.language.install,lang:0 @@ -567,6 +585,8 @@ msgid "" "If you check this, then the second time the user prints with same attachment " "name, it returns the previous report." msgstr "" +"Si vous cochez ceci, alors la seconde fois que l'utilisateur imprimera avec " +"le même nom de pièce jointe, cela retournera le rapport stocké" #. module: base #: model:ir.module.module,description:base.module_mrp_byproduct @@ -597,7 +617,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_hr_timesheet_invoice msgid "Invoice on Timesheets" -msgstr "" +msgstr "Facture sur les feuilles de temps" #. module: base #: view:base.module.upgrade:0 @@ -613,12 +633,12 @@ msgstr "" #. module: base #: field:res.country,name:0 msgid "Country Name" -msgstr "" +msgstr "Nom du pays" #. module: base #: model:res.country,name:base.co msgid "Colombia" -msgstr "" +msgstr "Colombie" #. module: base #: model:res.partner.title,name:base.res_partner_title_mister @@ -640,7 +660,7 @@ msgstr "" #. module: base #: view:res.partner:0 msgid "Sales & Purchases" -msgstr "" +msgstr "Achats et ventes" #. module: base #: view:ir.translation:0 @@ -721,6 +741,33 @@ msgid "" "module named account_voucher.\n" " " msgstr "" +"\n" +"Comptabilité et gestion financière\n" +"==================================\n" +"\n" +"Le module de comptabilité et de finance couvre :\n" +"------------------------------------------------\n" +" * Comptabilité générale\n" +" * Comptabilité de coût / comptabilité analytique\n" +" * Comptabilité de tiers\n" +" * Gestion des taxes\n" +" * Budgets\n" +" * Factures clients et fournisseurs\n" +" * Relevés bancaires\n" +" * Réconciliations par partenaire\n" +"\n" +"Il créé également un tableau de bord pour les comptables qui inclut :\n" +"---------------------------------------------------------------------\n" +" * Une liste des factures clients à approuver\n" +" * L'analyse de la société\n" +" * Un graphe de la trésorerie\n" +"\n" +"Les processus tels que le maintien de la comptabilité générale se fait par " +"le biais des revues financières définies (les lignes d'écriture à regrouper " +"le sont à travers un journal)\n" +"pour un exercice donné et pour la préparation des reçus il ya un module " +"nommé account_voucher.\n" +" " #. module: base #: view:ir.model:0 @@ -763,7 +810,7 @@ msgstr "" #. module: base #: model:res.country,name:base.jo msgid "Jordan" -msgstr "" +msgstr "Jordanie" #. module: base #: model:ir.module.module,shortdesc:base.module_l10n_hr @@ -788,7 +835,7 @@ msgstr "" #. module: base #: sql_constraint:res.company:0 msgid "The company name must be unique !" -msgstr "" +msgstr "Le nom de la société doit être unique !" #. module: base #: model:ir.ui.menu,name:base.menu_base_action_rule_admin @@ -820,6 +867,10 @@ msgid "" "invoice, then `object.invoice_address_id.mobile` is the field which gives " "the correct mobile number" msgstr "" +"Fournit les champs qui seront utilisés pour récupérer le numéro du " +"cellulaire. Exemple: vous sélectionnez une facture, alors, " +"`object.invoice_address_id.mobile` est le champ qui représente le numéro du " +"cellulaire correct." #. module: base #: view:ir.mail_server:0 @@ -840,7 +891,7 @@ msgstr "" #: field:base.language.export,name:0 #: field:ir.attachment,datas_fname:0 msgid "File Name" -msgstr "" +msgstr "Nom du fichier" #. module: base #: model:res.country,name:base.rs @@ -891,6 +942,33 @@ msgid "" "also possible in order to automatically create a meeting when a holiday " "request is accepted by setting up a type of meeting in Leave Type.\n" msgstr "" +"\n" +"Gère les absences et les demandes de congés\n" +"===========================================\n" +"\n" +"Cette application contrôle la programmation des congés de votre société. Il " +"permet aux employés de faire des demandes de congés. Ensuite, les managers " +"peuvent examiner les demandes et les approuver ou les rejeter. De cette " +"façon, vous pouvez contrôler la planification de l'ensemble des congés de " +"votre entreprise ou de votre département.\n" +"\n" +"Vous pouvez configurer plusieurs sortes d'absences (maladie, congés payés, " +"congés sans soldes…) et allouer rapidement ces absences à un employé ou un " +"département en utilisant les demandes de congés. Un employé peut aussi faire " +"une demande de congés pour plus de jours en ajoutant une allocation. Cela va " +"augmenter le total des jours disponibles pour ce type de congés (si la " +"demande est acceptée).\n" +"\n" +"Vous pouvez suivre les absences de différentes façons grâce aux rapports " +"suivants : \n" +"\n" +"* Résumé des absences\n" +"* Absences par département\n" +"* Analyse des absences\n" +"\n" +"Une synchronisation avec les agendas internes (Réunions du module CRM) est " +"aussi possible dans le but de créer automatiquement une réunion quand une " +"demande de congés est accepté en ajoutant une type de réunion Absence.\n" #. module: base #: selection:base.language.install,lang:0 @@ -900,7 +978,7 @@ msgstr "" #. module: base #: model:ir.ui.menu,name:base.menu_crm_config_opportunity msgid "Opportunities" -msgstr "" +msgstr "Opportunités" #. module: base #: model:ir.model,name:base.model_base_language_export @@ -910,7 +988,7 @@ msgstr "" #. module: base #: model:res.country,name:base.pg msgid "Papua New Guinea" -msgstr "" +msgstr "Papouasie-Nouvelle-Guinée" #. module: base #: help:ir.actions.report.xml,report_type:0 @@ -941,7 +1019,7 @@ msgstr "" #. module: base #: model:res.country,name:base.zw msgid "Zimbabwe" -msgstr "" +msgstr "Zimbabwe" #. module: base #: help:ir.model.constraint,type:0 @@ -957,7 +1035,7 @@ msgstr "" #. module: base #: model:res.country,name:base.es msgid "Spain" -msgstr "" +msgstr "Espagne" #. module: base #: help:ir.actions.act_window,domain:0 @@ -978,17 +1056,17 @@ msgstr "" #. module: base #: field:res.partner,mobile:0 msgid "Mobile" -msgstr "" +msgstr "Cellulaire" #. module: base #: model:res.country,name:base.om msgid "Oman" -msgstr "" +msgstr "Oman" #. module: base #: model:ir.module.module,shortdesc:base.module_mrp msgid "MRP" -msgstr "" +msgstr "MRP - PBM" #. module: base #: model:ir.module.module,description:base.module_hr_attendance @@ -1026,12 +1104,12 @@ msgstr "" #: model:ir.actions.act_window,name:base.act_menu_create #: view:wizard.ir.model.menu.create:0 msgid "Create Menu" -msgstr "" +msgstr "Créer un menu" #. module: base #: model:res.country,name:base.in msgid "India" -msgstr "" +msgstr "Inde" #. module: base #: model:ir.actions.act_window,name:base.res_request_link-act @@ -1047,7 +1125,7 @@ msgstr "" #. module: base #: model:ir.module.module,shortdesc:base.module_fleet msgid "Fleet Management" -msgstr "" +msgstr "Gestion de flotte" #. module: base #: help:ir.server.object.lines,value:0 @@ -1107,6 +1185,36 @@ msgid "" "* Planned Revenue by Stage and User (graph)\n" "* Opportunities by Stage (graph)\n" msgstr "" +"\n" +"Le module OpenERP de gestion de la relation client (CRM)\n" +"=============================================\n" +"\n" +"Cette application permet aux utilisateurs de gérer efficacement et " +"intelligemment leurs pistes, opportunités, réunions et appels " +"téléphoniques.\n" +"\n" +"Elle gère les tâches clés comme la communication, l'identification, les " +"assignations, les résolutions et les notifications.\n" +"\n" +"OpenERP assure que toutes les demandes sont suivis par les utilisateurs, les " +"clients et les fournisseurs. Il permet d'envoyer automatiquement des " +"rappels, d'escalader des requêtes, de lancer des actions spécifiques et de " +"nombreuses autres selon les règles de l'entreprise.\n" +"\n" +"Le grand avantage de ce système est que les utilisateurs n'ont rien à faire " +"de spécial. Le module CRM dispose d'une passerelle de courriel permettant de " +"synchroniser les courriels reçus et OpenERP. De cette façon, les " +"utilisateurs peuvent simplement envoyer des courriels au système de suivi " +"des demandes.\n" +"\n" +"OpenERP s'occupera de remercier les utilisateurs de leur message, de diriger " +"cette demande à l'équipe appropriée et de s'assurer que toute les " +"communications futures seront rangées à la bonne place.\n" +"\n" +"\n" +"Le tableau bord de cette application inclus:\n" +"* les revenus prévus par étape de vente et par utilisateur (graphique);\n" +"* les opportunités par étape de vente (graphique).\n" #. module: base #: selection:base.language.export,format:0 @@ -1241,17 +1349,17 @@ msgstr "" #: selection:ir.actions.server,state:0 #: selection:workflow.activity,kind:0 msgid "Dummy" -msgstr "" +msgstr "Factice" #. module: base #: constraint:ir.ui.view:0 msgid "Invalid XML for View Architecture!" -msgstr "" +msgstr "XML invalide pour l'architecture de la vue" #. module: base #: model:res.country,name:base.ky msgid "Cayman Islands" -msgstr "" +msgstr "Îles Caïmans" #. module: base #: view:ir.rule:0 @@ -1287,7 +1395,7 @@ msgstr "" #. module: base #: selection:ir.property,type:0 msgid "Char" -msgstr "" +msgstr "Caractère" #. module: base #: field:ir.module.category,visible:0 @@ -1365,6 +1473,9 @@ msgid "" "decimal number [00,53]. All days in a new year preceding the first Monday " "are considered to be in week 0." msgstr "" +"%W - Numéro de semaine dans l'année (lundi est le premier jour de la " +"semaine) en nombre décimal [00,53]. Tous les jours de la nouvelle année " +"précédant le premier lundi sont considérés faisant partie de la semaine 0." #. module: base #: code:addons/base/module/wizard/base_language_install.py:53 @@ -1390,13 +1501,13 @@ msgstr "" #. module: base #: field:ir.actions.act_url,url:0 msgid "Action URL" -msgstr "" +msgstr "URL de l'action" #. module: base #: field:base.module.import,module_name:0 #: field:ir.module.module,shortdesc:0 msgid "Module Name" -msgstr "" +msgstr "Nom du module" #. module: base #: model:res.country,name:base.mh @@ -1423,7 +1534,7 @@ msgstr "" #: view:ir.ui.view:0 #: selection:ir.ui.view,type:0 msgid "Search" -msgstr "" +msgstr "Recherche" #. module: base #: code:addons/osv.py:154 @@ -1451,12 +1562,12 @@ msgstr "" #: code:addons/base/res/res_users.py:131 #, python-format msgid "Operation Canceled" -msgstr "" +msgstr "Opération annulée" #. module: base #: model:ir.module.module,shortdesc:base.module_document msgid "Document Management System" -msgstr "" +msgstr "Système de gestion des documents" #. module: base #: model:ir.module.module,shortdesc:base.module_crm_claim @@ -1499,7 +1610,7 @@ msgstr "" #: model:ir.module.category,name:base.module_category_purchase_management #: model:ir.ui.menu,name:base.menu_purchase_root msgid "Purchases" -msgstr "" +msgstr "Achats" #. module: base #: model:res.country,name:base.md @@ -1524,12 +1635,12 @@ msgstr "" #. module: base #: view:ir.module.module:0 msgid "Features" -msgstr "" +msgstr "Fonctionnalités" #. module: base #: view:ir.attachment:0 msgid "Data" -msgstr "" +msgstr "Données" #. module: base #: model:ir.module.module,description:base.module_portal_claim @@ -1597,7 +1708,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 "Réseau social" #. module: base #: view:res.lang:0 @@ -12871,7 +12982,7 @@ msgstr "" #. module: base #: model:res.country,name:base.ao msgid "Angola" -msgstr "" +msgstr "Angola" #. module: base #: model:res.country,name:base.tf diff --git a/openerp/addons/base/i18n/gl.po b/openerp/addons/base/i18n/gl.po index b1a78185e33..48abd8027ae 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-03-04 06:03+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:30+0000\n" +"X-Generator: Launchpad (build 16967)\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 33bba236795..7022005574f 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-03-04 06:03+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:30+0000\n" +"X-Generator: Launchpad (build 16967)\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 242b49c86d7..86276f6bc25 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-03-04 06:03+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:31+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/hi.po b/openerp/addons/base/i18n/hi.po index 1b8a36beada..96d55ee9b36 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-03-04 06:04+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:31+0000\n" +"X-Generator: Launchpad (build 16967)\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 7e0b440a29d..62ce7012da7 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-03-04 06:09+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:35+0000\n" +"X-Generator: Launchpad (build 16967)\n" "Language: hr\n" #. module: base diff --git a/openerp/addons/base/i18n/hu.po b/openerp/addons/base/i18n/hu.po index a9b8c05473a..043900400b4 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-03-04 06:04+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:31+0000\n" +"X-Generator: Launchpad (build 16967)\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 19df5b5a136..b168e30f2d6 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\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 63fe93c7cd4..8f0474dbcb3 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-03-04 06:05+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:31+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -211,6 +211,15 @@ msgid "" "revenue\n" "reports." msgstr "" +"\n" +"Bentuk tagihan anda dari entri Expenses, Timesheet.\n" +"========================================================\n" +"\n" +"Modul untuk menerbitkan tagihan berbasis biaya (sdm, biaya, dsb).\n" +"\n" +"Anda dapat mendefinisikan daftar harga pada akun analitik, membuat laporan " +"anggaran \n" +"penghasilan." #. module: base #: code:addons/base/ir/ir_sequence.py:134 @@ -299,6 +308,12 @@ msgid "" "\n" " " msgstr "" +"\n" +"Lokalisasi skema akunting dan pajak Chili.\n" +"==============================================\n" +"Plan contable chileno e impuestos de acuerdo a disposiciones vigentes\n" +"\n" +" " #. module: base #: model:ir.module.module,shortdesc:base.module_sale @@ -398,6 +413,15 @@ msgid "" "invoices from picking, OpenERP is able to add and compute the shipping " "line.\n" msgstr "" +"\n" +"Mengizinkan anda untuk menambahkan metode deliveri pada order penjualan dan " +"pengambilan.\n" +"==============================================================\n" +"\n" +"Anda dapat menentukan carrier sendiri dan metode antar untuk harga tersebut. " +"Saat membuat\n" +"tagihan dari pengantaran, OpenERP dapat menambah dan menghitung biaya " +"pengiriman.\n" #. module: base #: code:addons/base/ir/ir_filters.py:80 diff --git a/openerp/addons/base/i18n/is.po b/openerp/addons/base/i18n/is.po index 111dd7f87e5..3752f2c679f 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-03-04 06:04+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:31+0000\n" +"X-Generator: Launchpad (build 16967)\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 ab827533fa3..f7a1bfdb4b0 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-03-04 06:05+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:32+0000\n" +"X-Generator: Launchpad (build 16967)\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 72eae935dcb..63d0e0638f3 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-03-04 06:05+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:32+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -411,7 +411,7 @@ msgstr "与信限度" #: field:ir.model.data,date_update:0 #: field:ir.model.relation,date_update:0 msgid "Update Date" -msgstr "日付の更新" +msgstr "更新日" #. module: base #: model:ir.module.module,shortdesc:base.module_base_action_rule @@ -4582,7 +4582,7 @@ msgstr "スペイン語(ホンジュラス)/ Español (HN)" #. module: base #: view:ir.sequence.type:0 msgid "Sequence Type" -msgstr "順序タイプ" +msgstr "付番タイプ" #. module: base #: view:base.language.export:0 @@ -5141,7 +5141,7 @@ msgstr "銀行口座タイプ" #. module: base #: help:ir.sequence,suffix:0 msgid "Suffix value of the record for the sequence" -msgstr "順序のためのレコードのサフィックス値" +msgstr "この付番定義でレコードに適用するサフィックス値" #. module: base #: help:ir.mail_server,smtp_user:0 @@ -6140,7 +6140,7 @@ msgstr "ショートカット" #. module: base #: field:ir.model.data,date_init:0 msgid "Init Date" -msgstr "整数データ" +msgstr "作成日" #. module: base #: selection:base.language.install,lang:0 @@ -7630,7 +7630,7 @@ msgstr "" #. module: base #: help:ir.sequence,number_next:0 msgid "Next number of this sequence" -msgstr "この順序の次の番号" +msgstr "この付番定義の次の番号" #. module: base #: view:res.partner:0 @@ -10135,7 +10135,7 @@ msgstr "発注分析計画" #: model:ir.actions.act_window,name:base.ir_sequence_type #: model:ir.ui.menu,name:base.menu_ir_sequence_type msgid "Sequence Codes" -msgstr "順序コード" +msgstr "付番コード" #. module: base #: selection:base.language.install,lang:0 @@ -10790,7 +10790,7 @@ msgstr "国の状態" #. module: base #: model:ir.ui.menu,name:base.next_id_5 msgid "Sequences & Identifiers" -msgstr "順序と識別子" +msgstr "付番定義とID" #. module: base #: model:ir.module.module,description:base.module_l10n_th @@ -10925,7 +10925,7 @@ msgstr "連絡先が会社の場合はチェックしてください。チェッ #. module: base #: view:ir.sequence.type:0 msgid "Sequences Type" -msgstr "順序タイプ" +msgstr "付番タイプ" #. module: base #: view:res.partner:0 @@ -11282,7 +11282,7 @@ msgstr "" #: view:ir.sequence:0 #: model:ir.ui.menu,name:base.menu_ir_sequence_form msgid "Sequences" -msgstr "順序" +msgstr "付番" #. module: base #: help:res.lang,code:0 @@ -11724,7 +11724,7 @@ msgstr "月:%(month)s" #: field:multi_company.default,sequence:0 #: field:res.partner.bank,sequence:0 msgid "Sequence" -msgstr "順序" +msgstr "付番" #. module: base #: model:res.country,name:base.tn @@ -12190,7 +12190,7 @@ msgstr "ハード島とマクドナルド諸島" msgid "" "External Key/Identifier that can be used for data integration with third-" "party systems" -msgstr "サードパーティのシステムとのデータ統合のために利用する外部キー / 識別子" +msgstr "サードパーティシステムとのデータ統合のために利用する外部キー / ID" #. module: base #: field:ir.actions.act_window,view_id:0 @@ -12519,7 +12519,7 @@ msgstr "CRMポータル" #. module: base #: model:ir.ui.menu,name:base.next_id_4 msgid "Low Level Objects" -msgstr "低レベルのオブジェクト" +msgstr "低レベルオブジェクト" #. module: base #: help:ir.values,model:0 @@ -12596,7 +12596,7 @@ msgstr "" #: view:ir.model.data:0 #: model:ir.ui.menu,name:base.ir_model_data_menu msgid "External Identifiers" -msgstr "外部識別子" +msgstr "外部ID" #. module: base #: selection:base.language.install,lang:0 @@ -13614,7 +13614,7 @@ msgstr "" #: view:ir.model.data:0 #: field:ir.model.data,name:0 msgid "External Identifier" -msgstr "外部識別子" +msgstr "外部ID" #. module: base #: model:ir.module.module,description:base.module_audittrail @@ -14048,9 +14048,7 @@ msgid "" "Two sequence object implementations are offered: Standard and 'No gap'. The " "later is slower than the former but forbids any gap in the sequence (while " "they are possible in the former)." -msgstr "" -"2つのシーケンスオブジェクトの実装が提供されます:標準と\"ギャップなし\"です。後者は前者よりも遅いですが、どんな順序のギャップを禁じます(前者は可能で" -"す)。" +msgstr "「標準」と「ギャップなし」の2種類の付番定義が可能です。後者の場合、付番ごとにギャップを設けることができません。" #. module: base #: model:res.country,name:base.gn @@ -14249,7 +14247,7 @@ msgstr "かつ" #: help:ir.values,res_id:0 msgid "" "Database identifier of the record to which this applies. 0 = for all records" -msgstr "これを適用するためのレコードのデータベース識別子。0 = 全てのレコードのため" +msgstr "" #. module: base #: field:ir.model.fields,relation:0 @@ -14903,7 +14901,7 @@ msgstr "クック諸島" #. module: base #: field:ir.model.data,noupdate:0 msgid "Non Updatable" -msgstr "更新可能でない" +msgstr "更新不可" #. module: base #: selection:base.language.install,lang:0 @@ -15311,7 +15309,7 @@ msgstr "" #. module: base #: help:ir.sequence,prefix:0 msgid "Prefix value of the record for the sequence" -msgstr "順序のためのレコードのプレフィックス値" +msgstr "この付番定義でレコードに適用するプレフィックス値" #. module: base #: model:res.country,name:base.sc @@ -15353,7 +15351,7 @@ msgstr "" #. module: base #: field:ir.model.data,complete_name:0 msgid "Complete ID" -msgstr "完了ID" +msgstr "完全ID" #. module: base #: model:ir.module.module,description:base.module_stock @@ -15447,7 +15445,7 @@ msgstr "製造プロセスを管理し、それらのプロセスのレポート #. module: base #: help:ir.sequence,number_increment:0 msgid "The next number of the sequence will be incremented by this number" -msgstr "順序の次の番号はこの数値だけ増加します。" +msgstr "付番毎にこの数値分だけ番号が増加します。" #. module: base #: selection:workflow.activity,kind:0 diff --git a/openerp/addons/base/i18n/ka.po b/openerp/addons/base/i18n/ka.po index 5049f475f6d..e227a1eeb17 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-03-04 06:02+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:29+0000\n" +"X-Generator: Launchpad (build 16967)\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 56144fd0745..559d5404844 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-03-04 06:05+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:32+0000\n" +"X-Generator: Launchpad (build 16967)\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 3bda6b5d13a..144f0c87918 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-03-04 06:06+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:33+0000\n" +"X-Generator: Launchpad (build 16967)\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 e362c97bf07..4ee73e3cb1c 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-03-04 06:06+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:33+0000\n" +"X-Generator: Launchpad (build 16967)\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 7c00e4a6466..c607e7da1ee 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-03-04 06:06+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:33+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/mk.po b/openerp/addons/base/i18n/mk.po index 59b8e0cec98..7c4972a5415 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-03-04 06:07+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:33+0000\n" +"X-Generator: Launchpad (build 16967)\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 db754c219dd..cee07a00d7d 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-03-04 06:07+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:34+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/nb.po b/openerp/addons/base/i18n/nb.po index e06ad54485e..1bdb6a4586b 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-03-04 06:07+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:34+0000\n" +"X-Generator: Launchpad (build 16967)\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 b606faeffad..1d54d67f386 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-03-04 06:00+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:28+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -13429,7 +13429,7 @@ msgstr "" #. module: base #: selection:res.currency,position:0 msgid "Before Amount" -msgstr "Voormalig bedrag" +msgstr "Voor bedrag" #. module: base #: field:res.request,act_from:0 diff --git a/openerp/addons/base/i18n/nl_BE.po b/openerp/addons/base/i18n/nl_BE.po index 7e7f119b9db..947ba509118 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-03-04 06:14+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:39+0000\n" +"X-Generator: Launchpad (build 16967)\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 5e86abf9fa6..8f0f6678410 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-03-04 06:08+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:34+0000\n" +"X-Generator: Launchpad (build 16967)\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 6be215090c5..d6556d54c4e 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-03-04 06:08+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:34+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing @@ -5633,7 +5633,7 @@ msgstr "Falta o valor do campo '%s'." #. module: base #: view:ir.rule:0 msgid "Write Access Right" -msgstr "" +msgstr "Permissões de Escrita" #. module: base #: model:ir.actions.act_window,help:base.action_res_groups diff --git a/openerp/addons/base/i18n/pt_BR.po b/openerp/addons/base/i18n/pt_BR.po index 2162fc2c0a2..77821aaaefa 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-03-04 06:12+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:38+0000\n" +"X-Generator: Launchpad (build 16967)\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 180a8a62e14..2cca4a60e14 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-03-04 06:08+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:35+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/ru.po b/openerp/addons/base/i18n/ru.po index dcbe8b5720a..2146841182c 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-03-04 06:09+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:35+0000\n" +"X-Generator: Launchpad (build 16967)\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 8ec906cc533..ee5c82b00fd 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-03-04 06:09+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:36+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/sl.po b/openerp/addons/base/i18n/sl.po index 397a8f49a89..55c241f3462 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-03-04 06:10+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:36+0000\n" +"X-Generator: Launchpad (build 16967)\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 301ea83076d..8814da0bc60 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-03-04 05:58+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:27+0000\n" +"X-Generator: Launchpad (build 16967)\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 c489716cfb9..014ca56f8fb 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-03-04 06:09+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:35+0000\n" +"X-Generator: Launchpad (build 16967)\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 e5d812f4805..86a4bacf873 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-03-04 06:16+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:41+0000\n" +"X-Generator: Launchpad (build 16967)\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 5982af2691f..bb452c8ce35 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-03-04 06:10+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:36+0000\n" +"X-Generator: Launchpad (build 16967)\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 f9f8ca739ca..2b1b772b964 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-03-04 06:11+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\n" #. module: base #: model:ir.module.module,description:base.module_account_check_writing diff --git a/openerp/addons/base/i18n/tlh.po b/openerp/addons/base/i18n/tlh.po index d2f6d3bf758..8d8ffb04643 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-03-04 06:11+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\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 2a24b4abc2e..6021dafeb01 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-03-04 06:11+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\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 cdd9ab74f32..12baea4370c 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-03-04 06:11+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\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 617dddd1f43..a616ae2d434 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-03-04 06:12+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\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 8d0606f4987..5f82fc7f1a0 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-03-04 06:12+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:37+0000\n" +"X-Generator: Launchpad (build 16967)\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 f8175c7974c..a192a6a169e 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-03-04 06:15+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:40+0000\n" +"X-Generator: Launchpad (build 16967)\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 05261c1e0bc..f3bc1c1923e 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-03-04 06:12+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:38+0000\n" +"X-Generator: Launchpad (build 16967)\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 a57c92f2c2b..c57c69227a2 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-03-04 06:14+0000\n" -"X-Generator: Launchpad (build 16948)\n" +"X-Launchpad-Export-Date: 2014-03-28 05:40+0000\n" +"X-Generator: Launchpad (build 16967)\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 b3df5bcbccb..9aa1e7c42a2 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -39,6 +39,7 @@ import ir_mail_server import ir_fields import ir_qweb import ir_http +import ir_logging # 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 7b0681fd661..4cd0492d95c 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -141,12 +141,12 @@ class ir_actions_report_xml(osv.osv): 'model': fields.char('Model', required=True), 'report_type': fields.selection([('qweb-pdf', 'PDF'), ('qweb-html', 'HTML'), - ('other', 'Other'), + ('controller', 'Controller'), ('pdf', 'RML pdf (deprecated)'), ('sxw', 'RML sxw (deprecated)'), ('webkit', 'Webkit (deprecated)'), - ], 'Report Type', required=True, help="PDF will use wkhtmltopdf to render html to pdf, HTML will directly show html, Other will force download the controller output keeping the MIME type."), - 'report_name': fields.char('Controller Name', required=True, help="URL of the report will be /report//, the default controller also use this field to get the name of the qweb ir.ui.view to render. For RML reports, this is the LocalService name."), + ], 'Report Type', required=True, help="HTML will open the report directly in your browser, PDF will use wkhtmltopdf to render the HTML into a PDF file and let you download it, Controller allows you to define the url of a custom controller outputting any kind of report."), + 'report_name': fields.char('Template Name', required=True, help="For QWeb reports, name of the template used in the rendering. The method 'render_html' of the model 'report.template_name' will be called (if any) to give the html. For RML reports, this is the LocalService name."), 'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups'), # options @@ -163,7 +163,7 @@ class ir_actions_report_xml(osv.osv): 'report_xsl': fields.char('XSL Path'), 'report_xml': fields.char('XML Path'), - 'report_rml': fields.char('Main Report File Path', help="The path to the main report file (depending on Report Type) or NULL if the content is in another data field"), + 'report_rml': fields.char('Main Report File Path/controller', help="The path to the main report file/controller (depending on Report Type) or NULL if the content is in another data field"), 'report_file': fields.related('report_rml', type="char", required=False, readonly=False, string='Report File', help="The path to the main report file (depending on Report Type) or NULL if the content is in another field", store=True), 'report_sxw': fields.function(_report_sxw, type='char', string='SXW Path'), diff --git a/openerp/addons/base/ir/ir_actions.xml b/openerp/addons/base/ir/ir_actions.xml index 77d7eb23e8c..4eb869daa80 100644 --- a/openerp/addons/base/ir/ir_actions.xml +++ b/openerp/addons/base/ir/ir_actions.xml @@ -59,12 +59,13 @@ - + + - - + + diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index 992ac1b5ff0..186c02f00b8 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -69,7 +69,7 @@ class ir_attachment(osv.osv): @tools.ormcache() def _filestore(self, cr, uid, context=None): - return os.path.join(tools.config['data_dir'], 'filestore', cr.dbname) + return tools.config.filestore(cr.dbname) # 'data' field implementation def _full_path(self, cr, uid, location, path): diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py index ae04dcf5853..62ecd605223 100644 --- a/openerp/addons/base/ir/ir_http.py +++ b/openerp/addons/base/ir/ir_http.py @@ -77,7 +77,9 @@ class ir_http(osv.AbstractModel): # what if error in security.check() # -> res_users.check() # -> res_users.check_credentials() - except Exception: + except (openerp.exceptions.AccessDenied, openerp.http.SessionExpiredException): + # All other exceptions mean undetermined status (e.g. connection pool full), + # let them bubble up request.session.logout() getattr(self, "_auth_method_%s" % auth_method)() return auth_method diff --git a/openerp/addons/base/ir/ir_logging.py b/openerp/addons/base/ir/ir_logging.py new file mode 100644 index 00000000000..dd06a19c0ae --- /dev/null +++ b/openerp/addons/base/ir/ir_logging.py @@ -0,0 +1,46 @@ +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2014 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +import logging + +from openerp.osv import osv, fields +from openerp.tools.translate import _ + +class ir_logging(osv.Model): + _name = 'ir.logging' + _order = 'id DESC' + + EXCEPTIONS_TYPE = [ + ('client', 'Client'), + ('server', 'Server') + ] + + _columns = { + 'create_date': fields.datetime('Create Date', readonly=True), + 'create_uid': fields.integer('Uid', readonly=True), # Integer not m2o is intentionnal + 'name': fields.char('Name', required=True), + 'type': fields.selection(EXCEPTIONS_TYPE, string='Type', required=True, select=True), + 'dbname': fields.char('Database Name'), + 'level': fields.char('Level'), + 'message': fields.text('Message', required=True), + 'path': fields.char('Path', required=True), + 'func': fields.char('Function', required=True), + 'line': fields.char('Line', required=True), + } + diff --git a/openerp/addons/base/ir/ir_logging_view.xml b/openerp/addons/base/ir/ir_logging_view.xml new file mode 100644 index 00000000000..f963fc0d393 --- /dev/null +++ b/openerp/addons/base/ir/ir_logging_view.xml @@ -0,0 +1,66 @@ + + + + + ir.logging + +
+ + + + + + + + + + + +
+
+
+ + ir.logging + + + + + + + + + + + + + + + + ir.logging + + + + + + + + + + + + + + + + + + + Logging + ir.logging + form + tree,form + + + +
+
diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index d119c0344b4..76166ee92e0 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -33,7 +33,7 @@ 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 _ -from openerp.osv.orm import except_orm, browse_record +from openerp.osv.orm import except_orm, browse_record, MAGIC_COLUMNS _logger = logging.getLogger(__name__) @@ -302,6 +302,8 @@ class ir_model_fields(osv.osv): def _drop_column(self, cr, uid, ids, context=None): for field in self.browse(cr, uid, ids, context): + if field.name in MAGIC_COLUMNS: + continue model = self.pool[field.model] cr.execute('select relkind from pg_class where relname=%s', (model._table,)) result = cr.fetchone() @@ -1117,6 +1119,10 @@ class ir_model_data(osv.osv): # Don't remove the LOG_ACCESS_COLUMNS unless _log_access # has been turned off on the model. field = self.pool[model].browse(cr, uid, [res_id], context=context)[0] + if not field.exists(): + _logger.info('Deleting orphan external_ids %s', external_ids) + self.unlink(cr, uid, external_ids) + continue if field.name in openerp.osv.orm.LOG_ACCESS_COLUMNS and self.pool[field.model]._log_access: continue if field.name == 'id': diff --git a/openerp/addons/base/ir/ir_qweb.py b/openerp/addons/base/ir/ir_qweb.py index 590ce90188f..f19a1fa6746 100644 --- a/openerp/addons/base/ir/ir_qweb.py +++ b/openerp/addons/base/ir/ir_qweb.py @@ -32,7 +32,7 @@ class QWebException(Exception): class QWebTemplateNotFound(QWebException): pass -def convert_to_qweb_exception(etype=None, **kw): +def raise_qweb_exception(etype=None, **kw): if etype is None: etype = QWebException orig_type, original, tb = sys.exc_info() @@ -43,7 +43,7 @@ def convert_to_qweb_exception(etype=None, **kw): e.qweb[k] = v # Will use `raise foo from bar` in python 3 and rename cause to __cause__ e.qweb['cause'] = original - return e + raise class QWebContext(dict): def __init__(self, cr, uid, data, loader=None, templates=None, context=None): @@ -166,7 +166,7 @@ class QWeb(orm.AbstractModel): 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) + raise_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: @@ -179,7 +179,7 @@ class QWeb(orm.AbstractModel): 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) + raise_qweb_exception(message="Could not evaluate expression %r" % expr, expression=expr, template=template) def eval_object(self, expr, qwebcontext): return self.eval(expr, qwebcontext) @@ -207,7 +207,7 @@ class QWeb(orm.AbstractModel): 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) + raise_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))) @@ -292,7 +292,7 @@ class QWeb(orm.AbstractModel): raise except Exception: template = qwebcontext.get('__template__') - raise convert_to_qweb_exception(message="Could not render element %r" % element.nodeName, node=element, template=template) + raise_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) @@ -488,7 +488,6 @@ class FieldConverter(osv.AbstractModel): 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, @@ -503,12 +502,14 @@ class FieldConverter(osv.AbstractModel): 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) - ) + if context and context.get('inherit_branding'): + # add branding attributes + 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) @@ -611,6 +612,9 @@ class DateTimeConverter(osv.AbstractModel): strftime_pattern = (u"%s %s" % (lang.date_format, lang.time_format)) pattern = openerp.tools.posix_to_ldml(strftime_pattern, locale=locale) + if options and options.get('hide_seconds'): + pattern = pattern.replace(":ss", "").replace(":s", "") + return babel.dates.format_datetime(value, format=pattern, locale=locale) class TextConverter(osv.AbstractModel): @@ -804,6 +808,38 @@ class RelativeDatetimeConverter(osv.AbstractModel): return babel.dates.format_timedelta( value - reference, add_direction=True, locale=locale) + +class Contact(orm.AbstractModel): + _name = 'ir.qweb.field.contact' + _inherit = 'ir.qweb.field.many2one' + + def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None): + opf = options.get('fields') or ["name", "address", "phone", "mobile", "fax", "email"] + + if not getattr(record, field_name): + return None + + id = getattr(record, field_name).id + field_browse = self.pool[column._obj].browse(cr, openerp.SUPERUSER_ID, id, context={"show_address": True}) + value = werkzeug.utils.escape( field_browse.name_get()[0][1] ) + + val = { + 'name': value.split("\n")[0], + 'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])), + 'phone': field_browse.phone, + 'mobile': field_browse.mobile, + 'fax': field_browse.fax, + 'city': field_browse.city, + 'country_id': field_browse.country_id and field_browse.country_id.name_get()[0][1], + 'email': field_browse.email, + 'fields': opf, + 'options': options + } + + html = self.pool["ir.ui.view"].render(cr, uid, "base.contact", val, engine='ir.qweb', context=context).decode('utf8') + + return HTMLSafe(html) + 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 diff --git a/openerp/addons/base/ir/ir_qweb.xml b/openerp/addons/base/ir/ir_qweb.xml new file mode 100644 index 00000000000..25bb4ef8ef9 --- /dev/null +++ b/openerp/addons/base/ir/ir_qweb.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index d4655bf8b9c..360c5e37b31 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -728,9 +728,26 @@ class view(osv.osv): def clear_cache(self): self.read_template.clear_cache(self) + def _contains_branded(self, node): + return node.tag == 't'\ + or 't-raw' in node.attrib\ + or any(self.is_node_branded(child) for child in node.iterdescendants()) + + def _pop_view_branding(self, element): + distributed_branding = dict( + (attribute, element.attrib.pop(attribute)) + for attribute in MOVABLE_BRANDING + if element.get(attribute)) + return distributed_branding + def distribute_branding(self, e, branding=None, parent_xpath='', index_map=misc.ConstantMapping(1)): if e.get('t-ignore') or e.tag == 'head': + # remove any view branding possibly injected by inheritance + attrs = set(MOVABLE_BRANDING) + for descendant in e.iterdescendants(tag=etree.Element): + if not attrs.intersection(descendant.attrib): continue + self._pop_view_branding(descendant) # TODO: find a better name and check if we have a string to boolean helper return @@ -742,15 +759,15 @@ class view(osv.osv): 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 set(('t-esc', 't-escf', 't-raw', 't-rawf')).intersection(e.attrib): + # nodes which fully generate their content and have no reason to + # be branded because they can not sensibly be edited + self._pop_view_branding(e) + elif self._contains_branded(e): + # if a branded element contains branded elements distribute own + # branding to children unless it's t-raw, then just remove branding + # on current element + distributed_branding = self._pop_view_branding(e) if 't-raw' not in e.attrib: # TODO: collections.Counter if remove p2.6 compat @@ -760,11 +777,12 @@ class view(osv.osv): 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) + self.distribute_branding(child) + else: + 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 diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index ae83aa4f2d1..64ab5676ca2 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -208,20 +208,19 @@ class res_company(osv.osv): res['value'] = {'currency_id': currency_id} return res - def _search(self, cr, uid, args, offset=0, limit=None, order=None, - context=None, count=False, access_rights_uid=None): + def name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100): if context is None: context = {} - if context.get('user_preference'): + if context.pop('user_preference', None): # We browse as superuser. Otherwise, the user would be able to # select only the currently visible companies (according to rules, # which are probably to allow to see the child companies) even if # she belongs to some other companies. user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids])) - return cmp_ids - return super(res_company, self)._search(cr, uid, args, offset=offset, limit=limit, order=order, - context=context, count=count, access_rights_uid=access_rights_uid) + uid = SUPERUSER_ID + args = (args or []) + [('id', 'in', cmp_ids)] + return super(res_company, self).name_search(cr, uid, name=name, args=args, operator=operator, context=context, limit=limit) def _company_default_get(self, cr, uid, object=False, field=False, context=None): """ diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 4fe6ff1989e..5bbd377f29d 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -493,6 +493,10 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): return res def execute(self, cr, uid, ids, context=None): + if context is None: + context = {} + + context = dict(context, active_test=False) if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'): raise openerp.exceptions.AccessError(_("Only administrators can change the settings")) @@ -500,7 +504,7 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin): ir_module = self.pool['ir.module.module'] res_groups = self.pool['res.groups'] - classified = self._get_classified_fields(cr, uid, context) + classified = self._get_classified_fields(cr, uid, context=context) config = self.browse(cr, uid, ids[0], context) diff --git a/openerp/addons/base/res/res_country.py b/openerp/addons/base/res/res_country.py index df68d211a97..df507dcbac9 100644 --- a/openerp/addons/base/res/res_country.py +++ b/openerp/addons/base/res/res_country.py @@ -56,6 +56,7 @@ addresses belonging to this country.\n\nYou can use the python-style string pate \n%(country_name)s: the name of the country \n%(country_code)s: the code of the country"""), 'currency_id': fields.many2one('res.currency', 'Currency'), + 'image': fields.binary("Image"), } _sql_constraints = [ ('name_uniq', 'unique (name)', diff --git a/openerp/addons/base/res/res_country_data.xml b/openerp/addons/base/res/res_country_data.xml index 13c1025cf6b..eff97fb0aac 100644 --- a/openerp/addons/base/res/res_country_data.xml +++ b/openerp/addons/base/res/res_country_data.xml @@ -5,46 +5,55 @@ United Arab Emirates ae + Afghanistan, Islamic State of af + Antigua and Barbuda ag + Anguilla ai + Albania al + Armenia am + Netherlands Antilles an + Angola ao + @@ -55,103 +64,123 @@ Argentina ar + American Samoa as + Austria at + Australia au + Aruba aw + Åland Islands ax + Azerbaijan az + Bosnia-Herzegovina ba + Barbados bb + Bangladesh bd + Belgium be + Burkina Faso bf + Bulgaria bg + Bahrain bh + Burundi bi + Benin bj + Saint Barthélémy bl + Bermuda bm + Brunei Darussalam bn + Bolivia bo + @@ -162,17 +191,20 @@ Brazil br + Bahamas bs + Bhutan bt + @@ -183,158 +215,189 @@ Botswana bw + Belarus by + Belize bz + Canada ca + Cocos (Keeling) Islands cc + Central African Republic cf + Congo, Democratic Republic of the cd + Congo cg + Switzerland ch + Ivory Coast (Cote D'Ivoire) ci + Cook Islands ck + Chile cl + Cameroon cm + China cn + Colombia co + Costa Rica cr + Cuba cu + Cape Verde cv + Curaçao cw + Christmas Island cx + Cyprus cy + Czech Republic cz + Germany de + Djibouti dj + Denmark dk + Dominica dm + Dominican Republic do + Algeria dz + Ecuador ec + Estonia ee + Egypt eg + @@ -345,63 +408,75 @@ Eritrea er + Spain es + Ethiopia et + Finland fi + Fiji fj + Falkland Islands fk + Micronesia fm + Faroe Islands fo + France fr + Gabon ga + Grenada gd + Georgia ge + @@ -412,31 +487,37 @@ Ghana gh + Gibraltar gi + Guernsey gg + Greenland gl + Gambia gm + Guinea gn + @@ -447,41 +528,49 @@ Equatorial Guinea gq + Greece gr + South Georgia and the South Sandwich Islands gs + Guatemala gt + Guam (USA) gu + Guinea Bissau gw + Guyana gy + Hong Kong hk + @@ -492,222 +581,266 @@ Honduras hn + Croatia hr + Haiti ht + Hungary hu + Indonesia id + Ireland ie + Israel il + Isle of Man im + India in + British Indian Ocean Territory io + Iraq iq + Iran ir + Iceland is + Italy it + Jersey je + Jamaica jm + Jordan jo + Japan jp + Kenya ke + Kyrgyz Republic (Kyrgyzstan) kg + Cambodia, Kingdom of kh + Kiribati ki + Comoros km + Saint Kitts & Nevis Anguilla kn + North Korea kp + South Korea kr + Kuwait kw + Cayman Islands ky + Kazakhstan kz + Laos la + Lebanon lb + Saint Lucia lc + Liechtenstein li + Sri Lanka lk + Liberia lr + Lesotho ls + Lithuania lt + Luxembourg lu + Latvia lv + Libya ly + Morocco ma + Monaco mc + Moldavia md + Montenegro me + @@ -718,142 +851,170 @@ Madagascar mg + Marshall Islands mh + Macedonia, the former Yugoslav Republic of mk + Mali ml + Myanmar mm + Mongolia mn + Macau mo + Northern Mariana Islands mp + Martinique (French) mq + Mauritania mr + Montserrat ms + Malta mt + Mauritius mu + Maldives mv + Malawi mw + Mexico mx + Malaysia my + Mozambique mz + Namibia na + New Caledonia (French) nc + Niger ne + Norfolk Island nf + Nigeria ng + Nicaragua ni + Netherlands nl + Norway no + Nepal np + Nauru nr + @@ -864,66 +1025,79 @@ Niue nu + New Zealand nz + Oman om + Panama pa + Peru pe + Polynesia (French) pf + Papua New Guinea pg + Philippines ph + Pakistan pk + Poland pl + Saint Pierre and Miquelon pm + Pitcairn Island pn + Puerto Rico pr + @@ -934,21 +1108,25 @@ Portugal pt + Palau pw + Paraguay py + Qatar qa + @@ -959,61 +1137,73 @@ Romania ro + Serbia rs + Russian Federation ru + Rwanda rw + Saudi Arabia sa + Solomon Islands sb + Seychelles sc + Sudan sd + Sweden se + Singapore sg + Saint Helena sh + Slovenia si + @@ -1024,131 +1214,157 @@ Slovakia sk + Sierra Leone sl + San Marino sm + Senegal sn + Somalia so + Suriname sr + South Sudan ss + Saint Tome (Sao Tome) and Principe st + El Salvador sv + Sint Maarten (Dutch part) sx + Syria sy + Swaziland sz + Turks and Caicos Islands tc + Chad td + French Southern Territories tf + Togo tg + Thailand th + Tajikistan tj + Tokelau tk + Turkmenistan tm + Tunisia tn + Tonga to + East Timor tp + Turkey tr + Trinidad and Tobago tt + Tuvalu tv + @@ -1159,23 +1375,27 @@ Tanzania tz + Ukraine ua + Uganda ug + United Kingdom gb + @@ -1186,52 +1406,62 @@ United States us + Uruguay uy + Uzbekistan uz + Holy See (Vatican City State) va + Saint Vincent & Grenadines vc + Venezuela ve + Virgin Islands (British) vg + Virgin Islands (USA) vi + Vietnam vn + Vanuatu vu + @@ -1242,11 +1472,13 @@ Samoa ws + Yemen ye + @@ -1262,11 +1494,13 @@ South Africa za + Zambia zm + @@ -1279,6 +1513,7 @@ Zimbabwe zw + diff --git a/openerp/addons/base/res/res_country_view.xml b/openerp/addons/base/res/res_country_view.xml index 8f64d330440..e4784c3d9ca 100644 --- a/openerp/addons/base/res/res_country_view.xml +++ b/openerp/addons/base/res/res_country_view.xml @@ -22,6 +22,7 @@ res.country
+ diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index b95f8c08a77..722d022634a 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -350,6 +350,7 @@ class res_partner(osv.osv, format_address): def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} + default['user_ids'] = False name = self.read(cr, uid, [id], ['name'], context)[0]['name'] default.update({'name': _('%s (copy)') % name}) return super(res_partner, self).copy(cr, uid, id, default, context) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index b2aba694078..b85c49abf15 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2010-2014 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -169,8 +169,9 @@ class res_users(osv.osv): } def on_change_login(self, cr, uid, ids, login, context=None): - v = {'email': login} if tools.single_email_re.match(login) else {} - return {'value': v} + if login and tools.single_email_re.match(login): + return {'value': {'email': login}} + return {} def onchange_state(self, cr, uid, ids, state_id, context=None): partner_ids = [user.partner_id.id for user in self.browse(cr, uid, ids, context=context)] @@ -585,7 +586,7 @@ class groups_implied(osv.osv): res = super(groups_implied, self).write(cr, uid, ids, values, context) if values.get('users') or values.get('implied_ids'): # add all implied groups (to all users of each group) - for g in self.browse(cr, uid, ids): + for g in self.browse(cr, uid, ids, context=context): gids = map(int, g.trans_implied_ids) vals = {'users': [(4, u.id) for u in g.users]} super(groups_implied, self).write(cr, uid, gids, vals, context) @@ -899,18 +900,22 @@ class change_password_wizard(osv.TransientModel): })) return {'user_ids': res} - def change_password_button(self, cr, uid, id, context=None): wizard = self.browse(cr, uid, id, context=context)[0] - user_ids = [] - 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) + need_reload = any(uid == user.user_id.id for user in wizard.user_ids) + line_ids = [user.id for user in wizard.user_ids] + + self.pool.get('change.password.user').change_password_button(cr, uid, line_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', - } + self.pool.get('change.password.user').write(cr, uid, line_ids, {'new_passwd': False}, context=context) + + if need_reload: + return { + 'type': 'ir.actions.client', + 'tag': 'reload' + } + + return {'type': 'ir.actions.act_window_close'} class change_password_user(osv.TransientModel): """ diff --git a/openerp/addons/base/res/res_users_view.xml b/openerp/addons/base/res/res_users_view.xml index ba603c7a0f0..8a3f372af7a 100644 --- a/openerp/addons/base/res/res_users_view.xml +++ b/openerp/addons/base/res/res_users_view.xml @@ -282,7 +282,7 @@ - diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 25df6e117d0..6113f17c5aa 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -113,3 +113,4 @@ "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 +"access_ir_logging","ir_logging admin","model_ir_logging","group_erp_manager",1,1,1,1 diff --git a/openerp/addons/base/static/img/country_flags/ad.png b/openerp/addons/base/static/img/country_flags/ad.png new file mode 100644 index 00000000000..3806c28c6d8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ad.png differ diff --git a/openerp/addons/base/static/img/country_flags/ae.png b/openerp/addons/base/static/img/country_flags/ae.png new file mode 100644 index 00000000000..4d5c0a3a657 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ae.png differ diff --git a/openerp/addons/base/static/img/country_flags/af.png b/openerp/addons/base/static/img/country_flags/af.png new file mode 100644 index 00000000000..299482a1fad Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/af.png differ diff --git a/openerp/addons/base/static/img/country_flags/ag.png b/openerp/addons/base/static/img/country_flags/ag.png new file mode 100644 index 00000000000..29ec9e8ad1e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ag.png differ diff --git a/openerp/addons/base/static/img/country_flags/ai.png b/openerp/addons/base/static/img/country_flags/ai.png new file mode 100644 index 00000000000..343a6dfc294 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ai.png differ diff --git a/openerp/addons/base/static/img/country_flags/al.png b/openerp/addons/base/static/img/country_flags/al.png new file mode 100644 index 00000000000..0d1b5f87cb3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/al.png differ diff --git a/openerp/addons/base/static/img/country_flags/am.png b/openerp/addons/base/static/img/country_flags/am.png new file mode 100644 index 00000000000..8023ad7a4b2 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/am.png differ diff --git a/openerp/addons/base/static/img/country_flags/an.png b/openerp/addons/base/static/img/country_flags/an.png new file mode 100644 index 00000000000..701d55fbda9 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/an.png differ diff --git a/openerp/addons/base/static/img/country_flags/ao.png b/openerp/addons/base/static/img/country_flags/ao.png new file mode 100644 index 00000000000..b599322efb8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ao.png differ diff --git a/openerp/addons/base/static/img/country_flags/ar.png b/openerp/addons/base/static/img/country_flags/ar.png new file mode 100644 index 00000000000..943ebb2be73 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ar.png differ diff --git a/openerp/addons/base/static/img/country_flags/as.png b/openerp/addons/base/static/img/country_flags/as.png new file mode 100644 index 00000000000..068d34174b6 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/as.png differ diff --git a/openerp/addons/base/static/img/country_flags/at.png b/openerp/addons/base/static/img/country_flags/at.png new file mode 100644 index 00000000000..758147d4bbb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/at.png differ diff --git a/openerp/addons/base/static/img/country_flags/au.png b/openerp/addons/base/static/img/country_flags/au.png new file mode 100644 index 00000000000..6e864267043 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/au.png differ diff --git a/openerp/addons/base/static/img/country_flags/aw.png b/openerp/addons/base/static/img/country_flags/aw.png new file mode 100644 index 00000000000..0f362bbb3fc Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/aw.png differ diff --git a/openerp/addons/base/static/img/country_flags/ax.png b/openerp/addons/base/static/img/country_flags/ax.png new file mode 100644 index 00000000000..e546ec92d5b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ax.png differ diff --git a/openerp/addons/base/static/img/country_flags/az.png b/openerp/addons/base/static/img/country_flags/az.png new file mode 100644 index 00000000000..334567372f2 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/az.png differ diff --git a/openerp/addons/base/static/img/country_flags/ba.png b/openerp/addons/base/static/img/country_flags/ba.png new file mode 100644 index 00000000000..2abf146fc11 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ba.png differ diff --git a/openerp/addons/base/static/img/country_flags/bb.png b/openerp/addons/base/static/img/country_flags/bb.png new file mode 100644 index 00000000000..8fbafd7d12a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bb.png differ diff --git a/openerp/addons/base/static/img/country_flags/bd.png b/openerp/addons/base/static/img/country_flags/bd.png new file mode 100644 index 00000000000..1754328d655 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bd.png differ diff --git a/openerp/addons/base/static/img/country_flags/be.png b/openerp/addons/base/static/img/country_flags/be.png new file mode 100644 index 00000000000..42e4ff638bc Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/be.png differ diff --git a/openerp/addons/base/static/img/country_flags/bf.png b/openerp/addons/base/static/img/country_flags/bf.png new file mode 100644 index 00000000000..bf69a1318e8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bf.png differ diff --git a/openerp/addons/base/static/img/country_flags/bg.png b/openerp/addons/base/static/img/country_flags/bg.png new file mode 100644 index 00000000000..dbe55253e01 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bg.png differ diff --git a/openerp/addons/base/static/img/country_flags/bh.png b/openerp/addons/base/static/img/country_flags/bh.png new file mode 100644 index 00000000000..50944f1ee6f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bh.png differ diff --git a/openerp/addons/base/static/img/country_flags/bi.png b/openerp/addons/base/static/img/country_flags/bi.png new file mode 100644 index 00000000000..6a04c66cdbb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bi.png differ diff --git a/openerp/addons/base/static/img/country_flags/bj.png b/openerp/addons/base/static/img/country_flags/bj.png new file mode 100644 index 00000000000..aac7f881956 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bj.png differ diff --git a/openerp/addons/base/static/img/country_flags/bl.png b/openerp/addons/base/static/img/country_flags/bl.png new file mode 100644 index 00000000000..8fdf4c45717 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bl.png differ diff --git a/openerp/addons/base/static/img/country_flags/bm.png b/openerp/addons/base/static/img/country_flags/bm.png new file mode 100644 index 00000000000..47753a3c677 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bm.png differ diff --git a/openerp/addons/base/static/img/country_flags/bn.png b/openerp/addons/base/static/img/country_flags/bn.png new file mode 100644 index 00000000000..97aa098d88f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bn.png differ diff --git a/openerp/addons/base/static/img/country_flags/bo.png b/openerp/addons/base/static/img/country_flags/bo.png new file mode 100644 index 00000000000..44a066b1601 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bo.png differ diff --git a/openerp/addons/base/static/img/country_flags/br.png b/openerp/addons/base/static/img/country_flags/br.png new file mode 100644 index 00000000000..7231f543ffb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/br.png differ diff --git a/openerp/addons/base/static/img/country_flags/bs.png b/openerp/addons/base/static/img/country_flags/bs.png new file mode 100644 index 00000000000..d7482884694 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bs.png differ diff --git a/openerp/addons/base/static/img/country_flags/bt.png b/openerp/addons/base/static/img/country_flags/bt.png new file mode 100644 index 00000000000..7f889b3c4b7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bt.png differ diff --git a/openerp/addons/base/static/img/country_flags/bw.png b/openerp/addons/base/static/img/country_flags/bw.png new file mode 100644 index 00000000000..f3bcf5663ef Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bw.png differ diff --git a/openerp/addons/base/static/img/country_flags/by.png b/openerp/addons/base/static/img/country_flags/by.png new file mode 100644 index 00000000000..fe37c575ac4 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/by.png differ diff --git a/openerp/addons/base/static/img/country_flags/bz.png b/openerp/addons/base/static/img/country_flags/bz.png new file mode 100644 index 00000000000..bbb9903a237 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/bz.png differ diff --git a/openerp/addons/base/static/img/country_flags/ca.png b/openerp/addons/base/static/img/country_flags/ca.png new file mode 100644 index 00000000000..12807f498ec Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ca.png differ diff --git a/openerp/addons/base/static/img/country_flags/cc.png b/openerp/addons/base/static/img/country_flags/cc.png new file mode 100644 index 00000000000..84ccc4ecaeb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cc.png differ diff --git a/openerp/addons/base/static/img/country_flags/cd.png b/openerp/addons/base/static/img/country_flags/cd.png new file mode 100644 index 00000000000..e96bce99ea7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cd.png differ diff --git a/openerp/addons/base/static/img/country_flags/cf.png b/openerp/addons/base/static/img/country_flags/cf.png new file mode 100644 index 00000000000..366d4cb55e5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cf.png differ diff --git a/openerp/addons/base/static/img/country_flags/cg.png b/openerp/addons/base/static/img/country_flags/cg.png new file mode 100644 index 00000000000..e049d47c408 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cg.png differ diff --git a/openerp/addons/base/static/img/country_flags/ch.png b/openerp/addons/base/static/img/country_flags/ch.png new file mode 100644 index 00000000000..815b6664b49 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ch.png differ diff --git a/openerp/addons/base/static/img/country_flags/ci.png b/openerp/addons/base/static/img/country_flags/ci.png new file mode 100644 index 00000000000..61e92e63a9d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ci.png differ diff --git a/openerp/addons/base/static/img/country_flags/ck.png b/openerp/addons/base/static/img/country_flags/ck.png new file mode 100644 index 00000000000..fb487762817 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ck.png differ diff --git a/openerp/addons/base/static/img/country_flags/cl.png b/openerp/addons/base/static/img/country_flags/cl.png new file mode 100644 index 00000000000..5ad2daaf25c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cl.png differ diff --git a/openerp/addons/base/static/img/country_flags/cm.png b/openerp/addons/base/static/img/country_flags/cm.png new file mode 100644 index 00000000000..80a639ce7dc Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cm.png differ diff --git a/openerp/addons/base/static/img/country_flags/cn.png b/openerp/addons/base/static/img/country_flags/cn.png new file mode 100644 index 00000000000..5b28787b636 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cn.png differ diff --git a/openerp/addons/base/static/img/country_flags/co.png b/openerp/addons/base/static/img/country_flags/co.png new file mode 100644 index 00000000000..53609723452 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/co.png differ diff --git a/openerp/addons/base/static/img/country_flags/cr.png b/openerp/addons/base/static/img/country_flags/cr.png new file mode 100644 index 00000000000..40ee573607b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cr.png differ diff --git a/openerp/addons/base/static/img/country_flags/cu.png b/openerp/addons/base/static/img/country_flags/cu.png new file mode 100644 index 00000000000..31c2bf7dd0c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cu.png differ diff --git a/openerp/addons/base/static/img/country_flags/cv.png b/openerp/addons/base/static/img/country_flags/cv.png new file mode 100644 index 00000000000..d4fd1c54552 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cv.png differ diff --git a/openerp/addons/base/static/img/country_flags/cw.png b/openerp/addons/base/static/img/country_flags/cw.png new file mode 100644 index 00000000000..71fb770b24c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cw.png differ diff --git a/openerp/addons/base/static/img/country_flags/cx.png b/openerp/addons/base/static/img/country_flags/cx.png new file mode 100644 index 00000000000..d093d2e8b3b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cx.png differ diff --git a/openerp/addons/base/static/img/country_flags/cy.png b/openerp/addons/base/static/img/country_flags/cy.png new file mode 100644 index 00000000000..abbf15ce0e3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cy.png differ diff --git a/openerp/addons/base/static/img/country_flags/cz.png b/openerp/addons/base/static/img/country_flags/cz.png new file mode 100644 index 00000000000..bd3cacfe4bb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/cz.png differ diff --git a/openerp/addons/base/static/img/country_flags/de.png b/openerp/addons/base/static/img/country_flags/de.png new file mode 100644 index 00000000000..a479fee6662 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/de.png differ diff --git a/openerp/addons/base/static/img/country_flags/dj.png b/openerp/addons/base/static/img/country_flags/dj.png new file mode 100644 index 00000000000..9ac6493eff3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/dj.png differ diff --git a/openerp/addons/base/static/img/country_flags/dk.png b/openerp/addons/base/static/img/country_flags/dk.png new file mode 100644 index 00000000000..d2882e82a16 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/dk.png differ diff --git a/openerp/addons/base/static/img/country_flags/dm.png b/openerp/addons/base/static/img/country_flags/dm.png new file mode 100644 index 00000000000..f70973854b4 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/dm.png differ diff --git a/openerp/addons/base/static/img/country_flags/do.png b/openerp/addons/base/static/img/country_flags/do.png new file mode 100644 index 00000000000..24614878d56 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/do.png differ diff --git a/openerp/addons/base/static/img/country_flags/dz.png b/openerp/addons/base/static/img/country_flags/dz.png new file mode 100644 index 00000000000..86c293aebef Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/dz.png differ diff --git a/openerp/addons/base/static/img/country_flags/ec.png b/openerp/addons/base/static/img/country_flags/ec.png new file mode 100644 index 00000000000..15ba2c3f2e9 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ec.png differ diff --git a/openerp/addons/base/static/img/country_flags/ee.png b/openerp/addons/base/static/img/country_flags/ee.png new file mode 100644 index 00000000000..fbf210ef42e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ee.png differ diff --git a/openerp/addons/base/static/img/country_flags/eg.png b/openerp/addons/base/static/img/country_flags/eg.png new file mode 100644 index 00000000000..0d8132a03a9 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/eg.png differ diff --git a/openerp/addons/base/static/img/country_flags/er.png b/openerp/addons/base/static/img/country_flags/er.png new file mode 100644 index 00000000000..c89d5a95644 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/er.png differ diff --git a/openerp/addons/base/static/img/country_flags/es.png b/openerp/addons/base/static/img/country_flags/es.png new file mode 100644 index 00000000000..ea384d4d516 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/es.png differ diff --git a/openerp/addons/base/static/img/country_flags/et.png b/openerp/addons/base/static/img/country_flags/et.png new file mode 100644 index 00000000000..d2d1e4255ee Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/et.png differ diff --git a/openerp/addons/base/static/img/country_flags/fi.png b/openerp/addons/base/static/img/country_flags/fi.png new file mode 100644 index 00000000000..195226a5042 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fi.png differ diff --git a/openerp/addons/base/static/img/country_flags/fj.png b/openerp/addons/base/static/img/country_flags/fj.png new file mode 100644 index 00000000000..daee24a3746 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fj.png differ diff --git a/openerp/addons/base/static/img/country_flags/fk.png b/openerp/addons/base/static/img/country_flags/fk.png new file mode 100644 index 00000000000..f202be3118f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fk.png differ diff --git a/openerp/addons/base/static/img/country_flags/fm.png b/openerp/addons/base/static/img/country_flags/fm.png new file mode 100644 index 00000000000..c157b518251 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fm.png differ diff --git a/openerp/addons/base/static/img/country_flags/fo.png b/openerp/addons/base/static/img/country_flags/fo.png new file mode 100644 index 00000000000..eceef2d8d73 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fo.png differ diff --git a/openerp/addons/base/static/img/country_flags/fr.png b/openerp/addons/base/static/img/country_flags/fr.png new file mode 100644 index 00000000000..8fdf4c45717 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/fr.png differ diff --git a/openerp/addons/base/static/img/country_flags/ga.png b/openerp/addons/base/static/img/country_flags/ga.png new file mode 100644 index 00000000000..d4a2b71f2d5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ga.png differ diff --git a/openerp/addons/base/static/img/country_flags/gb.png b/openerp/addons/base/static/img/country_flags/gb.png new file mode 100644 index 00000000000..bf90e9b8b9c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gb.png differ diff --git a/openerp/addons/base/static/img/country_flags/gd.png b/openerp/addons/base/static/img/country_flags/gd.png new file mode 100644 index 00000000000..807755f284f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gd.png differ diff --git a/openerp/addons/base/static/img/country_flags/ge.png b/openerp/addons/base/static/img/country_flags/ge.png new file mode 100644 index 00000000000..6e813b3b310 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ge.png differ diff --git a/openerp/addons/base/static/img/country_flags/gg.png b/openerp/addons/base/static/img/country_flags/gg.png new file mode 100644 index 00000000000..20f3b15c0fd Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gg.png differ diff --git a/openerp/addons/base/static/img/country_flags/gh.png b/openerp/addons/base/static/img/country_flags/gh.png new file mode 100644 index 00000000000..5eb077085c7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gh.png differ diff --git a/openerp/addons/base/static/img/country_flags/gi.png b/openerp/addons/base/static/img/country_flags/gi.png new file mode 100644 index 00000000000..79dbd3333d5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gi.png differ diff --git a/openerp/addons/base/static/img/country_flags/gl.png b/openerp/addons/base/static/img/country_flags/gl.png new file mode 100644 index 00000000000..f7e82893f1a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gl.png differ diff --git a/openerp/addons/base/static/img/country_flags/gm.png b/openerp/addons/base/static/img/country_flags/gm.png new file mode 100644 index 00000000000..8c539e2d23c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gm.png differ diff --git a/openerp/addons/base/static/img/country_flags/gn.png b/openerp/addons/base/static/img/country_flags/gn.png new file mode 100644 index 00000000000..c0d4c72c87a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gn.png differ diff --git a/openerp/addons/base/static/img/country_flags/gq.png b/openerp/addons/base/static/img/country_flags/gq.png new file mode 100644 index 00000000000..375a7b78f62 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gq.png differ diff --git a/openerp/addons/base/static/img/country_flags/gr.png b/openerp/addons/base/static/img/country_flags/gr.png new file mode 100644 index 00000000000..7c4471b86e2 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gr.png differ diff --git a/openerp/addons/base/static/img/country_flags/gs.png b/openerp/addons/base/static/img/country_flags/gs.png new file mode 100644 index 00000000000..b0269d14acf Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gs.png differ diff --git a/openerp/addons/base/static/img/country_flags/gt.png b/openerp/addons/base/static/img/country_flags/gt.png new file mode 100644 index 00000000000..6d6998c4c6c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gt.png differ diff --git a/openerp/addons/base/static/img/country_flags/gu.png b/openerp/addons/base/static/img/country_flags/gu.png new file mode 100644 index 00000000000..847d59520f5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gu.png differ diff --git a/openerp/addons/base/static/img/country_flags/gw.png b/openerp/addons/base/static/img/country_flags/gw.png new file mode 100644 index 00000000000..88ba1d8a531 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gw.png differ diff --git a/openerp/addons/base/static/img/country_flags/gy.png b/openerp/addons/base/static/img/country_flags/gy.png new file mode 100644 index 00000000000..de7bef45285 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/gy.png differ diff --git a/openerp/addons/base/static/img/country_flags/hk.png b/openerp/addons/base/static/img/country_flags/hk.png new file mode 100644 index 00000000000..62f6453b8b7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/hk.png differ diff --git a/openerp/addons/base/static/img/country_flags/hn.png b/openerp/addons/base/static/img/country_flags/hn.png new file mode 100644 index 00000000000..e1201738ca7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/hn.png differ diff --git a/openerp/addons/base/static/img/country_flags/hr.png b/openerp/addons/base/static/img/country_flags/hr.png new file mode 100644 index 00000000000..5e24e9a52d4 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/hr.png differ diff --git a/openerp/addons/base/static/img/country_flags/ht.png b/openerp/addons/base/static/img/country_flags/ht.png new file mode 100644 index 00000000000..58ec58e41be Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ht.png differ diff --git a/openerp/addons/base/static/img/country_flags/hu.png b/openerp/addons/base/static/img/country_flags/hu.png new file mode 100644 index 00000000000..e1f237f802d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/hu.png differ diff --git a/openerp/addons/base/static/img/country_flags/id.png b/openerp/addons/base/static/img/country_flags/id.png new file mode 100644 index 00000000000..1dc8207c288 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/id.png differ diff --git a/openerp/addons/base/static/img/country_flags/ie.png b/openerp/addons/base/static/img/country_flags/ie.png new file mode 100644 index 00000000000..fb8cf9382f1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ie.png differ diff --git a/openerp/addons/base/static/img/country_flags/il.png b/openerp/addons/base/static/img/country_flags/il.png new file mode 100644 index 00000000000..c4c4f21e128 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/il.png differ diff --git a/openerp/addons/base/static/img/country_flags/im.png b/openerp/addons/base/static/img/country_flags/im.png new file mode 100644 index 00000000000..6befe9efe3a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/im.png differ diff --git a/openerp/addons/base/static/img/country_flags/in.png b/openerp/addons/base/static/img/country_flags/in.png new file mode 100644 index 00000000000..a0daccd9397 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/in.png differ diff --git a/openerp/addons/base/static/img/country_flags/io.png b/openerp/addons/base/static/img/country_flags/io.png new file mode 100644 index 00000000000..a112651851b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/io.png differ diff --git a/openerp/addons/base/static/img/country_flags/iq.png b/openerp/addons/base/static/img/country_flags/iq.png new file mode 100644 index 00000000000..1095c9d312a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/iq.png differ diff --git a/openerp/addons/base/static/img/country_flags/ir.png b/openerp/addons/base/static/img/country_flags/ir.png new file mode 100644 index 00000000000..8b9c5fac4d0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ir.png differ diff --git a/openerp/addons/base/static/img/country_flags/iran.png b/openerp/addons/base/static/img/country_flags/iran.png new file mode 100644 index 00000000000..9ca5513ace0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/iran.png differ diff --git a/openerp/addons/base/static/img/country_flags/is.png b/openerp/addons/base/static/img/country_flags/is.png new file mode 100644 index 00000000000..c5d0ffb1ec3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/is.png differ diff --git a/openerp/addons/base/static/img/country_flags/it.png b/openerp/addons/base/static/img/country_flags/it.png new file mode 100644 index 00000000000..1cd74ec0ee0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/it.png differ diff --git a/openerp/addons/base/static/img/country_flags/je.png b/openerp/addons/base/static/img/country_flags/je.png new file mode 100644 index 00000000000..ca62fe471e3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/je.png differ diff --git a/openerp/addons/base/static/img/country_flags/jm.png b/openerp/addons/base/static/img/country_flags/jm.png new file mode 100644 index 00000000000..7458372eea8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/jm.png differ diff --git a/openerp/addons/base/static/img/country_flags/jo.png b/openerp/addons/base/static/img/country_flags/jo.png new file mode 100644 index 00000000000..b5e88a3c251 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/jo.png differ diff --git a/openerp/addons/base/static/img/country_flags/jp.png b/openerp/addons/base/static/img/country_flags/jp.png new file mode 100644 index 00000000000..21f38c35847 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/jp.png differ diff --git a/openerp/addons/base/static/img/country_flags/ke.png b/openerp/addons/base/static/img/country_flags/ke.png new file mode 100644 index 00000000000..57ef9e3f20b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ke.png differ diff --git a/openerp/addons/base/static/img/country_flags/kg.png b/openerp/addons/base/static/img/country_flags/kg.png new file mode 100644 index 00000000000..1b550f6cfaa Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kg.png differ diff --git a/openerp/addons/base/static/img/country_flags/kh.png b/openerp/addons/base/static/img/country_flags/kh.png new file mode 100644 index 00000000000..299ad93e08e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kh.png differ diff --git a/openerp/addons/base/static/img/country_flags/ki.png b/openerp/addons/base/static/img/country_flags/ki.png new file mode 100644 index 00000000000..cf730409013 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ki.png differ diff --git a/openerp/addons/base/static/img/country_flags/km.png b/openerp/addons/base/static/img/country_flags/km.png new file mode 100644 index 00000000000..df5c343fce5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/km.png differ diff --git a/openerp/addons/base/static/img/country_flags/kn.png b/openerp/addons/base/static/img/country_flags/kn.png new file mode 100644 index 00000000000..9ecfa0ab9c4 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kn.png differ diff --git a/openerp/addons/base/static/img/country_flags/kp.png b/openerp/addons/base/static/img/country_flags/kp.png new file mode 100644 index 00000000000..14db96ff065 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kp.png differ diff --git a/openerp/addons/base/static/img/country_flags/kr.png b/openerp/addons/base/static/img/country_flags/kr.png new file mode 100644 index 00000000000..8b66b25f75d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kr.png differ diff --git a/openerp/addons/base/static/img/country_flags/kw.png b/openerp/addons/base/static/img/country_flags/kw.png new file mode 100644 index 00000000000..33c04a64f70 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kw.png differ diff --git a/openerp/addons/base/static/img/country_flags/ky.png b/openerp/addons/base/static/img/country_flags/ky.png new file mode 100644 index 00000000000..84279c83bcf Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ky.png differ diff --git a/openerp/addons/base/static/img/country_flags/kz.png b/openerp/addons/base/static/img/country_flags/kz.png new file mode 100644 index 00000000000..f756682c74f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/kz.png differ diff --git a/openerp/addons/base/static/img/country_flags/la.png b/openerp/addons/base/static/img/country_flags/la.png new file mode 100644 index 00000000000..27d4e2be994 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/la.png differ diff --git a/openerp/addons/base/static/img/country_flags/lb.png b/openerp/addons/base/static/img/country_flags/lb.png new file mode 100644 index 00000000000..8df863b7ca1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lb.png differ diff --git a/openerp/addons/base/static/img/country_flags/lc.png b/openerp/addons/base/static/img/country_flags/lc.png new file mode 100644 index 00000000000..15af8fee7ff Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lc.png differ diff --git a/openerp/addons/base/static/img/country_flags/li.png b/openerp/addons/base/static/img/country_flags/li.png new file mode 100644 index 00000000000..f86197e9af6 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/li.png differ diff --git a/openerp/addons/base/static/img/country_flags/lk.png b/openerp/addons/base/static/img/country_flags/lk.png new file mode 100644 index 00000000000..46bab54aabc Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lk.png differ diff --git a/openerp/addons/base/static/img/country_flags/lr.png b/openerp/addons/base/static/img/country_flags/lr.png new file mode 100644 index 00000000000..3f2cc830120 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lr.png differ diff --git a/openerp/addons/base/static/img/country_flags/ls.png b/openerp/addons/base/static/img/country_flags/ls.png new file mode 100644 index 00000000000..6b6d6b17531 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ls.png differ diff --git a/openerp/addons/base/static/img/country_flags/lt.png b/openerp/addons/base/static/img/country_flags/lt.png new file mode 100644 index 00000000000..a25f6a31aae Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lt.png differ diff --git a/openerp/addons/base/static/img/country_flags/lu.png b/openerp/addons/base/static/img/country_flags/lu.png new file mode 100644 index 00000000000..2899c7bbba1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lu.png differ diff --git a/openerp/addons/base/static/img/country_flags/lv.png b/openerp/addons/base/static/img/country_flags/lv.png new file mode 100644 index 00000000000..674a7c6c9b0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/lv.png differ diff --git a/openerp/addons/base/static/img/country_flags/ly.png b/openerp/addons/base/static/img/country_flags/ly.png new file mode 100644 index 00000000000..0e4eb2a5627 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ly.png differ diff --git a/openerp/addons/base/static/img/country_flags/ma.png b/openerp/addons/base/static/img/country_flags/ma.png new file mode 100644 index 00000000000..b43ea8c8597 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ma.png differ diff --git a/openerp/addons/base/static/img/country_flags/mc.png b/openerp/addons/base/static/img/country_flags/mc.png new file mode 100644 index 00000000000..119460a5e7f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mc.png differ diff --git a/openerp/addons/base/static/img/country_flags/md.png b/openerp/addons/base/static/img/country_flags/md.png new file mode 100644 index 00000000000..a05ba191843 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/md.png differ diff --git a/openerp/addons/base/static/img/country_flags/me.png b/openerp/addons/base/static/img/country_flags/me.png new file mode 100644 index 00000000000..aead438a92f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/me.png differ diff --git a/openerp/addons/base/static/img/country_flags/mg.png b/openerp/addons/base/static/img/country_flags/mg.png new file mode 100644 index 00000000000..75242401c76 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mg.png differ diff --git a/openerp/addons/base/static/img/country_flags/mh.png b/openerp/addons/base/static/img/country_flags/mh.png new file mode 100644 index 00000000000..4cd0d244a49 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mh.png differ diff --git a/openerp/addons/base/static/img/country_flags/mk.png b/openerp/addons/base/static/img/country_flags/mk.png new file mode 100644 index 00000000000..f313b092e4c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mk.png differ diff --git a/openerp/addons/base/static/img/country_flags/ml.png b/openerp/addons/base/static/img/country_flags/ml.png new file mode 100644 index 00000000000..eb5579c08d5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ml.png differ diff --git a/openerp/addons/base/static/img/country_flags/mm.png b/openerp/addons/base/static/img/country_flags/mm.png new file mode 100644 index 00000000000..6723bbb3b03 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mm.png differ diff --git a/openerp/addons/base/static/img/country_flags/mn.png b/openerp/addons/base/static/img/country_flags/mn.png new file mode 100644 index 00000000000..607caac7659 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mn.png differ diff --git a/openerp/addons/base/static/img/country_flags/mo.png b/openerp/addons/base/static/img/country_flags/mo.png new file mode 100644 index 00000000000..f64c674be59 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mo.png differ diff --git a/openerp/addons/base/static/img/country_flags/mp.png b/openerp/addons/base/static/img/country_flags/mp.png new file mode 100644 index 00000000000..3453b270cc0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mp.png differ diff --git a/openerp/addons/base/static/img/country_flags/mq.png b/openerp/addons/base/static/img/country_flags/mq.png new file mode 100644 index 00000000000..54ba3e92b83 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mq.png differ diff --git a/openerp/addons/base/static/img/country_flags/mr.png b/openerp/addons/base/static/img/country_flags/mr.png new file mode 100644 index 00000000000..76b032b47b8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mr.png differ diff --git a/openerp/addons/base/static/img/country_flags/ms.png b/openerp/addons/base/static/img/country_flags/ms.png new file mode 100644 index 00000000000..4f291816856 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ms.png differ diff --git a/openerp/addons/base/static/img/country_flags/mt.png b/openerp/addons/base/static/img/country_flags/mt.png new file mode 100644 index 00000000000..dbdcbf9d503 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mt.png differ diff --git a/openerp/addons/base/static/img/country_flags/mu.png b/openerp/addons/base/static/img/country_flags/mu.png new file mode 100644 index 00000000000..6eae60e796b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mu.png differ diff --git a/openerp/addons/base/static/img/country_flags/mv.png b/openerp/addons/base/static/img/country_flags/mv.png new file mode 100644 index 00000000000..6d2597d66b1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mv.png differ diff --git a/openerp/addons/base/static/img/country_flags/mw.png b/openerp/addons/base/static/img/country_flags/mw.png new file mode 100644 index 00000000000..f2f3454334b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mw.png differ diff --git a/openerp/addons/base/static/img/country_flags/mx.png b/openerp/addons/base/static/img/country_flags/mx.png new file mode 100644 index 00000000000..4c5c32d0589 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mx.png differ diff --git a/openerp/addons/base/static/img/country_flags/my.png b/openerp/addons/base/static/img/country_flags/my.png new file mode 100644 index 00000000000..7ee43cc1925 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/my.png differ diff --git a/openerp/addons/base/static/img/country_flags/mz.png b/openerp/addons/base/static/img/country_flags/mz.png new file mode 100644 index 00000000000..4d47b29b02b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/mz.png differ diff --git a/openerp/addons/base/static/img/country_flags/na.png b/openerp/addons/base/static/img/country_flags/na.png new file mode 100644 index 00000000000..0e09fd2f12a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/na.png differ diff --git a/openerp/addons/base/static/img/country_flags/nc.png b/openerp/addons/base/static/img/country_flags/nc.png new file mode 100644 index 00000000000..5e9b0ca9f73 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nc.png differ diff --git a/openerp/addons/base/static/img/country_flags/ne.png b/openerp/addons/base/static/img/country_flags/ne.png new file mode 100644 index 00000000000..e96acdedbc0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ne.png differ diff --git a/openerp/addons/base/static/img/country_flags/nf.png b/openerp/addons/base/static/img/country_flags/nf.png new file mode 100644 index 00000000000..2bb62238166 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nf.png differ diff --git a/openerp/addons/base/static/img/country_flags/ng.png b/openerp/addons/base/static/img/country_flags/ng.png new file mode 100644 index 00000000000..052ec0e9761 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ng.png differ diff --git a/openerp/addons/base/static/img/country_flags/ni.png b/openerp/addons/base/static/img/country_flags/ni.png new file mode 100644 index 00000000000..4e455f6777e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ni.png differ diff --git a/openerp/addons/base/static/img/country_flags/nl.png b/openerp/addons/base/static/img/country_flags/nl.png new file mode 100644 index 00000000000..1b5938306f5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nl.png differ diff --git a/openerp/addons/base/static/img/country_flags/no.png b/openerp/addons/base/static/img/country_flags/no.png new file mode 100644 index 00000000000..bd2840d96c1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/no.png differ diff --git a/openerp/addons/base/static/img/country_flags/np.png b/openerp/addons/base/static/img/country_flags/np.png new file mode 100644 index 00000000000..4c4beda56fe Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/np.png differ diff --git a/openerp/addons/base/static/img/country_flags/nr.png b/openerp/addons/base/static/img/country_flags/nr.png new file mode 100644 index 00000000000..923bea03faf Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nr.png differ diff --git a/openerp/addons/base/static/img/country_flags/nu.png b/openerp/addons/base/static/img/country_flags/nu.png new file mode 100644 index 00000000000..1f745218efa Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nu.png differ diff --git a/openerp/addons/base/static/img/country_flags/nz.png b/openerp/addons/base/static/img/country_flags/nz.png new file mode 100644 index 00000000000..6d669ae696e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/nz.png differ diff --git a/openerp/addons/base/static/img/country_flags/om.png b/openerp/addons/base/static/img/country_flags/om.png new file mode 100644 index 00000000000..5c61b15a0a5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/om.png differ diff --git a/openerp/addons/base/static/img/country_flags/pa.png b/openerp/addons/base/static/img/country_flags/pa.png new file mode 100644 index 00000000000..b4857d13574 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pa.png differ diff --git a/openerp/addons/base/static/img/country_flags/pe.png b/openerp/addons/base/static/img/country_flags/pe.png new file mode 100644 index 00000000000..14f7e1c86d3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pe.png differ diff --git a/openerp/addons/base/static/img/country_flags/pf.png b/openerp/addons/base/static/img/country_flags/pf.png new file mode 100644 index 00000000000..db134fc81c4 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pf.png differ diff --git a/openerp/addons/base/static/img/country_flags/pg.png b/openerp/addons/base/static/img/country_flags/pg.png new file mode 100644 index 00000000000..56e85161956 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pg.png differ diff --git a/openerp/addons/base/static/img/country_flags/ph.png b/openerp/addons/base/static/img/country_flags/ph.png new file mode 100644 index 00000000000..e74d917eb3d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ph.png differ diff --git a/openerp/addons/base/static/img/country_flags/pk.png b/openerp/addons/base/static/img/country_flags/pk.png new file mode 100644 index 00000000000..adea341ccec Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pk.png differ diff --git a/openerp/addons/base/static/img/country_flags/pl.png b/openerp/addons/base/static/img/country_flags/pl.png new file mode 100644 index 00000000000..4d0f9d19f65 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pl.png differ diff --git a/openerp/addons/base/static/img/country_flags/pm.png b/openerp/addons/base/static/img/country_flags/pm.png new file mode 100644 index 00000000000..b34299ce47b Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pm.png differ diff --git a/openerp/addons/base/static/img/country_flags/pn.png b/openerp/addons/base/static/img/country_flags/pn.png new file mode 100644 index 00000000000..890c9593342 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pn.png differ diff --git a/openerp/addons/base/static/img/country_flags/pr.png b/openerp/addons/base/static/img/country_flags/pr.png new file mode 100644 index 00000000000..5e2c7c6078a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pr.png differ diff --git a/openerp/addons/base/static/img/country_flags/pt.png b/openerp/addons/base/static/img/country_flags/pt.png new file mode 100644 index 00000000000..5fe2ae2cf63 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pt.png differ diff --git a/openerp/addons/base/static/img/country_flags/pw.png b/openerp/addons/base/static/img/country_flags/pw.png new file mode 100644 index 00000000000..fe8ef26d2e6 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/pw.png differ diff --git a/openerp/addons/base/static/img/country_flags/py.png b/openerp/addons/base/static/img/country_flags/py.png new file mode 100644 index 00000000000..0a04748f182 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/py.png differ diff --git a/openerp/addons/base/static/img/country_flags/qa.png b/openerp/addons/base/static/img/country_flags/qa.png new file mode 100644 index 00000000000..35c44fc076d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/qa.png differ diff --git a/openerp/addons/base/static/img/country_flags/ro.png b/openerp/addons/base/static/img/country_flags/ro.png new file mode 100644 index 00000000000..0cb3f29f11d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ro.png differ diff --git a/openerp/addons/base/static/img/country_flags/rs.png b/openerp/addons/base/static/img/country_flags/rs.png new file mode 100644 index 00000000000..6f7d83de2e5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/rs.png differ diff --git a/openerp/addons/base/static/img/country_flags/ru.png b/openerp/addons/base/static/img/country_flags/ru.png new file mode 100644 index 00000000000..1a99c506234 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ru.png differ diff --git a/openerp/addons/base/static/img/country_flags/rw.png b/openerp/addons/base/static/img/country_flags/rw.png new file mode 100644 index 00000000000..2abba014617 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/rw.png differ diff --git a/openerp/addons/base/static/img/country_flags/sa.png b/openerp/addons/base/static/img/country_flags/sa.png new file mode 100644 index 00000000000..6c106a540a1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sa.png differ diff --git a/openerp/addons/base/static/img/country_flags/sb.png b/openerp/addons/base/static/img/country_flags/sb.png new file mode 100644 index 00000000000..a23c5bc58ba Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sb.png differ diff --git a/openerp/addons/base/static/img/country_flags/sc.png b/openerp/addons/base/static/img/country_flags/sc.png new file mode 100644 index 00000000000..d1acc28403e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sc.png differ diff --git a/openerp/addons/base/static/img/country_flags/sd.png b/openerp/addons/base/static/img/country_flags/sd.png new file mode 100644 index 00000000000..e7694590811 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sd.png differ diff --git a/openerp/addons/base/static/img/country_flags/se.png b/openerp/addons/base/static/img/country_flags/se.png new file mode 100644 index 00000000000..a30498df565 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/se.png differ diff --git a/openerp/addons/base/static/img/country_flags/sg.png b/openerp/addons/base/static/img/country_flags/sg.png new file mode 100644 index 00000000000..16bb5445c58 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sg.png differ diff --git a/openerp/addons/base/static/img/country_flags/sh.png b/openerp/addons/base/static/img/country_flags/sh.png new file mode 100644 index 00000000000..cb48a6a2e2f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sh.png differ diff --git a/openerp/addons/base/static/img/country_flags/si.png b/openerp/addons/base/static/img/country_flags/si.png new file mode 100644 index 00000000000..b749349245d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/si.png differ diff --git a/openerp/addons/base/static/img/country_flags/sk.png b/openerp/addons/base/static/img/country_flags/sk.png new file mode 100644 index 00000000000..1609f2c8d9a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sk.png differ diff --git a/openerp/addons/base/static/img/country_flags/sl.png b/openerp/addons/base/static/img/country_flags/sl.png new file mode 100644 index 00000000000..ef67f96c22a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sl.png differ diff --git a/openerp/addons/base/static/img/country_flags/sm.png b/openerp/addons/base/static/img/country_flags/sm.png new file mode 100644 index 00000000000..b515c509030 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sm.png differ diff --git a/openerp/addons/base/static/img/country_flags/sn.png b/openerp/addons/base/static/img/country_flags/sn.png new file mode 100644 index 00000000000..2cb1d0a36c3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sn.png differ diff --git a/openerp/addons/base/static/img/country_flags/so.png b/openerp/addons/base/static/img/country_flags/so.png new file mode 100644 index 00000000000..d6772bdd702 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/so.png differ diff --git a/openerp/addons/base/static/img/country_flags/sr.png b/openerp/addons/base/static/img/country_flags/sr.png new file mode 100644 index 00000000000..9be5dc7b952 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sr.png differ diff --git a/openerp/addons/base/static/img/country_flags/ss.png b/openerp/addons/base/static/img/country_flags/ss.png new file mode 100644 index 00000000000..a07a513e189 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ss.png differ diff --git a/openerp/addons/base/static/img/country_flags/st.png b/openerp/addons/base/static/img/country_flags/st.png new file mode 100644 index 00000000000..b3abd9852f3 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/st.png differ diff --git a/openerp/addons/base/static/img/country_flags/sv.png b/openerp/addons/base/static/img/country_flags/sv.png new file mode 100644 index 00000000000..4685c62e305 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sv.png differ diff --git a/openerp/addons/base/static/img/country_flags/sx.png b/openerp/addons/base/static/img/country_flags/sx.png new file mode 100644 index 00000000000..d8d40f75924 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sx.png differ diff --git a/openerp/addons/base/static/img/country_flags/sy.png b/openerp/addons/base/static/img/country_flags/sy.png new file mode 100644 index 00000000000..a45853957cc Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sy.png differ diff --git a/openerp/addons/base/static/img/country_flags/sz.png b/openerp/addons/base/static/img/country_flags/sz.png new file mode 100644 index 00000000000..49b2a9360c1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/sz.png differ diff --git a/openerp/addons/base/static/img/country_flags/tc.png b/openerp/addons/base/static/img/country_flags/tc.png new file mode 100644 index 00000000000..078b226810d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tc.png differ diff --git a/openerp/addons/base/static/img/country_flags/td.png b/openerp/addons/base/static/img/country_flags/td.png new file mode 100644 index 00000000000..2e8603a6012 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/td.png differ diff --git a/openerp/addons/base/static/img/country_flags/tf.png b/openerp/addons/base/static/img/country_flags/tf.png new file mode 100644 index 00000000000..945c7afb0b1 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tf.png differ diff --git a/openerp/addons/base/static/img/country_flags/tg.png b/openerp/addons/base/static/img/country_flags/tg.png new file mode 100644 index 00000000000..3154c5cb830 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tg.png differ diff --git a/openerp/addons/base/static/img/country_flags/th.png b/openerp/addons/base/static/img/country_flags/th.png new file mode 100644 index 00000000000..f39ce45eeee Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/th.png differ diff --git a/openerp/addons/base/static/img/country_flags/tj.png b/openerp/addons/base/static/img/country_flags/tj.png new file mode 100644 index 00000000000..15d59605186 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tj.png differ diff --git a/openerp/addons/base/static/img/country_flags/tk.png b/openerp/addons/base/static/img/country_flags/tk.png new file mode 100644 index 00000000000..b191458e187 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tk.png differ diff --git a/openerp/addons/base/static/img/country_flags/tl.png b/openerp/addons/base/static/img/country_flags/tl.png new file mode 100644 index 00000000000..0031a4e41f9 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tl.png differ diff --git a/openerp/addons/base/static/img/country_flags/tm.png b/openerp/addons/base/static/img/country_flags/tm.png new file mode 100644 index 00000000000..6699276a8ed Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tm.png differ diff --git a/openerp/addons/base/static/img/country_flags/tn.png b/openerp/addons/base/static/img/country_flags/tn.png new file mode 100644 index 00000000000..04587942bb7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tn.png differ diff --git a/openerp/addons/base/static/img/country_flags/to.png b/openerp/addons/base/static/img/country_flags/to.png new file mode 100644 index 00000000000..51a1556d5e9 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/to.png differ diff --git a/openerp/addons/base/static/img/country_flags/tp.png b/openerp/addons/base/static/img/country_flags/tp.png new file mode 100644 index 00000000000..2ec85c15394 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tp.png differ diff --git a/openerp/addons/base/static/img/country_flags/tr.png b/openerp/addons/base/static/img/country_flags/tr.png new file mode 100644 index 00000000000..ebf2a31e807 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tr.png differ diff --git a/openerp/addons/base/static/img/country_flags/tt.png b/openerp/addons/base/static/img/country_flags/tt.png new file mode 100644 index 00000000000..e49c3682a50 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tt.png differ diff --git a/openerp/addons/base/static/img/country_flags/tv.png b/openerp/addons/base/static/img/country_flags/tv.png new file mode 100644 index 00000000000..ab10c93d5d7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tv.png differ diff --git a/openerp/addons/base/static/img/country_flags/tz.png b/openerp/addons/base/static/img/country_flags/tz.png new file mode 100644 index 00000000000..d4e99a62df7 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/tz.png differ diff --git a/openerp/addons/base/static/img/country_flags/ua.png b/openerp/addons/base/static/img/country_flags/ua.png new file mode 100644 index 00000000000..57cf957010d Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ua.png differ diff --git a/openerp/addons/base/static/img/country_flags/ug.png b/openerp/addons/base/static/img/country_flags/ug.png new file mode 100644 index 00000000000..908784213f0 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ug.png differ diff --git a/openerp/addons/base/static/img/country_flags/us.png b/openerp/addons/base/static/img/country_flags/us.png new file mode 100644 index 00000000000..801ef4e8abb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/us.png differ diff --git a/openerp/addons/base/static/img/country_flags/uy.png b/openerp/addons/base/static/img/country_flags/uy.png new file mode 100644 index 00000000000..7af80710a3f Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/uy.png differ diff --git a/openerp/addons/base/static/img/country_flags/uz.png b/openerp/addons/base/static/img/country_flags/uz.png new file mode 100644 index 00000000000..54840bd935c Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/uz.png differ diff --git a/openerp/addons/base/static/img/country_flags/va.png b/openerp/addons/base/static/img/country_flags/va.png new file mode 100644 index 00000000000..28933fb7e04 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/va.png differ diff --git a/openerp/addons/base/static/img/country_flags/vc.png b/openerp/addons/base/static/img/country_flags/vc.png new file mode 100644 index 00000000000..62b9091dc9a Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/vc.png differ diff --git a/openerp/addons/base/static/img/country_flags/ve.png b/openerp/addons/base/static/img/country_flags/ve.png new file mode 100644 index 00000000000..7ab81205f84 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ve.png differ diff --git a/openerp/addons/base/static/img/country_flags/vg.png b/openerp/addons/base/static/img/country_flags/vg.png new file mode 100644 index 00000000000..9a33f8cf9e6 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/vg.png differ diff --git a/openerp/addons/base/static/img/country_flags/vi.png b/openerp/addons/base/static/img/country_flags/vi.png new file mode 100644 index 00000000000..b6361f49e57 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/vi.png differ diff --git a/openerp/addons/base/static/img/country_flags/vn.png b/openerp/addons/base/static/img/country_flags/vn.png new file mode 100644 index 00000000000..25753977ec5 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/vn.png differ diff --git a/openerp/addons/base/static/img/country_flags/vu.png b/openerp/addons/base/static/img/country_flags/vu.png new file mode 100644 index 00000000000..124c7cf7b56 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/vu.png differ diff --git a/openerp/addons/base/static/img/country_flags/ws.png b/openerp/addons/base/static/img/country_flags/ws.png new file mode 100644 index 00000000000..787354394c8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ws.png differ diff --git a/openerp/addons/base/static/img/country_flags/ye.png b/openerp/addons/base/static/img/country_flags/ye.png new file mode 100644 index 00000000000..07c4c8ef1fb Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/ye.png differ diff --git a/openerp/addons/base/static/img/country_flags/za.png b/openerp/addons/base/static/img/country_flags/za.png new file mode 100644 index 00000000000..dc4fb4df547 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/za.png differ diff --git a/openerp/addons/base/static/img/country_flags/zm.png b/openerp/addons/base/static/img/country_flags/zm.png new file mode 100644 index 00000000000..6275c83148e Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/zm.png differ diff --git a/openerp/addons/base/static/img/country_flags/zw.png b/openerp/addons/base/static/img/country_flags/zw.png new file mode 100644 index 00000000000..de98aa7f4d8 Binary files /dev/null and b/openerp/addons/base/static/img/country_flags/zw.png differ diff --git a/openerp/addons/base/tests/test_base.py b/openerp/addons/base/tests/test_base.py index 263cb0adf23..bbc5b21d1fb 100644 --- a/openerp/addons/base/tests/test_base.py +++ b/openerp/addons/base/tests/test_base.py @@ -9,6 +9,7 @@ class test_base(common.TransactionCase): super(test_base,self).setUp() self.res_partner = self.registry('res.partner') self.res_users = self.registry('res.users') + self.res_partner_title = self.registry('res.partner.title') # samples use effective TLDs from the Mozilla public suffix # list at http://publicsuffix.org @@ -285,27 +286,99 @@ class test_base(common.TransactionCase): 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) + title_sir = self.res_partner_title.create(cr, uid, {'name': 'Sir', 'domain': 'contact'}) + title_lady = self.res_partner_title.create(cr, uid, {'name': 'Lady', 'domain': 'contact'}) + test_users = [ + {'name': 'Alice', 'login': 'alice', 'color': 1, 'function': 'Friend', 'date': '2015-03-28', 'title': title_lady}, + {'name': 'Alice', 'login': 'alice2', 'color': 0, 'function': 'Friend', 'date': '2015-01-28', 'title': title_lady}, + {'name': 'Bob', 'login': 'bob', 'color': 2, 'function': 'Friend', 'date': '2015-03-02', 'title': title_sir}, + {'name': 'Eve', 'login': 'eve', 'color': 3, 'function': 'Eavesdropper', 'date': '2015-03-20', 'title': title_lady}, + {'name': 'Nab', 'login': 'nab', 'color': -3, 'function': '5$ Wrench', 'date': '2014-09-10', 'title': title_sir}, + {'name': 'Nab', 'login': 'nab-she', 'color': 6, 'function': '5$ Wrench', 'date': '2014-01-02', 'title': title_lady}, + ] + ids = [self.res_users.create(cr, uid, u) for u in test_users] + domain = [('id', 'in', ids)] - 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") + # group on local char field without domain and without active_test (-> empty WHERE clause) + groups_data = self.res_users.read_group(cr, uid, [], fields=['login'], groupby=['login'], orderby='login DESC', context={'active_test': False}) + self.assertGreater(len(groups_data), 6, "Incorrect number of results when grouping on a field") + + # group on local char field with limit + groups_data = self.res_users.read_group(cr, uid, domain, fields=['login'], groupby=['login'], orderby='login DESC', limit=3, offset=3) + self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field with limit") + self.assertEqual(['bob', 'alice2', 'alice'], [g['login'] for g in groups_data], 'Result mismatch') + + # group on inherited char field, aggregate on int field (second groupby ignored on purpose) + groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color', 'function'], groupby=['function', 'login']) + self.assertEqual(len(groups_data), 3, "Incorrect number of results when grouping on a field") + self.assertEqual(['5$ Wrench', 'Eavesdropper', 'Friend'], [g['function'] for g in groups_data], 'incorrect read_group order') 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'") + 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') + # group on inherited char field, reverse order + groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='name DESC') + self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') + + # group on int field, default ordering + groups_data = self.res_users.read_group(cr, uid, domain, fields=['color'], groupby='color') + self.assertEqual([-3, 0, 1, 2, 3, 6], [g['color'] for g in groups_data], 'Incorrect ordering of the list') + + # multi group, second level is int field, should still be summed in first level grouping + groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby=['name', 'color'], orderby='name DESC') + self.assertEqual(['Nab', 'Eve', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([3, 3, 2, 1], [g['color'] for g in groups_data], 'Incorrect ordering of the list') + + # group on inherited char field, multiple orders with directions + groups_data = self.res_users.read_group(cr, uid, domain, fields=['name', 'color'], groupby='name', orderby='color DESC, name') + self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") + self.assertEqual(['Eve', 'Nab', 'Bob', 'Alice'], [g['name'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([1, 2, 1, 2], [g['name_count'] for g in groups_data], 'Incorrect number of results') + + # group on inherited date column (res_partner.date) -> Year-Month, default ordering + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date']) + self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") + self.assertEqual(['January 2014', 'September 2014', 'January 2015', 'March 2015'], [g['date'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([1, 1, 1, 3], [g['date_count'] for g in groups_data], 'Incorrect number of results') + + # group on inherited date column (res_partner.date) -> Year-Month, custom order + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'date'], groupby=['date'], orderby='date DESC') + self.assertEqual(len(groups_data), 4, "Incorrect number of results when grouping on a field") + self.assertEqual(['March 2015', 'January 2015', 'September 2014', 'January 2014'], [g['date'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([3, 1, 1, 1], [g['date_count'] for g in groups_data], 'Incorrect number of results') + + # group on inherited many2one (res_partner.title), default order + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title']) + self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") + # m2o is returned as a (id, label) pair + self.assertEqual([(title_lady, 'Lady'), (title_sir, 'Sir')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results') + self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') + + # group on inherited many2one (res_partner.title), reversed natural order + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="title desc") + self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") + # m2o is returned as a (id, label) pair + self.assertEqual([(title_sir, 'Sir'), (title_lady, 'Lady')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results') + self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') + + # group on inherited many2one (res_partner.title), multiple orders with m2o in second position + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby="color desc, title desc") + self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") + # m2o is returned as a (id, label) pair + self.assertEqual([(title_lady, 'Lady'), (title_sir, 'Sir')], [g['title'] for g in groups_data], 'Incorrect ordering of the result') + self.assertEqual([4, 2], [g['title_count'] for g in groups_data], 'Incorrect number of results') + self.assertEqual([10, -1], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') + + # group on inherited many2one (res_partner.title), ordered by other inherited field (color) + groups_data = self.res_users.read_group(cr, uid, domain, fields=['function', 'color', 'title'], groupby=['title'], orderby='color') + self.assertEqual(len(groups_data), 2, "Incorrect number of results when grouping on a field") + # m2o is returned as a (id, label) pair + self.assertEqual([(title_sir, 'Sir'), (title_lady, 'Lady')], [g['title'] for g in groups_data], 'Incorrect ordering of the list') + self.assertEqual([2, 4], [g['title_count'] for g in groups_data], 'Incorrect number of results') + self.assertEqual([-1, 10], [g['color'] for g in groups_data], 'Incorrect aggregation of int column') - 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): diff --git a/openerp/addons/base/tests/test_fields.py b/openerp/addons/base/tests/test_fields.py index 47ffcd2f5b1..ce34bceb014 100644 --- a/openerp/addons/base/tests/test_fields.py +++ b/openerp/addons/base/tests/test_fields.py @@ -179,3 +179,51 @@ class TestPropertyField(common.TransactionCase): 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") + + +class TestHtmlField(common.TransactionCase): + + def setUp(self): + super(TestHtmlField, self).setUp() + self.partner = self.registry('res.partner') + + def test_00_sanitize(self): + cr, uid, context = self.cr, self.uid, {} + old_columns = self.partner._columns + self.partner._columns = dict(old_columns) + self.partner._columns.update({ + 'comment': fields.html('Secure Html', sanitize=False), + }) + some_ugly_html = """

Oops this should maybe be sanitized +% if object.some_field and not object.oriented: + + % if object.other_field: + + ${object.mako_thing} + + % endif + +%if object.dummy_field: +

Youpie

+%endif""" + + pid = self.partner.create(cr, uid, { + 'name': 'Raoul Poilvache', + 'comment': some_ugly_html, + }, context=context) + partner = self.partner.browse(cr, uid, pid, context=context) + self.assertEqual(partner.comment, some_ugly_html, 'Error in HTML field: content was sanitized but field has sanitize=False') + + self.partner._columns.update({ + 'comment': fields.html('Unsecure Html', sanitize=True), + }) + self.partner.write(cr, uid, [pid], { + 'comment': some_ugly_html, + }, context=context) + partner = self.partner.browse(cr, uid, pid, context=context) + # sanitize should have closed tags left open in the original html + self.assertIn('
+
', partner.comment, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True') + self.assertIn('', partner.comment, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True') + + self.partner._columns = old_columns diff --git a/openerp/addons/base/tests/test_ir_sequence.py b/openerp/addons/base/tests/test_ir_sequence.py index bc428d7f647..e925fffa3b1 100644 --- a/openerp/addons/base/tests/test_ir_sequence.py +++ b/openerp/addons/base/tests/test_ir_sequence.py @@ -8,6 +8,7 @@ # OPENERP_DATABASE=yy PYTHONPATH=../:. unit2 test_ir_sequence # This assume an existing database. import psycopg2 +import psycopg2.errorcodes import unittest2 import openerp @@ -111,11 +112,11 @@ class test_ir_sequence_no_gap(unittest2.TestCase): cr0 = cursor() cr1 = cursor() cr1._default_log_exceptions = False # Prevent logging a traceback - msg_re = '^could not obtain lock on row in relation "ir_sequence"$' - with self.assertRaisesRegexp(psycopg2.OperationalError, msg_re): + with self.assertRaises(psycopg2.OperationalError) as e: n0 = registry('ir.sequence').next_by_code(cr0, ADMIN_USER_ID, 'test_sequence_type_2', {}) assert n0 n1 = registry('ir.sequence').next_by_code(cr1, ADMIN_USER_ID, 'test_sequence_type_2', {}) + self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode") cr0.close() cr1.close() diff --git a/openerp/addons/base/tests/test_qweb.py b/openerp/addons/base/tests/test_qweb.py index 71beaab605a..ca1503a0c24 100644 --- a/openerp/addons/base/tests/test_qweb.py +++ b/openerp/addons/base/tests/test_qweb.py @@ -14,7 +14,8 @@ class TestQWebTField(common.TransactionCase): self.engine = self.registry('ir.qweb') def context(self, values): - return ir_qweb.QWebContext(self.cr, self.uid, values) + return ir_qweb.QWebContext( + self.cr, self.uid, values, context={'inherit_branding': True}) def test_trivial(self): field = document.createElement('span') diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index 6780996ed6e..06030a84792 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -1,6 +1,8 @@ # -*- encoding: utf-8 -*- from functools import partial +import unittest2 + from lxml import etree as ET from lxml.builder import E @@ -8,6 +10,24 @@ from openerp.tests import common Field = E.field +class ViewCase(common.TransactionCase): + def setUp(self): + super(ViewCase, self).setUp() + self.addTypeEqualityFunc(ET._Element, self.assertTreesEqual) + + def assertTreesEqual(self, n1, n2, msg=None): + self.assertEqual(n1.tag, n2.tag) + self.assertEqual((n1.text or '').strip(), (n2.text or '').strip(), msg) + self.assertEqual((n1.tail or '').strip(), (n2.tail or '').strip(), msg) + + # Because lxml uses ordereddicts in which order is important to + # equality (!?!?!?!) + self.assertEqual(dict(n1.attrib), dict(n2.attrib), msg) + + for c1, c2 in zip(n1, n2): + self.assertTreesEqual(c1, c2, msg) + + class TestNodeLocator(common.BaseCase): """ The node locator returns None when it can not find a node, and the first @@ -98,7 +118,7 @@ class TestNodeLocator(common.BaseCase): E.foo(attr='1', version='3')) self.assertIsNone(node) -class TestViewInheritance(common.TransactionCase): +class TestViewInheritance(ViewCase): def arch_for(self, name, view_type='form', parent=None): """ Generates a trivial view of the specified ``view_type``. @@ -206,7 +226,7 @@ class TestViewInheritance(common.TransactionCase): self.View.default_view( self.cr, self.uid, model=self.model, view_type='graph')) -class TestApplyInheritanceSpecs(common.TransactionCase): +class TestApplyInheritanceSpecs(ViewCase): """ Applies a sequence of inheritance specification nodes to a base architecture. IO state parameters (cr, uid, model, context) are used for error reporting @@ -230,8 +250,8 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form(Field(name="replacement"), string="Title"))) + self.base_arch, + E.form(Field(name="replacement"), string="Title")) def test_delete(self): spec = Field(name="target", position="replace") @@ -241,8 +261,8 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form(string="Title"))) + self.base_arch, + E.form(string="Title")) def test_insert_after(self): spec = Field( @@ -254,12 +274,12 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form( + self.base_arch, + E.form( Field(name="target"), Field(name="inserted"), string="Title" - ))) + )) def test_insert_before(self): spec = Field( @@ -271,11 +291,11 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form( + self.base_arch, + E.form( Field(name="inserted"), Field(name="target"), - string="Title"))) + string="Title")) def test_insert_inside(self): default = Field(Field(name="inserted"), name="target") @@ -289,13 +309,13 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form( + self.base_arch, + E.form( Field( Field(name="inserted"), Field(name="inserted 2"), name="target"), - string="Title"))) + string="Title")) def test_unpack_data(self): spec = E.data( @@ -310,15 +330,15 @@ class TestApplyInheritanceSpecs(common.TransactionCase): spec, None) self.assertEqual( - ET.tostring(self.base_arch), - ET.tostring(E.form( + self.base_arch, + E.form( Field( Field(name="inserted 0"), Field(name="inserted 1"), Field(name="inserted 2"), Field(name="inserted 3"), name="target"), - string="Title"))) + string="Title")) def test_invalid_position(self): spec = Field( @@ -350,18 +370,18 @@ class TestApplyInheritanceSpecs(common.TransactionCase): self.base_arch, spec, None) -class TestApplyInheritedArchs(common.TransactionCase): +class TestApplyInheritedArchs(ViewCase): """ Applies a sequence of modificator archs to a base view """ -class TestViewCombined(common.TransactionCase): +class TestViewCombined(ViewCase): """ Test fallback operations of View.read_combined: * defaults mapping * ? """ -class TestNoModel(common.TransactionCase): +class TestNoModel(ViewCase): def test_create_view_nomodel(self): View = self.registry('ir.ui.view') view_id = View.create(self.cr, self.uid, { @@ -411,13 +431,11 @@ class TestNoModel(common.TransactionCase): '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): + self.text_para.text = translated_text + self.assertEqual(sarch, self.arch) + +class TestTemplating(ViewCase): def setUp(self): import openerp.modules super(TestTemplating, self).setUp() @@ -473,7 +491,126 @@ class TestTemplating(common.TransactionCase): second.get('data-oe-id'), "second should come from the extension view") -class test_views(common.TransactionCase): + def test_branding_distribute_inner(self): + """ Checks that the branding is correctly distributed within a view + extension + """ + Views = self.registry('ir.ui.view') + id = Views.create(self.cr, self.uid, { + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + """ + }) + id2 = Views.create(self.cr, self.uid, { + 'name': "Extension", + 'type': 'qweb', + 'inherit_id': id, + 'arch': """ + + bar + + """ + }) + + arch_string = Views.read_combined( + self.cr, self.uid, id, fields=['arch'], + context={'inherit_branding': True})['arch'] + + arch = ET.fromstring(arch_string) + Views.distribute_branding(arch) + + self.assertEqual( + arch, + E.root( + E.item( + E.content("bar", { + 't-att-href': "foo", + 'data-oe-model': 'ir.ui.view', + 'data-oe-id': str(id2), + 'data-oe-field': 'arch', + 'data-oe-xpath': '/xpath/item/content[1]', + }), { + 'order': '2', + 'data-oe-source-id': str(id) + }), + E.item({ + 'order': '1', + 'data-oe-model': 'ir.ui.view', + 'data-oe-id': str(id), + 'data-oe-field': 'arch', + 'data-oe-xpath': '/root[1]/item[1]' + }) + ) + ) + + def test_esc_no_branding(self): + Views = self.registry('ir.ui.view') + id = Views.create(self.cr, self.uid, { + 'name': "Base View", + 'type': 'qweb', + 'arch': """ + + """, + }) + + arch_string = Views.read_combined( + self.cr, self.uid, id, fields=['arch'], + context={'inherit_branding': True})['arch'] + arch = ET.fromstring(arch_string) + Views.distribute_branding(arch) + + self.assertEqual(arch, E.root(E.item(E.span({'t-esc': "foo"})))) + + def test_ignore_unbrand(self): + Views = self.registry('ir.ui.view') + id = Views.create(self.cr, self.uid, { + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + + + """ + }) + id2 = Views.create(self.cr, self.uid, { + 'name': "Extension", + 'type': 'qweb', + 'inherit_id': id, + 'arch': """ + + bar + + """ + }) + + arch_string = Views.read_combined( + self.cr, self.uid, id, fields=['arch'], + context={'inherit_branding': True})['arch'] + + arch = ET.fromstring(arch_string) + Views.distribute_branding(arch) + + self.assertEqual( + arch, + E.root( + E.item( + {'t-ignore': 'true', 'order': '1'}, + E.t({'t-esc': 'foo'}), + E.item( + {'order': '2', 'data-oe-source-id': str(id)}, + E.content( + {'t-att-href': 'foo'}, + "bar") + ) + ) + ), + "t-ignore should apply to injected sub-view branding, not just to" + " the main view's" + ) + +class test_views(ViewCase): def test_nonexistent_attribute_removal(self): Views = self.registry('ir.ui.view') @@ -589,16 +726,17 @@ class test_views(common.TransactionCase): }) self.assertEqual(view['type'], 'form') self.assertEqual( - ET.tostring(ET.fromstring( + ET.fromstring( view['arch'], parser=ET.XMLParser(remove_blank_text=True) - )), - '' - '

Replacement data

' - '
' - '
' - '') + ), + E.form( + E.p("Replacement data"), + E.footer( + E.button(name="action_next", type="object", string="New button"), + thing="bob" + ), + string="Replacement title", version="7.0")) def test_view_inheritance_divergent_models(self): Views = self.registry('ir.ui.view') @@ -656,14 +794,13 @@ class test_views(common.TransactionCase): }) self.assertEqual(view['type'], 'form') self.assertEqual( - ET.tostring(ET.fromstring( + ET.fromstring( view['arch'], parser=ET.XMLParser(remove_blank_text=True) - )), - '
' - '

Replacement data

' - '
' - '
' - '
') - + ), + E.form( + E.p("Replacement data"), + E.footer( + E.button(name="action_next", type="object", string="New button")), + string="Replacement title", version="7.0" + )) diff --git a/openerp/addons/test_converter/tests/test_html.py b/openerp/addons/test_converter/tests/test_html.py index 2f0896990ea..3ef6566e829 100644 --- a/openerp/addons/test_converter/tests/test_html.py +++ b/openerp/addons/test_converter/tests/test_html.py @@ -112,11 +112,14 @@ class TestCurrencyExport(TestExport): 'widget': 'monetary', 'display_currency': 'c2' } + context = dict(inherit_branding=True) 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, })) + '', ir_qweb.QWebContext(self.cr, self.uid, {'obj': obj, 'c2': dest, }), + context=context, + ) return converted def test_currency_post(self): diff --git a/openerp/addons/test_impex/tests/test_export.py b/openerp/addons/test_impex/tests/test_export.py index 26219b36d3b..995d69471d6 100644 --- a/openerp/addons/test_impex/tests/test_export.py +++ b/openerp/addons/test_impex/tests/test_export.py @@ -309,8 +309,9 @@ class test_m2o(CreatorCase): def test_external_id(self): integer_id = self.registry('export.integer').create( self.cr, openerp.SUPERUSER_ID, {'value': 42}) - # __export__.$class.$id - external_id = u'__export__.export_many2one_%d' % integer_id + # Expecting the m2o target model name in the external id, + # not this model's name + external_id = u'__export__.export_integer_%d' % integer_id self.assertEqual( self.export(integer_id, fields=['value/id']), [[external_id]]) diff --git a/openerp/cli/server.py b/openerp/cli/server.py index 42d920da9aa..e7ba695f19c 100644 --- a/openerp/cli/server.py +++ b/openerp/cli/server.py @@ -127,7 +127,6 @@ def main(args): check_root_user() openerp.tools.config.parse_config(args) check_postgres_user() - openerp.netsvc.init_logger() report_configuration() config = openerp.tools.config diff --git a/openerp/http.py b/openerp/http.py index 1750478a836..5f37afbc116 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -23,6 +23,7 @@ import urlparse import warnings import babel.core +import psutil import psycopg2 import simplejson import werkzeug.contrib.sessions @@ -35,7 +36,7 @@ import werkzeug.wsgi import openerp from openerp.service import security, model as service_model -import openerp.tools +from openerp.tools.func import lazy_property _logger = logging.getLogger(__name__) @@ -50,6 +51,70 @@ request = _request_stack() A global proxy that always redirect to the current request object. """ +def replace_request_password(args): + # password is always 3rd argument in a request, we replace it in RPC logs + # so it's easier to forward logs for diagnostics/debugging purposes... + if len(args) > 2: + args = list(args) + args[2] = '*' + return tuple(args) + +def dispatch_rpc(service_name, method, params): + """ Handle a RPC call. + + This is pure Python code, the actual marshalling (from/to XML-RPC) is done + in a upper layer. + """ + try: + rpc_request = logging.getLogger(__name__ + '.rpc.request') + rpc_response = logging.getLogger(__name__ + '.rpc.response') + rpc_request_flag = rpc_request.isEnabledFor(logging.DEBUG) + rpc_response_flag = rpc_response.isEnabledFor(logging.DEBUG) + if rpc_request_flag or rpc_response_flag: + start_time = time.time() + start_rss, start_vms = 0, 0 + start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info() + if rpc_request and rpc_response_flag: + openerp.netsvc.log(rpc_request, logging.DEBUG, '%s.%s' % (service_name, method), replace_request_password(params)) + + threading.current_thread().uid = None + threading.current_thread().dbname = None + if service_name == 'common': + dispatch = openerp.service.common.dispatch + elif service_name == 'db': + dispatch = openerp.service.db.dispatch + elif service_name == 'object': + dispatch = openerp.service.model.dispatch + elif service_name == 'report': + dispatch = openerp.service.report.dispatch + else: + dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name) + result = dispatch(method, params) + + if rpc_request_flag or rpc_response_flag: + end_time = time.time() + end_rss, end_vms = 0, 0 + end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info() + logline = '%s.%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (service_name, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024) + if rpc_response_flag: + openerp.netsvc.log(rpc_response, logging.DEBUG, logline, result) + else: + openerp.netsvc.log(rpc_request, logging.DEBUG, logline, replace_request_password(params), depth=1) + + return result + except (openerp.osv.orm.except_orm, openerp.exceptions.AccessError, \ + openerp.exceptions.AccessDenied, openerp.exceptions.Warning, \ + openerp.exceptions.RedirectWarning): + raise + except openerp.exceptions.DeferredException, e: + _logger.exception(openerp.tools.exception_to_unicode(e)) + openerp.tools.debugger.post_mortem(openerp.tools.config, e.traceback) + raise + except Exception, e: + _logger.exception(openerp.tools.exception_to_unicode(e)) + openerp.tools.debugger.post_mortem(openerp.tools.config, sys.exc_info()) + raise + def local_redirect(path, query=None, keep_hash=False, forward_debug=True, code=303): url = path if not query: @@ -133,6 +198,10 @@ class WebRequest(object): self.auth_method = None self._cr_cm = None self._cr = None + + # prevents transaction commit, use when you catch an exception during handling + self._failed = None + # set db/uid trackers - they're cleaned up at the WSGI # dispatching phase in openerp.service.wsgi_server.application if self.db: @@ -180,10 +249,13 @@ class WebRequest(object): _request_stack.pop() if self._cr: - # Dont commit test cursors - if not openerp.tests.common.release_test_cursor(self.session_id): - if exc_type is None: + # Dont close test cursors + if not openerp.tests.common.release_test_cursor(self._cr): + if exc_type is None and not self._failed: self._cr.commit() + else: + # just to be explicit - happens at close() anyway + self._cr.rollback() self._cr.close() # just to be sure no one tries to re-use the request self.disable_db = True @@ -209,20 +281,19 @@ class WebRequest(object): # Backward for 7.0 if self.endpoint.first_arg_is_req: args = (request,) + args + # Correct exception handling and concurency retry @service_model.check def checked_call(___dbname, *a, **kw): + # The decorator can call us more than once if there is an database error. In this + # case, the request cursor is unusable. Rollback transaction to create a new one. + if self._cr and not openerp.tools.config['test_enable']: + self._cr.rollback() return self.endpoint(*a, **kw) - # FIXME: code and rollback management could be cleaned - try: - if self.db: - return checked_call(self.db, *args, **kwargs) - return self.endpoint(*args, **kwargs) - except Exception: - if self._cr: - self._cr.rollback() - raise + if self.db: + return checked_call(self.db, *args, **kwargs) + return self.endpoint(*args, **kwargs) @property def debug(self): @@ -362,21 +433,25 @@ class JsonRequest(WebRequest): response['id'] = self.jsonrequest.get('id') response["result"] = self._call_function(**self.params) except AuthenticationError, e: - _logger.exception("Exception during JSON request handling.") + _logger.exception("JSON-RPC AuthenticationError in %s.", self.httprequest.path) se = serialize_exception(e) error = { 'code': 100, 'message': "OpenERP Session Invalid", 'data': se } + self._failed = e # prevent tx commit except Exception, e: - _logger.exception("Exception during JSON request handling.") + # Mute test cursor error for runbot + if not (openerp.tools.config['test_enable'] and isinstance(e, psycopg2.OperationalError)): + _logger.exception("JSON-RPC Exception in %s.", self.httprequest.path) se = serialize_exception(e) error = { 'code': 200, 'message': "OpenERP Server Error", 'data': se } + self._failed = e # prevent tx commit if error: response["error"] = error @@ -618,7 +693,7 @@ class SessionExpiredException(Exception): class Service(object): """ .. deprecated:: 8.0 - Use ``openerp.netsvc.dispatch_rpc()`` instead. + Use ``dispatch_rpc()`` instead. """ def __init__(self, session, service_name): self.session = session @@ -626,7 +701,7 @@ class Service(object): def __getattr__(self, method): def proxy_method(*args): - result = openerp.netsvc.dispatch_rpc(self.service_name, method, args) + result = dispatch_rpc(self.service_name, method, args) return result return proxy_method @@ -699,7 +774,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): HTTP_HOST=wsgienv['HTTP_HOST'], REMOTE_ADDR=wsgienv['REMOTE_ADDR'], ) - uid = openerp.netsvc.dispatch_rpc('common', 'authenticate', [db, login, password, env]) + uid = dispatch_rpc('common', 'authenticate', [db, login, password, env]) else: security.check(db, uid, password) self.db = db @@ -733,7 +808,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): self.setdefault("uid", None) self.setdefault("login", None) self.setdefault("password", None) - self.setdefault("context", {'tz': "UTC", "uid": None}) + self.setdefault("context", {}) def get_context(self): """ @@ -803,14 +878,14 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): def send(self, service_name, method, *args): """ .. deprecated:: 8.0 - Use ``openerp.netsvc.dispatch_rpc()`` instead. + Use ``dispatch_rpc()`` instead. """ - return openerp.netsvc.dispatch_rpc(service_name, method, args) + return dispatch_rpc(service_name, method, args) def proxy(self, service): """ .. deprecated:: 8.0 - Use ``openerp.netsvc.dispatch_rpc()`` instead. + Use ``dispatch_rpc()`` instead. """ return Service(self, service) @@ -1003,22 +1078,25 @@ class Root(object): path = openerp.tools.config.session_dir _logger.debug('HTTP sessions stored in: %s', path) self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession) + self._loaded = False - # TODO should we move this to ir.http so that only configured modules are served ? - _logger.info("HTTP Configuring static files") - self.load_addons() - + @lazy_property + def nodb_routing_map(self): _logger.info("Generating nondb routing") - self.nodb_routing_map = routing_map([''] + openerp.conf.server_wide_modules, True) + return routing_map([''] + openerp.conf.server_wide_modules, True) def __call__(self, environ, start_response): """ Handle a WSGI request """ + if not self._loaded: + self._loaded = True + self.load_addons() return self.dispatch(environ, start_response) def load_addons(self): - """ Load all addons from addons patch containg static files and + """ Load all addons from addons path containing static files and controllers and configure them. """ + # TODO should we move this to ir.http so that only configured modules are served ? statics = {} for addons_path in openerp.modules.module.ad_paths: @@ -1032,12 +1110,16 @@ class Root(object): _logger.debug("Loading %s", module) if 'openerp.addons' in sys.modules: m = __import__('openerp.addons.' + module) + else: + m = None addons_module[module] = m addons_manifest[module] = manifest statics['/%s/static' % module] = path_static - app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, statics) - self.dispatch = DisableCacheMiddleware(app) + if statics: + _logger.info("HTTP Configuring static files") + app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, statics) + self.dispatch = DisableCacheMiddleware(app) def setup_session(self, httprequest): # recover or create session @@ -1163,7 +1245,7 @@ class Root(object): return request.registry['ir.http'].routing_map() def db_list(force=False, httprequest=None): - dbs = openerp.netsvc.dispatch_rpc("db", "list", [force]) + dbs = dispatch_rpc("db", "list", [force]) return db_filter(dbs, httprequest=httprequest) def db_filter(dbs, httprequest=None): @@ -1208,18 +1290,10 @@ class CommonController(Controller): @route('/jsonrpc', type='json', auth="none") def jsonrpc(self, service, method, args): """ Method used by client APIs to contact OpenERP. """ - return openerp.netsvc.dispatch_rpc(service, method, args) + return dispatch_rpc(service, method, args) - @route('/gen_session_id', type='json', auth="none") - def gen_session_id(self): - nsession = root.session_store.new() - return nsession.sid - -root = None - -def wsgi_postload(): - global root - root = Root() - openerp.service.wsgi_server.register_wsgi_handler(root) +# register main wsgi handler +root = Root() +openerp.service.wsgi_server.register_wsgi_handler(root) # vim:et:ts=4:sw=4: diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 7ca0a6785d6..5635e42e780 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -42,6 +42,7 @@ from openerp import SUPERUSER_ID from openerp.tools.translate import _ from openerp.modules.module import initialize_sys_path, \ load_openerp_module, init_module_models, adapt_version +from module import runs_post_install _logger = logging.getLogger(__name__) _test_logger = logging.getLogger('openerp.tests') @@ -187,6 +188,10 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules= # Yamel test report.record_result(load_test(module_name, idref, mode)) # Python tests + ir_http = registry['ir.http'] + if hasattr(ir_http, '_routing_map'): + # Force routing map to be rebuilt between each module test suite + del(ir_http._routing_map) report.record_result(openerp.modules.module.run_unit_tests(module_name, cr.dbname)) processed_modules.append(package.name) @@ -421,8 +426,13 @@ def load_modules(db, force_demo=False, status=None, update_module=False): for model in registry.models.values(): model._register_hook(cr) + # STEP 9: Run the post-install tests + cr.commit() + if openerp.tools.config['test_enable']: + cr.execute("SELECT name FROM ir_module_module WHERE state='installed'") + for module_name in cr.fetchall(): + report.record_result(openerp.modules.module.run_unit_tests(module_name[0], cr.dbname, position=runs_post_install)) finally: cr.close() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/modules/module.py b/openerp/modules/module.py index 554b38f06cf..82e86e83ce2 100644 --- a/openerp/modules/module.py +++ b/openerp/modules/module.py @@ -38,7 +38,6 @@ import openerp.release as release 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 = [] @@ -170,13 +169,15 @@ def get_module_icon(module): return ('/' + module + '/') + '/'.join(iconpath) return '/base/' + '/'.join(iconpath) -def load_information_from_description_file(module): +def load_information_from_description_file(module, mod_path=None): """ :param module: The name of the module (sale, purchase, ...) + :param mod_path: Physical path of module, if not providedThe name of the module (sale, purchase, ...) """ - terp_file = get_module_resource(module, '__openerp__.py') - mod_path = get_module_path(module) + if not mod_path: + mod_path = get_module_path(module) + terp_file = opj(mod_path, '__openerp__.py') if terp_file: info = {} if os.path.isfile(terp_file): @@ -340,7 +341,8 @@ def get_test_modules(module): # Use a custom stream object to log the test executions. class TestStream(object): - def __init__(self): + def __init__(self, logger_name='openerp.tests'): + self.logger = logging.getLogger(logger_name) self.r = re.compile(r'^-*$|^ *... *$|^ok$') def flush(self): pass @@ -352,34 +354,10 @@ class TestStream(object): if not first: c = '` ' + c first = False - _test_logger.info(c) + self.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 - """ - 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) @@ -396,6 +374,30 @@ def runs_at(test, hook, default): 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 run_unit_tests(module_name, dbname, position=runs_at_install): + """ + :returns: ``True`` if all of ``module_name``'s tests succeeded, ``False`` + if any of them failed. + :rtype: bool + """ + 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(position, tests)) + _logger.info('running %s tests.', m.__name__) + + result = unittest2.TextTestRunner(verbosity=2, stream=TestStream(m.__name__)).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 unwrap_suite(test): """ Attempts to unpack testsuites (holding suites or cases) in order to diff --git a/openerp/netsvc.py b/openerp/netsvc.py index 755f6513b25..d762eb5006f 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2012 OpenERP SA () +# Copyright (C) 2004-2014 OpenERP SA () # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,23 +19,29 @@ # ############################################################################## - import logging import logging.handlers import os +import pprint import release import sys import threading -import time -import types -from pprint import pformat -import psutil -import tools +import psycopg2 + import openerp +import sql_db +import tools _logger = logging.getLogger(__name__) +def log(logger, level, prefix, msg, depth=None): + indent='' + indent_after=' '*len(prefix) + for line in (prefix + pprint.pformat(msg, depth=depth)).split('\n'): + logger.log(level, indent+line) + indent=indent_after + def LocalService(name): """ The openerp.netsvc.LocalService() function is deprecated. It still works @@ -62,6 +68,36 @@ def LocalService(name): with registry.cursor() as cr: return registry['ir.actions.report.xml']._lookup_report(cr, name[len('report.'):]) +class PostgreSQLHandler(logging.Handler): + """ PostgreSQL Loggin Handler will store logs in the database, by default + the current database, can be set using --log-db=DBNAME + """ + def emit(self, record): + ct = threading.current_thread() + ct_db = getattr(ct, 'dbname', None) + ct_uid = getattr(ct, 'uid', None) + dbname = tools.config['log_db'] or ct_db + if dbname: + cr = None + try: + cr = sql_db.db_connect(dbname).cursor() + msg = unicode(record.msg) + traceback = getattr(record, 'exc_text', '') + if traceback: + msg = "%s\n%s" % (msg, traceback) + level = logging.getLevelName(record.levelno) + val = (ct_uid, ct_uid, 'server', dbname, record.name, level, msg, record.pathname, record.lineno, record.funcName) + cr.execute(""" + INSERT INTO ir_logging(create_date, write_date, create_uid, write_uid, type, dbname, name, level, message, path, line, func) + VALUES (NOW() at time zone 'UTC', NOW() at time zone 'UTC', %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """, val ) + cr.commit() + except Exception, e: + pass + finally: + if cr: + cr.close() + BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, _NOTHING, DEFAULT = range(10) #The background is set with 40 plus the number of the color, and the foreground with 30 #These are the sequences need to get colored ouput @@ -89,7 +125,13 @@ class ColoredFormatter(DBFormatter): record.levelname = COLOR_PATTERN % (30 + fg_color, 40 + bg_color, record.levelname) return DBFormatter.format(self, record) +_logger_init = False def init_logger(): + global _logger_init + if _logger_init: + return + _logger_init = True + from tools.translate import resetlocale resetlocale() @@ -101,7 +143,7 @@ def init_logger(): if os.name == 'nt': handler = logging.handlers.NTEventLogHandler("%s %s" % (release.description, release.version)) else: - handler = logging.handlers.SysLogHandler('/dev/log') + handler = logging.handlers.SysLogHandler() format = '%s %s' % (release.description, release.version) \ + ':%(dbname)s:%(levelname)s:%(name)s:%(message)s' @@ -109,11 +151,12 @@ def init_logger(): # LogFile Handler logf = tools.config['logfile'] try: + # We check we have the right location for the log files dirname = os.path.dirname(logf) if dirname and not os.path.isdir(dirname): os.makedirs(dirname) if tools.config['logrotate'] is not False: - handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30) + handler = logging.handlers.TimedRotatingFileHandler(filename=logf, when='D', interval=1, backupCount=30) elif os.name == 'posix': handler = logging.handlers.WatchedFileHandler(logf) else: @@ -129,15 +172,23 @@ def init_logger(): # behind Apache with mod_wsgi, handler.stream will have type mod_wsgi.Log, # which has no fileno() method. (mod_wsgi.Log is what is being bound to # sys.stderr when the logging.StreamHandler is being constructed above.) - if isinstance(handler, logging.StreamHandler) \ - and hasattr(handler.stream, 'fileno') \ - and os.isatty(handler.stream.fileno()): + def is_a_tty(stream): + return hasattr(stream, 'fileno') and os.isatty(stream.fileno()) + + if isinstance(handler, logging.StreamHandler) and is_a_tty(handler.stream): formatter = ColoredFormatter(format) else: formatter = DBFormatter(format) handler.setFormatter(formatter) - # Configure handlers + logging.getLogger().addHandler(handler) + + if tools.config['log_db']: + postgresqlHandler = PostgreSQLHandler() + postgresqlHandler.setLevel(logging.WARNING) + logging.getLogger().addHandler(postgresqlHandler) + + # Configure loggers levels pseudo_config = PSEUDOCONFIG_MAPPER.get(tools.config['log_level'], []) logconfig = tools.config['log_handler'] @@ -147,26 +198,22 @@ def init_logger(): loggername, level = logconfig_item.split(':') level = getattr(logging, level, logging.INFO) logger = logging.getLogger(loggername) - logger.handlers = [] logger.setLevel(level) - logger.addHandler(handler) - if loggername != '': - logger.propagate = False for logconfig_item in logging_configurations: _logger.debug('logger level set: "%s"', logconfig_item) DEFAULT_LOG_CONFIGURATION = [ 'openerp.workflow.workitem:WARNING', - 'openerp.netsvc.rpc.request:INFO', - 'openerp.netsvc.rpc.response:INFO', + 'openerp.http.rpc.request:INFO', + 'openerp.http.rpc.response:INFO', 'openerp.addons.web.http:INFO', 'openerp.sql_db:INFO', ':INFO', ] PSEUDOCONFIG_MAPPER = { - 'debug_rpc_answer': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG', 'openerp.netsvc.rpc.response:DEBUG'], - 'debug_rpc': ['openerp:DEBUG','openerp.netsvc.rpc.request:DEBUG'], + 'debug_rpc_answer': ['openerp:DEBUG','openerp.http.rpc.request:DEBUG', 'openerp.http.rpc.response:DEBUG'], + 'debug_rpc': ['openerp:DEBUG','openerp.http.rpc.request:DEBUG'], 'debug': ['openerp:DEBUG'], 'debug_sql': ['openerp.sql_db:DEBUG'], 'info': [], @@ -175,99 +222,4 @@ PSEUDOCONFIG_MAPPER = { 'critical': ['openerp:CRITICAL'], } -# A alternative logging scheme for automated runs of the -# server intended to test it. -def init_alternative_logger(): - class H(logging.Handler): - def emit(self, record): - if record.levelno > 20: - print record.levelno, record.pathname, record.msg - handler = H() - # Add the handler to the 'openerp' logger. - logger = logging.getLogger('openerp') - logger.addHandler(handler) - logger.setLevel(logging.ERROR) - -def replace_request_password(args): - # password is always 3rd argument in a request, we replace it in RPC logs - # so it's easier to forward logs for diagnostics/debugging purposes... - if len(args) > 2: - args = list(args) - args[2] = '*' - return tuple(args) - -def log(logger, level, prefix, msg, depth=None): - indent='' - indent_after=' '*len(prefix) - for line in (prefix+pformat(msg, depth=depth)).split('\n'): - logger.log(level, indent+line) - indent=indent_after - -def dispatch_rpc(service_name, method, params): - """ Handle a RPC call. - - This is pure Python code, the actual marshalling (from/to XML-RPC) is done - in a upper layer. - """ - try: - rpc_request = logging.getLogger(__name__ + '.rpc.request') - rpc_response = logging.getLogger(__name__ + '.rpc.response') - rpc_request_flag = rpc_request.isEnabledFor(logging.DEBUG) - rpc_response_flag = rpc_response.isEnabledFor(logging.DEBUG) - if rpc_request_flag or rpc_response_flag: - start_time = time.time() - start_rss, start_vms = 0, 0 - start_rss, start_vms = psutil.Process(os.getpid()).get_memory_info() - if rpc_request and rpc_response_flag: - log(rpc_request,logging.DEBUG,'%s.%s'%(service_name,method), replace_request_password(params)) - - threading.current_thread().uid = None - threading.current_thread().dbname = None - if service_name == 'common': - dispatch = openerp.service.common.dispatch - elif service_name == 'db': - dispatch = openerp.service.db.dispatch - elif service_name == 'object': - dispatch = openerp.service.model.dispatch - elif service_name == 'report': - dispatch = openerp.service.report.dispatch - else: - dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name) - result = dispatch(method, params) - - if rpc_request_flag or rpc_response_flag: - end_time = time.time() - end_rss, end_vms = 0, 0 - end_rss, end_vms = psutil.Process(os.getpid()).get_memory_info() - logline = '%s.%s time:%.3fs mem: %sk -> %sk (diff: %sk)' % (service_name, method, end_time - start_time, start_vms / 1024, end_vms / 1024, (end_vms - start_vms)/1024) - if rpc_response_flag: - log(rpc_response,logging.DEBUG, logline, result) - else: - log(rpc_request,logging.DEBUG, logline, replace_request_password(params), depth=1) - - return result - except openerp.osv.orm.except_orm: - raise - except openerp.exceptions.AccessError: - raise - except openerp.exceptions.AccessDenied: - raise - except openerp.exceptions.Warning: - raise - except openerp.exceptions.RedirectWarning: - raise - except openerp.exceptions.DeferredException, e: - _logger.exception(tools.exception_to_unicode(e)) - post_mortem(e.traceback) - raise - except Exception, e: - _logger.exception(tools.exception_to_unicode(e)) - post_mortem(sys.exc_info()) - raise - -def post_mortem(info): - if tools.config['debug_mode'] and isinstance(info[2], types.TracebackType): - import pdb - pdb.post_mortem(info[2]) - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 478f982cd69..d5d0ee0fa30 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -236,15 +236,24 @@ class char(_column): class text(_column): _type = 'text' + class html(text): _type = 'html' _symbol_c = '%s' - def _symbol_f(x): - if x is None or x == False: + + def _symbol_set_html(self, value): + if value is None or value is False: return None - return html_sanitize(x) - - _symbol_set = (_symbol_c, _symbol_f) + if not self._sanitize: + return value + return html_sanitize(value) + + def __init__(self, string='unknown', sanitize=True, **args): + super(html, self).__init__(string=string, **args) + self._sanitize = sanitize + # symbol_set redefinition because of sanitize specific behavior + self._symbol_f = self._symbol_set_html + self._symbol_set = (self._symbol_c, self._symbol_f) import __builtin__ diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 3126507608f..64fa06783ab 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -75,7 +75,7 @@ _schema = logging.getLogger(__name__ + '.schema') # List of etree._Element subclasses that we choose to ignore when parsing XML. from openerp.tools import SKIPPED_ELEMENT_TYPES -regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I) +regex_order = re.compile('^( *([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I) regex_object_name = re.compile(r'^[a-z0-9_.]+$') AUTOINIT_RECALCULATE_STORED_FIELDS = 1000 @@ -1124,7 +1124,7 @@ class BaseModel(object): def _get_xml_id(self, cr, uid, r): model_data = self.pool.get('ir.model.data') - data_ids = model_data.search(cr, uid, [('model', '=', r._table_name), ('res_id', '=', r['id'])]) + data_ids = model_data.search(cr, uid, [('model', '=', r._model._name), ('res_id', '=', r['id'])]) if len(data_ids): d = model_data.read(cr, uid, data_ids, ['name', 'module'])[0] if d['module']: @@ -1134,13 +1134,13 @@ class BaseModel(object): else: postfix = 0 while True: - n = self._table+'_'+str(r['id']) + (postfix and ('_'+str(postfix)) or '' ) + n = r._model._table+'_'+str(r['id']) + (postfix and ('_'+str(postfix)) or '' ) if not model_data.search(cr, uid, [('name', '=', n)]): break postfix += 1 model_data.create(cr, SUPERUSER_ID, { 'name': n, - 'model': self._name, + 'model': r._model._name, 'res_id': r['id'], 'module': '__export__', }) @@ -2185,36 +2185,42 @@ 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): + def _read_group_prepare(self, orderby, aggregated_fields, groupby, qualified_groupby_field, query, groupby_type=None): """ - Generates the ORDER BY sql clause for the read group method. Adds the missing JOIN clause + Prepares the GROUP BY and ORDER BY terms 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 + :param qualified_groupby_field: the fully qualified SQL name for the grouped field + :param osv.Query query: the query under construction + :param groupby_type: the type of the grouped field + :return: (groupby_terms, orderby_terms) """ - 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)) + orderby_terms = [] + groupby_terms = [qualified_groupby_field] if groupby else [] + if not orderby: + return groupby_terms, orderby_terms - if orderby_list: - return ' ORDER BY %s' % (','.join(orderby_list)), ob and ','.join(ob) or '' - else: - return '', '' + self._check_qorder(orderby) + for order_part in orderby.split(','): + order_split = order_part.split() + order_field = order_split[0] + if order_field == groupby: + if groupby_type == 'many2one': + order_clause = self._generate_order_by(order_part, query).replace('ORDER BY ', '') + if order_clause: + orderby_terms.append(order_clause) + groupby_terms += [order_term.split()[0] for order_term in order_clause.split(',')] + else: + orderby_terms.append(order_part) + elif order_field in aggregated_fields: + orderby_terms.append(order_part) + else: + # Cannot order by a field that will not appear in the results (needs to be grouped or aggregated) + _logger.warn('%s: read_group order by `%s` ignored, cannot sort on empty columns (not grouped/aggregated)', + self._name, order_part) + return groupby_terms, orderby_terms def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False): """ @@ -2275,9 +2281,9 @@ class BaseModel(object): # TODO it seems fields_get can be replaced by _all_columns (no need for translation) fget = self.fields_get(cr, uid, fields) - flist = '' - group_count = group_by = groupby group_by_params = {} + select_terms = [] + groupby_type = None if groupby: if fget.get(groupby): groupby_type = fget[groupby]['type'] @@ -2305,12 +2311,9 @@ class BaseModel(object): 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 - flist = "%s as %s " % (qualified_groupby_field, groupby) - else: - flist = qualified_groupby_field + select_terms.append("%s as %s " % (qualified_groupby_field, groupby)) else: # Don't allow arbitrary values, as this would be a SQL injection vector! raise except_orm(_('Invalid group_by'), @@ -2318,34 +2321,48 @@ class BaseModel(object): aggregated_fields = [ f for f in fields - if f not in ('id', 'sequence') + if f not in ('id', 'sequence', groupby) if fget[f]['type'] in ('integer', 'float') 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 = self._inherits_join_calc(f, query) - flist += "%s(%s) AS %s" % (group_operator, qualified_field, f) + select_terms.append("%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 '' + order = orderby or groupby or '' + groupby_terms, orderby_terms = self._read_group_prepare(order, aggregated_fields, groupby, qualified_groupby_field, query, groupby_type) from_clause, where_clause, where_clause_params = query.get_sql() - 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 + (ob and ',') + ob + orderby_clause + limit_str + offset_str, where_clause_params) - alldata = {} - groupby = group_by + count_field = '_' + else: + count_field = groupby + prefix_terms = lambda prefix, terms: (prefix + " " + ",".join(terms)) if terms else '' + prefix_term = lambda prefix, term: ('%s %s' % (prefix, term)) if term else '' + + query = """ + SELECT min(%(table)s.id) AS id, count(%(table)s.id) AS %(count_field)s_count + %(extra_fields)s + FROM %(from)s + %(where)s + %(groupby)s + %(orderby)s + %(limit)s + %(offset)s + """ % { + 'table': self._table, + 'count_field': count_field, + 'extra_fields': prefix_terms(',', select_terms), + 'from': from_clause, + 'where': prefix_term('WHERE', where_clause), + 'groupby': prefix_terms('GROUP BY', groupby_terms), + 'orderby': prefix_terms('ORDER BY', orderby_terms), + 'limit': prefix_term('LIMIT', int(limit) if limit else None), + 'offset': prefix_term('OFFSET', int(offset) if limit else None), + } + cr.execute(query, where_clause_params) + alldata = {} fetched_data = cr.dictfetchall() data_ids = [] @@ -2356,8 +2373,6 @@ class BaseModel(object): data_ids.append(r['id']) del r['id'] - - if groupby: data = self.read(cr, uid, data_ids, [groupby], context=context) # restore order of the search as read() uses the default _order (this is only for groups, so the footprint of data should be small): @@ -2847,7 +2862,7 @@ class BaseModel(object): msg = "Table '%s': dropping index for column '%s' of type '%s' as it is not required anymore" _schema.debug(msg, self._table, k, f._type) - if isinstance(f, fields.many2one): + if isinstance(f, fields.many2one) or (isinstance(f, fields.function) and f._type == 'many2one' and f.store): dest_model = self.pool[f._obj] if dest_model._table != 'ir_actions': self._m2o_fix_foreign_key(cr, self._table, k, dest_model, f.ondelete) @@ -2882,7 +2897,7 @@ class BaseModel(object): todo_end.append((order, self._update_store, (f, k))) # and add constraints if needed - if isinstance(f, fields.many2one): + if isinstance(f, fields.many2one) or (isinstance(f, fields.function) and f._type == 'many2one' and f.store): if f._obj not in self.pool: raise except_orm('Programming Error', 'There is no reference available for %s' % (f._obj,)) dest_model = self.pool[f._obj] diff --git a/openerp/service/db.py b/openerp/service/db.py index f48a1e6e91b..bb97e72f992 100644 --- a/openerp/service/db.py +++ b/openerp/service/db.py @@ -1,12 +1,15 @@ # -*- coding: utf-8 -*- - -import base64 -import contextlib +from contextlib import closing +from functools import wraps import logging import os +import shutil import threading import traceback -from contextlib import contextmanager, closing +import tempfile +import zipfile + +import psycopg2 import openerp from openerp import SUPERUSER_ID @@ -28,7 +31,8 @@ def _initialize_db(id, db_name, demo, lang, user_password): self_actions[id]['progress'] = 0 db = openerp.sql_db.db_connect(db_name) with closing(db.cursor()) as cr: - openerp.modules.db.initialize(cr) # TODO this should be removed as it is done by RegistryManager.new(). + # TODO this should be removed as it is done by RegistryManager.new(). + openerp.modules.db.initialize(cr) openerp.tools.config['lang'] = lang cr.commit() @@ -55,14 +59,13 @@ def _initialize_db(id, db_name, demo, lang, user_password): self_actions[id]['traceback'] = traceback.format_exc() def dispatch(method, params): - if method in [ 'create', 'get_progress', 'drop', 'dump', - 'restore', 'rename', - 'change_admin_password', 'migrate_databases', - 'create_database', 'duplicate_database' ]: + if method in ['create', 'get_progress', 'drop', 'dump', 'restore', 'rename', + 'change_admin_password', 'migrate_databases', + 'create_database', 'duplicate_database']: passwd = params[0] params = params[1:] security.check_super(passwd) - elif method in [ 'db_exist', 'list', 'list_lang', 'server_version' ]: + elif method in ['db_exist', 'list', 'list_lang', 'server_version']: # params = params # No security check for these methods pass @@ -78,9 +81,9 @@ def _create_empty_database(name): cr.execute("SELECT datname FROM pg_database WHERE datname = %s", (name,)) if cr.fetchall(): - raise openerp.exceptions.Warning(" %s database already exists!" % name ) + raise openerp.exceptions.Warning("database %r already exists!" % (name,)) else: - cr.autocommit(True) # avoid transaction block + cr.autocommit(True) # avoid transaction block cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "%s" """ % (name, chosen_template)) def exp_create(db_name, demo, lang, user_password='admin'): @@ -96,7 +99,7 @@ def exp_create(db_name, demo, lang, user_password='admin'): _logger.info('CREATE DATABASE %s', db_name.lower()) create_thread = threading.Thread(target=_initialize_db, - args=(id, db_name, demo, lang, user_password)) + args=(id, db_name, demo, lang, user_password)) create_thread.start() self_actions[id]['thread'] = create_thread return id @@ -121,14 +124,19 @@ def exp_duplicate_database(db_original_name, db_name): openerp.sql_db.close_db(db_original_name) db = openerp.sql_db.db_connect('postgres') with closing(db.cursor()) as cr: - cr.autocommit(True) # avoid transaction block + cr.autocommit(True) # avoid transaction block cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "%s" """ % (db_name, db_original_name)) + + from_fs = openerp.tools.config.filestore(db_original_name) + to_fs = openerp.tools.config.filestore(db_name) + if os.path.exists(from_fs) and not os.path.exists(to_fs): + shutil.copy(from_fs, to_fs) return True def exp_get_progress(id): if self_actions[id]['thread'].isAlive(): # return openerp.modules.init_progress[db_name] - return min(self_actions[id].get('progress', 0),0.95), [] + return min(self_actions[id].get('progress', 0), 0.95), [] else: clean = self_actions[id]['clean'] if clean: @@ -140,9 +148,9 @@ def exp_get_progress(id): self_actions.pop(id) return 1.0, users else: - e = self_actions[id]['exception'] # TODO this seems wrong: actions[id]['traceback'] is set, but not 'exception'. - self_actions.pop(id) - raise Exception, e + a = self_actions.pop(id) + exc, tb = a['exception'], a['traceback'] + raise Exception, exc, tb def exp_drop(db_name): if db_name not in exp_list(True): @@ -152,18 +160,17 @@ def exp_drop(db_name): db = openerp.sql_db.db_connect('postgres') with closing(db.cursor()) as cr: - cr.autocommit(True) # avoid transaction block + cr.autocommit(True) # avoid transaction block # Try to terminate all other connections that might prevent # dropping the database try: - # PostgreSQL 9.2 renamed pg_stat_activity.procpid to pid: # http://www.postgresql.org/docs/9.2/static/release-9-2.html#AEN110389 pid_col = 'pid' if cr._cnx.server_version >= 90200 else 'procpid' cr.execute("""SELECT pg_terminate_backend(%(pid_col)s) FROM pg_stat_activity - WHERE datname = %%s AND + WHERE datname = %%s AND %(pid_col)s != pg_backend_pid()""" % {'pid_col': pid_col}, (db_name,)) except Exception: @@ -176,96 +183,146 @@ def exp_drop(db_name): raise Exception("Couldn't drop database %s: %s" % (db_name, e)) else: _logger.info('DROP DB: %s', db_name) + + fs = openerp.tools.config.filestore(db_name) + if os.path.exists(fs): + shutil.rmtree(fs) return True -@contextlib.contextmanager -def _set_pg_password_in_environment(): +def _set_pg_password_in_environment(func): """ On systems where pg_restore/pg_dump require an explicit password (i.e. when not connecting via unix sockets, and most importantly on Windows), it is necessary to pass the PG user password in the environment or in a special .pgpass file. - This context management method handles setting + This decorator handles setting :envvar:`PGPASSWORD` if it is not already set, and removing it afterwards. See also http://www.postgresql.org/docs/8.4/static/libpq-envars.html - + .. note:: This is not thread-safe, and should never be enabled for SaaS (giving SaaS users the super-admin password is not a good idea anyway) """ - if os.environ.get('PGPASSWORD') or not openerp.tools.config['db_password']: - yield - else: - os.environ['PGPASSWORD'] = openerp.tools.config['db_password'] - try: - yield - finally: - del os.environ['PGPASSWORD'] - + @wraps(func) + def wrapper(*args, **kwargs): + if os.environ.get('PGPASSWORD') or not openerp.tools.config['db_password']: + return func(*args, **kwargs) + else: + os.environ['PGPASSWORD'] = openerp.tools.config['db_password'] + try: + return func(*args, **kwargs) + finally: + del os.environ['PGPASSWORD'] + return wrapper def exp_dump(db_name): - with _set_pg_password_in_environment(): - cmd = ['pg_dump', '--format=c', '--no-owner'] + with tempfile.TemporaryFile() as t: + dump_db(db_name, t) + t.seek(0) + return t.read().encode('base64') + +@_set_pg_password_in_environment +def dump_db(db, stream): + """Dump database `db` into file-like object `stream`""" + with openerp.tools.osutil.tempdir() as dump_dir: + registry = openerp.modules.registry.RegistryManager.get(db) + with registry.cursor() as cr: + filestore = registry['ir.attachment']._filestore(cr, SUPERUSER_ID) + if os.path.exists(filestore): + shutil.copytree(filestore, os.path.join(dump_dir, 'filestore')) + + dump_file = os.path.join(dump_dir, 'dump.sql') + cmd = ['pg_dump', '--format=p', '--no-owner', '--file=' + dump_file] if openerp.tools.config['db_user']: cmd.append('--username=' + openerp.tools.config['db_user']) if openerp.tools.config['db_host']: cmd.append('--host=' + openerp.tools.config['db_host']) if openerp.tools.config['db_port']: cmd.append('--port=' + str(openerp.tools.config['db_port'])) - cmd.append(db_name) + cmd.append(db) - stdin, stdout = openerp.tools.exec_pg_command_pipe(*tuple(cmd)) - stdin.close() - data = stdout.read() - res = stdout.close() + if openerp.tools.exec_pg_command(*cmd): + _logger.error('DUMP DB: %s failed! Please verify the configuration of the database ' + 'password on the server. You may need to create a .pgpass file for ' + 'authentication, or specify `db_password` in the server configuration ' + 'file.', db) + raise Exception("Couldn't dump database") - if not data or res: - _logger.error( - 'DUMP DB: %s failed! Please verify the configuration of the database password on the server. ' - 'You may need to create a .pgpass file for authentication, or specify `db_password` in the ' - 'server configuration file.\n %s', db_name, data) - raise Exception, "Couldn't dump database" - _logger.info('DUMP DB successful: %s', db_name) + openerp.tools.osutil.zip_dir(dump_dir, stream, include_dir=False) - return base64.encodestring(data) + _logger.info('DUMP DB successful: %s', db) -def exp_restore(db_name, data): - with _set_pg_password_in_environment(): - if exp_db_exist(db_name): - _logger.warning('RESTORE DB: %s already exists', db_name) - raise Exception, "Database already exists" +def exp_restore(db_name, data, copy=False): + data_file = tempfile.NamedTemporaryFile(delete=False) + try: + data_file.write(data.decode('base64')) + data_file.close() + restore_db(db_name, data_file.name, copy=copy) + finally: + os.unlink(data_file.name) + return True - _create_empty_database(db_name) +@_set_pg_password_in_environment +def restore_db(db, dump_file, copy=False): + assert isinstance(db, basestring) + if exp_db_exist(db): + _logger.warning('RESTORE DB: %s already exists', db) + raise Exception("Database already exists") - cmd = ['pg_restore', '--no-owner'] + _create_empty_database(db) + + filestore_path = None + with openerp.tools.osutil.tempdir() as dump_dir: + if zipfile.is_zipfile(dump_file): + # v8 format + with zipfile.ZipFile(dump_file, 'r') as z: + # only extract known members! + filestore = [m for m in z.namelist() if m.startswith('filestore/')] + z.extractall(dump_dir, ['dump.sql'] + filestore) + + if filestore: + filestore_path = os.path.join(dump_dir, 'filestore') + + pg_cmd = 'psql' + pg_args = ['-q', '-f', os.path.join(dump_dir, 'dump.sql')] + + else: + # <= 7.0 format (raw pg_dump output) + pg_cmd = 'pg_restore' + pg_args = ['--no-owner', dump_file] + + args = [] if openerp.tools.config['db_user']: - cmd.append('--username=' + openerp.tools.config['db_user']) + args.append('--username=' + openerp.tools.config['db_user']) if openerp.tools.config['db_host']: - cmd.append('--host=' + openerp.tools.config['db_host']) + args.append('--host=' + openerp.tools.config['db_host']) if openerp.tools.config['db_port']: - cmd.append('--port=' + str(openerp.tools.config['db_port'])) - cmd.append('--dbname=' + db_name) - args2 = tuple(cmd) + args.append('--port=' + str(openerp.tools.config['db_port'])) + args.append('--dbname=' + db) + pg_args = args + pg_args - buf=base64.decodestring(data) - if os.name == "nt": - tmpfile = (os.environ['TMP'] or 'C:\\') + os.tmpnam() - file(tmpfile, 'wb').write(buf) - args2=list(args2) - args2.append(tmpfile) - args2=tuple(args2) - stdin, stdout = openerp.tools.exec_pg_command_pipe(*args2) - if not os.name == "nt": - stdin.write(base64.decodestring(data)) - stdin.close() - res = stdout.close() - if res: - raise Exception, "Couldn't restore database" - _logger.info('RESTORE DB: %s', db_name) + if openerp.tools.exec_pg_command(pg_cmd, *pg_args): + raise Exception("Couldn't restore database") - return True + registry = openerp.modules.registry.RegistryManager.new(db) + with registry.cursor() as cr: + if copy: + # if it's a copy of a database, force generation of a new dbuuid + registry['ir.config_parameter'].init(cr, force=True) + if filestore_path: + filestore_dest = registry['ir.attachment']._filestore(cr, SUPERUSER_ID) + shutil.move(filestore_path, filestore_dest) + + if openerp.tools.config['unaccent']: + try: + with cr.savepoint(): + cr.execute("CREATE EXTENSION unaccent") + except psycopg2.Error: + pass + + _logger.info('RESTORE DB: %s', db) def exp_rename(old_name, new_name): openerp.modules.registry.RegistryManager.delete(old_name) @@ -273,15 +330,21 @@ def exp_rename(old_name, new_name): db = openerp.sql_db.db_connect('postgres') with closing(db.cursor()) as cr: - cr.autocommit(True) # avoid transaction block + cr.autocommit(True) # avoid transaction block try: cr.execute('ALTER DATABASE "%s" RENAME TO "%s"' % (old_name, new_name)) _logger.info('RENAME DB: %s -> %s', old_name, new_name) except Exception, e: _logger.error('RENAME DB: %s -> %s failed:\n%s', old_name, new_name, e) raise Exception("Couldn't rename database %s to %s: %s" % (old_name, new_name, e)) + + old_fs = openerp.tools.config.filestore(old_name) + new_fs = openerp.tools.config.filestore(new_name) + if os.path.exists(old_fs) and not os.path.exists(new_fs): + shutil.move(old_fs, new_fs) return True +@openerp.tools.mute_logger('openerp.sql_db') def exp_db_exist(db_name): ## Not True: in fact, check if connection to database is possible. The database may exists return bool(openerp.sql_db.db_connect(db_name)) diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py deleted file mode 100644 index e25e75dba62..00000000000 --- a/openerp/service/http_server.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright P. Christeas 2008-2010 -# Copyright 2010 OpenERP SA. (http://www.openerp.com) -# -# -# WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsibility of assessing all potential -# consequences resulting from its eventual inadequacies and bugs -# End users who are looking for a ready-to-use solution with commercial -# guarantees and support are strongly advised to contract a Free Software -# Service Company -# -# This program is Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -############################################################################### - - -""" This module offers the family of HTTP-based servers. These are not a single - class/functionality, but a set of network stack layers, implementing - extendable HTTP protocols. - - The OpenERP server defines a single instance of a HTTP server, listening at - the standard 8069, 8071 ports (well, it is 2 servers, and ports are - configurable, of course). This "single" server then uses a `MultiHTTPHandler` - to dispatch requests to the appropriate channel protocol, like the XML-RPC, - static HTTP, DAV or other. -""" - -import base64 -import posixpath -import urllib -import os -import logging - -from websrv_lib import * -import openerp.tools as tools - -try: - import fcntl -except ImportError: - fcntl = None - -try: - from ssl import SSLError -except ImportError: - class SSLError(Exception): pass - -_logger = logging.getLogger(__name__) - -# TODO delete this for 6.2, it is still needed for 6.1. -class HttpLogHandler: - """ helper class for uniform log handling - Please define self._logger at each class that is derived from this - """ - _logger = None - - def log_message(self, format, *args): - self._logger.debug(format % args) # todo: perhaps other level - - def log_error(self, format, *args): - self._logger.error(format % args) - - def log_exception(self, format, *args): - self._logger.exception(format, *args) - - def log_request(self, code='-', size='-'): - self._logger.debug('"%s" %s %s', - self.requestline, str(code), str(size)) - -class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler): - _logger = logging.getLogger(__name__) - - _HTTP_OPTIONS = { 'Allow': ['OPTIONS', 'GET', 'HEAD'] } - - def __init__(self,request, client_address, server): - HTTPHandler.__init__(self,request,client_address,server) - document_root = tools.config.get('static_http_document_root', False) - assert document_root, "Please specify static_http_document_root in configuration, or disable static-httpd!" - self.__basepath = document_root - - def translate_path(self, path): - """Translate a /-separated PATH to the local filename syntax. - - Components that mean special things to the local file system - (e.g. drive or directory names) are ignored. (XXX They should - probably be diagnosed.) - - """ - # abandon query parameters - path = path.split('?',1)[0] - path = path.split('#',1)[0] - path = posixpath.normpath(urllib.unquote(path)) - words = path.split('/') - words = filter(None, words) - path = self.__basepath - for word in words: - if word in (os.curdir, os.pardir): continue - path = os.path.join(path, word) - return path - -def init_static_http(): - if not tools.config.get('static_http_enable', False): - return - - document_root = tools.config.get('static_http_document_root', False) - assert document_root, "Document root must be specified explicitly to enable static HTTP service (option --static-http-document-root)" - - base_path = tools.config.get('static_http_url_prefix', '/') - - reg_http_service(base_path, StaticHTTPHandler) - - _logger.info("Registered HTTP dir %s for %s", document_root, base_path) - -import security - -class OpenERPAuthProvider(AuthProvider): - """ Require basic authentication.""" - def __init__(self,realm='OpenERP User'): - self.realm = realm - self.auth_creds = {} - self.auth_tries = 0 - self.last_auth = None - - def authenticate(self, db, user, passwd, client_address): - try: - uid = security.login(db,user,passwd) - if uid is False: - return False - return user, passwd, db, uid - except Exception,e: - _logger.debug("Fail auth: %s" % e ) - return False - - def checkRequest(self,handler,path, db=False): - auth_str = handler.headers.get('Authorization',False) - try: - if not db: - db = handler.get_db_from_path(path) - except Exception: - if path.startswith('/'): - path = path[1:] - psp= path.split('/') - if len(psp)>1: - db = psp[0] - else: - #FIXME! - _logger.info("Wrong path: %s, failing auth" %path) - raise AuthRejectedExc("Authorization failed. Wrong sub-path.") - if self.auth_creds.get(db): - return True - if auth_str and auth_str.startswith('Basic '): - auth_str=auth_str[len('Basic '):] - (user,passwd) = base64.decodestring(auth_str).split(':') - _logger.info("Found user=\"%s\", passwd=\"***\" for db=\"%s\"", user, db) - acd = self.authenticate(db,user,passwd,handler.client_address) - if acd != False: - self.auth_creds[db] = acd - self.last_auth = db - return True - if self.auth_tries > 5: - _logger.info("Failing authorization after 5 requests w/o password") - raise AuthRejectedExc("Authorization failed.") - self.auth_tries += 1 - raise AuthRequiredExc(atype='Basic', realm=self.realm) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index 506a07d0295..5e72ba570b5 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -72,7 +72,7 @@ def xmlrpc_return(start_response, service, method, params, string_faultcode=Fals # This also mimics SimpleXMLRPCDispatcher._marshaled_dispatch() for # exception handling. try: - result = openerp.netsvc.dispatch_rpc(service, method, params) + result = openerp.http.dispatch_rpc(service, method, params) response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None) except Exception, e: if string_faultcode: @@ -164,153 +164,6 @@ def wsgi_xmlrpc(environ, start_response): params, method = xmlrpclib.loads(data) return xmlrpc_return(start_response, service, method, params, string_faultcode) -def wsgi_webdav(environ, start_response): - pi = environ['PATH_INFO'] - if environ['REQUEST_METHOD'] == 'OPTIONS' and pi in ['*','/']: - return return_options(environ, start_response) - elif pi.startswith('/webdav'): - http_dir = websrv_lib.find_http_service(pi) - if http_dir: - path = pi[len(http_dir.path):] - if path.startswith('/'): - environ['PATH_INFO'] = path - else: - environ['PATH_INFO'] = '/' + path - return http_to_wsgi(http_dir)(environ, start_response) - -def return_options(environ, start_response): - # Microsoft specific header, see - # http://www.ibm.com/developerworks/rational/library/2089.html - if 'Microsoft' in environ.get('User-Agent', ''): - options = [('MS-Author-Via', 'DAV')] - else: - options = [] - options += [('DAV', '1 2'), ('Allow', 'GET HEAD PROPFIND OPTIONS REPORT')] - start_response("200 OK", [('Content-Length', str(0))] + options) - return [] - -def http_to_wsgi(http_dir): - """ - Turn a BaseHTTPRequestHandler into a WSGI entry point. - - Actually the argument is not a bare BaseHTTPRequestHandler but is wrapped - (as a class, so it needs to be instanciated) in a HTTPDir. - - This code is adapted from wbsrv_lib.MultiHTTPHandler._handle_one_foreign(). - It is a temporary solution: the HTTP sub-handlers (in particular the - document_webdav addon) have to be WSGIfied. - """ - def wsgi_handler(environ, start_response): - - headers = {} - for key, value in environ.items(): - if key.startswith('HTTP_'): - key = key[5:].replace('_', '-').title() - headers[key] = value - if key == 'CONTENT_LENGTH': - key = key.replace('_', '-').title() - headers[key] = value - if environ.get('Content-Type'): - headers['Content-Type'] = environ['Content-Type'] - - path = urllib.quote(environ.get('PATH_INFO', '')) - if environ.get('QUERY_STRING'): - path += '?' + environ['QUERY_STRING'] - - request_version = 'HTTP/1.1' # TODO - request_line = "%s %s %s\n" % (environ['REQUEST_METHOD'], path, request_version) - - class Dummy(object): - pass - - # Let's pretend we have a server to hand to the handler. - server = Dummy() - server.server_name = environ['SERVER_NAME'] - server.server_port = int(environ['SERVER_PORT']) - - # Initialize the underlying handler and associated auth. provider. - con = openerp.service.websrv_lib.noconnection(environ['wsgi.input']) - handler = http_dir.instanciate_handler(con, environ['REMOTE_ADDR'], server) - - # Populate the handler as if it is called by a regular HTTP server - # and the request is already parsed. - handler.wfile = StringIO.StringIO() - handler.rfile = environ['wsgi.input'] - handler.headers = headers - handler.command = environ['REQUEST_METHOD'] - handler.path = path - handler.request_version = request_version - handler.close_connection = 1 - handler.raw_requestline = request_line - handler.requestline = request_line - - # Handle authentication if there is an auth. provider associated to - # the handler. - if hasattr(handler, 'auth_provider'): - try: - handler.auth_provider.checkRequest(handler, path) - except websrv_lib.AuthRequiredExc, ae: - # Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the - # authorisation features of HTTP/1.1 - if request_version != 'HTTP/1.1' and ('Darwin/9.' not in handler.headers.get('User-Agent', '')): - start_response("403 Forbidden", []) - return [] - start_response("401 Authorization required", [ - ('WWW-Authenticate', '%s realm="%s"' % (ae.atype,ae.realm)), - # ('Connection', 'keep-alive'), - ('Content-Type', 'text/html'), - ('Content-Length', 4), # len(self.auth_required_msg) - ]) - return ['Blah'] # self.auth_required_msg - except websrv_lib.AuthRejectedExc,e: - start_response("403 %s" % (e.args[0],), []) - return [] - - method_name = 'do_' + handler.command - - # Support the OPTIONS method even when not provided directly by the - # handler. TODO I would prefer to remove it and fix the handler if - # needed. - if not hasattr(handler, method_name): - if handler.command == 'OPTIONS': - return return_options(environ, start_response) - start_response("501 Unsupported method (%r)" % handler.command, []) - return [] - - # Finally, call the handler's method. - try: - method = getattr(handler, method_name) - method() - # The DAV handler buffers its output and provides a _flush() - # method. - getattr(handler, '_flush', lambda: None)() - response = parse_http_response(handler.wfile.getvalue()) - response_headers = response.getheaders() - body = response.read() - start_response(str(response.status) + ' ' + response.reason, response_headers) - return [body] - except (websrv_lib.AuthRejectedExc, websrv_lib.AuthRequiredExc): - raise - except Exception, e: - start_response("500 Internal error", []) - return [] - - return wsgi_handler - -def parse_http_response(s): - """ Turn a HTTP response string into a httplib.HTTPResponse object.""" - class DummySocket(StringIO.StringIO): - """ - This is used to provide a StringIO to httplib.HTTPResponse - which, instead of taking a file object, expects a socket and - uses its makefile() method. - """ - def makefile(self, *args, **kw): - return self - response = httplib.HTTPResponse(DummySocket(s)) - response.begin() - return response - # WSGI handlers registered through the register_wsgi_handler() function below. module_handlers = [] # RPC endpoints registered through the register_rpc_endpoint() function below. @@ -342,7 +195,7 @@ def application_unproxied(environ, start_response): del threading.current_thread().dbname # Try all handlers until one returns some result (i.e. not None). - wsgi_handlers = [wsgi_xmlrpc, wsgi_webdav] + wsgi_handlers = [wsgi_xmlrpc] wsgi_handlers += module_handlers for handler in wsgi_handlers: result = handler(environ, start_response) diff --git a/openerp/sql_db.py b/openerp/sql_db.py index 694ae02b3d9..59841656d8c 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -148,7 +148,7 @@ class Cursor(object): def check(f): @wraps(f) def wrapper(self, *args, **kwargs): - if self.__closed: + if self._closed: msg = 'Unable to use a closed cursor.' if self.__closer: msg += ' It was closed at %s, line %s' % self.__closer @@ -165,7 +165,7 @@ class Cursor(object): self.sql_log = _logger.isEnabledFor(logging.DEBUG) self.sql_log_count = 0 - self.__closed = True # avoid the call of close() (by __del__) if an exception + self._closed = True # avoid the call of close() (by __del__) if an exception # is raised by any of the following initialisations self._pool = pool self.dbname = dbname @@ -180,7 +180,7 @@ class Cursor(object): self.__caller = frame_codeinfo(currentframe(),2) else: self.__caller = False - self.__closed = False # real initialisation value + self._closed = False # real initialisation value self.autocommit(False) self.__closer = False @@ -189,7 +189,7 @@ class Cursor(object): self.cache = {} def __del__(self): - if not self.__closed and not self._cnx.closed: + if not self._closed and not self._cnx.closed: # Oops. 'self' has not been closed explicitly. # The cursor will be deleted by the garbage collector, # but the database connection is not put back into the connection @@ -302,7 +302,7 @@ class Cursor(object): # collected as fast as they should). The problem is probably due in # part because browse records keep a reference to the cursor. del self._obj - self.__closed = True + self._closed = True # Clean the underlying connection. self._cnx.rollback() diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 4dcd2938ffe..a53a8d82240 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -15,9 +15,10 @@ import time import unittest2 import urllib2 import xmlrpclib - from datetime import datetime, timedelta +import werkzeug + import openerp _logger = logging.getLogger(__name__) @@ -48,10 +49,9 @@ def acquire_test_cursor(session_id): cr._test_lock.acquire() return cr -def release_test_cursor(session_id): +def release_test_cursor(cr): if openerp.tools.config['test_enable']: - cr = HTTP_SESSION.get(session_id) - if cr: + if hasattr(cr, '_test_lock'): cr._test_lock.release() return True return False @@ -212,7 +212,8 @@ class HttpCase(TransactionCase): # OSError, and no errno/strerror/filename, only a pair of # unnamed arguments (matching errno and strerror) err, _ = e.args - if err == errno.EINTR: continue + if err == errno.EINTR: + continue raise if ready: @@ -224,24 +225,24 @@ class HttpCase(TransactionCase): # process lines if '\n' in buf: line, buf = buf.split('\n', 1) - line = str(line) - if 'CoreText' in line: - continue + + # relay everything from console.log, even 'ok' or 'error...' lines + _logger.info("phantomjs: %s", line) + if line == "ok": break if line.startswith("error"): line_ = line[6:] - try: line_ = json.loads(line_) - except ValueError: pass + # when error occurs the execution stack may be sent as as JSON + 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)) + _logger.info('phantom_run executing %s', ' '.join(cmd)) try: phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError: @@ -252,6 +253,7 @@ class HttpCase(TransactionCase): # kill phantomjs if phantom.exit() wasn't called in the test if phantom.poll() is None: phantom.terminate() + _logger.info("phantom_run execution finished") def phantom_jsfile(self, jsfile, timeout=30, **kw): options = { diff --git a/openerp/tests/phantomtest.js b/openerp/tests/phantomtest.js index 86176402627..5a6a9696cc0 100644 --- a/openerp/tests/phantomtest.js +++ b/openerp/tests/phantomtest.js @@ -6,7 +6,8 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) { (function waitLoop() { if(new Date - start > timeout) { - error(timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms"); + console.log('error', timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms"); + phantom.exit(1); } else if (ready()) { callback(); } else { @@ -15,10 +16,6 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) { }()); } -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]); @@ -49,10 +46,12 @@ function PhantomTest() { })); msg.push('(leaf frame on top)') } - error(JSON.stringify(msg.join('\n'))); + console.log('error', JSON.stringify(msg.join('\n'))); + phantom.exit(1); }; this.page.onAlert = function(message) { - error(message); + console.log('error', message); + phantom.exit(1); }; this.page.onConsoleMessage = function(message) { console.log(message); @@ -78,7 +77,8 @@ function PhantomTest() { if(!found) { console.log('Injecting', src, 'needed for', need); if(!self.page.injectJs(src)) { - error("Cannot inject " + src); + console.log('error', "Cannot inject " + src); + phantom.exit(1); } } } @@ -88,8 +88,9 @@ function PhantomTest() { 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); + + "\n\n" + (document.body && document.body.innerHTML)).replace(/[^a-z0-9\s~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "*"); + console.log('error', message); + phantom.exit(1); }); }, self.timeout); @@ -108,25 +109,28 @@ function PhantomTest() { var url = self.origin + url_path; self.page.open(url, function(status) { if (status !== 'success') { - error("failed to load " + url) + console.log('error', "failed to load " + url); + phantom.exit(1); } else { console.log('loaded', url, status); // process ready waitFor(function() { - console.log("waiting for: calling page evaluate"); + console.log("PhantomTest.run: wait for condition: " + ready); return self.page.evaluate(function (ready) { - console.log("waiting for", ready); var r = false; try { - console.log("waiting for: page evaluating ", ready); + console.log("page.evaluate eval expr:", ready); r = !!eval(ready); - } catch(ex) { } - console.log("waiting for: returning from page evaluate"); + } catch(ex) { + } + console.log("page.evaluate eval result:", r); return r; }, ready); // run test }, function() { + console.log("PhantomTest.run: condition statified, executing: " + code); self.page.evaluate(function (code) { return eval(code); }, code); + console.log("PhantomTest.run: execution launched, waiting for console.log('ok')..."); }); } }); diff --git a/openerp/tools/__init__.py b/openerp/tools/__init__.py index 03e2eda038a..c927b2fc87a 100644 --- a/openerp/tools/__init__.py +++ b/openerp/tools/__init__.py @@ -35,7 +35,7 @@ from yaml_import import * from sql import * from float_utils import * from mail import * - +from debugger import * # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 255a065aa4f..6b21bda8b4f 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +#openerp.loggers.handlers. -*- coding: utf-8 -*- ############################################################################## # # OpenERP, Open Source Management Solution @@ -76,9 +76,10 @@ class configmanager(object): } # Not exposed in the configuration file. - self.blacklist_for_save = set( - ['publisher_warranty_url', 'load_language', 'root_path', - 'init', 'save', 'config', 'update', 'stop_after_init']) + self.blacklist_for_save = set([ + 'publisher_warranty_url', 'load_language', 'root_path', + 'init', 'save', 'config', 'update', 'stop_after_init' + ]) # dictionary mapping option destination (keys in self.options) to MyOptions. self.casts = {} @@ -87,7 +88,10 @@ class configmanager(object): self.config_file = fname self.has_ssl = check_ssl() - self._LOGLEVELS = dict([(getattr(loglevels, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET')]) + self._LOGLEVELS = dict([ + (getattr(loglevels, 'LOG_%s' % x), getattr(logging, x)) + for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET') + ]) version = "%s %s" % (release.description, release.version) self.parser = parser = optparse.OptionParser(version=version, option_class=MyOption) @@ -148,19 +152,11 @@ class configmanager(object): parser.add_option_group(group) # WEB - # TODO move to web addons after MetaOption merge group = optparse.OptionGroup(parser, "Web interface Configuration") group.add_option("--db-filter", dest="dbfilter", default='.*', help="Filter listed database", metavar="REGEXP") parser.add_option_group(group) - # Static HTTP - group = optparse.OptionGroup(parser, "Static HTTP service") - group.add_option("--static-http-enable", dest="static_http_enable", action="store_true", my_default=False, help="enable static HTTP service for serving plain HTML files") - group.add_option("--static-http-document-root", dest="static_http_document_root", help="specify the directory containing your static HTML files (e.g '/var/www/')") - group.add_option("--static-http-url-prefix", dest="static_http_url_prefix", help="specify the URL root prefix where you want web browsers to access your static HTML files (e.g '/')") - parser.add_option_group(group) - # Testing Group group = optparse.OptionGroup(parser, "Testing Configuration") group.add_option("--test-file", dest="test_file", my_default=False, @@ -179,16 +175,20 @@ class configmanager(object): group.add_option("--logrotate", dest="logrotate", action="store_true", my_default=False, help="enable logfile rotation") group.add_option("--syslog", action="store_true", dest="syslog", my_default=False, help="Send the log to the syslog server") group.add_option('--log-handler', action="append", default=DEFAULT_LOG_HANDLER, my_default=DEFAULT_LOG_HANDLER, metavar="PREFIX:LEVEL", help='setup a handler at LEVEL for a given PREFIX. An empty PREFIX indicates the root logger. This option can be repeated. Example: "openerp.orm:DEBUG" or "werkzeug:CRITICAL" (default: ":INFO")') - group.add_option('--log-request', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.request:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.request:DEBUG') - group.add_option('--log-response', action="append_const", dest="log_handler", const="openerp.netsvc.rpc.response:DEBUG", help='shortcut for --log-handler=openerp.netsvc.rpc.response:DEBUG') - group.add_option('--log-web', action="append_const", dest="log_handler", const="openerp.addons.web.http:DEBUG", help='shortcut for --log-handler=openerp.addons.web.http:DEBUG') + group.add_option('--log-request', action="append_const", dest="log_handler", const="openerp.http.rpc.request:DEBUG", help='shortcut for --log-handler=openerp.http.rpc.request:DEBUG') + group.add_option('--log-response', action="append_const", dest="log_handler", const="openerp.http.rpc.response:DEBUG", help='shortcut for --log-handler=openerp.http.rpc.response:DEBUG') + group.add_option('--log-web', action="append_const", dest="log_handler", const="openerp.http:DEBUG", help='shortcut for --log-handler=openerp.http:DEBUG') group.add_option('--log-sql', action="append_const", dest="log_handler", const="openerp.sql_db:DEBUG", help='shortcut for --log-handler=openerp.sql_db:DEBUG') + group.add_option('--log-db', dest='log_db', help="Logging database", my_default=False) # For backward-compatibility, map the old log levels to something # quite close. - levels = ['info', 'debug_rpc', 'warn', 'test', 'critical', - 'debug_sql', 'error', 'debug', 'debug_rpc_answer', 'notset'] - group.add_option('--log-level', dest='log_level', type='choice', choices=levels, - my_default='info', help='specify the level of the logging. Accepted values: ' + str(levels) + ' (deprecated option).') + levels = [ + 'info', 'debug_rpc', 'warn', 'test', 'critical', + 'debug_sql', 'error', 'debug', 'debug_rpc_answer', 'notset' + ] + group.add_option('--log-level', dest='log_level', type='choice', + choices=levels, my_default='info', + help='specify the level of the logging. Accepted values: %s (deprecated option).' % (levels,)) parser.add_option_group(group) @@ -305,9 +305,10 @@ class configmanager(object): self.options[option.dest] = option.my_default self.casts[option.dest] = option - self.parse_config(None, False) + # generate default config + self._parse_config() - def parse_config(self, args=None, complete=True): + def parse_config(self, args=None): """ Parse the configuration file (if any) and the command-line arguments. @@ -321,10 +322,12 @@ class configmanager(object): Typical usage of this method: openerp.tools.config.parse_config(sys.argv[1:]) - - :param complete: this is a hack used in __init__(), leave it to True. - """ + self._parse_config(args) + openerp.netsvc.init_logger() + openerp.modules.module.initialize_sys_path() + + def _parse_config(self, args=None): if args is None: args = [] opt, args = self.parser.parse_args(args) @@ -383,8 +386,7 @@ class configmanager(object): 'db_maxconn', 'import_partial', 'addons_path', 'xmlrpc', 'syslog', 'without_demo', 'timezone', 'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs', - 'static_http_enable', 'static_http_document_root', 'static_http_url_prefix', - 'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level' + 'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level', 'log_db' ] for arg in keys: @@ -495,8 +497,6 @@ class configmanager(object): openerp.conf.server_wide_modules = map(lambda m: m.strip(), opt.server_wide_modules.split(',')) else: openerp.conf.server_wide_modules = ['web','web_kanban'] - if complete: - openerp.modules.module.initialize_sys_path() def _generate_pgpassfile(self): """ @@ -654,6 +654,9 @@ class configmanager(object): os.chmod(d, 0700) return d + def filestore(self, dbname): + return os.path.join(self['data_dir'], 'filestore', dbname) + config = configmanager() diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index 43ee96660bd..a4231529b8f 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -857,12 +857,12 @@ form: module.record_id""" % (xml_id,) def _tag_template(self, cr, el, data_node=None): # This helper transforms a