bth-openerp
2013-10-29 10:22:54 +05:30
92 changed files with 2731 additions and 818 deletions
+2 -2
View File
@@ -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: 2013-10-11 04:37+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:33+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:39+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:35+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -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: 2013-10-11 04:39+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:35+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:39+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:35+0000\n"
"X-Generator: Launchpad (build 16810)\n"
"X-Poedit-Language: Czech\n"
#. module: base
+2 -2
View File
@@ -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: 2013-10-11 04:39+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:35+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:40+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
"X-Poedit-Country: GREECE\n"
"X-Poedit-Language: Greek\n"
"X-Poedit-SourceCharset: utf-8\n"
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
"Language: \n"
#. module: base
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:40+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
"X-Poedit-Country: IRAN, ISLAMIC REPUBLIC OF\n"
"X-Poedit-Language: Persian\n"
+2 -2
View File
@@ -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: 2013-10-11 04:49+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:40+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:40+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+8 -4
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
"Language: hr\n"
#. module: base
@@ -3994,7 +3994,7 @@ msgstr "12. %w ==> 5 ( Petak je 6ti dan)"
#. module: base
#: constraint:res.partner.category:0
msgid "Error ! You can not create recursive categories."
msgstr "Graška ! Ne može se stvoriti kategorije s rekurzijom."
msgstr "Greška! Ne možete kreirati rekurzivne kategorije."
#. module: base
#: view:res.lang:0
@@ -8815,6 +8815,10 @@ msgid ""
"\n"
"(Document type: %s)"
msgstr ""
"Za ovu vrstu dokumenta imate pravo pristupa samo onima koje ste vi "
"kreirali.\n"
"\n"
"(Vrstu dokumenta: %s)"
#. module: base
#: view:base.language.export:0
@@ -9872,7 +9876,7 @@ msgstr "Kreirano"
#: help:ir.actions.server,model_id:0
msgid ""
"Select the object on which the action will work (read, write, create)."
msgstr "Odaberite objekt na koje će akcija raditi (read, write, create)."
msgstr "Odaberite objekt na koje će akcija raditi (čitaj, piši, kreiraj)."
#. module: base
#: field:base.language.import,name:0
+7 -7
View File
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
"PO-Revision-Date: 2013-03-14 10:08+0000\n"
"Last-Translator: krnkris <Unknown>\n"
"PO-Revision-Date: 2013-10-15 13:13+0000\n"
"Last-Translator: tdombos <Unknown>\n"
"Language-Team: Hungarian <openerp-hungarian-team@lists.launchpad.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-10-11 04:41+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -6230,7 +6230,7 @@ msgstr "Kenya"
#: model:ir.actions.act_window,name:base.action_translation
#: model:ir.ui.menu,name:base.menu_action_translation
msgid "Translated Terms"
msgstr "Lefordított feltételek"
msgstr "Lefordított kifejezések"
#. module: base
#: selection:base.language.install,lang:0
@@ -12491,7 +12491,7 @@ msgstr "This method does not exist anymore"
#: model:ir.actions.act_window,name:base.action_wizard_update_translations
#: model:ir.ui.menu,name:base.menu_wizard_update_translations
msgid "Synchronize Terms"
msgstr "Feltételek szinkronizáása"
msgstr "Kifejezések szinkronizáása"
#. module: base
#: field:res.lang,thousands_sep:0
@@ -13640,7 +13640,7 @@ msgstr "Érvénytelen adatbázis azonosító '%s' ehhez a mezőhöz '%%(field)s'
#. module: base
#: view:res.lang:0
msgid "Update Languague Terms"
msgstr "Nyelvi feltételek frissítése"
msgstr "Nyelvi kifejezések frissítése"
#. module: base
#: field:workflow.activity,join_mode:0
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:37+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+9 -9
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -4448,7 +4448,7 @@ msgstr "メールサーバを特に指定しないメールは最も高い優先
#. module: base
#: model:ir.module.module,summary:base.module_sale
msgid "Quotations, Sales Orders, Invoicing"
msgstr ""
msgstr "見積、受注、請求"
#. module: base
#: field:res.partner,parent_id:0
@@ -5037,7 +5037,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_event_sale
msgid "Events Sales"
msgstr ""
msgstr "イベント販売"
#. module: base
#: model:res.country,name:base.ls
@@ -7967,7 +7967,7 @@ msgstr ""
#: view:res.partner:0
#: field:res.partner,user_id:0
msgid "Salesperson"
msgstr ""
msgstr "営業担当者"
#. module: base
#: view:res.lang:0
@@ -9727,7 +9727,7 @@ msgstr "カスタム"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_margin
msgid "Margins in Sales Orders"
msgstr "受注オーダーのマージン"
msgstr "受注マージン"
#. module: base
#: model:ir.module.module,shortdesc:base.module_purchase
@@ -10478,7 +10478,7 @@ msgstr "この会社に関連した銀行口座"
#: model:ir.ui.menu,name:base.menu_sales
#: model:ir.ui.menu,name:base.next_id_64
msgid "Sales"
msgstr "受注"
msgstr "販売"
#. module: base
#: field:ir.actions.server,child_ids:0
@@ -10814,7 +10814,7 @@ msgstr "ユーザ自身がダッシュボードビュー(Webクライアント
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_stock
msgid "Sales and Warehouse Management"
msgstr ""
msgstr "販売・倉庫管理"
#. module: base
#: model:ir.module.module,description:base.module_hr_recruitment
@@ -15538,7 +15538,7 @@ msgstr "コンテキスト"
#. module: base
#: model:ir.module.module,shortdesc:base.module_sale_mrp
msgid "Sales and MRP Management"
msgstr "受注とMRP管理"
msgstr "販売・MRP管理"
#. module: base
#: model:ir.actions.act_window,help:base.action_partner_form
+2 -2
View File
@@ -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: 2013-10-11 04:40+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:36+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:42+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:38+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+89 -6
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
@@ -12022,6 +12022,31 @@ msgid ""
" Reporting / Accounting / **Follow-ups Analysis\n"
"\n"
msgstr ""
"\n"
"Төлөгдөөгүй нэхэмжлэлүүдэд олон шаттай дуудлаг хийх, захиадал явуулах ажлыг "
"автоматжуулах модуль.\n"
"=========================================================================\n"
"\n"
"Дараах менюгээр олон шатлалтай дуудлагуудыг тодорхойлж болно:\n"
"---------------------------------------------------------------\n"
" Тохиргоо / Мөшгөлтийн Түвшин\n"
" \n"
"Нэгэнт тодорхойлсон бол дараах менюгээр орж дуудлагуудын автоматаар тогтмол "
"хэвлэж болно:\n"
"-----------------------------------------------------------------------------"
"-------------------------\n"
" Төлбөрийн Мөшгөлт / Имэйл болон захидал илгээх\n"
"\n"
"Энэ нь PDF үүсгэх / имэйл илгээх / гар үйлдлүүдийг олон шатлалтай дуудлага "
"дээр үндэслэн үүсгэдэг. \n"
"Ялгаатай компаниудад ялгаатай бодлогыг тодорхойлж болно. \n"
"\n"
"Хэрэв тухайлсан харилцагч/дансны бичилт дээр мөшгөлтийг шалгахыг хүсвэл "
"дараах менюгээр хийх боломжтой:\n"
"-----------------------------------------------------------------------------"
"-------------------------------------\n"
" Тайлан / Санхүү / **Мөшгөлтийн шинжилгээ\n"
"\n"
#. module: base
#: code:addons/base/ir/ir_model.py:735
@@ -12196,6 +12221,20 @@ msgid ""
"You can define the different phases of interviews and easily rate the "
"applicant from the kanban view.\n"
msgstr ""
"\n"
"Ажлын байр, ажилтан авах процессийг удирдана\n"
"================================================\n"
"\n"
"Энэ модуль нь ажлыг хөтлөх, амралтыг хөтлөх, өргөдөл болон ярилцлагыг хөтлөх "
"зэрэг ажлыг хялбараар хийх боломжийг олгодог...\n"
"\n"
"Энэ нь имэйл үүдтэй уялддаг бөгөөд <jobs@yourcompany.com> гэсэн хаяг руу "
"ирсэн имэйлээс өргөдлүүдийг татан авдаг. Мөн баримтын модультай уялдсан "
"байдаг бөгөөд файлаар ирсэн CV-үүдийг хадгалж дараа хайлт хийх боломжийг "
"бүрдүүлдэг. Үүнтэй төстэйгээр Санал асуулга модультай уялдаж ярилцлагыг "
"хөтлөдөг. \n"
"Ярилцлагын ялгаатай шатуудыг тодорхойлж эдгээртээ үнэлгээ өгөх зэрэг ажлыг "
"канбан харагдацаас хялбараар хийж болдог.\n"
#. module: base
#: field:ir.model.fields,model:0
@@ -12242,7 +12281,7 @@ msgstr ""
#. module: base
#: help:res.partner,ean13:0
msgid "BarCode"
msgstr ""
msgstr "Зураасан код"
#. module: base
#: help:ir.model.fields,model_id:0
@@ -12423,7 +12462,7 @@ msgstr "Оффисын Хангамжууд"
#. module: base
#: field:ir.attachment,res_model:0
msgid "Resource Model"
msgstr "Нөөцийн модел"
msgstr "Нөөц модел"
#. module: base
#: code:addons/custom.py:555
@@ -12721,6 +12760,9 @@ msgid ""
"Allow users to sign up through OAuth2 Provider.\n"
"===============================================\n"
msgstr ""
"\n"
"OAuth2-р хэрэглэгчид бүртгүүлэх, нэвтрэх боломжийг олгодог.\n"
"===============================================\n"
#. module: base
#: field:change.password.user,user_id:0
@@ -12744,7 +12786,7 @@ msgstr "Пуэрто Рико"
#. module: base
#: model:ir.module.module,shortdesc:base.module_web_tests_demo
msgid "Demonstration of web/javascript tests"
msgstr ""
msgstr "Веб/javascript тестийн жишээ, үзүүлэн"
#. module: base
#: field:workflow.transition,signal:0
@@ -13076,6 +13118,13 @@ msgid ""
"\n"
"The decimal precision is configured per company.\n"
msgstr ""
"\n"
"Үнийн нарийвчлалыг тохируулахыг олон зорилгоор ашиглаж болно: санхүү, "
"борлуулалт, худалдан авалт\n"
"============================================================================="
"====================\n"
"\n"
"Аравны нарийвчлал нь компанийн хүрээнд хийгдэнэ.\n"
#. module: base
#: selection:res.company,paper_format:0
@@ -13175,6 +13224,9 @@ msgid ""
"(if you delete a native ACL, it will be re-created when you reload the "
"module."
msgstr ""
"Идэвхтэй талбарыг сонгоогүй тохиолдолд ACL-г устгалгүйгээр идэвхгүй болгоно. "
"(Анхны эх ACL-г устгасан байлаа ч модулийг ахин ачаалахад дахин шинээр "
"үүсдэг)"
#. module: base
#: model:ir.model,name:base.model_ir_fields_converter
@@ -13230,6 +13282,17 @@ msgid ""
"into mail.message with attachments.\n"
" "
msgstr ""
"\n"
"Энэ модуль нь Outlook Залгаасыг өгдөг.\n"
"=========================================\n"
"\n"
"Outlook залгаас нь MS Outlook дотороосоо имэйлдээ OpenERP обьекуудтыг \n"
"сонгох хавсаргах боломжийг олгодог. Харилцагч, даалгавар, төсөл, "
"шинжилгээний данс \n"
"гэх мэт дуртай обьектоо сонгож имэйлдээ оруулж mail.message обьектот "
"хавсралтын хамт\n"
"архивладаг.\n"
" "
#. module: base
#: model:ir.module.module,shortdesc:base.module_l10n_bo
@@ -17186,6 +17249,15 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Хаягийн дэвтэртэй холбогч нэмэхээр бол дарна.\n"
" </p><p>\n"
" OpenERP нь захиалагчтай холбоотой бүх үйл ажиллагааг хялбар "
"хөтлөдөг, үүнд: \n"
" захиалагчтай харилцсан харилцаа, бизнес боломжийн түүх, "
"баримтууд гэх мэт.\n"
" </p>\n"
" "
#. module: base
#: model:res.partner.category,name:base.res_partner_category_2
@@ -17228,6 +17300,17 @@ msgid ""
"on a supplier purchase order into several accounts and analytic plans.\n"
" "
msgstr ""
"\n"
"Шинжилгээний тархалт болон худалдан авалтын захиалгын менежментийг хийх "
"суурь модуль.\n"
"====================================================================\n"
"\n"
"Шинжилгээний хэд хэдэн төлөвлөгөөг үүсгэх боломжийг хэрэглэгчид олгодог. Энэ "
"нь нийлүүлэгчийн\n"
"худалдан авалтын захиалгын нэг мөр дээр олон данс болон шинжилгээний "
"төлөвлөгөөг сонгож, хуваах \n"
"боломжийг олгодог.\n"
" "
#. module: base
#: model:res.country,name:base.lk
@@ -17247,7 +17330,7 @@ msgstr "Орос хэл / русский язык"
#. module: base
#: model:ir.module.module,shortdesc:base.module_auth_signup
msgid "Signup"
msgstr ""
msgstr "Бүртгүүлэх"
#, python-format
#~ msgid "new"
+2 -2
View File
@@ -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: 2013-10-11 04:43+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:39+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:35+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:47+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:39+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:38+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:34+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:44+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:40+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:49+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:45+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:41+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:44+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:46+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:42+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+2 -2
View File
@@ -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: 2013-10-11 04:48+0000\n"
"X-Generator: Launchpad (build 16799)\n"
"X-Launchpad-Export-Date: 2013-10-24 04:43+0000\n"
"X-Generator: Launchpad (build 16810)\n"
#. module: base
#: model:ir.module.module,description:base.module_account_check_writing
+6
View File
@@ -262,10 +262,14 @@ class ir_attachment(osv.osv):
return len(result) if count else list(result)
def read(self, cr, uid, ids, fields_to_read=None, context=None, load='_classic_read'):
if isinstance(ids, (int, long)):
ids = [ids]
self.check(cr, uid, ids, 'read', context=context)
return super(ir_attachment, self).read(cr, uid, ids, fields_to_read, context, load)
def write(self, cr, uid, ids, vals, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
self.check(cr, uid, ids, 'write', context=context, values=vals)
if 'file_size' in vals:
del vals['file_size']
@@ -276,6 +280,8 @@ class ir_attachment(osv.osv):
return super(ir_attachment, self).copy(cr, uid, id, default, context)
def unlink(self, cr, uid, ids, context=None):
if isinstance(ids, (int, long)):
ids = [ids]
self.check(cr, uid, ids, 'unlink', context=context)
location = self.pool.get('ir.config_parameter').get_param(cr, uid, 'ir_attachment.location')
if location:
+1 -1
View File
@@ -192,7 +192,7 @@ class ir_fields_converter(orm.Model):
def _str_id(self, cr, uid, model, column, value, context=None):
return value, []
_str_to_char = _str_to_text = _str_to_binary = _str_id
_str_to_reference = _str_to_char = _str_to_text = _str_to_binary = _str_id
def _str_to_date(self, cr, uid, model, column, value, context=None):
try:
+5 -2
View File
@@ -198,6 +198,7 @@ class ir_model(osv.osv):
select=vals.get('select_level', '0'),
update_custom_fields=True)
self.pool[vals['model']]._auto_init(cr, ctx)
self.pool[vals['model']]._auto_end(cr, ctx) # actually create FKs!
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return res
@@ -356,6 +357,7 @@ class ir_model_fields(osv.osv):
select=vals.get('select_level', '0'),
update_custom_fields=True)
self.pool[vals['model']]._auto_init(cr, ctx)
self.pool[vals['model']]._auto_end(cr, ctx) # actually create FKs!
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return res
@@ -470,6 +472,7 @@ class ir_model_fields(osv.osv):
for col_name, col_prop, val in patch_struct[1]:
setattr(obj._columns[col_name], col_prop, val)
obj._auto_init(cr, ctx)
obj._auto_end(cr, ctx) # actually create FKs!
openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname)
return res
@@ -933,8 +936,8 @@ class ir_model_data(osv.osv):
results = cr.fetchall()
for imd_id2,res_id2,real_id2,real_model in results:
if not real_id2:
self._get_id.clear_cache(self, uid, module, xml_id)
self.get_object_reference.clear_cache(self, uid, module, xml_id)
self._get_id.clear_cache(self)
self.get_object_reference.clear_cache(self)
cr.execute('delete from ir_model_data where id=%s', (imd_id2,))
res_id = False
else:
+164 -55
View File
@@ -2,17 +2,18 @@
import cStringIO
import json
import datetime
import dateutil
import dateutil.relativedelta
import logging
import re
import traceback
import urllib
import xml # FIXME use lxml and etree
import Image
import math
import werkzeug.utils
from openerp.osv import osv, orm, fields
import openerp.tools
_logger = logging.getLogger(__name__)
@@ -44,6 +45,13 @@ BUILTINS = {
'relativedelta': lambda *a, **kw : dateutil.relativedelta.relativedelta(*a, **kw),
}
class QWebException(Exception):
def __init__(self, message, template=None, node=None, attribute=None):
self.message = message
self.template = template
self.node = node
self.attribute = attribute
## We use a jinja2 sandboxed environment to render qWeb templates.
#from openerp.tools.safe_eval import safe_eval as eval
#from jinja2.sandbox import SandboxedEnvironment
@@ -52,9 +60,14 @@ BUILTINS = {
#SAFE = ["_name"]
class QWebContext(dict):
def __init__(self, data, undefined_handler=None, loader=None):
def __init__(self, cr, uid, data, undefined_handler=None, loader=None,
templates=None, context=None):
self.cr = cr
self.uid = uid
self.loader = loader
self.undefined_handler = undefined_handler
self.templates = templates or {}
self.context = context
dic = BUILTINS.copy()
dic.update(data)
super(QWebContext, self).__init__(dic)
@@ -90,9 +103,11 @@ class QWebContext(dict):
return eval(expr, None, self)
def copy(self):
return QWebContext(dict.copy(self),
return QWebContext(self.cr, self.uid, dict.copy(self),
undefined_handler=self.undefined_handler,
loader=self.loader)
loader=self.loader,
templates=self.templates,
context=self.context)
def __copy__(self):
return self.copy()
@@ -142,7 +157,6 @@ class QWeb(orm.AbstractModel):
def __init__(self, pool, cr):
super(QWeb, self).__init__(pool, cr)
self._t = {}
self._render_tag = self.prefixed_methods('render_tag_')
self._render_att = self.prefixed_methods('render_att_')
@@ -163,7 +177,7 @@ class QWeb(orm.AbstractModel):
def register_tag(self, tag, func):
self._render_tag[tag] = func
def load_document(self, x):
def load_document(self, x, into):
"""
Loads an XML document and installs any contained template in the engine
"""
@@ -176,15 +190,15 @@ class QWeb(orm.AbstractModel):
for n in dom.documentElement.childNodes:
if n.nodeType == self.node.ELEMENT_NODE and n.getAttribute('t-name'):
self._t[str(n.getAttribute("t-name"))] = n
into[str(n.getAttribute("t-name"))] = n
def get_template(self, name, context):
if context.loader and name not in self._t:
if context.loader and name not in context.templates:
xml_doc = context.loader(name)
self.load_document(xml_doc)
self.load_document(xml_doc, into=context.templates)
if name in self._t:
return self._t[name]
if name in context.templates:
return context.templates[name]
raise KeyError('qweb: template "%s" not found' % name)
@@ -194,7 +208,8 @@ class QWeb(orm.AbstractModel):
except (osv.except_osv, orm.except_orm), err:
raise orm.except_orm("QWeb Error", "Invalid expression %r while rendering template '%s'.\n\n%s" % (expr, v.get('__template__'), err[1]))
except Exception:
raise SyntaxError("QWeb: invalid expression %r while rendering template '%s'.\n\n%s" % (expr, v.get('__template__'), traceback.format_exc()))
raise QWebException("QWeb: invalid expression %r while rendering template '%s'." % (expr, v.get('__template__')),
template=v.get('__template__'))
def eval_object(self, expr, v):
return self.eval(expr, v)
@@ -227,11 +242,13 @@ class QWeb(orm.AbstractModel):
else:
return 0
def render(self, tname, v=None, out=None, loader=None, undefined_handler=None):
def render(self, cr, uid, tname, v=None, loader=None,
undefined_handler=None, context=None):
if v is None:
v = {}
if not isinstance(v, QWebContext):
v = QWebContext(v, undefined_handler=undefined_handler, loader=loader)
v = QWebContext(cr, uid, v, undefined_handler=undefined_handler,
loader=loader, context=context)
v['__template__'] = tname
stack = v.get('__stack__', [])
if stack:
@@ -289,7 +306,16 @@ class QWeb(orm.AbstractModel):
else:
g_inner = []
for n in e.childNodes:
g_inner.append(self.render_node(n, v))
try:
g_inner.append(self.render_node(n, v))
except (osv.except_osv, orm.except_orm), err:
raise err
except QWebException, err:
if not err.node:
err.node = e
raise err
except Exception, err:
raise QWebException("%s" % err, template=v.get('__template__'), node=e)
name = str(e.nodeName)
inner = "".join(g_inner)
trim = t_att.get("trim", 0)
@@ -402,7 +428,7 @@ class QWeb(orm.AbstractModel):
d = v if 'import' in t_att else v.copy()
d[0] = self.render_element(e, t_att, g_att, d)
return self.render(self.eval_format(t_att["call"], d), d)
return self.render(None, None, self.eval_format(t_att["call"], d), d)
def render_tag_set(self, e, t_att, g_att, v):
if "value" in t_att:
@@ -431,8 +457,8 @@ class QWeb(orm.AbstractModel):
converter = self.get_converter_for(field_type)
return converter.to_html(record._cr, record._uid, field_name, record, options,
e, t_att, g_att, v)
return converter.to_html(v.cr, v.uid, field_name, record, options,
e, t_att, g_att, v, context=v.context)
def get_converter_for(self, field_type):
return self.pool.get('ir.qweb.field.' + field_type,
@@ -452,7 +478,8 @@ class FieldConverter(osv.AbstractModel):
_name = 'ir.qweb.field'
def attributes(self, cr, uid, field_name, record, options,
source_element, g_att, t_att, qweb_context):
source_element, g_att, t_att, qweb_context,
context=None):
"""
Generates the metadata attributes (prefixed by ``data-oe-`` for the
root node of the field conversion. Attribute values are escaped by the
@@ -481,20 +508,20 @@ class FieldConverter(osv.AbstractModel):
('data-oe-expression', t_att['field']),
]
def value_to_html(self, cr, uid, value, column, options=None):
def value_to_html(self, cr, uid, value, column, options=None, context=None):
""" Converts a single value to its HTML version/output
"""
return werkzeug.utils.escape(value)
def record_to_html(self, cr, uid, field_name, record, column, options=None):
def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
""" Converts the specified field of the browse_record ``record`` to
HTML
"""
return self.value_to_html(
cr, uid, record[field_name], column, options=None)
cr, uid, record[field_name], column, options=None, context=context)
def to_html(self, cr, uid, field_name, record, options,
source_element, t_att, g_att, qweb_context):
source_element, t_att, g_att, qweb_context, context=None):
""" Converts a ``t-field`` to its HTML output. A ``t-field`` may be
extended by a ``t-field-options``, which is a JSON-serialized mapping
of configuration values.
@@ -507,7 +534,7 @@ class FieldConverter(osv.AbstractModel):
content = self.record_to_html(
cr, uid, field_name, record,
record._model._all_columns[field_name].column,
options)
options, context=context)
except Exception:
_logger.warning("Could not get field %s for model %s",
field_name, record._model._name, exc_info=True)
@@ -532,22 +559,86 @@ class FieldConverter(osv.AbstractModel):
return self.qweb_object().render_element(
source_element, t_att, g_att, qweb_context, content or '')
def user_lang(self, cr, uid, context):
"""
Fetches the res.lang object corresponding to the language code stored
in the user's context. Fallbacks to en_US if no lang is present in the
context *or the language code is not valid*.
:returns: res.lang browse_record
"""
if context is None: context = {}
lang_code = context.get('lang') or 'en_US'
Lang = self.pool['res.lang']
lang_ids = Lang.search(cr, uid, [('code', '=', lang_code)], context=context) \
or Lang.search(cr, uid, [('code', '=', 'en_US')], context=context)
return Lang.browse(cr, uid, lang_ids[0], context=context)
class FloatConverter(osv.AbstractModel):
_name = 'ir.qweb.field.float'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None):
width, precision = column.digits or (None, None)
fmt = '{value}' if precision is None else '{value:.{precision}f}'
def precision(self, cr, uid, column, options=None, context=None):
_, precision = column.digits or (None, None)
return precision
return werkzeug.utils.escape(
fmt.format(value=value, width=width, precision=precision, ))
def value_to_html(self, cr, uid, value, column, options=None, context=None):
precision = self.precision(cr, uid, column, options=options, context=context)
fmt = '%f' if precision is None else '%.{precision}f'
lang = self.user_lang(cr, uid, context)
formatted = lang.format(fmt.format(precision=precision),
value, grouping=True)
# %f does not strip trailing zeroes. %g does but its precision causes
# it to switch to scientific notation starting at a million *and* to
# strip decimals. So use %f and if no precision was specified manually
# strip trailing 0.
if not precision:
formatted = re.sub(r'(?:(0|\d+?)0+)$', r'\1', formatted)
return werkzeug.utils.escape(formatted)
class DateConverter(osv.AbstractModel):
_name = 'ir.qweb.field.date'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None, context=None):
lang = self.user_lang(cr, uid, context=context)
parse_format = openerp.tools.DEFAULT_SERVER_DATE_FORMAT
out_format = lang.date_format.encode('utf-8')
if isinstance(value, basestring):
value = datetime.datetime.strptime(value, parse_format)
return value.strftime(out_format)
class DateTimeConverter(osv.AbstractModel):
_name = 'ir.qweb.field.datetime'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None, context=None):
lang = self.user_lang(cr, uid, context=context)
parse_format = openerp.tools.DEFAULT_SERVER_DATETIME_FORMAT
out_format = (u"%s %s" % (lang.date_format, lang.time_format)).encode('utf-8')
if isinstance(value, basestring):
value = datetime.datetime.strptime(value, parse_format)
value = column.context_timestamp(
cr, uid, timestamp=value, context=context)
return value.strftime(out_format)
class TextConverter(osv.AbstractModel):
_name = 'ir.qweb.field.text'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None):
def value_to_html(self, cr, uid, value, column, options=None, context=None):
"""
Escapes the value and converts newlines to br. This is bullshit.
"""
@@ -557,8 +648,7 @@ class SelectionConverter(osv.AbstractModel):
_name = 'ir.qweb.field.selection'
_inherit = 'ir.qweb.field'
def record_to_html(self, cr, uid, field_name, record, column, options=None):
# FIXME: context
def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
value = record[field_name]
selection = dict(fields.selection.reify(
cr, uid, record._model, column))
@@ -569,16 +659,18 @@ class ManyToOneConverter(osv.AbstractModel):
_name = 'ir.qweb.field.many2one'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None):
def value_to_html(self, cr, uid, value, column, options=None, context=None):
# value may be a browse_null
if not value: return ''
return werkzeug.utils.escape(value.name_get()[0][1]).replace('\n', '<br>\n')
name_got = value._model.name_get(
cr, openerp.SUPERUSER_ID, value.id, context=context)[0][1]
return werkzeug.utils.escape(name_got).replace('\n', '<br>\n')
class HTMLConverter(osv.AbstractModel):
_name = 'ir.qweb.field.html'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None):
def value_to_html(self, cr, uid, value, column, options=None, context=None):
return value
class ImageConverter(osv.AbstractModel):
@@ -593,7 +685,7 @@ class ImageConverter(osv.AbstractModel):
_name = 'ir.qweb.field.image'
_inherit = 'ir.qweb.field'
def value_to_html(self, cr, uid, value, column, options=None):
def value_to_html(self, cr, uid, value, column, options=None, context=None):
try:
image = Image.open(cStringIO.StringIO(value.decode('base64')))
image.verify()
@@ -608,6 +700,10 @@ class MonetaryConverter(osv.AbstractModel):
""" ``monetary`` converter, has a mandatory option
``display_currency``.
The currency is used for formatting *and rounding* of the float value. It
is assumed that the linked res_currency has a non-empty rounding value and
res.currency's ``round`` method is used to perform rounding.
.. note:: the monetary converter internally adds the qweb context to its
options mapping, so that the context is available to callees.
It's set under the ``_qweb_context`` key.
@@ -616,32 +712,45 @@ class MonetaryConverter(osv.AbstractModel):
_inherit = 'ir.qweb.field'
def to_html(self, cr, uid, field_name, record, options,
source_element, t_att, g_att, qweb_context):
source_element, t_att, g_att, qweb_context, context=None):
options['_qweb_context'] = qweb_context
return super(MonetaryConverter, self).to_html(
cr, uid, field_name, record, options,
source_element, t_att, g_att, qweb_context)
source_element, t_att, g_att, qweb_context, context=context)
def record_to_html(self, cr, uid, field_name, record, column, options):
def record_to_html(self, cr, uid, field_name, record, column, options, context=None):
Currency = self.pool['res.currency']
display = self.display_currency(cr, uid, options)
symbol_pre = symbol_post = space_pre = space_post = u''
if display.position == 'before':
space_pre = u' '
symbol_pre = display.symbol
else:
space_post = u' '
symbol_post = display.symbol
# lang.format mandates a sprintf-style format. These formats are non-
# minimal (they have a default fixed precision instead), and
# lang.format will not set one by default. currency.round will not
# provide one either. So we need to generate a precision value
# (integer > 0) from the currency's rounding (a float generally < 1.0).
#
# The log10 of the rounding should be the number of digits involved if
# negative, if positive clamp to 0 digits and call it a day.
# nb: int() ~ floor(), we want nearest rounding instead
precision = int(round(math.log10(display.rounding)))
fmt = "%.{0}f".format(-precision if precision < 0 else 0)
return u'{symbol_pre}{space_pre}' \
u'<span class="oe_currency_value">{0}</span>' \
u'{space_post}{symbol_post}'.format(
Currency.round(cr, uid, display, record[field_name]),
space_pre=space_pre,
symbol_pre=symbol_pre,
space_post=space_post,
symbol_post=symbol_post,)
lang = self.user_lang(cr, uid, context=context)
formatted_amount = lang.format(
fmt, Currency.round(cr, uid, display, record[field_name]),
grouping=True, monetary=True)
pre = post = u''
if display.position == 'before':
pre = u'{symbol} '
else:
post = u' {symbol}'
return u'{pre}<span class="oe_currency_value">{0}</span>{post}'.format(
formatted_amount,
pre=pre, post=post,
).format(
symbol=display.symbol,
)
def display_currency(self, cr, uid, options):
return self.qweb_object().eval_object(
+15 -21
View File
@@ -161,18 +161,18 @@ class ir_translation(osv.osv):
'''
if context is None:
context = {}
res = {}
res = dict.fromkeys(ids, False)
for record in self.browse(cr, uid, ids, context=context):
if record.type != 'model':
res[record.id] = record.src
else:
model_name, field = record.name.split(',')
model = self.pool.get(model_name)
#We need to take the context without the language information, because we want to read the
#value store in db and not on the one associate with current language.
context_wo_lang = context.copy()
context_wo_lang.pop('lang', None)
res[record.id] = model.read(cr, uid, record.res_id, [field], context=context_wo_lang)[field]
if model and model.exists(cr, uid, record.res_id, context=context):
# Pass context without lang, need to read real stored field, not translation
context_no_lang = dict(context, lang=None)
result = model.read(cr, uid, record.res_id, [field], context=context_no_lang)
res[record.id] = result[field] if result else False
return res
def _set_src(self, cr, uid, id, name, value, args, context=None):
@@ -268,13 +268,8 @@ class ir_translation(osv.osv):
return translations
def _set_ids(self, cr, uid, name, tt, lang, ids, value, src=None):
# clear the caches
tr = self._get_ids(cr, uid, name, tt, lang, ids)
for res_id in tr:
if tr[res_id]:
self._get_source.clear_cache(self, uid, name, tt, lang, tr[res_id])
self._get_ids.clear_cache(self, uid, name, tt, lang, res_id)
self._get_source.clear_cache(self, uid, name, tt, lang)
self._get_ids.clear_cache(self)
self._get_source.clear_cache(self)
cr.execute('delete from ir_translation '
'where lang=%s '
@@ -346,8 +341,8 @@ class ir_translation(osv.osv):
if context is None:
context = {}
ids = super(ir_translation, self).create(cr, uid, vals, context=context)
self._get_source.clear_cache(self, uid, vals.get('name',0), vals.get('type',0), vals.get('lang',0), vals.get('src',0))
self._get_ids.clear_cache(self, uid, vals.get('name',0), vals.get('type',0), vals.get('lang',0), vals.get('res_id',0))
self._get_source.clear_cache(self)
self._get_ids.clear_cache(self)
return ids
def write(self, cursor, user, ids, vals, context=None):
@@ -360,9 +355,8 @@ class ir_translation(osv.osv):
if vals.get('value'):
vals.update({'state':'translated'})
result = super(ir_translation, self).write(cursor, user, ids, vals, context=context)
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['res_id'])
self._get_source.clear_cache(self)
self._get_ids.clear_cache(self)
return result
def unlink(self, cursor, user, ids, context=None):
@@ -370,9 +364,9 @@ class ir_translation(osv.osv):
context = {}
if isinstance(ids, (int, long)):
ids = [ids]
for trans_obj in self.read(cursor, user, ids, ['name','type','res_id','src','lang'], context=context):
self._get_source.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['src'])
self._get_ids.clear_cache(self, user, trans_obj['name'], trans_obj['type'], trans_obj['lang'], trans_obj['res_id'])
self._get_source.clear_cache(self)
self._get_ids.clear_cache(self)
result = super(ir_translation, self).unlink(cursor, user, ids, context=context)
return result
@@ -34,6 +34,7 @@
<field name="lang"/>
</group>
<group>
<field name="module" group="base.group_no_one"/>
<field name="type"/>
<field name="res_id"/>
</group>
+4 -3
View File
@@ -775,7 +775,7 @@ class view(osv.osv):
for key in values:
value = isinstance(values, (dict,)) and values[key] or key
if isinstance(value, (browse_record,)):
if value.__dict__.get('_uid') == openerp.SUPERUSER_ID and uid != openerp.SUPERUSER_ID:
if getattr(value, '_uid', None) == openerp.SUPERUSER_ID and uid != openerp.SUPERUSER_ID:
message = 'SUPERUSER_ID Access used for rendering "%s" in a xml view: %s' % (key, id_or_xml_id,)
_logger.warn(message)
elif isinstance(value, (dict, list, browse_record_list,)):
@@ -786,8 +786,9 @@ class view(osv.osv):
return self.read_template(cr, uid, name, context=context)
return self.pool[engine].render(
id_or_xml_id, values,
loader=loader, undefined_handler=lambda key, v: None)
cr, uid, id_or_xml_id, values,
loader=loader, undefined_handler=lambda key, v: None,
context=context)
# maybe used to print the workflow ?
@@ -47,33 +47,8 @@ class base_module_import(osv.osv_memory):
}
def importzip(self, cr, uid, ids, context):
(data,) = self.browse(cr, uid, ids , context=context)
module_data = data.module_file
zip_data = base64.decodestring(module_data)
fp = StringIO()
fp.write(zip_data)
try:
file_data = zipfile.ZipFile(fp, 'r')
except zipfile.BadZipfile:
raise osv.except_osv(_('Error!'), _('File is not a zip file!'))
init_file_name = sorted(file_data.namelist())[0]
module_name = os.path.split(init_file_name)[0]
file_path = os.path.join(ADDONS_PATH, '%s.zip' % module_name)
try:
zip_file = open(file_path, 'wb')
except IOError:
raise osv.except_osv(_('Error!'),
_('Can not create the module file: %s!') % \
(file_path,) )
zip_file.write(zip_data)
zip_file.close()
self.pool.get('ir.module.module').update_list(cr, uid,
{'module_name': module_name,})
self.write(cr, uid, ids, {'state':'done', 'module_name': module_name},
context)
return False
#TODO: drop this model and the corresponding view/action in trunk
raise NotImplementedError('This feature is not available')
def action_module_open(self, cr, uid, ids, context):
(data,) = self.browse(cr, uid, ids , context=context)
+11 -17
View File
@@ -194,30 +194,24 @@ class lang(osv.osv):
def format(self, cr, uid, ids, percent, value, grouping=False, monetary=False, context=None):
""" Format() will return the language-specific output for float values"""
if percent[0] != '%':
raise ValueError("format() must be given exactly one %char format specifier")
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
eval_lang_grouping = eval(lang_grouping)
formatted = percent % value
# floats and decimal ints need special action!
if percent[-1] in 'eEfFgG':
seps = 0
parts = formatted.split('.')
if grouping:
lang_grouping, thousands_sep, decimal_point = \
self._lang_data_get(cr, uid, ids[0], monetary)
eval_lang_grouping = eval(lang_grouping)
if grouping:
parts[0], seps = intersperse(parts[0], eval_lang_grouping, thousands_sep)
if percent[-1] in 'eEfFgG':
parts = formatted.split('.')
parts[0], _ = intersperse(parts[0], eval_lang_grouping, thousands_sep)
formatted = decimal_point.join(parts)
while seps:
sp = formatted.find(' ')
if sp == -1: break
formatted = formatted[:sp] + formatted[sp+1:]
seps -= 1
elif percent[-1] in 'diu':
if grouping:
formatted = decimal_point.join(parts)
elif percent[-1] in 'diu':
formatted = intersperse(formatted, eval_lang_grouping, thousands_sep)[0]
return formatted
-7
View File
@@ -171,13 +171,6 @@ class res_users(osv.osv):
def on_change_login(self, cr, uid, ids, login, context=None):
return {'value': {'email': login}}
def on_change_company_id(self, cr, uid, ids, company_id):
return {'warning' : {
'title': _("Company Switch Warning"),
'message': _("Please keep in mind that documents currently displayed may not be relevant after switching to another company. If you have unsaved changes, please make sure to save and close all forms before switching to a different company. (You can click on Cancel in the User Preferences now)"),
}
}
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)]
return self.pool.get('res.partner').onchange_state(cr, uid, partner_ids, state_id, context=context)
+1 -1
View File
@@ -283,7 +283,7 @@
<field name="lang" readonly="0"/>
<field name="tz" readonly="0"/>
<field name="company_id" widget="selection" readonly="0"
groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/>
groups="base.group_multi_company"/>
</group>
<group string="Email Preferences">
<field name="email" widget="email" readonly="0"/>
@@ -114,6 +114,8 @@
access_ir_qweb,access_ir_qweb,model_ir_qweb,,0,0,0,0
access_ir_qweb_field,access_ir_qweb_field,model_ir_qweb_field,,0,0,0,0
access_ir_qweb_field_float,access_ir_qweb_field_float,model_ir_qweb_field_float,,0,0,0,0
access_ir_qweb_field_date,access_ir_qweb_field_date,model_ir_qweb_field_date,,0,0,0,0
access_ir_qweb_field_datetime,access_ir_qweb_field_datetime,model_ir_qweb_field_datetime,,0,0,0,0
access_ir_qweb_field_text,access_ir_qweb_field_text,model_ir_qweb_field_text,,0,0,0,0
access_ir_qweb_field_selection,access_ir_qweb_field_selection,model_ir_qweb_field_selection,,0,0,0,0
access_ir_qweb_field_many2one,access_ir_qweb_field_many2one,model_ir_qweb_field_many2one,,0,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
114 access_ir_qweb access_ir_qweb model_ir_qweb 0 0 0 0
115 access_ir_qweb_field access_ir_qweb_field model_ir_qweb_field 0 0 0 0
116 access_ir_qweb_field_float access_ir_qweb_field_float model_ir_qweb_field_float 0 0 0 0
117 access_ir_qweb_field_date access_ir_qweb_field_date model_ir_qweb_field_date 0 0 0 0
118 access_ir_qweb_field_datetime access_ir_qweb_field_datetime model_ir_qweb_field_datetime 0 0 0 0
119 access_ir_qweb_field_text access_ir_qweb_field_text model_ir_qweb_field_text 0 0 0 0
120 access_ir_qweb_field_selection access_ir_qweb_field_selection model_ir_qweb_field_selection 0 0 0 0
121 access_ir_qweb_field_many2one access_ir_qweb_field_many2one model_ir_qweb_field_many2one 0 0 0 0
+1098 -28
View File
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -166,11 +166,15 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
# upgrading the module information
modobj.write(cr, SUPERUSER_ID, [module_id], modobj.get_values_from_terp(package.data))
_load_data(cr, module_name, idref, mode, kind='data')
if hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed'):
has_demo = hasattr(package, 'demo') or (package.dbdemo and package.state != 'installed')
if has_demo:
status['progress'] = (index + 0.75) / len(graph)
_load_data(cr, module_name, idref, mode, kind='demo')
cr.execute('update ir_module_module set demo=%s where id=%s', (True, module_id))
migrations.migrate_module(package, 'post')
if has_demo:
# launch tests only in demo mode, as most tests will depend
# on demo data. Other tests can be added into the regular
# 'data' section, but should probably not alter the data,
@@ -186,8 +190,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
processed_modules.append(package.name)
migrations.migrate_module(package, 'post')
ver = adapt_version(package.data['version'])
# Set new modules and dependencies
modobj.write(cr, SUPERUSER_ID, [module_id], {'state': 'installed', 'latest_version': ver})
+4 -4
View File
@@ -305,18 +305,16 @@ class RegistryManager(object):
r, c = cr.fetchone()
# Check if the model registry must be reloaded (e.g. after the
# database has been updated by another process).
if registry.base_registry_signaling_sequence != r:
if registry.base_registry_signaling_sequence > 1 and registry.base_registry_signaling_sequence != r:
changed = True
_logger.info("Reloading the model registry after database signaling.")
registry = cls.new(db_name)
registry.base_registry_signaling_sequence = r
# Check if the model caches must be invalidated (e.g. after a write
# occured on another process). Don't clear right after a registry
# has been reload.
elif registry.base_cache_signaling_sequence != c:
elif registry.base_cache_signaling_sequence > 1 and registry.base_cache_signaling_sequence != c:
changed = True
_logger.info("Invalidating all model caches after database signaling.")
registry.base_cache_signaling_sequence = c
registry.clear_caches()
registry.reset_any_cache_cleared()
# One possible reason caches have been invalidated is the
@@ -326,6 +324,8 @@ class RegistryManager(object):
for column in model._columns.values():
if hasattr(column, 'digits_change'):
column.digits_change(cr)
registry.base_registry_signaling_sequence = r
registry.base_cache_signaling_sequence = c
finally:
cr.close()
return changed
+24 -18
View File
@@ -117,8 +117,7 @@ class _column(object):
self.groups = False # CSV list of ext IDs of groups that can access this field
self.deprecated = False # Optional deprecation warning
for a in args:
if args[a]:
setattr(self, a, args[a])
setattr(self, a, args[a])
def restart(self):
pass
@@ -208,27 +207,29 @@ class reference(_column):
return model.name_get(cr, uid, [int(res_id)], context=context)[0][1]
return tools.ustr(value)
# takes a string (encoded in utf8) and returns a string (encoded in utf8)
def _symbol_set_char(self, symb):
#TODO:
# * we need to remove the "symb==False" from the next line BUT
# for now too many things rely on this broken behavior
# * the symb==None test should be common to all data types
if symb is None or symb == False:
return None
# we need to convert the string to a unicode object to be able
# to evaluate its length (and possibly truncate it) reliably
u_symb = tools.ustr(symb)
return u_symb[:self.size].encode('utf8')
class char(_column):
_type = 'char'
def __init__(self, string="unknown", size=None, **args):
_column.__init__(self, string=string, size=size or None, **args)
self._symbol_set = (self._symbol_c, self._symbol_set_char)
# takes a string (encoded in utf8) and returns a string (encoded in utf8)
def _symbol_set_char(self, symb):
#TODO:
# * we need to remove the "symb==False" from the next line BUT
# for now too many things rely on this broken behavior
# * the symb==None test should be common to all data types
if symb is None or symb == False:
return None
# we need to convert the string to a unicode object to be able
# to evaluate its length (and possibly truncate it) reliably
u_symb = tools.ustr(symb)
return u_symb[:self.size].encode('utf8')
# self._symbol_set_char defined to keep the backward compatibility
self._symbol_f = self._symbol_set_char = lambda x: _symbol_set_char(self, x)
self._symbol_set = (self._symbol_c, self._symbol_f)
class text(_column):
@@ -1150,6 +1151,11 @@ class function(_column):
self._symbol_f = integer._symbol_f
self._symbol_set = integer._symbol_set
if type == 'char':
self._symbol_c = char._symbol_c
self._symbol_f = lambda x: _symbol_set_char(self, x)
self._symbol_set = (self._symbol_c, self._symbol_f)
def digits_change(self, cr):
if self._type == 'float':
if self.digits_compute:
+35 -25
View File
@@ -1010,8 +1010,10 @@ class BaseModel(object):
raise except_orm('Error',
('Invalid function definition %s in object %s !\nYou must use the definition: store={object:(fnct, fields, priority, time length)}.' % (store_field, self._name)))
self.pool._store_function.setdefault(object, [])
self.pool._store_function[object].append((self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length))
self.pool._store_function[object].sort(lambda x, y: cmp(x[4], y[4]))
t = (self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length)
if not t in self.pool._store_function[object]:
self.pool._store_function[object].append((self._name, store_field, fnct, tuple(fields2) if fields2 else None, order, length))
self.pool._store_function[object].sort(lambda x, y: cmp(x[4], y[4]))
for (key, _, msg) in self._sql_constraints:
self.pool._sql_error[self._table+'_'+key] = msg
@@ -2461,8 +2463,12 @@ class BaseModel(object):
"""
Record the creation of a constraint for this model, to make it possible
to delete it later when the module is uninstalled. Type can be either
'f' or 'u' depending on the constraing being a foreign key or not.
'f' or 'u' depending on the constraint being a foreign key or not.
"""
if not self._module:
# no need to save constraints for custom models as they're not part
# of any module
return
assert type in ('f', 'u')
cr.execute("""
SELECT 1 FROM ir_model_constraint, ir_module_module
@@ -4122,9 +4128,9 @@ class BaseModel(object):
return browse_null()
def _store_get_values(self, cr, uid, ids, fields, context):
"""Returns an ordered list of fields.functions to call due to
"""Returns an ordered list of fields.function to call due to
an update operation on ``fields`` of records with ``ids``,
obtained by calling the 'store' functions of these fields,
obtained by calling the 'store' triggers of these fields,
as setup by their 'store' attribute.
:return: [(priority, model_name, [record_ids,], [function_fields,])]
@@ -4133,42 +4139,46 @@ class BaseModel(object):
stored_functions = self.pool._store_function.get(self._name, [])
# use indexed names for the details of the stored_functions:
model_name_, func_field_to_compute_, id_mapping_fnct_, trigger_fields_, priority_ = range(5)
model_name_, func_field_to_compute_, target_ids_func_, trigger_fields_, priority_ = range(5)
# only keep functions that should be triggered for the ``fields``
# only keep store triggers that should be triggered for the ``fields``
# being written to.
to_compute = [f for f in stored_functions \
triggers_to_compute = [f for f in stored_functions \
if ((not f[trigger_fields_]) or set(fields).intersection(f[trigger_fields_]))]
mapping = {}
for function in to_compute:
# use admin user for accessing objects having rules defined on store fields
target_ids = [id for id in function[id_mapping_fnct_](self, cr, SUPERUSER_ID, ids, context) if id]
to_compute_map = {}
target_id_results = {}
for store_trigger in triggers_to_compute:
target_func_id_ = id(store_trigger[target_ids_func_])
if not target_func_id_ in target_id_results:
# use admin user for accessing objects having rules defined on store fields
target_id_results[target_func_id_] = [i for i in store_trigger[target_ids_func_](self, cr, SUPERUSER_ID, ids, context) if i]
target_ids = target_id_results[target_func_id_]
# the compound key must consider the priority and model name
key = (function[priority_], function[model_name_])
key = (store_trigger[priority_], store_trigger[model_name_])
for target_id in target_ids:
mapping.setdefault(key, {}).setdefault(target_id,set()).add(tuple(function))
to_compute_map.setdefault(key, {}).setdefault(target_id,set()).add(tuple(store_trigger))
# Here mapping looks like:
# { (10, 'model_a') : { target_id1: [ (function_1_tuple, function_2_tuple) ], ... }
# (20, 'model_a') : { target_id2: [ (function_3_tuple, function_4_tuple) ], ... }
# (99, 'model_a') : { target_id1: [ (function_5_tuple, function_6_tuple) ], ... }
# Here to_compute_map looks like:
# { (10, 'model_a') : { target_id1: [ (trigger_1_tuple, trigger_2_tuple) ], ... }
# (20, 'model_a') : { target_id2: [ (trigger_3_tuple, trigger_4_tuple) ], ... }
# (99, 'model_a') : { target_id1: [ (trigger_5_tuple, trigger_6_tuple) ], ... }
# }
# Now we need to generate the batch function calls list
# call_map =
# { (10, 'model_a') : [(10, 'model_a', [record_ids,], [function_fields,])] }
call_map = {}
for ((priority,model), id_map) in mapping.iteritems():
functions_ids_maps = {}
for ((priority,model), id_map) in to_compute_map.iteritems():
trigger_ids_maps = {}
# function_ids_maps =
# { (function_1_tuple, function_2_tuple) : [target_id1, target_id2, ..] }
for id, functions in id_map.iteritems():
functions_ids_maps.setdefault(tuple(functions), []).append(id)
for functions, ids in functions_ids_maps.iteritems():
call_map.setdefault((priority,model),[]).append((priority, model, ids,
[f[func_field_to_compute_] for f in functions]))
for target_id, triggers in id_map.iteritems():
trigger_ids_maps.setdefault(tuple(triggers), []).append(target_id)
for triggers, target_ids in trigger_ids_maps.iteritems():
call_map.setdefault((priority,model),[]).append((priority, model, target_ids,
[t[func_field_to_compute_] for t in triggers]))
ordered_keys = call_map.keys()
ordered_keys.sort()
result = []
@@ -53,6 +53,12 @@ class TestIntegerExport(TestBasicExport):
self.assertEqual(value, "42")
class TestFloatExport(TestBasicExport):
def setUp(self):
super(TestFloatExport, self).setUp()
self.registry('res.lang').write(self.cr, self.uid, [1], {
'grouping': '[3,0]'
})
def test_float(self):
converter = self.get_converter('float')
@@ -65,6 +71,9 @@ class TestFloatExport(TestBasicExport):
value = converter(42.01234)
self.assertEqual(value, "42.01234")
value = converter(1234567.89)
self.assertEqual(value, '1,234,567.89')
def test_numeric(self):
converter = self.get_converter('numeric')
@@ -98,7 +107,7 @@ class TestCurrencyExport(TestExport):
self.cr, self.uid, 'value', obj, options,
doc.createElement('span'),
{'field': 'obj.value', 'field-options': json.dumps(options)},
'', ir_qweb.QWebContext({'obj': obj, 'c2': dest, }))
'', ir_qweb.QWebContext(self.cr, self.uid, {'obj': obj, 'c2': dest, }))
return converted
def test_currency_post(self):
@@ -263,5 +272,30 @@ class TestHTMLExport(TestBasicExport):
value = converter(input)
self.assertEqual(value, input)
class TestDatetimeExport(TestBasicExport):
def setUp(self):
super(TestDatetimeExport, self).setUp()
# set user tz to known value
Users = self.registry('res.users')
Users.write(self.cr, self.uid, self.uid, {
'tz': 'Pacific/Niue'
}, context=None)
def test_date(self):
converter = self.get_converter('date')
value = converter('2011-05-03')
# default lang/format is US
self.assertEqual(value, '05/03/2011')
def test_datetime(self):
converter = self.get_converter('datetime')
value = converter('2011-05-03 11:12:13')
# default lang/format is US
self.assertEqual(value, '05/03/2011 00:12:13')
# o2m, m2m?
# reference?
+66
View File
@@ -149,6 +149,59 @@ class TestCleaner(unittest2.TestCase):
for text in out_lst:
self.assertNotIn(text, new_html, 'html_email_cleaner did not remove unwanted content')
def test_05_shorten(self):
# TEST: shorten length
test_str = '''<div>
<span>
</span>
<p>Hello, <span>Raoul</span>
<bold>You</bold> are
pretty</p>
<span>Really</span>
</div>
'''
# shorten at 'H' of Hello -> should shorten after Hello,
html = html_email_clean(test_str, shorten=True, max_length=1, remove=True)
self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('Raoul', html, 'html_email_cleaner: shorten error or too long')
self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion')
# shorten at 'are' -> should shorten after are
html = html_email_clean(test_str, shorten=True, max_length=17, remove=True)
self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('Raoul', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('are', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('pretty', html, 'html_email_cleaner: shorten error or too long')
self.assertNotIn('Really', html, 'html_email_cleaner: shorten error or too long')
self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion')
# TEST: shorten in quote
test_str = '''<div> Blahble
bluih blouh
<blockquote>This is a quote
<span>And this is quite a long quote, after all.</span>
</blockquote>
</div>'''
# shorten in the quote
html = html_email_clean(test_str, shorten=True, max_length=25, remove=True)
self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long')
self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion')
# shorten in second word
html = html_email_clean(test_str, shorten=True, max_length=9, remove=True)
self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('blouh', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long')
self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion')
# shorten waaay too large
html = html_email_clean(test_str, shorten=True, max_length=900, remove=True)
self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short')
self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short')
self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long')
def test_10_email_text(self):
""" html_email_clean test for text-based emails """
new_html = html_email_clean(test_mail_examples.TEXT_1, remove=True)
@@ -257,6 +310,19 @@ class TestCleaner(unittest2.TestCase):
'tasks using the gantt chart and control deadlines']:
self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options')
def test_70_read_more(self):
new_html = html_email_clean(test_mail_examples.BUG1, remove=True, shorten=True, max_length=100)
for ext in test_mail_examples.BUG_1_IN:
self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed valid content')
for ext in test_mail_examples.BUG_1_OUT:
self.assertNotIn(ext, new_html, 'html_email_cleaner did not removed invalid content')
new_html = html_email_clean(test_mail_examples.BUG2, remove=True, shorten=True, max_length=250)
for ext in test_mail_examples.BUG_2_IN:
self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed valid content')
for ext in test_mail_examples.BUG_2_OUT:
self.assertNotIn(ext, new_html, 'html_email_cleaner did not removed invalid content')
def test_90_misc(self):
# False boolean for text must return empty string
new_html = html_email_clean(False)
+319
View File
@@ -785,3 +785,322 @@ MSOFFICE_3 = """<div>
MSOFFICE_3_IN = ['I saw your boss yesterday']
MSOFFICE_3_OUT = ['I noticed you recently downloaded OpenERP.', 'You indicated that you wish', 'Belgium: +32.81.81.37.00']
# ------------------------------------------------------------
# Test cases coming from bugs
# ------------------------------------------------------------
# bug: read more not apparent, strange message in read more span
BUG1 = """<pre>Hi Migration Team,
Paragraph 1, blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah.
Paragraph 2, blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah.
Paragraph 3, blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah blah blah blah blah blah blah
blah blah blah blah blah blah blah blah.
Thanks.
Regards,
--
Olivier Laurent
Migration Manager
OpenERP SA
Chaussée de Namur, 40
B-1367 Gérompont
Tel: +32.81.81.37.00
Web: http://www.openerp.com</pre>"""
BUG_1_IN = [
'Hi Migration Team',
'Paragraph 1'
]
BUG_1_OUT = [
'Olivier Laurent',
'Chaussée de Namur',
'81.81.37.00',
'openerp.com',
]
BUG2 = """
<div>
<br>
<div class="moz-forward-container"><br>
<br>
-------- Original Message --------
<table class="moz-email-headers-table" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Subject:
</th>
<td>Fwd: TR: OpenERP S.A. Payment Reminder</td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Date: </th>
<td>Wed, 16 Oct 2013 14:11:13 +0200</td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">From: </th>
<td>Christine Herrmann <a class="moz-txt-link-rfc2396E" href="mailto:che@openerp.com">&lt;che@openerp.com&gt;</a></td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">To: </th>
<td><a class="moz-txt-link-abbreviated" href="mailto:online@openerp.com">online@openerp.com</a></td>
</tr>
</tbody>
</table>
<br>
<br>
<br>
<div class="moz-forward-container"><br>
<br>
-------- Message original --------
<table class="moz-email-headers-table" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Sujet:
</th>
<td>TR: OpenERP S.A. Payment Reminder</td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Date&nbsp;:
</th>
<td>Wed, 16 Oct 2013 10:34:45 -0000</td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">De&nbsp;: </th>
<td>Ida Siwatala <a class="moz-txt-link-rfc2396E" href="mailto:infos@inzoservices.com">&lt;infos@inzoservices.com&gt;</a></td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Répondre
à&nbsp;: </th>
<td><a class="moz-txt-link-abbreviated" href="mailto:catchall@openerp.my.openerp.com">catchall@openerp.my.openerp.com</a></td>
</tr>
<tr>
<th nowrap="" valign="BASELINE" align="RIGHT">Pour&nbsp;:
</th>
<td>Christine Herrmann (che) <a class="moz-txt-link-rfc2396E" href="mailto:che@openerp.com">&lt;che@openerp.com&gt;</a></td>
</tr>
</tbody>
</table>
<br>
<br>
<div>
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Bonjour,</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Pourriez-vous
me faire un retour sur ce point.</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Cordialement</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<div>
<div style="border:none;border-top:solid #B5C4DF
1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:&quot;Tahoma&quot;,&quot;sans-serif&quot;">De&nbsp;:</span></b><span style="font-size:10.0pt;font-family:&quot;Tahoma&quot;,&quot;sans-serif&quot;">
Ida Siwatala [<a class="moz-txt-link-freetext" href="mailto:infos@inzoservices.com">mailto:infos@inzoservices.com</a>]
<br>
<b>Envoyé&nbsp;:</b> vendredi 4 octobre 2013 20:03<br>
<b>À&nbsp;:</b> 'Followers of
INZO-services-8-all-e-Maxime-Lisbonne-77176-Savigny-le-temple-France'<br>
<b>Objet&nbsp;:</b> RE: OpenERP S.A. Payment Reminder</span></p>
</div>
</div>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Bonsoir,</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Je
me permets de revenir vers vous par écrit , car j’ai
fait 2 appels vers votre service en exposant mon
problème, mais je n’ai pas eu de retour.</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Cela
fait un mois que j’ai fait la souscription de votre
produit, mais je me rends compte qu’il est pas adapté à
ma situation ( fonctionnalité manquante et surtout je
n’ai pas beaucoup de temps à passer à résoudre des
bugs). </span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">C’est
pourquoi , j’ai demandé qu’un accord soit trouvé avec
vous pour annuler le contrat (tout en vous payant le
mois d’utilisation de septembre).</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Pourriez-vous
me faire un retour sur ce point.</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Cordialement,</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D">Ida
Siwatala</span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;color:#1F497D"></span></p>
<p>&nbsp;</p>
<p class="MsoNormal"><b><span style="font-size:10.0pt;font-family:&quot;Tahoma&quot;,&quot;sans-serif&quot;">De&nbsp;:</span></b><span style="font-size:10.0pt;font-family:&quot;Tahoma&quot;,&quot;sans-serif&quot;">
<a href="mailto:che@openerp.com">che@openerp.com</a>
[<a href="mailto:che@openerp.com">mailto:che@openerp.com</a>]
<br>
<b>Envoyé&nbsp;:</b> vendredi 4 octobre 2013 17:41<br>
<b>À&nbsp;:</b> <a href="mailto:infos@inzoservices.com">infos@inzoservices.com</a><br>
<b>Objet&nbsp;:</b> OpenERP S.A. Payment Reminder</span></p>
<p>&nbsp;</p>
<div>
<p style="background:white"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222">Dear
INZO services,</span></p>
<p style="background:white"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222">Exception
made if there was a mistake of ours, it seems that the
following amount stays unpaid. Please, take
appropriate measures in order to carry out this
payment in the next 8 days. </span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222"></span></p>
<p>&nbsp;</p>
<table class="MsoNormalTable" style="width:100.0%;border:outset 1.5pt" width="100%" border="1" cellpadding="0">
<tbody>
<tr>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Date de facturation</p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Description</p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Reference</p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Due Date</p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Amount (€)</p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal">Lit.</p>
</td>
</tr>
<tr>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal"><b>2013-09-24</b></p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal"><b>2013/1121</b></p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal"><b>Enterprise - Inzo Services
- Juillet 2013</b></p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal"><b>2013-09-24</b></p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt">
<p class="MsoNormal"><b>420.0</b></p>
</td>
<td style="padding:.75pt .75pt .75pt .75pt"><br>
</td>
</tr>
<tr>
<td style="padding:.75pt .75pt .75pt .75pt"><br>
</td>
<td style="border:none;padding:.75pt .75pt .75pt
.75pt"><br>
</td>
<td style="border:none;padding:.75pt .75pt .75pt
.75pt"><br>
</td>
<td style="border:none;padding:.75pt .75pt .75pt
.75pt"><br>
</td>
<td style="border:none;padding:.75pt .75pt .75pt
.75pt"><br>
</td>
<td style="border:none;padding:.75pt .75pt .75pt
.75pt"><br>
</td>
</tr>
</tbody>
</table>
<p class="MsoNormal" style="text-align:center;background:white" align="center"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222">Amount
due : 420.00 € </span></p>
<p style="background:white"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222">Would
your payment have been carried out after this mail was
sent, please ignore this message. Do not hesitate to
contact our accounting department. </span></p>
<p class="MsoNormal" style="background:white"><span style="font-size:9.0pt;font-family:&quot;Arial&quot;,&quot;sans-serif&quot;;color:#222222"><br>
Best Regards, <br>
Aurore Lesage <br>
OpenERP<br>
Chaussée de Namur, 40 <br>
B-1367 Grand Rosières <br>
Tel: +32.81.81.37.00 - Fax: +32.81.73.35.01 <br>
E-mail : <a href="mailto:ale@openerp.com">ale@openerp.com</a> <br>
Web: <a href="http://www.openerp.com">http://www.openerp.com</a></span></p>
</div>
</div>
</div>
--<br>
INZO services <small>Sent by <a style="color:inherit" href="http://www.openerp.com">OpenERP
S.A.</a> using <a style="color:inherit" href="https://www.openerp.com/">OpenERP</a>.</small>
<small>Access your messages and documents <a style="color:inherit" href="https://accounts.openerp.com?db=openerp#action=mail.action_mail_redirect&amp;login=che&amp;message_id=5750830">in
OpenERP</a></small> <br>
<pre class="moz-signature" cols="72">--
Christine Herrmann
OpenERP
Chaussée de Namur, 40
B-1367 Grand Rosières
Tel: +32.81.81.37.00 - Fax: +32.81.73.35.01
Web: <a class="moz-txt-link-freetext" href="http://www.openerp.com">http://www.openerp.com</a> </pre>
<br>
</div>
<br>
<br>
</div>
<br>
</div>"""
BUG_2_IN = [
'read more',
'...',
]
BUG_2_OUT = [
'Fwd: TR: OpenERP S.A'
'fait un mois'
]
+14 -11
View File
@@ -4,7 +4,6 @@ from xml.dom import minidom as dom
import common
from openerp.addons.base.ir import ir_qweb
import openerp.addons.base.ir.ir_qweb
impl = dom.getDOMImplementation()
document = impl.createDocument(None, None, None)
@@ -14,6 +13,9 @@ class TestQWebTField(common.TransactionCase):
super(TestQWebTField, self).setUp()
self.engine = self.registry('ir.qweb')
def context(self, values):
return ir_qweb.QWebContext(self.cr, self.uid, values)
def test_trivial(self):
field = document.createElement('span')
field.setAttribute('t-field', u'company.name')
@@ -22,10 +24,8 @@ class TestQWebTField(common.TransactionCase):
company_id = Companies.create(self.cr, self.uid, {
'name': "My Test Company"
})
root_company = Companies.browse(self.cr, self.uid, company_id)
result = self.engine.render_node(field, ir_qweb.QWebContext({
'company': root_company,
result = self.engine.render_node(field, self.context({
'company': Companies.browse(self.cr, self.uid, company_id),
}))
self.assertEqual(
@@ -45,11 +45,10 @@ class TestQWebTField(common.TransactionCase):
company_id = Companies.create(self.cr, self.uid, {
'name': s,
})
root_company = Companies.browse(self.cr, self.uid, company_id)
result = self.engine.render_node(field, ir_qweb.QWebContext({
'company': root_company,
result = self.engine.render_node(field, self.context({
'company': Companies.browse(self.cr, self.uid, company_id),
}))
self.assertEqual(
result,
'<span data-oe-model="res.company" data-oe-id="%d" '
@@ -65,7 +64,9 @@ class TestQWebTField(common.TransactionCase):
with self.assertRaisesRegexp(
AssertionError,
r'^RTE widgets do not work correctly'):
self.engine.render_node(field, ir_qweb.QWebContext({'company': None}))
self.engine.render_node(field, self.context({
'company': None
}))
def test_reject_t_tag(self):
field = document.createElement('t')
@@ -74,4 +75,6 @@ class TestQWebTField(common.TransactionCase):
with self.assertRaisesRegexp(
AssertionError,
r'^t-field can not be used on a t element'):
self.engine.render_node(field, ir_qweb.QWebContext({'company': None}))
self.engine.render_node(field, self.context({
'company': None
}))
+8 -9
View File
@@ -1,4 +1,7 @@
import lru
import logging
logger = logging.getLogger(__name__)
class ormcache(object):
""" LRU cache decorator for orm methods,
@@ -54,15 +57,11 @@ class ormcache(object):
"""
d = self.lru(self2)
if args:
try:
key = args[self.skiparg-2:]
del d[key]
self2.pool._any_cache_cleared = True
except KeyError:
pass
else:
d.clear()
self2.pool._any_cache_cleared = True
logger.warn("ormcache.clear arguments are deprecated and ignored "
"(while clearing caches on (%s).%s)",
self2._name, self.method.__name__)
d.clear()
self2.pool._any_cache_cleared = True
class ormcache_multi(ormcache):
def __init__(self, skiparg=2, size=8192, multi=3):
+60 -38
View File
@@ -203,17 +203,39 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
iteration += 1
new_node = _insert_new_node(node, -1, new_node_tag, text[idx:] + (cur_node.tail or ''), None, {})
def _truncate_node(node, position, find_first_blank=True):
# truncate text
innertext = node.text[0:position]
outertext = node.text[position:]
if find_first_blank:
stop_idx = outertext.find(' ')
if stop_idx == -1:
stop_idx = len(outertext)
def _truncate_node(node, position, simplify_whitespaces=True):
""" Truncate a node text at a given position. This algorithm will shorten
at the end of the word whose ending character exceeds position.
:param bool simplify_whitespaces: whether to try to count all successive
whitespaces as one character. This
option should not be True when trying
to keep 'pre' consistency.
"""
if node.text is None:
node.text = ''
truncate_idx = -1
if simplify_whitespaces:
cur_char_nbr = 0
word = None
node_words = node.text.strip(' \t\r\n').split()
for word in node_words:
cur_char_nbr += len(word)
if cur_char_nbr >= position:
break
if word:
truncate_idx = node.text.find(word) + len(word)
else:
stop_idx = 0
node.text = innertext + outertext[0:stop_idx]
truncate_idx = position
if truncate_idx == -1 or truncate_idx > len(node.text):
truncate_idx = len(node.text)
# compose new text bits
innertext = node.text[0:truncate_idx]
outertext = node.text[truncate_idx:]
node.text = innertext
# create <span> ... <a href="#">read more</a></span> node
read_more_node = _create_node(
expand_options.get('oe_expand_container_tag', 'span'),
@@ -240,7 +262,7 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
)
read_more_node.append(read_more_link_node)
# create outertext node
overtext_node = _create_node('span', outertext[stop_idx:])
overtext_node = _create_node('span', outertext)
# tag node
overtext_node.set('in_overlength', '1')
# add newly created nodes in dom
@@ -272,17 +294,16 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
html = '<div>%s</div>' % html
root = lxml.html.fromstring(html)
# remove all tails and replace them by a span element, because managing text and tails can be a pain in the ass
for node in root.getiterator():
quote_tags = re.compile(r'(\n(>)+[^\n\r]*)')
signature = re.compile(r'([-]{2,}[\s]?[\r\n]{1,2}[\s\S]+)')
for node in root.iter():
# remove all tails and replace them by a span element, because managing text and tails can be a pain in the ass
if node.tail:
tail_node = _create_node('span', node.tail)
node.tail = None
node.addnext(tail_node)
# form node and tag text-based quotes and signature
quote_tags = re.compile(r'(\n(>)+[^\n\r]*)')
signature = re.compile(r'([-]{2,}[\s]?[\r\n]{1,2}[^.]+)')
for node in root.getiterator():
# form node and tag text-based quotes and signature
_tag_matching_regex_in_text(quote_tags, node, 'span', {'text_quote': '1'})
_tag_matching_regex_in_text(signature, node, 'span', {'text_signature': '1'})
@@ -296,11 +317,9 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
overlength_section_id = None
overlength_section_count = 0
cur_char_nbr = 0
# for node in root.getiterator():
for node in root.iter():
# update: add a text argument
if node.text is None:
node.text = ''
# do not take into account multiple spaces that are displayed as max 1 space in html
node_text = ' '.join((node.text and node.text.strip(' \t\r\n') or '').split())
# root: try to tag the client used to write the html
if 'WordSection1' in node.get('class', '') or 'MsoNormal' in node.get('class', ''):
@@ -347,22 +366,22 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
# 3/ add the truncated text in a new node, next to 'read more' node
node_text = (node.text or '').strip().strip('\n').strip()
if shorten and not overlength and cur_char_nbr + len(node_text) > max_length:
overlength = True
if protect_sections:
node_to_truncate = node
while node_to_truncate.getparent() is not None and \
(node_to_truncate.getparent().get('section_inner') or node_to_truncate.getparent().get('section_closure')):
node_to_truncate = node
while node_to_truncate.getparent() is not None:
if node_to_truncate.get('in_quote'):
node_to_truncate = node_to_truncate.getparent()
overlength_section_id = node_to_truncate.get('section_closure')
position = len(node_to_truncate.text)
find_first_blank = False
else:
node_to_truncate = node
position = max_length - cur_char_nbr
find_first_blank = True
elif protect_sections and (node_to_truncate.getparent().get('section_inner') or node_to_truncate.getparent().get('section_closure')):
node_to_truncate = node_to_truncate.getparent()
overlength_section_id = node_to_truncate.get('section_closure')
else:
break
overlength = True
node_to_truncate.set('truncate', '1')
node_to_truncate.set('truncate_position', str(position))
node_to_truncate.set('truncate_blank', str(find_first_blank))
if node_to_truncate == node:
node_to_truncate.set('truncate_position', str(max_length - cur_char_nbr))
else:
node_to_truncate.set('truncate_position', str(len(node.text or '')))
cur_char_nbr += len(node_text)
# Tree modification
@@ -370,7 +389,7 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
for node in root.iter():
if node.get('truncate'):
_truncate_node(node, int(node.get('truncate_position', '0')), bool(node.get('truncate_blank', 'True')))
_truncate_node(node, int(node.get('truncate_position', '0')), node.tag != 'pre')
# Post processing
# ------------------------------------------------------------
@@ -385,17 +404,20 @@ def html_email_clean(html, remove=False, shorten=False, max_length=300, expand_o
to_remove.append(node)
if node.get('tail_remove'):
node.tail = ''
# clean node
for attribute_name in ['in_quote', 'tail_remove', 'in_overlength', 'msoffice', 'hotmail', 'truncate', 'truncate_position']:
node.attrib.pop(attribute_name, None)
for node in to_remove:
if remove:
node.getparent().remove(node)
else:
if not expand_options.get('oe_expand_a_class', 'oe_mail_expand') in node.get('class', ''): # trick: read more link should be displayed even if it's in overlength
node_class = node.get('class', '') + ' ' + 'oe_mail_cleaned'
node_class = node.get('class', '') + ' oe_mail_cleaned'
node.set('class', node_class)
# html: \n that were tail of elements have been encapsulated into <span> -> back to \n
html = etree.tostring(root, pretty_print=False)
linebreaks = re.compile(r'<span>([\s]*[\r\n]+[\s]*)<\/span>', re.IGNORECASE | re.DOTALL)
linebreaks = re.compile(r'<span[^>]*>([\s]*[\r\n]+[\s]*)<\/span>', re.IGNORECASE | re.DOTALL)
html = _replace_matching_regex(linebreaks, html, '\n')
return html