diff --git a/openerp-server b/openerp-server index 277451df74edeed58fa5e551f69f75173f7c51e3..94dc6d6df6f0f38d4eb0173a3373117b5b056702 100755 --- a/openerp-server +++ b/openerp-server @@ -27,7 +27,7 @@ OpenERP is an ERP+CRM program for small and medium businesses. The whole source code is distributed under the terms of the GNU Public Licence. -(c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a. +(c) 2003-TODAY, Fabien Pinckaers - OpenERP SA """ import logging @@ -88,8 +88,11 @@ def setup_pid_file(): def preload_registry(dbname): """ Preload a registry, and start the cron.""" - db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) - pool.get('ir.cron').restart(db.dbname) + try: + db, pool = openerp.pooler.get_db_and_pool(dbname, update_module=config['init'] or config['update'], pooljobs=False) + pool.get('ir.cron').restart(db.dbname) + except Exception: + logging.exception('Failed to initialize database `%s`.', dbname) def run_test_file(dbname, test_file): """ Preload a registry, possibly run a test file, and start the cron.""" @@ -233,6 +236,8 @@ def quit_on_signals(): if __name__ == "__main__": + os.environ["TZ"] = "UTC" + check_root_user() openerp.tools.config.parse_config(sys.argv[1:]) check_postgres_user() diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index f19c5bc7832c920544a37b0dfe251dcc71b38f1b..4857ff0bedf93d94258045a996c1b4d507631f16 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -67,7 +67,7 @@ 'res/res_currency_view.xml', 'res/res_partner_event_view.xml', 'res/wizard/partner_sms_send_view.xml', - 'res/wizard/partner_wizard_spam_view.xml', + 'res/wizard/partner_wizard_massmail_view.xml', 'res/wizard/partner_clear_ids_view.xml', 'res/wizard/partner_wizard_ean_check_view.xml', 'res/res_partner_data.xml', diff --git a/openerp/addons/base/base_data.xml b/openerp/addons/base/base_data.xml index 00fb83a0796d7c81c19207bd8a01b5b2f9f96f93..f3c305fb789b22d0336d3c9e99cab5f39db6022f 100644 --- a/openerp/addons/base/base_data.xml +++ b/openerp/addons/base/base_data.xml @@ -1086,16 +1086,17 @@ <field eval="time.strftime('%Y-01-01')" name="name"/> </record> - <record id="VEB" model="res.currency"> - <field name="name">VEB</field> - <field name="symbol">Bs</field> - <field name="rounding">2.95</field> + <!-- VEF was previously VEB --> + <record id="VEF" model="res.currency"> + <field name="name">VEF</field> + <field name="symbol">Bs.F</field> + <field name="rounding">0.0001</field> <field name="accuracy">4</field> <field name="company_id" ref="main_company"/> </record> - <record id="rateVEB" model="res.currency.rate"> - <field name="rate">2768.45</field> - <field name="currency_id" ref="VEB"/> + <record id="rateVEF" model="res.currency.rate"> + <field name="rate">5.864</field> + <field name="currency_id" ref="VEF"/> <field eval="time.strftime('%Y-01-01')" name="name"/> </record> @@ -1599,12 +1600,20 @@ <field name="rounding">0.01</field> <field name="accuracy">4</field> <field name="symbol">¢</field> + <field name="company_id" ref="main_company"/> </record> <record id="rateCRC" model="res.currency.rate"> <field name="rate">691.3153</field> <field name="currency_id" ref="CRC"/> <field eval="time.strftime('%Y-01-01')" name="name"/> - </record> + </record> + + <record id="ir_mail_server_localhost0" model="ir.mail_server"> + <field name="name">localhost</field> + <field name="smtp_host">localhost</field> + <field eval="25" name="smtp_port"/> + <field eval="10" name="priority"/> + </record> <record id="MUR" model="res.currency"> <field name="name">MUR</field> diff --git a/openerp/addons/base/base_update.xml b/openerp/addons/base/base_update.xml index b87c0ef4382ec3028d5d3e57c730fc41077b43e9..444c7b5189c0fdb747a71e19ee86f4fe3a076851 100644 --- a/openerp/addons/base/base_update.xml +++ b/openerp/addons/base/base_update.xml @@ -75,29 +75,29 @@ --> <record id="view_users_form_simple_modif" model="ir.ui.view"> - <field name="name">res.users.form.modif</field> + <field name="name">res.users.preferences.form</field> <field name="model">res.users</field> <field name="type">form</field> <field eval="18" name="priority"/> <field name="arch" type="xml"> <form string="Users"> - <field name="name"/> + <field name="name" readonly="1"/> <newline/> <group colspan="2" col="2"> <separator string="Preferences" colspan="2"/> - <field name="view"/> - <field name="context_lang"/> - <field name="context_tz"/> - <field name="menu_tips"/> + <field name="view" readonly="0"/> + <field name="context_lang" readonly="0"/> + <field name="context_tz" readonly="0"/> + <field name="menu_tips" readonly="0"/> </group> <group name="default_filters" colspan="2" col="2"> <separator string="Default Filters" colspan="2"/> - <field name="company_id" widget="selection" + <field name="company_id" widget="selection" readonly="0" groups="base.group_multi_company" on_change="on_change_company_id(company_id)"/> </group> <separator string="Email Preferences" colspan="4"/> - <field colspan="4" name="user_email" widget="email"/> - <field colspan="4" name="signature"/> + <field colspan="4" name="user_email" widget="email" readonly="0"/> + <field colspan="4" name="signature" readonly="0"/> </form> </field> </record> @@ -147,7 +147,7 @@ <page string="Access Rights"> <field nolabel="1" name="groups_id"/> </page> - <page string="Companies" groups="base.group_multi_company"> + <page string="Allowed Companies" groups="base.group_multi_company"> <field colspan="4" nolabel="1" name="company_ids" select="1"/> </page> </notebook> diff --git a/openerp/addons/base/i18n/cs.po b/openerp/addons/base/i18n/cs.po index bfa8ea8ed2590f01e2d7c7ac8460ff5ab1a16313..1a20a156fe93987a514912bb69f0fa428f8ffd31 100644 --- a/openerp/addons/base/i18n/cs.po +++ b/openerp/addons/base/i18n/cs.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" -"PO-Revision-Date: 2011-09-09 10:34+0000\n" +"PO-Revision-Date: 2011-09-16 16:25+0000\n" "Last-Translator: Jiřà Hajda <robie@centrum.cz>\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-09-10 05:01+0000\n" -"X-Generator: Launchpad (build 13900)\n" +"X-Launchpad-Export-Date: 2011-09-17 04:54+0000\n" +"X-Generator: Launchpad (build 13955)\n" "X-Poedit-Language: Czech\n" #. module: base @@ -3812,7 +3812,7 @@ msgstr "" #. module: base #: view:publisher_warranty.contract.wizard:0 msgid "Please enter the serial key provided in your contract document:" -msgstr "ProsÃme zadejte sériové ÄÃslo poskytnuté ve dokumentu vaÅ¡Ã smlouvy:" +msgstr "ProsÃme zadejte sériové ÄÃslo poskytnuté v dokumentu vaÅ¡Ã smlouvy:" #. module: base #: view:workflow.activity:0 @@ -7379,7 +7379,7 @@ msgstr "Typ výkazu" #: field:workflow.instance,state:0 #: field:workflow.workitem,state:0 msgid "State" -msgstr "Stát" +msgstr "Stav" #. module: base #: selection:base.language.install,lang:0 diff --git a/openerp/addons/base/i18n/en_GB.po b/openerp/addons/base/i18n/en_GB.po index e9c4a7b1bc0766c0ea43a6f326b301c2e07c26e4..45a316765219f4baf52dd934f19ba5c02debf64c 100644 --- a/openerp/addons/base/i18n/en_GB.po +++ b/openerp/addons/base/i18n/en_GB.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-server\n" "Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" "POT-Creation-Date: 2011-01-11 11:14+0000\n" -"PO-Revision-Date: 2011-07-28 15:35+0000\n" +"PO-Revision-Date: 2011-09-22 14:47+0000\n" "Last-Translator: John Bradshaw <Unknown>\n" "Language-Team: English (United Kingdom) <en_GB@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2011-09-01 04:44+0000\n" -"X-Generator: Launchpad (build 13827)\n" +"X-Launchpad-Export-Date: 2011-09-23 04:38+0000\n" +"X-Generator: Launchpad (build 14012)\n" #. module: base #: view:ir.filters:0 @@ -1972,7 +1972,7 @@ msgstr "Iteration Actions" #. module: base #: help:multi_company.default,company_id:0 msgid "Company where the user is connected" -msgstr "" +msgstr "Company where the user is connected" #. module: base #: field:publisher_warranty.contract,date_stop:0 @@ -2583,7 +2583,7 @@ msgstr "Search Actions" #: model:ir.actions.act_window,name:base.action_view_partner_wizard_ean_check #: view:partner.wizard.ean.check:0 msgid "Ean check" -msgstr "" +msgstr "Ean check" #. module: base #: field:res.partner,vat:0 @@ -2623,7 +2623,7 @@ msgstr "GPL-2 or later version" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_sir msgid "M." -msgstr "" +msgstr "M." #. module: base #: code:addons/base/module/module.py:429 @@ -3001,7 +3001,7 @@ msgstr "License" #. module: base #: field:ir.attachment,url:0 msgid "Url" -msgstr "" +msgstr "Url" #. module: base #: selection:ir.actions.todo,restart:0 @@ -3153,7 +3153,7 @@ msgstr "Workflows" #. module: base #: field:ir.translation,xml_id:0 msgid "XML Id" -msgstr "" +msgstr "XML Id" #. module: base #: model:ir.actions.act_window,name:base.action_config_user_form @@ -3224,7 +3224,7 @@ msgstr "Abkhazian / аҧÑуа" #. module: base #: view:base.module.configuration:0 msgid "System Configuration Done" -msgstr "" +msgstr "System Configuration Done" #. module: base #: code:addons/orm.py:929 @@ -3271,7 +3271,7 @@ msgstr "That contract is already registered in the system." #. module: base #: help:ir.sequence,suffix:0 msgid "Suffix value of the record for the sequence" -msgstr "" +msgstr "Suffix value of the record for the sequence" #. module: base #: selection:base.language.install,lang:0 @@ -3343,7 +3343,7 @@ msgstr "Installed" #. module: base #: selection:base.language.install,lang:0 msgid "Ukrainian / українÑька" -msgstr "" +msgstr "Ukrainian / українÑька" #. module: base #: model:ir.actions.act_window,name:base.action_translation @@ -3389,7 +3389,7 @@ msgstr "Next Number" #. module: base #: help:workflow.transition,condition:0 msgid "Expression to be satisfied if we want the transition done." -msgstr "" +msgstr "Expression to be satisfied if we want the transition done." #. module: base #: selection:base.language.install,lang:0 @@ -3518,6 +3518,12 @@ msgid "" "Would your payment have been carried out after this mail was sent, please " "consider the present one as void." msgstr "" +"Please note that the following payments are now due. If your payment " +" has been sent, kindly forward your payment details. If " +"payment will be delayed, please contact us to " +"discuss. \n" +"If payment was performed after this mail was sent, please consider the " +"present one as void." #. module: base #: model:res.country,name:base.mx @@ -3673,6 +3679,8 @@ msgid "" "If set to true, the action will not be displayed on the right toolbar of a " "form view" msgstr "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view" #. module: base #: model:res.country,name:base.ms @@ -3717,7 +3725,7 @@ msgstr "English (UK)" #. module: base #: selection:base.language.install,lang:0 msgid "Japanese / 日本語" -msgstr "" +msgstr "Japanese / 日本語" #. module: base #: help:workflow.transition,act_from:0 @@ -3725,6 +3733,8 @@ msgid "" "Source activity. When this activity is over, the condition is tested to " "determine if we can start the ACT_TO activity." msgstr "" +"Source activity. When this activity is over, the condition is tested to " +"determine if we can start the ACT_TO activity." #. module: base #: model:res.partner.category,name:base.res_partner_category_3 @@ -3885,7 +3895,7 @@ msgstr "Init Date" #. module: base #: selection:base.language.install,lang:0 msgid "Gujarati / ગà«àªœàª°àª¾àª¤à«€" -msgstr "" +msgstr "Gujarati / ગà«àªœàª°àª¾àª¤à«€" #. module: base #: code:addons/base/module/module.py:257 @@ -3953,6 +3963,9 @@ msgid "" "form, signal tests the name of the pressed button. If signal is NULL, no " "button is necessary to validate this transition." msgstr "" +"When the operation of transition comes from a button press in the client " +"form, signal tests the name of the pressed button. If signal is NULL, no " +"button is necessary to validate this transition." #. module: base #: help:multi_company.default,object_id:0 @@ -3972,7 +3985,7 @@ msgstr "Menu Name" #. module: base #: view:ir.module.module:0 msgid "Author Website" -msgstr "" +msgstr "Author Website" #. module: base #: view:ir.attachment:0 @@ -4012,6 +4025,8 @@ msgid "" "Whether values for this field can be translated (enables the translation " "mechanism for that field)" msgstr "" +"Whether values for this field can be translated (enables the translation " +"mechanism for that field)" #. module: base #: view:res.lang:0 @@ -4072,13 +4087,13 @@ msgstr "Price Accuracy" #. module: base #: selection:base.language.install,lang:0 msgid "Latvian / latvieÅ¡u valoda" -msgstr "" +msgstr "Latvian / latvieÅ¡u valoda" #. module: base #: view:res.config:0 #: view:res.config.installer:0 msgid "vsep" -msgstr "" +msgstr "vsep" #. module: base #: selection:base.language.install,lang:0 @@ -4099,7 +4114,7 @@ msgstr "Workitem" #. module: base #: view:ir.actions.todo:0 msgid "Set as Todo" -msgstr "" +msgstr "Set as Todo" #. module: base #: field:ir.actions.act_window.view,act_window_id:0 @@ -4177,7 +4192,7 @@ msgstr "Menus" #. module: base #: selection:base.language.install,lang:0 msgid "Serbian (Latin) / srpski" -msgstr "" +msgstr "Serbian (Latin) / srpski" #. module: base #: model:res.country,name:base.il @@ -4353,7 +4368,7 @@ msgstr "" #. module: base #: view:base.language.import:0 msgid "- module,type,name,res_id,src,value" -msgstr "" +msgstr "- module,type,name,res_id,src,value" #. module: base #: selection:base.language.install,lang:0 @@ -4372,7 +4387,7 @@ msgstr "" #. module: base #: help:ir.model.fields,relation:0 msgid "For relationship fields, the technical name of the target model" -msgstr "" +msgstr "For relationship fields, the technical name of the target model" #. module: base #: selection:base.language.install,lang:0 @@ -4387,7 +4402,7 @@ msgstr "Inherited View" #. module: base #: view:ir.translation:0 msgid "Source Term" -msgstr "" +msgstr "Source Term" #. module: base #: model:ir.ui.menu,name:base.menu_main_pm @@ -4397,7 +4412,7 @@ msgstr "Project" #. module: base #: field:ir.ui.menu,web_icon_hover_data:0 msgid "Web Icon Image (hover)" -msgstr "" +msgstr "Web Icon Image (hover)" #. module: base #: view:base.module.import:0 @@ -4417,7 +4432,7 @@ msgstr "Create User" #. module: base #: view:partner.clear.ids:0 msgid "Want to Clear Ids ? " -msgstr "" +msgstr "Want to Clear Ids ? " #. module: base #: field:publisher_warranty.contract,name:0 @@ -4469,17 +4484,17 @@ msgstr "Fed. State" #. module: base #: field:ir.actions.server,copy_object:0 msgid "Copy Of" -msgstr "" +msgstr "Copy Of" #. module: base #: field:ir.model,osv_memory:0 msgid "In-memory model" -msgstr "" +msgstr "In-memory model" #. module: base #: view:partner.clear.ids:0 msgid "Clear Ids" -msgstr "" +msgstr "Clear Ids" #. module: base #: model:res.country,name:base.io @@ -4501,7 +4516,7 @@ msgstr "Field Mapping" #. module: base #: view:publisher_warranty.contract:0 msgid "Refresh Validation Dates" -msgstr "" +msgstr "Refresh Validation Dates" #. module: base #: view:ir.model:0 @@ -4572,7 +4587,7 @@ msgstr "_Ok" #. module: base #: help:ir.filters,user_id:0 msgid "False means for every user" -msgstr "" +msgstr "False means for every user" #. module: base #: code:addons/base/module/module.py:198 @@ -4621,6 +4636,7 @@ msgstr "Contacts" msgid "" "Unable to delete this document because it is used as a default property" msgstr "" +"Unable to delete this document because it is used as a default property" #. module: base #: view:res.widget.wizard:0 @@ -4674,7 +4690,7 @@ msgstr "" #: code:addons/orm.py:1350 #, python-format msgid "Insufficient fields for Calendar View!" -msgstr "" +msgstr "Insufficient fields for Calendar View!" #. module: base #: selection:ir.property,type:0 @@ -4687,6 +4703,8 @@ msgid "" "The path to the main report file (depending on Report Type) or NULL if the " "content is in another data field" msgstr "" +"The path to the main report file (depending on Report Type) or NULL if the " +"content is in another data field" #. module: base #: help:res.config.users,company_id:0 @@ -4748,7 +4766,7 @@ msgstr "Close" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (MX) / Español (MX)" -msgstr "" +msgstr "Spanish (MX) / Español (MX)" #. module: base #: view:res.log:0 @@ -4783,7 +4801,7 @@ msgstr "Publisher Warranty Contracts" #. module: base #: help:res.log,name:0 msgid "The logging message." -msgstr "" +msgstr "The logging message." #. module: base #: field:base.language.export,format:0 @@ -5018,7 +5036,7 @@ msgstr "" #. module: base #: help:ir.cron,interval_number:0 msgid "Repeat every x." -msgstr "" +msgstr "Repeat every x." #. module: base #: wizard_view:server.action.create,step_1:0 @@ -5078,6 +5096,8 @@ msgid "" "If specified, this action will be opened at logon for this user, in addition " "to the standard menu." msgstr "" +"If specified, this action will be opened at logon for this user, in addition " +"to the standard menu." #. module: base #: view:ir.values:0 @@ -5088,7 +5108,7 @@ msgstr "Client Actions" #: code:addons/orm.py:1806 #, python-format msgid "The exists method is not implemented on this object !" -msgstr "" +msgstr "The exists method is not implemented on this object !" #. module: base #: code:addons/base/module/module.py:336 @@ -5113,7 +5133,7 @@ msgstr "Connect Events to Actions" #. module: base #: model:ir.model,name:base.model_base_update_translations msgid "base.update.translations" -msgstr "" +msgstr "base.update.translations" #. module: base #: field:ir.module.category,parent_id:0 @@ -5124,7 +5144,7 @@ msgstr "Parent Category" #. module: base #: selection:ir.property,type:0 msgid "Integer Big" -msgstr "" +msgstr "Integer Big" #. module: base #: selection:res.partner.address,type:0 @@ -5158,7 +5178,7 @@ msgstr "Communication" #. module: base #: view:ir.actions.report.xml:0 msgid "RML Report" -msgstr "" +msgstr "RML Report" #. module: base #: model:ir.model,name:base.model_ir_server_object_lines @@ -5206,7 +5226,7 @@ msgstr "Nigeria" #: code:addons/base/ir/ir_model.py:250 #, python-format msgid "For selection fields, the Selection Options must be given!" -msgstr "" +msgstr "For selection fields, the Selection Options must be given!" #. module: base #: model:ir.actions.act_window,name:base.action_partner_sms_send @@ -5254,6 +5274,13 @@ msgid "" "installed the CRM, with the history tab, you can track all the interactions " "with a partner such as opportunities, emails, or sales orders issued." msgstr "" +"Customers (also called Partners in other areas of the system) helps you " +"manage your address book of companies whether they are prospects, customers " +"and/or suppliers. The partner form allows you to track and record all the " +"necessary information to interact with your partners from the company " +"address to their contacts as well as pricelists, and much more. If you " +"installed the CRM, with the history tab, you can track all interactions with " +"a partner such as opportunities, emails, or sales orders issued." #. module: base #: model:res.country,name:base.ph @@ -5278,7 +5305,7 @@ msgstr "Content" #. module: base #: help:ir.rule,global:0 msgid "If no group is specified the rule is global and applied to everyone" -msgstr "" +msgstr "If no group is specified the rule is global and applied to everyone" #. module: base #: model:res.country,name:base.td @@ -5355,6 +5382,9 @@ msgid "" "groups. If this field is empty, OpenERP will compute visibility based on the " "related object's read access." msgstr "" +"If you have groups, the visibility of this menu will be based on these " +"groups. If this field is empty, OpenERP will compute visibility based on the " +"related object's read access." #. module: base #: model:ir.actions.act_window,name:base.action_ui_view_custom @@ -5496,7 +5526,7 @@ msgstr "Spanish (EC) / Español (EC)" #. module: base #: help:ir.ui.view,xml_id:0 msgid "ID of the view defined in xml file" -msgstr "" +msgstr "ID of the view defined in xml file" #. module: base #: model:ir.model,name:base.model_base_module_import @@ -5512,7 +5542,7 @@ msgstr "American Samoa" #. module: base #: help:ir.actions.act_window,res_model:0 msgid "Model name of the object to open in the view window" -msgstr "" +msgstr "Model name of the object to open in the view window" #. module: base #: field:res.log,secondary:0 @@ -5692,11 +5722,15 @@ msgid "" "Warning: if \"email_from\" and \"smtp_server\" aren't configured, it won't " "be possible to email new users." msgstr "" +"If an email is provided, the user will be sent a message welcoming them.\n" +"\n" +"Warning: if \"email_from\" and \"smtp_server\" aren't configured, it won't " +"be possible to email new users." #. module: base #: selection:base.language.install,lang:0 msgid "Flemish (BE) / Vlaams (BE)" -msgstr "" +msgstr "Flemish (BE) / Vlaams (BE)" #. module: base #: field:ir.cron,interval_number:0 @@ -5746,7 +5780,7 @@ msgstr "ir.actions.todo" #: code:addons/base/res/res_config.py:94 #, python-format msgid "Couldn't find previous ir.actions.todo" -msgstr "" +msgstr "Couldn't find previous ir.actions.todo" #. module: base #: view:ir.actions.act_window:0 @@ -5761,7 +5795,7 @@ msgstr "Custom Shortcuts" #. module: base #: selection:base.language.install,lang:0 msgid "Vietnamese / Tiếng Việt" -msgstr "" +msgstr "Vietnamese / Tiếng Việt" #. module: base #: model:res.country,name:base.dz @@ -5776,7 +5810,7 @@ msgstr "Belgium" #. module: base #: model:ir.model,name:base.model_osv_memory_autovacuum msgid "osv_memory.autovacuum" -msgstr "" +msgstr "osv_memory.autovacuum" #. module: base #: field:base.language.export,lang:0 @@ -5809,30 +5843,30 @@ msgstr "Companies" #. module: base #: view:res.lang:0 msgid "%H - Hour (24-hour clock) [00,23]." -msgstr "" +msgstr "%H - Hour (24-hour clock) [00,23]." #. module: base #: model:ir.model,name:base.model_res_widget msgid "res.widget" -msgstr "" +msgstr "res.widget" #. module: base #: code:addons/base/ir/ir_model.py:258 #, python-format msgid "Model %s does not exist!" -msgstr "" +msgstr "Model %s does not exist!" #. module: base #: code:addons/base/res/res_lang.py:159 #, python-format msgid "You cannot delete the language which is User's Preferred Language !" -msgstr "" +msgstr "You cannot delete the language which is User's Preferred Language !" #. module: base #: code:addons/fields.py:103 #, python-format msgid "Not implemented get_memory method !" -msgstr "" +msgstr "Not implemented get_memory method !" #. module: base #: view:ir.actions.server:0 @@ -5879,7 +5913,7 @@ msgstr "Neutral Zone" #. module: base #: selection:base.language.install,lang:0 msgid "Hindi / हिंदी" -msgstr "" +msgstr "Hindi / हिंदी" #. module: base #: view:ir.model:0 @@ -5926,7 +5960,7 @@ msgstr "Window Actions" #. module: base #: view:res.lang:0 msgid "%I - Hour (12-hour clock) [01,12]." -msgstr "" +msgstr "%I - Hour (12-hour clock) [01,12]." #. module: base #: selection:publisher_warranty.contract.wizard,state:0 @@ -5964,12 +5998,14 @@ msgid "" "View type: set to 'tree' for a hierarchical tree view, or 'form' for other " "views" msgstr "" +"View type: set to 'tree' for a hierarchical tree view, or 'form' for other " +"views" #. module: base #: code:addons/base/res/res_config.py:421 #, python-format msgid "Click 'Continue' to configure the next addon..." -msgstr "" +msgstr "Click 'Continue' to configure the next addon..." #. module: base #: field:ir.actions.server,record_id:0 @@ -6010,7 +6046,7 @@ msgstr "" #: code:addons/base/ir/ir_actions.py:629 #, python-format msgid "Please specify server option --email-from !" -msgstr "" +msgstr "Please specify server option --email-from !" #. module: base #: field:base.language.import,name:0 @@ -6070,6 +6106,7 @@ msgid "" "It gives the status if the tip has to be displayed or not when a user " "executes an action" msgstr "" +"It shows if the tip is to be displayed or not when a user executes an action" #. module: base #: view:ir.model:0 @@ -6126,7 +6163,7 @@ msgstr "Code" #. module: base #: model:ir.model,name:base.model_res_config_installer msgid "res.config.installer" -msgstr "" +msgstr "res.config.installer" #. module: base #: model:res.country,name:base.mc @@ -6170,7 +6207,7 @@ msgstr "Sequence Codes" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CO) / Español (CO)" -msgstr "" +msgstr "Spanish (CO) / Español (CO)" #. module: base #: view:base.module.configuration:0 @@ -6178,6 +6215,8 @@ msgid "" "All pending configuration wizards have been executed. You may restart " "individual wizards via the list of configuration wizards." msgstr "" +"All pending configuration wizards have been executed. You may restart " +"individual wizards via the list of configuration wizards." #. module: base #: wizard_button:server.action.create,step_1,create:0 @@ -6187,7 +6226,7 @@ msgstr "Create" #. module: base #: view:ir.sequence:0 msgid "Current Year with Century: %(year)s" -msgstr "" +msgstr "Current Year with Century: %(year)s" #. module: base #: field:ir.exports,export_fields:0 @@ -6202,13 +6241,13 @@ msgstr "France" #. module: base #: model:ir.model,name:base.model_res_log msgid "res.log" -msgstr "" +msgstr "res.log" #. module: base #: help:ir.translation,module:0 #: help:ir.translation,xml_id:0 msgid "Maps to the ir_model_data for which this translation is provided." -msgstr "" +msgstr "Maps to the ir_model_data for which this translation is provided." #. module: base #: view:workflow.activity:0 @@ -6302,7 +6341,7 @@ msgstr "Todo" #. module: base #: field:ir.attachment,datas:0 msgid "File Content" -msgstr "" +msgstr "File Content" #. module: base #: model:res.country,name:base.pa @@ -6319,12 +6358,13 @@ msgstr "Ltd" msgid "" "The group that a user must have to be authorized to validate this transition." msgstr "" +"The group that a user must have to be authorized to validate this transition." #. module: base #: constraint:res.config.users:0 #: constraint:res.users:0 msgid "The chosen company is not in the allowed companies for this user" -msgstr "" +msgstr "The chosen company is not in the allowed companies for this user" #. module: base #: model:res.country,name:base.gi @@ -6346,6 +6386,7 @@ msgstr "Pitcairn Island" msgid "" "We suggest to reload the menu tab to see the new menus (Ctrl+T then Ctrl+R)." msgstr "" +"We suggest reloading the menu tab to see the new menus (Ctrl+T then Ctrl+R)." #. module: base #: model:ir.actions.act_window,name:base.action_rule @@ -6398,7 +6439,7 @@ msgstr "Search View" #. module: base #: sql_constraint:res.lang:0 msgid "The code of the language must be unique !" -msgstr "" +msgstr "The code of the language must be unique !" #. module: base #: model:ir.actions.act_window,name:base.action_attachment @@ -6441,7 +6482,7 @@ msgstr "Write Access" #. module: base #: view:res.lang:0 msgid "%m - Month number [01,12]." -msgstr "" +msgstr "%m - Month number [01,12]." #. module: base #: field:res.bank,city:0 @@ -6499,7 +6540,7 @@ msgstr "English (US)" #: view:ir.model.data:0 #: model:ir.ui.menu,name:base.ir_model_data_menu msgid "Object Identifiers" -msgstr "" +msgstr "Object Identifiers" #. module: base #: model:ir.actions.act_window,help:base.action_partner_title_partner @@ -6507,11 +6548,13 @@ msgid "" "Manage the partner titles you want to have available in your system. The " "partner titles is the legal status of the company: Private Limited, SA, etc." msgstr "" +"Manage the partner titles you want to have available in your system. The " +"partner title is the legal status of the company: Private Limited, SA, etc." #. module: base #: view:base.language.export:0 msgid "To browse official translations, you can start with these links:" -msgstr "" +msgstr "To browse official translations, you can start with these links:" #. module: base #: code:addons/base/ir/ir_model.py:484 @@ -6520,6 +6563,8 @@ msgid "" "You can not read this document (%s) ! Be sure your user belongs to one of " "these groups: %s." msgstr "" +"You can not read this document (%s) ! Be sure your user belongs to one of " +"these groups: %s." #. module: base #: view:res.bank:0 @@ -6538,7 +6583,7 @@ msgstr "Installed version" #. module: base #: selection:base.language.install,lang:0 msgid "Mongolian / монгол" -msgstr "" +msgstr "Mongolian / монгол" #. module: base #: model:res.country,name:base.mr @@ -6553,7 +6598,7 @@ msgstr "ir.translation" #. module: base #: view:base.module.update:0 msgid "Module update result" -msgstr "" +msgstr "Module update result" #. module: base #: view:workflow.activity:0 @@ -6575,7 +6620,7 @@ msgstr "Parent Company" #. module: base #: selection:base.language.install,lang:0 msgid "Spanish (CR) / Español (CR)" -msgstr "" +msgstr "Spanish (CR) / Español (CR)" #. module: base #: field:res.currency.rate,rate:0 @@ -6615,6 +6660,9 @@ msgid "" "for the currency: %s \n" "at the date: %s" msgstr "" +"No rate found \n" +"for the currency: %s \n" +"at the date: %s" #. module: base #: model:ir.actions.act_window,help:base.action_ui_view_custom @@ -6622,6 +6670,8 @@ msgid "" "Customized views are used when users reorganize the content of their " "dashboard views (via web client)" msgstr "" +"Customised views are used when users reorganise the content of their " +"dashboard views (via web client)" #. module: base #: field:ir.model,name:0 @@ -6660,7 +6710,7 @@ msgstr "Icon" #. module: base #: help:ir.model.fields,model_id:0 msgid "The model this field belongs to" -msgstr "" +msgstr "The model this field belongs to" #. module: base #: model:res.country,name:base.mq @@ -6670,7 +6720,7 @@ msgstr "Martinique (French)" #. module: base #: view:ir.sequence.type:0 msgid "Sequences Type" -msgstr "" +msgstr "Sequences Type" #. module: base #: model:ir.actions.act_window,name:base.res_request-act @@ -6694,7 +6744,7 @@ msgstr "Or" #: model:ir.actions.act_window,name:base.res_log_act_window #: model:ir.ui.menu,name:base.menu_res_log_act_window msgid "Client Logs" -msgstr "" +msgstr "Client Logs" #. module: base #: model:res.country,name:base.al @@ -6713,6 +6763,8 @@ msgid "" "You cannot delete the language which is Active !\n" "Please de-activate the language first." msgstr "" +"You cannot delete a language which is active !\n" +"Please de-activate the language first." #. module: base #: view:base.language.install:0 @@ -6721,6 +6773,8 @@ msgid "" "Please be patient, this operation may take a few minutes (depending on the " "number of modules currently installed)..." msgstr "" +"Please be patient, this operation may take a few minutes (depending on the " +"number of modules currently installed)..." #. module: base #: field:ir.ui.menu,child_id:0 @@ -6739,18 +6793,18 @@ msgstr "Problem in configuration `Record Id` in Server Action!" #: code:addons/orm.py:2316 #, python-format msgid "ValidateError" -msgstr "" +msgstr "ValidateError" #. module: base #: view:base.module.import:0 #: view:base.module.update:0 msgid "Open Modules" -msgstr "" +msgstr "Open Modules" #. module: base #: model:ir.actions.act_window,help:base.action_res_bank_form msgid "Manage bank records you want to be used in the system." -msgstr "" +msgstr "Manage bank records you want to be used in the system." #. module: base #: view:base.module.import:0 @@ -6768,6 +6822,8 @@ msgid "" "The path to the main report file (depending on Report Type) or NULL if the " "content is in another field" msgstr "" +"The path to the main report file (depending on Report Type) or NULL if the " +"content is in another field" #. module: base #: model:res.country,name:base.la @@ -6794,6 +6850,8 @@ msgid "" "The sum of the data (2nd field) is null.\n" "We can't draw a pie chart !" msgstr "" +"The sum of the data (2nd field) is null.\n" +"We can't draw a pie chart !" #. module: base #: model:ir.ui.menu,name:base.menu_lunch_reporting @@ -6815,7 +6873,7 @@ msgstr "Togo" #. module: base #: selection:ir.module.module,license:0 msgid "Other Proprietary" -msgstr "" +msgstr "Other Proprietary" #. module: base #: selection:workflow.activity,kind:0 @@ -6826,7 +6884,7 @@ msgstr "Stop All" #: code:addons/orm.py:412 #, python-format msgid "The read_group method is not implemented on this object !" -msgstr "" +msgstr "The read_group method is not implemented on this object !" #. module: base #: view:ir.model.data:0 @@ -6846,7 +6904,7 @@ msgstr "Cascade" #. module: base #: field:workflow.transition,group_id:0 msgid "Group Required" -msgstr "" +msgstr "Group Required" #. module: base #: view:ir.actions.configuration.wizard:0 @@ -6869,17 +6927,19 @@ msgid "" "Enable this if you want to execute missed occurences as soon as the server " "restarts." msgstr "" +"Enable this if you want to execute missed occurences as soon as the server " +"restarts." #. module: base #: view:base.module.upgrade:0 msgid "Start update" -msgstr "" +msgstr "Start update" #. module: base #: code:addons/base/publisher_warranty/publisher_warranty.py:144 #, python-format msgid "Contract validation error" -msgstr "" +msgstr "Contract validation error" #. module: base #: field:res.country.state,name:0 @@ -6906,7 +6966,7 @@ msgstr "ir.actions.report.xml" #. module: base #: model:res.partner.title,shortcut:base.res_partner_title_miss msgid "Mss" -msgstr "" +msgstr "Mss" #. module: base #: model:ir.model,name:base.model_ir_ui_view @@ -6916,7 +6976,7 @@ msgstr "ir.ui.view" #. module: base #: constraint:res.partner:0 msgid "Error ! You can not create recursive associated members." -msgstr "" +msgstr "Error ! You can not create recursive associated members." #. module: base #: help:res.lang,code:0 @@ -6931,7 +6991,7 @@ msgstr "OpenERP Partners" #. module: base #: model:ir.ui.menu,name:base.menu_hr_manager msgid "HR Manager Dashboard" -msgstr "" +msgstr "HR Manager Dashboard" #. module: base #: code:addons/base/module/module.py:253 @@ -6939,11 +6999,12 @@ msgstr "" msgid "" "Unable to install module \"%s\" because an external dependency is not met: %s" msgstr "" +"Unable to install module \"%s\" because an external dependency is not met: %s" #. module: base #: view:ir.module.module:0 msgid "Search modules" -msgstr "" +msgstr "Search modules" #. module: base #: model:res.country,name:base.by @@ -6968,6 +7029,10 @@ msgid "" "not connect to the system. You can assign them groups in order to give them " "specific access to the applications they need to use in the system." msgstr "" +"Create and manage users that will connect to the system. Users can be " +"deactivated should there be a period of time during which they will/should " +"not connect to the system. You can assign them groups to give them specific " +"access to the applications they need to use." #. module: base #: selection:res.request,priority:0 @@ -6983,13 +7048,13 @@ msgstr "Street2" #. module: base #: model:ir.actions.act_window,name:base.action_view_base_module_update msgid "Module Update" -msgstr "" +msgstr "Module Update" #. module: base #: code:addons/base/module/wizard/base_module_upgrade.py:95 #, python-format msgid "Following modules are not installed or unknown: %s" -msgstr "" +msgstr "Following modules are not installed or unknown: %s" #. module: base #: view:ir.cron:0 @@ -7018,7 +7083,7 @@ msgstr "Open Window" #. module: base #: field:ir.actions.act_window,auto_search:0 msgid "Auto Search" -msgstr "" +msgstr "Auto Search" #. module: base #: field:ir.actions.act_window,filter:0 @@ -7064,25 +7129,25 @@ msgstr "Load" #: help:res.config.users,name:0 #: help:res.users,name:0 msgid "The new user's real name, used for searching and most listings" -msgstr "" +msgstr "The new user's real name, used for searching and most listings" #. module: base #: code:addons/osv.py:154 #: code:addons/osv.py:156 #, python-format msgid "Integrity Error" -msgstr "" +msgstr "Integrity Error" #. module: base #: model:ir.model,name:base.model_ir_wizard_screen msgid "ir.wizard.screen" -msgstr "" +msgstr "ir.wizard.screen" #. module: base #: code:addons/base/ir/ir_model.py:223 #, python-format msgid "Size of the field can never be less than 1 !" -msgstr "" +msgstr "Size of the field can never be less than 1 !" #. module: base #: model:res.country,name:base.so @@ -7092,7 +7157,7 @@ msgstr "Somalia" #. module: base #: selection:publisher_warranty.contract,state:0 msgid "Terminated" -msgstr "" +msgstr "Terminated" #. module: base #: model:res.partner.category,name:base.res_partner_category_13 @@ -7102,7 +7167,7 @@ msgstr "Important customers" #. module: base #: view:res.lang:0 msgid "Update Terms" -msgstr "" +msgstr "Update Terms" #. module: base #: field:partner.sms.send,mobile_to:0 @@ -7121,7 +7186,7 @@ msgstr "Arguments" #: code:addons/orm.py:716 #, python-format msgid "Database ID doesn't exist: %s : %s" -msgstr "" +msgstr "Database ID doesn't exist: %s : %s" #. module: base #: selection:ir.module.module,license:0 @@ -7137,7 +7202,7 @@ msgstr "GPL Version 3" #: code:addons/orm.py:836 #, python-format msgid "key '%s' not found in selection field '%s'" -msgstr "" +msgstr "key '%s' not found in selection field '%s'" #. module: base #: view:partner.wizard.ean.check:0 @@ -7148,7 +7213,7 @@ msgstr "Correct EAN13" #: code:addons/orm.py:2317 #, python-format msgid "The value \"%s\" for the field \"%s\" is not in the selection" -msgstr "" +msgstr "The value \"%s\" for the field \"%s\" is not in the selection" #. module: base #: field:res.partner,customer:0 diff --git a/openerp/addons/base/i18n/kk.po b/openerp/addons/base/i18n/kk.po new file mode 100644 index 0000000000000000000000000000000000000000..1df9844334b4046e0bc2cfd2a19bec3760639caf --- /dev/null +++ b/openerp/addons/base/i18n/kk.po @@ -0,0 +1,9248 @@ +# Kazakh translation for openobject-server +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 +# This file is distributed under the same license as the openobject-server package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-server\n" +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" +"POT-Creation-Date: 2011-01-11 11:14+0000\n" +"PO-Revision-Date: 2011-09-16 07:28+0000\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: Kazakh <kk@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2011-09-17 04:54+0000\n" +"X-Generator: Launchpad (build 13955)\n" + +#. module: base +#: view:ir.filters:0 +#: field:ir.model.fields,domain:0 +#: field:ir.rule,domain:0 +#: field:ir.rule,domain_force:0 +#: field:res.partner.title,domain:0 +msgid "Domain" +msgstr "Домен" + +#. module: base +#: model:res.country,name:base.sh +msgid "Saint Helena" +msgstr "Әулие Елена ар." + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "Other Configuration" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "DateTime" +msgstr "Күн мен уақыт" + +#. module: base +#: code:addons/fields.py:534 +#, python-format +msgid "" +"The second argument of the many2many field %s must be a SQL table !You used " +"%s, which is not a valid SQL table name." +msgstr "" + +#. module: base +#: view:ir.values:0 +#: field:ir.values,meta_unpickle:0 +msgid "Metadata" +msgstr "Метаақпарат" + +#. module: base +#: field:ir.ui.view,arch:0 +#: field:ir.ui.view.custom,arch:0 +msgid "View Architecture" +msgstr "" + +#. module: base +#: field:base.language.import,code:0 +msgid "Code (eg:en__US)" +msgstr "" + +#. module: base +#: view:workflow:0 +#: view:workflow.activity:0 +#: field:workflow.activity,wkf_id:0 +#: field:workflow.instance,wkf_id:0 +#: field:workflow.transition,wkf_id:0 +#: field:workflow.workitem,wkf_id:0 +msgid "Workflow" +msgstr "" + +#. module: base +#: view:partner.sms.send:0 +msgid "SMS - Gateway: clickatell" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Hungarian / Magyar" +msgstr "" + +#. module: base +#: selection:ir.model.fields,select_level:0 +msgid "Not Searchable" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (VE) / Español (VE)" +msgstr "" + +#. module: base +#: field:ir.actions.server,wkf_model_id:0 +msgid "Workflow On" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,display_menu_tip:0 +msgid "Display Menu Tips" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Created Views" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:485 +#, python-format +msgid "" +"You can not write in this document (%s) ! Be sure your user belongs to one " +"of these groups: %s." +msgstr "" + +#. module: base +#: help:ir.model.fields,domain:0 +msgid "" +"The optional domain to restrict possible values for relationship fields, " +"specified as a Python expression defining a list of triplets. For example: " +"[('color','=','red')]" +msgstr "" + +#. module: base +#: field:res.partner,ref:0 +msgid "Reference" +msgstr "Сілтеме" + +#. module: base +#: field:ir.actions.act_window,target:0 +msgid "Target Window" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:507 +#, python-format +msgid "Warning!" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:304 +#, python-format +msgid "" +"Properties of base fields cannot be altered in this manner! Please modify " +"them through Python code, preferably through a custom addon!" +msgstr "" + +#. module: base +#: code:addons/osv.py:133 +#, python-format +msgid "Constraint Error" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_ui_view_custom +msgid "ir.ui.view.custom" +msgstr "" + +#. module: base +#: model:res.country,name:base.sz +msgid "Swaziland" +msgstr "Свазиленд" + +#. module: base +#: code:addons/orm.py:1993 +#: code:addons/orm.py:3653 +#, python-format +msgid "created." +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_woodsuppliers0 +msgid "Wood Suppliers" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:303 +#, python-format +msgid "" +"Some installed modules depend on the module you plan to Uninstall :\n" +" %s" +msgstr "" + +#. module: base +#: field:ir.sequence,number_increment:0 +msgid "Increment Number" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_company_tree +#: model:ir.ui.menu,name:base.menu_action_res_company_tree +msgid "Company's Structure" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Inuktitut / áƒá“„ᒃᑎá‘ᑦ" +msgstr "" + +#. module: base +#: view:res.partner:0 +msgid "Search Partner" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:132 +#, python-format +msgid "\"smtp_server\" needs to be set to send mails to users" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_export_language.py:60 +#, python-format +msgid "new" +msgstr "жаңа" + +#. module: base +#: field:ir.actions.report.xml,multi:0 +msgid "On multiple doc." +msgstr "" + +#. module: base +#: field:ir.module.category,module_nr:0 +msgid "Number of Modules" +msgstr "" + +#. module: base +#: help:multi_company.default,company_dest_id:0 +msgid "Company to store the current record" +msgstr "" + +#. module: base +#: field:res.partner.bank.type.field,size:0 +msgid "Max. Size" +msgstr "" + +#. module: base +#: field:res.partner.address,name:0 +msgid "Contact Name" +msgstr "Контакт атауы" + +#. module: base +#: code:addons/base/module/wizard/base_export_language.py:56 +#, python-format +msgid "" +"Save this document to a %s file and edit it with a specific software or a " +"text editor. The file encoding is UTF-8." +msgstr "" + +#. module: base +#: sql_constraint:res.lang:0 +msgid "The name of the language must be unique !" +msgstr "" + +#. module: base +#: selection:res.request,state:0 +msgid "active" +msgstr "белÑенді" + +#. module: base +#: field:ir.actions.wizard,wiz_name:0 +msgid "Wizard Name" +msgstr "" + +#. module: base +#: code:addons/orm.py:2160 +#, python-format +msgid "Invalid group_by" +msgstr "" + +#. module: base +#: field:res.partner,credit_limit:0 +msgid "Credit Limit" +msgstr "" + +#. module: base +#: field:ir.model.data,date_update:0 +msgid "Update Date" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Owner" +msgstr "ИеÑÑ–" + +#. module: base +#: field:ir.actions.act_window,src_model:0 +msgid "Source Object" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +msgid "Config Wizard Steps" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_ui_view_sc +msgid "ir.ui.view_sc" +msgstr "" + +#. module: base +#: field:res.widget.user,widget_id:0 +#: field:res.widget.wizard,widgets_list:0 +msgid "Widget" +msgstr "" + +#. module: base +#: view:ir.model.access:0 +#: field:ir.model.access,group_id:0 +#: view:res.config.users:0 +msgid "Group" +msgstr "Тобы" + +#. module: base +#: field:ir.exports.line,name:0 +#: field:ir.translation,name:0 +#: field:res.partner.bank.type.field,name:0 +msgid "Field Name" +msgstr "" + +#. module: base +#: wizard_view:server.action.create,init:0 +#: wizard_field:server.action.create,init,type:0 +msgid "Select Action Type" +msgstr "" + +#. module: base +#: model:res.country,name:base.tv +msgid "Tuvalu" +msgstr "Тувалу" + +#. module: base +#: selection:ir.model,state:0 +msgid "Custom Object" +msgstr "" + +#. module: base +#: field:res.lang,date_format:0 +msgid "Date Format" +msgstr "Уақыт таңба пшімі" + +#. module: base +#: field:res.bank,email:0 +#: field:res.partner.address,email:0 +msgid "E-Mail" +msgstr "Ðл.поштаÑÑ‹" + +#. module: base +#: model:res.country,name:base.an +msgid "Netherlands Antilles" +msgstr "ÐидерландиÑның Ðнтиль аралдары" + +#. module: base +#: code:addons/base/res/res_user.py:389 +#, python-format +msgid "" +"You can not remove the admin user as it is used internally for resources " +"created by OpenERP (updates, module installation, ...)" +msgstr "" + +#. module: base +#: model:res.country,name:base.gf +msgid "French Guyana" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Greek / Ελληνικά" +msgstr "ГрециÑ" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Bosnian / bosanski jezik" +msgstr "" + +#. module: base +#: help:ir.actions.report.xml,attachment_use:0 +msgid "" +"If you check this, then the second time the user prints with same attachment " +"name, it returns the previous report." +msgstr "" + +#. module: base +#: code:addons/orm.py:904 +#, python-format +msgid "The read method is not implemented on this object !" +msgstr "" + +#. module: base +#: help:res.lang,iso_code:0 +msgid "This ISO code is the name of po files to use for translations" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "Your system will be updated." +msgstr "" + +#. module: base +#: field:ir.actions.todo,note:0 +#: selection:ir.property,type:0 +msgid "Text" +msgstr "Мәтін" + +#. module: base +#: field:res.country,name:0 +msgid "Country Name" +msgstr "" + +#. module: base +#: model:res.country,name:base.co +msgid "Colombia" +msgstr "КолумбиÑ" + +#. module: base +#: view:ir.module.module:0 +msgid "Schedule Upgrade" +msgstr "" + +#. module: base +#: code:addons/orm.py:838 +#, python-format +msgid "Key/value '%s' not found in selection field '%s'" +msgstr "" + +#. module: base +#: help:res.country,code:0 +msgid "" +"The ISO country code in two chars.\n" +"You can use this field for quick search." +msgstr "" + +#. module: base +#: model:res.country,name:base.pw +msgid "Palau" +msgstr "Палау" + +#. module: base +#: view:res.partner:0 +msgid "Sales & Purchases" +msgstr "" + +#. module: base +#: view:ir.translation:0 +msgid "Untranslated" +msgstr "Ðударылмаған" + +#. module: base +#: help:ir.actions.act_window,context:0 +msgid "" +"Context dictionary as Python expression, empty by default (Default: {})" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_action_wizard +#: view:ir.actions.wizard:0 +#: model:ir.ui.menu,name:base.menu_ir_action_wizard +msgid "Wizards" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_miscellaneoussuppliers0 +msgid "Miscellaneous Suppliers" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:255 +#, python-format +msgid "Custom fields must have a name that starts with 'x_' !" +msgstr "" + +#. module: base +#: help:ir.actions.server,action_id:0 +msgid "Select the Action Window, Report, Wizard to be executed." +msgstr "" + +#. module: base +#: view:res.config.users:0 +msgid "New User" +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "Export done" +msgstr "" + +#. module: base +#: view:ir.model:0 +msgid "Model Description" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,src_model:0 +msgid "" +"Optional model name of the objects on which this action should be visible" +msgstr "" + +#. module: base +#: field:workflow.transition,trigger_expr_id:0 +msgid "Trigger Expression" +msgstr "" + +#. module: base +#: model:res.country,name:base.jo +msgid "Jordan" +msgstr "Хордан" + +#. module: base +#: view:ir.module.module:0 +msgid "Certified" +msgstr "" + +#. module: base +#: model:res.country,name:base.er +msgid "Eritrea" +msgstr "ÐритреÑ" + +#. module: base +#: view:res.config:0 +#: view:res.config.installer:0 +msgid "description" +msgstr "ÑипаттамаÑÑ‹" + +#. module: base +#: model:ir.ui.menu,name:base.menu_base_action_rule +msgid "Automated Actions" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_actions +msgid "ir.actions.actions" +msgstr "" + +#. module: base +#: view:partner.wizard.ean.check:0 +msgid "Want to check Ean ? " +msgstr "" + +#. module: base +#: field:ir.values,key2:0 +msgid "Event Type" +msgstr "Оқиға түрі" + +#. module: base +#: view:base.language.export:0 +msgid "" +"OpenERP translations (core, modules, clients) are managed through " +"Launchpad.net, our open source project management facility. We use their " +"online interface to synchronize all translations efforts." +msgstr "" + +#. module: base +#: field:res.partner,title:0 +msgid "Partner Form" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Swedish / svenska" +msgstr "" + +#. module: base +#: model:res.country,name:base.rs +msgid "Serbia" +msgstr "СербиÑ" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Wizard View" +msgstr "" + +#. module: base +#: model:res.country,name:base.kh +msgid "Cambodia, Kingdom of" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_sequence_form +#: view:ir.sequence:0 +#: model:ir.ui.menu,name:base.menu_ir_sequence_form +#: model:ir.ui.menu,name:base.next_id_5 +msgid "Sequences" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_language_import +msgid "Language Import" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_config_users +msgid "res.config.users" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Albanian / Shqip" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_crm_config_opportunity +msgid "Opportunities" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_language_export +msgid "base.language.export" +msgstr "" + +#. module: base +#: model:res.country,name:base.pg +msgid "Papua New Guinea" +msgstr "Папуа - Жаңа ГвинеÑ" + +#. module: base +#: help:ir.actions.report.xml,report_type:0 +msgid "Report Type, e.g. pdf, html, raw, sxw, odt, html2html, mako2html, ..." +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_4 +msgid "Basic Partner" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "," +msgstr "" + +#. module: base +#: view:res.partner:0 +msgid "My Partners" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "XML Report" +msgstr "" + +#. module: base +#: model:res.country,name:base.es +msgid "Spain" +msgstr "ИÑпаниÑ" + +#. module: base +#: model:ir.ui.menu,name:base.menu_translation_export +msgid "Import / Export" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,domain:0 +msgid "" +"Optional domain filtering of the destination data, as a Python expression" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade +#: model:ir.model,name:base.model_base_module_upgrade +msgid "Module Upgrade" +msgstr "" + +#. module: base +#: view:res.config.users:0 +msgid "" +"Groups are used to define access rights on objects and the visibility of " +"screens and menus" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (UY) / Español (UY)" +msgstr "" + +#. module: base +#: field:res.partner,mobile:0 +#: field:res.partner.address,mobile:0 +msgid "Mobile" +msgstr "Қалтафон" + +#. module: base +#: model:res.country,name:base.om +msgid "Oman" +msgstr "Оман" + +#. module: base +#: model:ir.actions.act_window,name:base.action_payterm_form +#: model:ir.model,name:base.model_res_payterm +msgid "Payment term" +msgstr "" + +#. module: base +#: model:res.country,name:base.nu +msgid "Niue" +msgstr "ÐиуÑ" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Work Days" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "Other OSI Approved Licence" +msgstr "" + +#. module: base +#: help:res.config.users,context_lang:0 +#: help:res.users,context_lang:0 +msgid "" +"Sets the language for the user's user interface, when UI translations are " +"available" +msgstr "" + +#. module: base +#: code:addons/orm.py:1043 +#, python-format +msgid "The unlink method is not implemented on this object !" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.act_menu_create +#: view:wizard.ir.model.menu.create:0 +msgid "Create Menu" +msgstr "" + +#. module: base +#: model:res.country,name:base.in +msgid "India" +msgstr "ҮндіÑтан" + +#. module: base +#: model:ir.actions.act_window,name:base.res_request_link-act +#: model:ir.ui.menu,name:base.menu_res_request_link_act +msgid "Request Reference Types" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "client_action_multi, client_action_relate" +msgstr "" + +#. module: base +#: model:res.country,name:base.ad +msgid "Andorra, Principality of" +msgstr "" + +#. module: base +#: field:ir.module.category,child_ids:0 +#: field:res.partner.category,child_ids:0 +msgid "Child Categories" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_config_parameter +msgid "ir.config_parameter" +msgstr "" + +#. module: base +#: selection:base.language.export,format:0 +msgid "TGZ Archive" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%B - Full month name." +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: field:ir.attachment,type:0 +#: field:ir.model,state:0 +#: field:ir.model.fields,state:0 +#: field:ir.property,type:0 +#: field:ir.server.object.lines,type:0 +#: field:ir.translation,type:0 +#: view:ir.ui.view:0 +#: view:ir.values:0 +#: field:ir.values,key:0 +#: view:res.partner:0 +#: view:res.partner.address:0 +msgid "Type" +msgstr "Түрі" + +#. module: base +#: code:addons/orm.py:210 +#, python-format +msgid "" +"Language with code \"%s\" is not defined in your system !\n" +"Define it through the Administration menu." +msgstr "" + +#. module: base +#: model:res.country,name:base.gu +msgid "Guam (USA)" +msgstr "Гуам (ÐҚШ)" + +#. module: base +#: model:ir.ui.menu,name:base.menu_hr_project +msgid "Human Resources Dashboard" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:507 +#, python-format +msgid "Setting empty passwords is not allowed for security reasons!" +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +#: selection:workflow.activity,kind:0 +msgid "Dummy" +msgstr "Жай" + +#. module: base +#: constraint:ir.ui.view:0 +msgid "Invalid XML for View Architecture!" +msgstr "" + +#. module: base +#: model:res.country,name:base.ky +msgid "Cayman Islands" +msgstr "Кайман ар-Ñ‹" + +#. module: base +#: model:res.country,name:base.kr +msgid "South Korea" +msgstr "Корей РеÑпубликаÑÑ‹" + +#. module: base +#: model:ir.actions.act_window,name:base.action_workflow_transition_form +#: model:ir.ui.menu,name:base.menu_workflow_transition +#: view:workflow.activity:0 +msgid "Transitions" +msgstr "" + +#. module: base +#: code:addons/orm.py:4020 +#, python-format +msgid "Record #%d of %s not found, cannot copy!" +msgstr "" + +#. module: base +#: field:ir.module.module,contributors:0 +msgid "Contributors" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Char" +msgstr "Симв." + +#. module: base +#: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_form +#: model:ir.ui.menu,name:base.menu_publisher_warranty_contract +msgid "Contracts" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (AR) / Español (AR)" +msgstr "" + +#. module: base +#: model:res.country,name:base.ug +msgid "Uganda" +msgstr "Уганда" + +#. module: base +#: field:ir.model.access,perm_unlink:0 +msgid "Delete Access" +msgstr "" + +#. module: base +#: model:res.country,name:base.ne +msgid "Niger" +msgstr "Ðигер" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Chinese (HK)" +msgstr "" + +#. module: base +#: model:res.country,name:base.ba +msgid "Bosnia-Herzegovina" +msgstr "БоÑÐ½Ð¸Ñ Ð¶Ó™Ð½Ðµ Герцоговина" + +#. module: base +#: view:base.language.export:0 +msgid "" +"To improve or expand the official translations, you should use directly " +"Lauchpad's web interface (Rosetta). If you need to perform mass translation, " +"Launchpad also allows uploading full .po files at once" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (GT) / Español (GT)" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "" +"%W - Week number of the year (Monday as the first day of the week) as a " +"decimal number [00,53]. All days in a new year preceding the first Monday " +"are considered to be in week 0." +msgstr "" + +#. module: base +#: field:ir.module.module,website:0 +#: field:res.partner,website:0 +msgid "Website" +msgstr "Веб Ñайт" + +#. module: base +#: model:res.country,name:base.gs +msgid "S. Georgia & S. Sandwich Isls." +msgstr "" + +#. module: base +#: field:ir.actions.url,url:0 +msgid "Action URL" +msgstr "" + +#. module: base +#: field:base.module.import,module_name:0 +msgid "Module Name" +msgstr "" + +#. module: base +#: model:res.country,name:base.mh +msgid "Marshall Islands" +msgstr "Маршалл аралдары" + +#. module: base +#: code:addons/base/ir/ir_model.py:328 +#, python-format +msgid "Changing the model of a field is forbidden!" +msgstr "" + +#. module: base +#: model:res.country,name:base.ht +msgid "Haiti" +msgstr "Гаити" + +#. module: base +#: view:ir.ui.view:0 +#: selection:ir.ui.view,type:0 +msgid "Search" +msgstr "Іздеу" + +#. module: base +#: code:addons/osv.py:136 +#, python-format +msgid "" +"The operation cannot be completed, probably due to the following:\n" +"- deletion: you may be trying to delete a record while other records still " +"reference it\n" +"- creation/update: a mandatory field is not correctly set" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "" +"2. Group-specific rules are combined together with a logical AND operator" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:206 +#, python-format +msgid "Operation Canceled" +msgstr "" + +#. module: base +#: help:base.language.export,lang:0 +msgid "To export a new language, do not select a language." +msgstr "" + +#. module: base +#: view:res.request:0 +msgid "Request Date" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_hr_dasboard +msgid "Dashboard" +msgstr "ÐÑпаптар панелі" + +#. module: base +#: model:ir.ui.menu,name:base.menu_purchase_root +msgid "Purchases" +msgstr "" + +#. module: base +#: model:res.country,name:base.md +msgid "Moldavia" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Features" +msgstr "Мүмкіндіктер" + +#. module: base +#: view:ir.module.module:0 +#: report:ir.module.reference.graph:0 +msgid "Version" +msgstr "ÐÒ±Ñқа" + +#. module: base +#: view:ir.model.access:0 +#: field:ir.model.access,perm_read:0 +#: view:ir.rule:0 +msgid "Read Access" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_exports +msgid "ir.exports" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_update_translations.py:38 +#, python-format +msgid "No language with code \"%s\" exists" +msgstr "" + +#. module: base +#: code:addons/base/publisher_warranty/publisher_warranty.py:163 +#, python-format +msgid "Error during communication with the publisher warranty server." +msgstr "" + +#. module: base +#: help:ir.actions.server,email:0 +msgid "" +"Provides the fields that will be used to fetch the email address, e.g. when " +"you select the invoice, then `object.invoice_address_id.email` is the field " +"which gives the correct address" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%Y - Year with century." +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "-" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract.wizard:0 +msgid "" +"This wizard helps you register a publisher warranty contract in your OpenERP " +"system. After the contract has been registered, you will be able to send " +"issues directly to OpenERP." +msgstr "" + +#. module: base +#: code:addons/orm.py:1744 +#, python-format +msgid "The search method is not implemented on this object !" +msgstr "" + +#. module: base +#: view:wizard.ir.model.menu.create:0 +msgid "Create _Menu" +msgstr "" + +#. module: base +#: field:res.payterm,name:0 +msgid "Payment Term (short name)" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_bank +#: view:res.bank:0 +#: field:res.partner.bank,bank:0 +msgid "Bank" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_exports_line +msgid "ir.exports.line" +msgstr "" + +#. module: base +#: help:base.language.install,overwrite:0 +msgid "" +"If you check this box, your customized translations will be overwritten and " +"replaced by the official ones." +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_rml:0 +msgid "Main report file path" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_action_report_xml +#: field:ir.module.module,reports_by_module:0 +#: model:ir.ui.menu,name:base.menu_ir_action_report_xml +msgid "Reports" +msgstr "" + +#. module: base +#: help:ir.actions.act_window.view,multi:0 +#: help:ir.actions.report.xml,multi:0 +msgid "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view." +msgstr "" + +#. module: base +#: field:workflow,on_create:0 +msgid "On Create" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:607 +#, python-format +msgid "" +"'%s' contains too many dots. XML ids should not contain dots ! These are " +"used to refer to other modules data, as in module.reference_id" +msgstr "" + +#. module: base +#: field:partner.sms.send,user:0 +#: field:res.config.users,login:0 +#: field:res.users,login:0 +msgid "Login" +msgstr "Кіру" + +#. module: base +#: view:ir.actions.server:0 +msgid "" +"Access all the fields related to the current object using expressions, i.e. " +"object.partner_id.name " +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_country_state +msgid "Country state" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Float" +msgstr "Қалқымалы" + +#. module: base +#: model:ir.model,name:base.model_res_request_link +msgid "res.request.link" +msgstr "" + +#. module: base +#: field:ir.actions.wizard,name:0 +msgid "Wizard Info" +msgstr "" + +#. module: base +#: view:base.language.export:0 +#: model:ir.actions.act_window,name:base.action_wizard_lang_export +#: model:ir.ui.menu,name:base.menu_wizard_lang_export +msgid "Export Translation" +msgstr "" + +#. module: base +#: help:res.log,secondary:0 +msgid "" +"Do not display this log if it belongs to the same object the user is working " +"on" +msgstr "" + +#. module: base +#: model:res.country,name:base.tp +msgid "East Timor" +msgstr "Ð¨Ñ‹Ò“Ñ‹Ñ Ð¢Ð¸Ð¼Ð¾Ñ€" + +#. module: base +#: model:res.company,follow_up_msg:base.main_company +msgid "" +"Date : %(date)s\n" +"\n" +"Dear %(partner_name)s,\n" +"\n" +"Please find in attachment a reminder of all your unpaid invoices, for a " +"total amount due of:\n" +"\n" +"%(followup_amount).2f %(company_currency)s\n" +"\n" +"Thanks,\n" +"--\n" +"%(user_signature)s\n" +"%(company_name)s" +msgstr "" + +#. module: base +#: field:res.currency,accuracy:0 +msgid "Computational Accuracy" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Sinhalese / සිංහල" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_wizard_ir_model_menu_create_line +msgid "wizard.ir.model.menu.create.line" +msgstr "" + +#. module: base +#: field:ir.attachment,res_id:0 +msgid "Attached ID" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Day: %(day)s" +msgstr "" + +#. module: base +#: model:res.country,name:base.mv +msgid "Maldives" +msgstr "Мальдив ар-Ñ‹" + +#. module: base +#: help:ir.values,res_id:0 +msgid "Keep 0 if the action must appear on all resources." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_rule +msgid "ir.rule" +msgstr "" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Days" +msgstr "күн" + +#. module: base +#: help:ir.actions.server,condition:0 +msgid "" +"Condition that is to be tested before action is executed, e.g. " +"object.list_price > object.cost_price" +msgstr "" + +#. module: base +#: code:addons/base/res/partner/partner.py:155 +#: code:addons/base/res/res_company.py:66 +#, python-format +msgid " (copy)" +msgstr " (көшірме)" + +#. module: base +#: view:res.lang:0 +msgid "7. %H:%M:%S ==> 18:25:20" +msgstr "" + +#. module: base +#: view:res.partner:0 +#: view:res.partner.category:0 +#: field:res.partner.category,partner_ids:0 +msgid "Partners" +msgstr "" + +#. module: base +#: field:res.partner.category,parent_left:0 +msgid "Left parent" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_widget_act_window +#: model:ir.ui.menu,name:base.menu_res_widget_act_window +msgid "Homepage Widgets" +msgstr "" + +#. module: base +#: help:ir.actions.server,message:0 +msgid "" +"Specify the message. You can use the fields from the object. e.g. `Dear [[ " +"object.partner_id.name ]]`" +msgstr "" + +#. module: base +#: field:ir.attachment,res_model:0 +msgid "Attached Model" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "Domain Setup" +msgstr "" + +#. module: base +#: field:ir.actions.server,trigger_name:0 +msgid "Trigger Name" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_model_access +msgid "ir.model.access" +msgstr "" + +#. module: base +#: field:ir.cron,priority:0 +#: field:res.request,priority:0 +#: field:res.request.link,priority:0 +msgid "Priority" +msgstr "Маңыздылығы" + +#. module: base +#: field:workflow.transition,act_from:0 +msgid "Source Activity" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Legend (for prefix, suffix)" +msgstr "" + +#. module: base +#: selection:ir.server.object.lines,type:0 +msgid "Formula" +msgstr "Формула" + +#. module: base +#: code:addons/base/res/res_user.py:389 +#, python-format +msgid "Can not remove root user!" +msgstr "" + +#. module: base +#: model:res.country,name:base.mw +msgid "Malawi" +msgstr "Малави" + +#. module: base +#: code:addons/base/res/res_user.py:51 +#: code:addons/base/res/res_user.py:413 +#, python-format +msgid "%s (copy)" +msgstr "" + +#. module: base +#: field:res.partner.address,type:0 +msgid "Address Type" +msgstr "" + +#. module: base +#: view:ir.ui.menu:0 +msgid "Full Path" +msgstr "Толық жолы" + +#. module: base +#: view:res.request:0 +msgid "References" +msgstr "References" + +#. module: base +#: view:res.lang:0 +msgid "" +"%U - Week number of the year (Sunday as the first day of the week) as a " +"decimal number [00,53]. All days in a new year preceding the first Sunday " +"are considered to be in week 0." +msgstr "" + +#. module: base +#: view:ir.ui.view:0 +msgid "Advanced" +msgstr "Жетелеу" + +#. module: base +#: model:res.country,name:base.fi +msgid "Finland" +msgstr "ФинлÑндиÑ" + +#. module: base +#: selection:ir.actions.act_window,view_type:0 +#: selection:ir.actions.act_window.view,view_mode:0 +#: view:ir.ui.view:0 +#: selection:ir.ui.view,type:0 +#: selection:wizard.ir.model.menu.create.line,view_type:0 +msgid "Tree" +msgstr "Бұтақ" + +#. module: base +#: help:res.config.users,password:0 +msgid "" +"Keep empty if you don't want the user to be able to connect on the system." +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Create / Write / Copy" +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "https://help.launchpad.net/Translations" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,view_mode:0 +msgid "View Mode" +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "" +"When using CSV format, please also check that the first line of your file is " +"one of the following:" +msgstr "" + +#. module: base +#: code:addons/fields.py:114 +#, python-format +msgid "Not implemented search_memory method !" +msgstr "" + +#. module: base +#: view:res.log:0 +msgid "Logs" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish / Español" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Korean (KP) / í•œêµì–´ (KP)" +msgstr "" + +#. module: base +#: view:base.module.update:0 +msgid "" +"This wizard will scan all module repositories on the server side to detect " +"newly added modules as well as any change to existing modules." +msgstr "" + +#. module: base +#: field:res.company,logo:0 +msgid "Logo" +msgstr "" + +#. module: base +#: view:res.partner.address:0 +msgid "Search Contact" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Uninstall (beta)" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window,target:0 +#: selection:ir.actions.url,target:0 +msgid "New Window" +msgstr "" + +#. module: base +#: model:res.country,name:base.bs +msgid "Bahamas" +msgstr "" + +#. module: base +#: code:addons/base/res/partner/partner.py:250 +#, python-format +msgid "" +"Couldn't generate the next id because some partners have an alphabetic id !" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Attachment" +msgstr "" + +#. module: base +#: model:res.country,name:base.ie +msgid "Ireland" +msgstr "" + +#. module: base +#: field:base.module.update,update:0 +msgid "Number of modules updated" +msgstr "" + +#. module: base +#: code:addons/fields.py:100 +#, python-format +msgid "Not implemented set_memory method !" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +msgid "Workflow Activity" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "" +"Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND " +"GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_ui_view +msgid "" +"Views allows you to personalize each view of OpenERP. You can add new " +"fields, move fields, rename them or delete the ones that you do not need." +msgstr "" + +#. module: base +#: field:ir.actions.act_window,groups_id:0 +#: model:ir.actions.act_window,name:base.action_res_groups +#: view:ir.actions.report.xml:0 +#: field:ir.actions.report.xml,groups_id:0 +#: view:ir.actions.todo:0 +#: field:ir.actions.todo,groups_id:0 +#: field:ir.actions.wizard,groups_id:0 +#: view:ir.model:0 +#: field:ir.model.fields,groups:0 +#: field:ir.rule,groups:0 +#: view:ir.ui.menu:0 +#: field:ir.ui.menu,groups_id:0 +#: model:ir.ui.menu,name:base.menu_action_res_groups +#: field:res.config.users,groups_id:0 +#: view:res.groups:0 +#: view:res.users:0 +#: field:res.users,groups_id:0 +msgid "Groups" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (CL) / Español (CL)" +msgstr "" + +#. module: base +#: view:res.config.users:0 +msgid "" +"Create additional users and assign them groups that will allow them to have " +"access to selected functionalities within the system. Click on 'Done' if you " +"do not wish to add more users at this stage, you can always do this later." +msgstr "" + +#. module: base +#: model:res.country,name:base.bz +msgid "Belize" +msgstr "" + +#. module: base +#: model:res.country,name:base.ge +msgid "Georgia" +msgstr "" + +#. module: base +#: model:res.country,name:base.pl +msgid "Poland" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,view_mode:0 +msgid "" +"Comma-separated list of allowed view modes, such as 'form', 'tree', " +"'calendar', etc. (Default: tree,form)" +msgstr "" + +#. module: base +#: code:addons/orm.py:3147 +#, python-format +msgid "A document was modified since you last viewed it (%s:%d)" +msgstr "" + +#. module: base +#: view:workflow:0 +msgid "Workflow Editor" +msgstr "" + +#. module: base +#: selection:ir.module.module,state:0 +#: selection:ir.module.module.dependency,state:0 +msgid "To be removed" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_sequence +msgid "ir.sequence" +msgstr "" + +#. module: base +#: help:ir.actions.server,expression:0 +msgid "" +"Enter the field/expression that will return the list. E.g. select the sale " +"order in Object, and you can have loop on the sales order line. Expression = " +"`object.order_line`." +msgstr "" + +#. module: base +#: field:ir.property,fields_id:0 +#: selection:ir.translation,type:0 +#: field:multi_company.default,field_id:0 +msgid "Field" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "Groups (no group = global)" +msgstr "" + +#. module: base +#: model:res.country,name:base.fo +msgid "Faroe Islands" +msgstr "" + +#. module: base +#: selection:res.config.users,view:0 +#: selection:res.config.view,view:0 +#: selection:res.users,view:0 +msgid "Simplified" +msgstr "" + +#. module: base +#: model:res.country,name:base.st +msgid "Saint Tome (Sao Tome) and Principe" +msgstr "" + +#. module: base +#: selection:res.partner.address,type:0 +msgid "Invoice" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Portugese (BR) / Português (BR)" +msgstr "" + +#. module: base +#: model:res.country,name:base.bb +msgid "Barbados" +msgstr "" + +#. module: base +#: model:res.country,name:base.mg +msgid "Madagascar" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:96 +#, python-format +msgid "" +"The Object name must start with x_ and not contain any special character !" +msgstr "" + +#. module: base +#: field:ir.actions.configuration.wizard,note:0 +msgid "Next Wizard" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_menu_admin +#: view:ir.ui.menu:0 +#: field:ir.ui.menu,name:0 +msgid "Menu" +msgstr "" + +#. module: base +#: field:res.currency,rate:0 +msgid "Current Rate" +msgstr "" + +#. module: base +#: field:ir.ui.view.custom,ref_id:0 +msgid "Original View" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Action To Launch" +msgstr "" + +#. module: base +#: field:ir.actions.url,target:0 +msgid "Action Target" +msgstr "" + +#. module: base +#: model:res.country,name:base.ai +msgid "Anguilla" +msgstr "" + +#. module: base +#: field:ir.ui.view_sc,name:0 +msgid "Shortcut Name" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,limit:0 +msgid "Default limit for the list view" +msgstr "" + +#. module: base +#: help:ir.actions.server,write_id:0 +msgid "" +"Provide the field name that the record id refers to for the write operation. " +"If it is empty it will refer to the active id of the object." +msgstr "" + +#. module: base +#: model:res.country,name:base.zw +msgid "Zimbabwe" +msgstr "" + +#. module: base +#: view:base.module.update:0 +msgid "Please be patient, as this operation may take a few seconds..." +msgstr "" + +#. module: base +#: help:ir.values,action_id:0 +msgid "This field is not used, it only helps you to select the right action." +msgstr "" + +#. module: base +#: field:ir.actions.server,email:0 +msgid "Email Address" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "French (BE) / Français (BE)" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +#: field:workflow.activity,action_id:0 +msgid "Server Action" +msgstr "" + +#. module: base +#: model:res.country,name:base.tt +msgid "Trinidad and Tobago" +msgstr "" + +#. module: base +#: model:res.country,name:base.lv +msgid "Latvia" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Values" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Field Mappings" +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "Export Translations" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_custom +msgid "Customization" +msgstr "" + +#. module: base +#: model:res.country,name:base.py +msgid "Paraguay" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_act_window_close +msgid "ir.actions.act_window_close" +msgstr "" + +#. module: base +#: field:ir.server.object.lines,col1:0 +msgid "Destination" +msgstr "" + +#. module: base +#: model:res.country,name:base.lt +msgid "Lithuania" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_view_partner_clear_ids +#: model:ir.model,name:base.model_partner_clear_ids +#: view:partner.clear.ids:0 +msgid "Clear IDs" +msgstr "" + +#. module: base +#: help:ir.cron,model:0 +msgid "" +"Name of object whose function will be called when this scheduler will run. " +"e.g. 'res.partener'" +msgstr "" + +#. module: base +#: code:addons/orm.py:1040 +#, python-format +msgid "The perm_read method is not implemented on this object !" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%y - Year without century [00,99]." +msgstr "" + +#. module: base +#: model:res.country,name:base.si +msgid "Slovenia" +msgstr "" + +#. module: base +#: model:res.country,name:base.pk +msgid "Pakistan" +msgstr "" + +#. module: base +#: code:addons/orm.py:1350 +#, python-format +msgid "Invalid Object Architecture!" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_email_gateway_form +msgid "Messages" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:303 +#: code:addons/base/ir/ir_model.py:317 +#: code:addons/base/ir/ir_model.py:319 +#: code:addons/base/ir/ir_model.py:321 +#: code:addons/base/ir/ir_model.py:328 +#: code:addons/base/ir/ir_model.py:331 +#: code:addons/base/module/wizard/base_update_translations.py:38 +#, python-format +msgid "Error!" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%p - Equivalent of either AM or PM." +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Iteration Actions" +msgstr "" + +#. module: base +#: help:multi_company.default,company_id:0 +msgid "Company where the user is connected" +msgstr "" + +#. module: base +#: field:publisher_warranty.contract,date_stop:0 +msgid "Ending Date" +msgstr "" + +#. module: base +#: model:res.country,name:base.nz +msgid "New Zealand" +msgstr "" + +#. module: base +#: code:addons/orm.py:3366 +#, python-format +msgid "" +"One of the records you are trying to modify has already been deleted " +"(Document type: %s)." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_country +msgid "" +"Display and manage the list of all countries that can be assigned to your " +"partner records. You can create or delete countries to make sure the ones " +"you are working on will be maintained." +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_7 +msgid "Openstuff.net" +msgstr "" + +#. module: base +#: model:res.country,name:base.nf +msgid "Norfolk Island" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Korean (KR) / í•œêµì–´ (KR)" +msgstr "" + +#. module: base +#: help:ir.model.fields,model:0 +msgid "The technical name of the model this field belongs to" +msgstr "" + +#. module: base +#: field:ir.actions.server,action_id:0 +#: selection:ir.actions.server,state:0 +msgid "Client Action" +msgstr "" + +#. module: base +#: model:res.country,name:base.bd +msgid "Bangladesh" +msgstr "" + +#. module: base +#: constraint:res.company:0 +msgid "Error! You can not create recursive companies." +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract,state:0 +msgid "Valid" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "XSL" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:322 +#, python-format +msgid "Can not upgrade module '%s'. It is not installed." +msgstr "" + +#. module: base +#: model:res.country,name:base.cu +msgid "Cuba" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_event +msgid "res.partner.event" +msgstr "" + +#. module: base +#: model:res.widget,title:base.facebook_widget +msgid "Facebook" +msgstr "" + +#. module: base +#: model:res.country,name:base.am +msgid "Armenia" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_property_form +#: model:ir.ui.menu,name:base.menu_ir_property_form_all +msgid "Configuration Parameters" +msgstr "" + +#. module: base +#: constraint:ir.cron:0 +msgid "Invalid arguments" +msgstr "" + +#. module: base +#: model:res.country,name:base.se +msgid "Sweden" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window.view,view_mode:0 +#: selection:ir.ui.view,type:0 +#: selection:wizard.ir.model.menu.create.line,view_type:0 +msgid "Gantt" +msgstr "" + +#. module: base +#: view:ir.property:0 +msgid "Property" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_bank_type +#: view:res.partner.bank.type:0 +msgid "Bank Account Type" +msgstr "" + +#. module: base +#: field:base.language.export,config_logo:0 +#: field:base.language.import,config_logo:0 +#: field:base.language.install,config_logo:0 +#: field:base.module.import,config_logo:0 +#: field:base.module.update,config_logo:0 +#: field:base.update.translations,config_logo:0 +#: field:ir.actions.configuration.wizard,config_logo:0 +#: field:ir.wizard.screen,config_logo:0 +#: field:publisher_warranty.contract.wizard,config_logo:0 +#: field:res.config,config_logo:0 +#: field:res.config.installer,config_logo:0 +#: field:res.config.users,config_logo:0 +#: field:res.config.view,config_logo:0 +msgid "Image" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Iteration Action Configuration" +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract,state:0 +msgid "Canceled" +msgstr "" + +#. module: base +#: model:res.country,name:base.at +msgid "Austria" +msgstr "" + +#. module: base +#: selection:base.language.install,state:0 +#: selection:base.module.import,state:0 +#: selection:base.module.update,state:0 +msgid "done" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window.view,view_mode:0 +#: model:ir.ui.menu,name:base.menu_calendar_configuration +#: selection:ir.ui.view,type:0 +#: selection:wizard.ir.model.menu.create.line,view_type:0 +msgid "Calendar" +msgstr "" + +#. module: base +#: field:res.partner.address,partner_id:0 +msgid "Partner Name" +msgstr "" + +#. module: base +#: field:workflow.activity,signal_send:0 +msgid "Signal (subflow.*)" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_17 +msgid "HR sector" +msgstr "" + +#. module: base +#: code:addons/orm.py:3817 +#, python-format +msgid "" +"Invalid \"order\" specified. A valid \"order\" specification is a comma-" +"separated list of valid field names (optionally followed by asc/desc for the " +"direction)" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_module_module_dependency +msgid "Module dependency" +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract.wizard,state:0 +msgid "Draft" +msgstr "" + +#. module: base +#: selection:res.config.users,view:0 +#: selection:res.config.view,view:0 +#: selection:res.users,view:0 +msgid "Extended" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_title_contact +msgid "" +"Manage the contact titles you want to have available in your system and the " +"way you want to print them in letters and other documents. Some example: " +"Mr., Mrs. " +msgstr "" + +#. module: base +#: field:res.company,rml_footer1:0 +msgid "Report Footer 1" +msgstr "" + +#. module: base +#: field:res.company,rml_footer2:0 +msgid "Report Footer 2" +msgstr "" + +#. module: base +#: view:ir.model.access:0 +#: view:res.groups:0 +#: field:res.groups,model_access:0 +msgid "Access Controls" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: field:ir.module.module,dependencies_id:0 +msgid "Dependencies" +msgstr "" + +#. module: base +#: field:multi_company.default,company_id:0 +msgid "Main Company" +msgstr "" + +#. module: base +#: field:ir.ui.menu,web_icon_hover:0 +msgid "Web Icon File (hover)" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "" +"If you use a formula type, use a python expression using the variable " +"'object'." +msgstr "" + +#. module: base +#: field:res.partner.address,birthdate:0 +msgid "Birthdate" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_title_contact +#: model:ir.ui.menu,name:base.menu_partner_title_contact +msgid "Contact Titles" +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "" +"Please double-check that the file encoding is set to UTF-8 (sometimes called " +"Unicode) when the translator exports it." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (DO) / Español (DO)" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow_activity +msgid "workflow.activity" +msgstr "" + +#. module: base +#: help:ir.ui.view_sc,res_id:0 +msgid "" +"Reference of the target resource, whose model/table depends on the 'Resource " +"Name' field." +msgstr "" + +#. module: base +#: field:ir.model.fields,select_level:0 +msgid "Searchable" +msgstr "" + +#. module: base +#: model:res.country,name:base.uy +msgid "Uruguay" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Finnish / Suomi" +msgstr "" + +#. module: base +#: field:ir.rule,perm_write:0 +msgid "Apply For Write" +msgstr "" + +#. module: base +#: field:ir.sequence,prefix:0 +msgid "Prefix" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "German / Deutsch" +msgstr "" + +#. module: base +#: help:ir.actions.server,trigger_name:0 +msgid "Select the Signal name that is to be used as the trigger." +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Fields Mapping" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Portugese / Português" +msgstr "" + +#. module: base +#: model:res.partner.title,name:base.res_partner_title_sir +msgid "Sir" +msgstr "" + +#. module: base +#: code:addons/orm.py:1622 +#, python-format +msgid "There is no view of type '%s' defined for the structure!" +msgstr "" + +#. module: base +#: field:ir.default,ref_id:0 +msgid "ID Ref." +msgstr "" + +#. module: base +#: model:ir.actions.server,name:base.action_start_configurator +#: model:ir.ui.menu,name:base.menu_view_base_module_configuration +msgid "Start Configuration" +msgstr "" + +#. module: base +#: model:res.country,name:base.mt +msgid "Malta" +msgstr "" + +#. module: base +#: field:ir.actions.server,fields_lines:0 +msgid "Field Mappings." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_module_module +#: view:ir.model.data:0 +#: field:ir.model.data,module:0 +#: view:ir.module.module:0 +#: field:ir.module.module.dependency,module_id:0 +#: report:ir.module.reference.graph:0 +#: field:ir.translation,module:0 +msgid "Module" +msgstr "" + +#. module: base +#: field:ir.attachment,description:0 +#: view:ir.module.module:0 +#: field:ir.module.module,description:0 +#: field:res.partner.bank,name:0 +#: view:res.partner.event:0 +#: field:res.partner.event,description:0 +#: view:res.request:0 +msgid "Description" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_workflow_instance_form +#: model:ir.ui.menu,name:base.menu_workflow_instance +msgid "Instances" +msgstr "" + +#. module: base +#: model:res.country,name:base.aq +msgid "Antarctica" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,auto:0 +msgid "Custom python parser" +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "_Import" +msgstr "" + +#. module: base +#: view:res.partner.canal:0 +msgid "Channel" +msgstr "" + +#. module: base +#: field:res.lang,grouping:0 +msgid "Separator Format" +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract,state:0 +msgid "Unvalidated" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.next_id_9 +msgid "Database Structure" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_mass_mail +#: model:ir.model,name:base.model_partner_wizard_spam +#: view:partner.wizard.spam:0 +msgid "Mass Mailing" +msgstr "" + +#. module: base +#: model:res.country,name:base.yt +msgid "Mayotte" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:597 +#, python-format +msgid "Please specify an action to launch !" +msgstr "" + +#. module: base +#: view:res.payterm:0 +msgid "Payment Term" +msgstr "" + +#. module: base +#: selection:res.lang,direction:0 +msgid "Right-to-Left" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +#: model:ir.actions.act_window,name:base.actions_ir_filters_view +#: view:ir.filters:0 +#: model:ir.model,name:base.model_ir_filters +#: model:ir.ui.menu,name:base.menu_ir_filters +msgid "Filters" +msgstr "" + +#. module: base +#: code:addons/orm.py:758 +#, python-format +msgid "Please check that all your lines have %d columns." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_cron_act +#: view:ir.cron:0 +#: model:ir.ui.menu,name:base.menu_ir_cron_act +msgid "Scheduled Actions" +msgstr "" + +#. module: base +#: field:res.partner.address,title:0 +#: field:res.partner.title,name:0 +#: field:res.widget,title:0 +msgid "Title" +msgstr "" + +#. module: base +#: help:ir.property,res_id:0 +msgid "If not set, acts as a default value for new resources" +msgstr "" + +#. module: base +#: code:addons/orm.py:3448 +#, python-format +msgid "Recursivity Detected." +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:262 +#, python-format +msgid "Recursion error in modules dependencies !" +msgstr "" + +#. module: base +#: view:base.language.install:0 +msgid "" +"This wizard helps you add a new language to your OpenERP system. After " +"loading a new language it becomes available as default interface language " +"for users and partners." +msgstr "" + +#. module: base +#: view:ir.model:0 +msgid "Create a Menu" +msgstr "" + +#. module: base +#: help:res.partner,vat:0 +msgid "" +"Value Added Tax number. Check the box if the partner is subjected to the " +"VAT. Used by the VAT legal statement." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_maintenance_contract +msgid "maintenance.contract" +msgstr "" + +#. module: base +#: model:res.country,name:base.ru +msgid "Russian Federation" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Urdu / اردو" +msgstr "" + +#. module: base +#: field:res.company,name:0 +msgid "Company Name" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_country +#: model:ir.ui.menu,name:base.menu_country_partner +msgid "Countries" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "RML (deprecated - use Report)" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "Record rules" +msgstr "" + +#. module: base +#: view:ir.property:0 +msgid "Field Information" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +msgid "Search Actions" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_view_partner_wizard_ean_check +#: view:partner.wizard.ean.check:0 +msgid "Ean check" +msgstr "" + +#. module: base +#: field:res.partner,vat:0 +msgid "VAT" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "12. %w ==> 5 ( Friday is the 6th day)" +msgstr "" + +#. module: base +#: constraint:res.partner.category:0 +msgid "Error ! You can not create recursive categories." +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%x - Appropriate date representation." +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%d - Day of the month [01,31]." +msgstr "" + +#. module: base +#: model:res.country,name:base.tj +msgid "Tajikistan" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "GPL-2 or later version" +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_sir +msgid "M." +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:429 +#, python-format +msgid "" +"Can not create the module file:\n" +" %s" +msgstr "" + +#. module: base +#: code:addons/orm.py:2973 +#, python-format +msgid "" +"Operation prohibited by access rules, or performed on an already deleted " +"document (Operation: read, Document type: %s)." +msgstr "" + +#. module: base +#: model:res.country,name:base.nr +msgid "Nauru" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:200 +#, python-format +msgid "The certificate ID of the module must be unique !" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_property +msgid "ir.property" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window,view_type:0 +#: selection:ir.actions.act_window.view,view_mode:0 +#: view:ir.ui.view:0 +#: selection:ir.ui.view,type:0 +#: selection:wizard.ir.model.menu.create.line,view_type:0 +msgid "Form" +msgstr "" + +#. module: base +#: model:res.country,name:base.me +msgid "Montenegro" +msgstr "" + +#. module: base +#: view:ir.cron:0 +msgid "Technical Data" +msgstr "" + +#. module: base +#: view:res.partner:0 +#: field:res.partner,category_id:0 +msgid "Categories" +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "" +"If you need another language than the official ones available, you can " +"import a language pack from here. Other OpenERP languages than the official " +"ones can be found on launchpad." +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: selection:ir.module.module,state:0 +#: selection:ir.module.module.dependency,state:0 +msgid "To be upgraded" +msgstr "" + +#. module: base +#: model:res.country,name:base.ly +msgid "Libya" +msgstr "" + +#. module: base +#: model:res.country,name:base.cf +msgid "Central African Republic" +msgstr "" + +#. module: base +#: model:res.country,name:base.li +msgid "Liechtenstein" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_partner_sms_send +#: view:partner.sms.send:0 +msgid "Send SMS" +msgstr "" + +#. module: base +#: field:res.partner,ean13:0 +msgid "EAN13" +msgstr "" + +#. module: base +#: code:addons/orm.py:1622 +#, python-format +msgid "Invalid Architecture!" +msgstr "" + +#. module: base +#: model:res.country,name:base.pt +msgid "Portugal" +msgstr "" + +#. module: base +#: sql_constraint:ir.model.data:0 +msgid "" +"You cannot have multiple records with the same id for the same module !" +msgstr "" + +#. module: base +#: field:ir.module.module,certificate:0 +msgid "Quality Certificate" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "6. %d, %m ==> 05, 12" +msgstr "" + +#. module: base +#: field:res.config.users,date:0 +#: field:res.users,date:0 +msgid "Last Connection" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,help:0 +msgid "Action description" +msgstr "" + +#. module: base +#: help:res.partner,customer:0 +msgid "Check this box if the partner is a customer." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_lang_act_window +#: model:ir.model,name:base.model_res_lang +#: model:ir.ui.menu,name:base.menu_res_lang_act_window +#: view:res.lang:0 +msgid "Languages" +msgstr "" + +#. module: base +#: selection:workflow.activity,join_mode:0 +#: selection:workflow.activity,split_mode:0 +msgid "Xor" +msgstr "" + +#. module: base +#: model:res.country,name:base.ec +msgid "Ecuador" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_export_language.py:52 +#, python-format +msgid "" +"Save this document to a .CSV file and open it with your favourite " +"spreadsheet software. The file encoding is UTF-8. You have to translate the " +"latest column before reimporting it." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_customer_form +#: model:ir.actions.act_window,name:base.action_partner_form +#: model:ir.ui.menu,name:base.menu_partner_form +#: view:res.partner:0 +msgid "Customers" +msgstr "" + +#. module: base +#: model:res.country,name:base.au +msgid "Australia" +msgstr "" + +#. module: base +#: help:res.partner,lang:0 +msgid "" +"If the selected language is loaded in the system, all documents related to " +"this partner will be printed in this language. If not, it will be english." +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Menu :" +msgstr "" + +#. module: base +#: selection:ir.model.fields,state:0 +msgid "Base Field" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract:0 +msgid "Validate" +msgstr "" + +#. module: base +#: field:ir.actions.todo,restart:0 +msgid "Restart" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_sxw_content:0 +#: field:ir.actions.report.xml,report_sxw_content_data:0 +msgid "SXW content" +msgstr "" + +#. module: base +#: view:ir.actions.wizard:0 +#: field:wizard.ir.model.menu.create.line,wizard_id:0 +msgid "Wizard" +msgstr "" + +#. module: base +#: view:ir.cron:0 +msgid "Action to Trigger" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:136 +#, python-format +msgid "\"email_from\" needs to be set to send welcome mails to users" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Constraint" +msgstr "" + +#. module: base +#: selection:ir.values,key:0 +#: selection:res.partner.address,type:0 +msgid "Default" +msgstr "" + +#. module: base +#: view:ir.model.fields:0 +#: field:ir.model.fields,required:0 +#: field:res.partner.bank.type.field,required:0 +msgid "Required" +msgstr "" + +#. module: base +#: view:res.users:0 +msgid "Default Filters" +msgstr "" + +#. module: base +#: field:res.request.history,name:0 +msgid "Summary" +msgstr "" + +#. module: base +#: field:multi_company.default,expression:0 +msgid "Expression" +msgstr "" + +#. module: base +#: help:ir.actions.server,subject:0 +msgid "" +"Specify the subject. You can use fields from the object, e.g. `Hello [[ " +"object.partner_id.name ]]`" +msgstr "" + +#. module: base +#: view:res.company:0 +msgid "Header/Footer" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,help:0 +msgid "" +"Optional help text for the users with a description of the target view, such " +"as its usage and purpose." +msgstr "" + +#. module: base +#: model:res.country,name:base.va +msgid "Holy See (Vatican City State)" +msgstr "" + +#. module: base +#: field:base.module.import,module_file:0 +msgid "Module .ZIP file" +msgstr "" + +#. module: base +#: field:ir.ui.view,xml_id:0 +msgid "XML ID" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_16 +msgid "Telecom sector" +msgstr "" + +#. module: base +#: field:workflow.transition,trigger_model:0 +msgid "Trigger Object" +msgstr "" + +#. module: base +#: view:res.users:0 +msgid "Current Activity" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: field:workflow.activity,in_transitions:0 +msgid "Incoming Transitions" +msgstr "" + +#. module: base +#: model:res.country,name:base.sr +msgid "Suriname" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.marketing_menu +msgid "Marketing" +msgstr "" + +#. module: base +#: view:res.partner.bank:0 +#: model:res.partner.bank.type,name:base.bank_normal +msgid "Bank account" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (HN) / Español (HN)" +msgstr "" + +#. module: base +#: view:ir.sequence.type:0 +msgid "Sequence Type" +msgstr "" + +#. module: base +#: view:ir.ui.view.custom:0 +msgid "Customized Architecture" +msgstr "" + +#. module: base +#: field:ir.module.module,license:0 +msgid "License" +msgstr "" + +#. module: base +#: field:ir.attachment,url:0 +msgid "Url" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,restart:0 +msgid "Always" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "SQL Constraint" +msgstr "" + +#. module: base +#: field:ir.actions.server,srcmodel_id:0 +#: field:ir.model.fields,model_id:0 +msgid "Model" +msgstr "" + +#. module: base +#: view:base.language.install:0 +msgid "" +"The selected language has been successfully installed. You must change the " +"preferences of the user and open a new menu to view the changes." +msgstr "" + +#. module: base +#: sql_constraint:ir.config_parameter:0 +msgid "Key must be unique." +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +msgid "Open a Window" +msgstr "" + +#. module: base +#: model:res.country,name:base.gq +msgid "Equatorial Guinea" +msgstr "" + +#. module: base +#: view:base.module.import:0 +#: model:ir.actions.act_window,name:base.action_view_base_module_import +msgid "Module Import" +msgstr "" + +#. module: base +#: field:res.bank,zip:0 +#: field:res.partner.address,zip:0 +#: field:res.partner.bank,zip:0 +msgid "Zip" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: field:ir.module.module,author:0 +msgid "Author" +msgstr "" + +#. module: base +#: model:res.country,name:base.mk +msgid "FYROM" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%c - Appropriate date and time representation." +msgstr "" + +#. module: base +#: code:addons/base/res/res_config.py:422 +#, python-format +msgid "" +"Your database is now fully configured.\n" +"\n" +"Click 'Continue' and enjoy your OpenERP experience..." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Hebrew / עִבְרִי" +msgstr "" + +#. module: base +#: model:res.country,name:base.bo +msgid "Bolivia" +msgstr "" + +#. module: base +#: model:res.country,name:base.gh +msgid "Ghana" +msgstr "" + +#. module: base +#: field:res.lang,direction:0 +msgid "Direction" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +#: model:ir.actions.act_window,name:base.action_ui_view +#: field:ir.actions.act_window,view_ids:0 +#: field:ir.actions.act_window,views:0 +#: field:ir.module.module,views_by_module:0 +#: model:ir.ui.menu,name:base.menu_action_ui_view +#: view:ir.ui.view:0 +msgid "Views" +msgstr "" + +#. module: base +#: view:res.groups:0 +#: field:res.groups,rule_groups:0 +msgid "Rules" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:216 +#, python-format +msgid "You try to remove a module that is installed or will be installed" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "The selected modules have been updated / installed !" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (PR) / Español (PR)" +msgstr "" + +#. module: base +#: model:res.country,name:base.gt +msgid "Guatemala" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_workflow_form +#: model:ir.ui.menu,name:base.menu_low_workflow +#: model:ir.ui.menu,name:base.menu_workflow +#: model:ir.ui.menu,name:base.menu_workflow_root +msgid "Workflows" +msgstr "" + +#. module: base +#: field:ir.translation,xml_id:0 +msgid "XML Id" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_config_user_form +msgid "Create Users" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_title +msgid "res.partner.title" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "tree_but_action, client_print_multi" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_retailers0 +msgid "Retailers" +msgstr "" + +#. module: base +#: help:ir.cron,priority:0 +msgid "" +"0=Very Urgent\n" +"10=Not urgent" +msgstr "" + +#. module: base +#: view:res.config:0 +#: view:res.config.installer:0 +msgid "Skip" +msgstr "" + +#. module: base +#: model:res.country,name:base.ls +msgid "Lesotho" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:114 +#, python-format +msgid "You can not remove the model '%s' !" +msgstr "" + +#. module: base +#: model:res.country,name:base.ke +msgid "Kenya" +msgstr "" + +#. module: base +#: view:res.partner.event:0 +msgid "Event" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_custom_reports +msgid "Custom Reports" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Abkhazian / аҧÑуа" +msgstr "" + +#. module: base +#: view:base.module.configuration:0 +msgid "System Configuration Done" +msgstr "" + +#. module: base +#: code:addons/orm.py:929 +#, python-format +msgid "Error occurred while validating the field(s) %s: %s" +msgstr "" + +#. module: base +#: view:ir.property:0 +msgid "Generic" +msgstr "" + +#. module: base +#: model:res.country,name:base.sm +msgid "San Marino" +msgstr "" + +#. module: base +#: model:res.country,name:base.bm +msgid "Bermuda" +msgstr "" + +#. module: base +#: model:res.country,name:base.pe +msgid "Peru" +msgstr "" + +#. module: base +#: selection:ir.model.fields,on_delete:0 +msgid "Set NULL" +msgstr "" + +#. module: base +#: model:res.country,name:base.bj +msgid "Benin" +msgstr "" + +#. module: base +#: code:addons/base/publisher_warranty/publisher_warranty.py:281 +#, python-format +msgid "That contract is already registered in the system." +msgstr "" + +#. module: base +#: help:ir.sequence,suffix:0 +msgid "Suffix value of the record for the sequence" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (PY) / Español (PY)" +msgstr "" + +#. module: base +#: field:ir.config_parameter,key:0 +msgid "Key" +msgstr "" + +#. module: base +#: field:res.company,rml_header:0 +msgid "RML Header" +msgstr "" + +#. module: base +#: field:partner.sms.send,app_id:0 +msgid "API ID" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:486 +#, python-format +msgid "" +"You can not create this document (%s) ! Be sure your user belongs to one of " +"these groups: %s." +msgstr "" + +#. module: base +#: model:res.country,name:base.mu +msgid "Mauritius" +msgstr "" + +#. module: base +#: view:ir.model.access:0 +#: view:ir.rule:0 +msgid "Full Access" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +#: view:ir.actions.report.xml:0 +#: view:ir.actions.wizard:0 +#: view:ir.model.fields:0 +#: model:ir.ui.menu,name:base.menu_security +msgid "Security" +msgstr "" + +#. module: base +#: model:res.widget,title:base.openerp_favorites_twitter_widget +msgid "OpenERP Favorites" +msgstr "" + +#. module: base +#: model:res.country,name:base.za +msgid "South Africa" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: selection:ir.module.module,state:0 +#: selection:ir.module.module.dependency,state:0 +msgid "Installed" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Ukrainian / українÑька" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_translation +#: model:ir.ui.menu,name:base.menu_action_translation +msgid "Translation Terms" +msgstr "" + +#. module: base +#: model:res.country,name:base.sn +msgid "Senegal" +msgstr "" + +#. module: base +#: model:res.country,name:base.hu +msgid "Hungary" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_groups +msgid "res.groups" +msgstr "" + +#. module: base +#: model:res.country,name:base.br +msgid "Brazil" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%M - Minute [00,59]." +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "Affero GPL-3" +msgstr "" + +#. module: base +#: field:ir.sequence,number_next:0 +msgid "Next Number" +msgstr "" + +#. module: base +#: help:workflow.transition,condition:0 +msgid "Expression to be satisfied if we want the transition done." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (PA) / Español (PA)" +msgstr "" + +#. module: base +#: view:res.currency:0 +#: field:res.currency,rate_ids:0 +msgid "Rates" +msgstr "" + +#. module: base +#: model:res.country,name:base.sy +msgid "Syria" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "======================================================" +msgstr "" + +#. module: base +#: help:ir.actions.server,mobile:0 +msgid "" +"Provides fields that be used to fetch the mobile number, e.g. you select the " +"invoice, then `object.invoice_address_id.mobile` is the field which gives " +"the correct mobile number" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "System update completed" +msgstr "" + +#. module: base +#: selection:res.request,state:0 +msgid "draft" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +#: field:res.currency,date:0 +#: field:res.currency.rate,name:0 +#: field:res.partner,date:0 +#: field:res.partner.event,date:0 +#: field:res.request,date_sent:0 +msgid "Date" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_sxw:0 +msgid "SXW path" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Data" +msgstr "" + +#. module: base +#: field:ir.ui.menu,parent_id:0 +#: field:wizard.ir.model.menu.create,menu_id:0 +msgid "Parent Menu" +msgstr "" + +#. module: base +#: field:ir.rule,perm_unlink:0 +msgid "Apply For Delete" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:319 +#, python-format +msgid "Cannot rename column to %s, because that column already exists!" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Attached To" +msgstr "" + +#. module: base +#: field:res.lang,decimal_point:0 +msgid "Decimal Separator" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_res_groups +msgid "" +"A group is a set of functional areas that will be assigned to the user in " +"order to give them access and rights to specific applications and tasks in " +"the system. You can create custom groups or edit the ones existing by " +"default in order to customize the view of the menu that users will be able " +"to see. Whether they can have a read, write, create and delete access right " +"can be managed from here." +msgstr "" + +#. module: base +#: view:res.partner:0 +#: view:res.request:0 +#: field:res.request,history:0 +msgid "History" +msgstr "" + +#. module: base +#: field:ir.attachment,create_uid:0 +msgid "Creator" +msgstr "" + +#. module: base +#: model:res.company,overdue_msg:base.main_company +msgid "" +"Please note that the following payments are now due. If your payment " +" has been sent, kindly forward your payment details. If " +"payment will be delayed further, please contact us " +"to discuss. \n" +"Would your payment have been carried out after this mail was sent, please " +"consider the present one as void." +msgstr "" + +#. module: base +#: model:res.country,name:base.mx +msgid "Mexico" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_base_config_plugins +msgid "Plugins" +msgstr "" + +#. module: base +#: field:res.company,child_ids:0 +msgid "Child Companies" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_users +msgid "res.users" +msgstr "" + +#. module: base +#: model:res.country,name:base.ni +msgid "Nicaragua" +msgstr "" + +#. module: base +#: code:addons/orm.py:1046 +#, python-format +msgid "The write method is not implemented on this object !" +msgstr "" + +#. module: base +#: view:res.partner.event:0 +msgid "General Description" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_config_simple_view_form +#: view:res.config.view:0 +msgid "Configure Your Interface" +msgstr "" + +#. module: base +#: field:ir.values,meta:0 +msgid "Meta Datas" +msgstr "" + +#. module: base +#: sql_constraint:ir.ui.view_sc:0 +msgid "Shortcut for this menu already exists!" +msgstr "" + +#. module: base +#: model:res.country,name:base.ve +msgid "Venezuela" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "9. %j ==> 340" +msgstr "" + +#. module: base +#: model:res.country,name:base.zm +msgid "Zambia" +msgstr "" + +#. module: base +#: help:res.partner,user_id:0 +msgid "" +"The internal user that is in charge of communicating with this partner if " +"any." +msgstr "" + +#. module: base +#: field:res.partner,parent_id:0 +msgid "Parent Partner" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Cancel Upgrade" +msgstr "" + +#. module: base +#: model:res.country,name:base.ci +msgid "Ivory Coast (Cote D'Ivoire)" +msgstr "" + +#. module: base +#: model:res.country,name:base.kz +msgid "Kazakhstan" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%w - Weekday number [0(Sunday),6]." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_form +msgid "" +"A customer is an entity you do business with, like a company or an " +"organization. A customer can have several contacts or addresses which are " +"the people working for this company. You can use the history tab, to follow " +"all transactions related to a customer: sales order, emails, opportunities, " +"claims, etc. If you use the email gateway, the Outlook or the Thunderbird " +"plugin, don't forget to register emails to each contact so that the gateway " +"will automatically attach incoming emails to the right partner." +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,name:0 +#: field:ir.actions.todo,name:0 +#: field:ir.cron,name:0 +#: field:ir.model.access,name:0 +#: field:ir.model.fields,name:0 +#: field:ir.module.category,name:0 +#: field:ir.module.module,name:0 +#: field:ir.module.module.dependency,name:0 +#: report:ir.module.reference.graph:0 +#: field:ir.property,name:0 +#: field:ir.rule,name:0 +#: field:ir.sequence,name:0 +#: field:ir.sequence.type,name:0 +#: field:ir.values,name:0 +#: field:multi_company.default,name:0 +#: field:res.bank,name:0 +#: field:res.config.view,name:0 +#: field:res.lang,name:0 +#: field:res.partner,name:0 +#: field:res.partner.bank.type,name:0 +#: view:res.partner.event:0 +#: field:res.request.link,name:0 +#: field:workflow,name:0 +#: field:workflow.activity,name:0 +msgid "Name" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,multi:0 +msgid "" +"If set to true, the action will not be displayed on the right toolbar of a " +"form view" +msgstr "" + +#. module: base +#: model:res.country,name:base.ms +msgid "Montserrat" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:205 +#, python-format +msgid "" +"The Selection Options expression is not a valid Pythonic expression.Please " +"provide an expression in the [('key','Label'), ...] format." +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_translation_app +msgid "Application Terms" +msgstr "" + +#. module: base +#: help:res.config.users,context_tz:0 +#: help:res.users,context_tz:0 +msgid "" +"The user's timezone, used to perform timezone conversions between the server " +"and the client." +msgstr "" + +#. module: base +#: field:ir.module.module,demo:0 +msgid "Demo data" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "English (UK)" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Japanese / 日本語" +msgstr "" + +#. module: base +#: help:workflow.transition,act_from:0 +msgid "" +"Source activity. When this activity is over, the condition is tested to " +"determine if we can start the ACT_TO activity." +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_3 +msgid "Starter Partner" +msgstr "" + +#. module: base +#: help:ir.model.fields,relation_field:0 +msgid "" +"For one2many fields, the field on the target model that implement the " +"opposite many2one relationship" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_act_window_view +msgid "ir.actions.act_window.view" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Web" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "English (CA)" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_publisher_warranty_contract +msgid "publisher_warranty.contract" +msgstr "" + +#. module: base +#: model:res.country,name:base.et +msgid "Ethiopia" +msgstr "" + +#. module: base +#: help:res.country.state,code:0 +msgid "The state code in three chars.\n" +msgstr "" + +#. module: base +#: model:res.country,name:base.sj +msgid "Svalbard and Jan Mayen Islands" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_wizard +#: selection:ir.ui.menu,action:0 +msgid "ir.actions.wizard" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +#: view:ir.actions.report.xml:0 +#: view:ir.actions.server:0 +#: view:ir.filters:0 +#: view:res.request:0 +msgid "Group By" +msgstr "" + +#. module: base +#: view:res.config:0 +#: view:res.config.installer:0 +msgid "title" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_language_install +msgid "Install Language" +msgstr "" + +#. module: base +#: view:ir.translation:0 +msgid "Translation" +msgstr "" + +#. module: base +#: selection:res.request,state:0 +msgid "closed" +msgstr "" + +#. module: base +#: selection:base.language.export,state:0 +msgid "get" +msgstr "" + +#. module: base +#: help:ir.model.fields,on_delete:0 +msgid "On delete property for many2one fields" +msgstr "" + +#. module: base +#: field:ir.actions.server,write_id:0 +msgid "Write Id" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_product +msgid "Products" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,domain:0 +#: field:ir.filters,domain:0 +msgid "Domain Value" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "SMS Configuration" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (BO) / Español (BO)" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_access_act +#: model:ir.ui.menu,name:base.menu_ir_access_act +msgid "Access Controls List" +msgstr "" + +#. module: base +#: model:res.country,name:base.um +msgid "USA Minor Outlying Islands" +msgstr "" + +#. module: base +#: field:res.partner.bank,state:0 +#: field:res.partner.bank.type.field,bank_type_id:0 +msgid "Bank Type" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:58 +#: code:addons/base/res/res_user.py:67 +#, python-format +msgid "The name of the group can not start with \"-\"" +msgstr "" + +#. module: base +#: view:ir.ui.view_sc:0 +#: field:res.partner.title,shortcut:0 +msgid "Shortcut" +msgstr "" + +#. module: base +#: field:ir.model.data,date_init:0 +msgid "Init Date" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Gujarati / ગà«àªœàª°àª¾àª¤à«€" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:257 +#, python-format +msgid "" +"Unable to process module \"%s\" because an external dependency is not met: %s" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract.wizard:0 +msgid "Please enter the serial key provided in your contract document:" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: field:workflow.activity,flow_start:0 +msgid "Flow Start" +msgstr "" + +#. module: base +#: code:addons/__init__.py:834 +#, python-format +msgid "module base cannot be loaded! (hint: verify addons-path)" +msgstr "" + +#. module: base +#: view:res.partner.bank:0 +msgid "Bank Account Owner" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.act_values_form +msgid "Client Actions Connections" +msgstr "" + +#. module: base +#: field:ir.attachment,res_name:0 +#: field:ir.ui.view_sc,resource:0 +msgid "Resource Name" +msgstr "" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Hours" +msgstr "" + +#. module: base +#: model:res.country,name:base.gp +msgid "Guadeloupe (French)" +msgstr "" + +#. module: base +#: code:addons/base/res/res_lang.py:157 +#: code:addons/base/res/res_lang.py:159 +#: code:addons/base/res/res_lang.py:161 +#, python-format +msgid "User Error" +msgstr "" + +#. module: base +#: help:workflow.transition,signal:0 +msgid "" +"When the operation of transition comes from a button pressed in the client " +"form, signal tests the name of the pressed button. If signal is NULL, no " +"button is necessary to validate this transition." +msgstr "" + +#. module: base +#: help:multi_company.default,object_id:0 +msgid "Object affected by this rule" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Directory" +msgstr "" + +#. module: base +#: field:wizard.ir.model.menu.create,name:0 +msgid "Menu Name" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Author Website" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Month" +msgstr "" + +#. module: base +#: model:res.country,name:base.my +msgid "Malaysia" +msgstr "" + +#. module: base +#: view:base.language.install:0 +#: model:ir.actions.act_window,name:base.action_view_base_language_install +msgid "Load Official Translation" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_request_history +msgid "res.request.history" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Client Action Configuration" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_address +#: view:res.partner.address:0 +msgid "Partner Addresses" +msgstr "" + +#. module: base +#: help:ir.model.fields,translate:0 +msgid "" +"Whether values for this field can be translated (enables the translation " +"mechanism for that field)" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%S - Seconds [00,61]." +msgstr "" + +#. module: base +#: model:res.country,name:base.cv +msgid "Cape Verde" +msgstr "" + +#. module: base +#: view:base.module.import:0 +msgid "Select module package to import (.zip file):" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.act_res_partner_event +#: field:res.partner,events:0 +#: field:res.partner.event,name:0 +#: model:res.widget,title:base.events_widget +msgid "Events" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_url +#: selection:ir.ui.menu,action:0 +msgid "ir.actions.url" +msgstr "" + +#. module: base +#: model:res.widget,title:base.currency_converter_widget +msgid "Currency Converter" +msgstr "" + +#. module: base +#: code:addons/orm.py:156 +#, python-format +msgid "Wrong ID for the browse record, got %r, expected an integer." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_addess_tree +#: view:res.partner:0 +msgid "Partner Contacts" +msgstr "" + +#. module: base +#: field:base.module.update,add:0 +msgid "Number of modules added" +msgstr "" + +#. module: base +#: view:res.currency:0 +msgid "Price Accuracy" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Latvian / latvieÅ¡u valoda" +msgstr "" + +#. module: base +#: view:res.config:0 +#: view:res.config.installer:0 +msgid "vsep" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "French / Français" +msgstr "" + +#. module: base +#: code:addons/orm.py:1049 +#, python-format +msgid "The create method is not implemented on this object !" +msgstr "" + +#. module: base +#: field:workflow.triggers,workitem_id:0 +msgid "Workitem" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +msgid "Set as Todo" +msgstr "" + +#. module: base +#: field:ir.actions.act_window.view,act_window_id:0 +#: view:ir.actions.actions:0 +#: field:ir.actions.todo,action_id:0 +#: field:ir.ui.menu,action:0 +#: field:ir.values,action_id:0 +#: selection:ir.values,key:0 +#: view:res.users:0 +msgid "Action" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Email Configuration" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_cron +msgid "ir.cron" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "Combination of rules" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Current Year without Century: %(y)s" +msgstr "" + +#. module: base +#: field:ir.actions.server,trigger_obj_id:0 +msgid "Trigger On" +msgstr "" + +#. module: base +#: sql_constraint:ir.rule:0 +msgid "Rule must have at least one checked access right !" +msgstr "" + +#. module: base +#: model:res.country,name:base.fj +msgid "Fiji" +msgstr "" + +#. module: base +#: field:ir.model.fields,size:0 +msgid "Size" +msgstr "" + +#. module: base +#: model:res.country,name:base.sd +msgid "Sudan" +msgstr "" + +#. module: base +#: model:res.country,name:base.fm +msgid "Micronesia" +msgstr "" + +#. module: base +#: view:res.request.history:0 +msgid "Request History" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,menus:0 +#: field:ir.module.module,menus_by_module:0 +#: view:res.groups:0 +msgid "Menus" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Serbian (Latin) / srpski" +msgstr "" + +#. module: base +#: model:res.country,name:base.il +msgid "Israel" +msgstr "" + +#. module: base +#: model:ir.actions.wizard,name:base.wizard_server_action_create +msgid "Create Action" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_model_model +#: model:ir.model,name:base.model_ir_model +#: model:ir.ui.menu,name:base.ir_model_model_menu +msgid "Objects" +msgstr "" + +#. module: base +#: field:res.lang,time_format:0 +msgid "Time Format" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Defined Reports" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "Report xml" +msgstr "" + +#. module: base +#: field:base.language.export,modules:0 +#: model:ir.actions.act_window,name:base.action_module_open_categ +#: model:ir.actions.act_window,name:base.open_module_tree +#: view:ir.module.module:0 +#: model:ir.ui.menu,name:base.menu_management +#: model:ir.ui.menu,name:base.menu_module_tree +msgid "Modules" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: selection:workflow.activity,kind:0 +#: field:workflow.activity,subflow_id:0 +#: field:workflow.workitem,subflow_id:0 +msgid "Subflow" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_config +msgid "res.config" +msgstr "" + +#. module: base +#: field:workflow.transition,signal:0 +msgid "Signal (button Name)" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_bank_form +#: model:ir.ui.menu,name:base.menu_action_res_bank_form +#: view:res.bank:0 +#: field:res.partner,bank_ids:0 +msgid "Banks" +msgstr "" + +#. module: base +#: view:res.log:0 +msgid "Unread" +msgstr "" + +#. module: base +#: field:ir.cron,doall:0 +msgid "Repeat Missed" +msgstr "" + +#. module: base +#: help:ir.actions.server,state:0 +msgid "Type of the Action that is to be executed" +msgstr "" + +#. module: base +#: field:ir.server.object.lines,server_id:0 +msgid "Object Mapping" +msgstr "" + +#. module: base +#: help:res.currency,rate:0 +#: help:res.currency.rate,rate:0 +msgid "The rate of the currency to the currency of rate 1" +msgstr "" + +#. module: base +#: model:res.country,name:base.uk +msgid "United Kingdom" +msgstr "" + +#. module: base +#: view:res.config:0 +#: view:res.config.users:0 +#: view:res.config.view:0 +msgid "res_config_contents" +msgstr "" + +#. module: base +#: help:res.partner.category,active:0 +msgid "The active field allows you to hide the category without removing it." +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Object:" +msgstr "" + +#. module: base +#: model:res.country,name:base.bw +msgid "Botswana" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_title_partner +#: model:ir.ui.menu,name:base.menu_partner_title_partner +#: view:res.partner.title:0 +msgid "Partner Titles" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,auto_refresh:0 +msgid "Add an auto-refresh on the view" +msgstr "" + +#. module: base +#: help:res.partner,employee:0 +msgid "Check this box if the partner is an Employee." +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_rml_content:0 +#: field:ir.actions.report.xml,report_rml_content_data:0 +msgid "RML content" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_workflow_workitem_form +#: model:ir.ui.menu,name:base.menu_workflow_workitem +msgid "Workitems" +msgstr "" + +#. module: base +#: field:base.language.export,advice:0 +msgid "Advice" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_attachment +msgid "ir.attachment" +msgstr "" + +#. module: base +#: code:addons/orm.py:3533 +#, python-format +msgid "" +"You cannot perform this operation. New Record Creation is not allowed for " +"this object as this object is for reporting purpose." +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "- module,type,name,res_id,src,value" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Lithuanian / Lietuvių kalba" +msgstr "" + +#. module: base +#: help:ir.actions.server,record_id:0 +msgid "" +"Provide the field name where the record id is stored after the create " +"operations. If it is empty, you can not track the new record." +msgstr "" + +#. module: base +#: help:ir.model.fields,relation:0 +msgid "For relationship fields, the technical name of the target model" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Indonesian / Bahasa Indonesia" +msgstr "" + +#. module: base +#: field:ir.ui.view,inherit_id:0 +msgid "Inherited View" +msgstr "" + +#. module: base +#: view:ir.translation:0 +msgid "Source Term" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_main_pm +msgid "Project" +msgstr "" + +#. module: base +#: field:ir.ui.menu,web_icon_hover_data:0 +msgid "Web Icon Image (hover)" +msgstr "" + +#. module: base +#: view:base.module.import:0 +msgid "Module file successfully imported!" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,state:0 +msgid "Cancelled" +msgstr "" + +#. module: base +#: view:res.config.users:0 +msgid "Create User" +msgstr "" + +#. module: base +#: view:partner.clear.ids:0 +msgid "Want to Clear Ids ? " +msgstr "" + +#. module: base +#: field:publisher_warranty.contract,name:0 +#: field:publisher_warranty.contract.wizard,name:0 +msgid "Serial Key" +msgstr "" + +#. module: base +#: selection:res.request,priority:0 +msgid "Low" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_audit +msgid "Audit" +msgstr "" + +#. module: base +#: model:res.country,name:base.lc +msgid "Saint Lucia" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract:0 +msgid "Maintenance Contract" +msgstr "" + +#. module: base +#: help:ir.actions.server,trigger_obj_id:0 +msgid "Select the object from the model on which the workflow will executed." +msgstr "" + +#. module: base +#: field:res.partner,employee:0 +msgid "Employee" +msgstr "" + +#. module: base +#: field:ir.model.access,perm_create:0 +msgid "Create Access" +msgstr "" + +#. module: base +#: field:res.partner.address,state_id:0 +msgid "Fed. State" +msgstr "" + +#. module: base +#: field:ir.actions.server,copy_object:0 +msgid "Copy Of" +msgstr "" + +#. module: base +#: field:ir.model,osv_memory:0 +msgid "In-memory model" +msgstr "" + +#. module: base +#: view:partner.clear.ids:0 +msgid "Clear Ids" +msgstr "" + +#. module: base +#: model:res.country,name:base.io +msgid "British Indian Ocean Territory" +msgstr "" + +#. module: base +#: field:res.config.users,view:0 +#: field:res.config.view,view:0 +#: field:res.users,view:0 +msgid "Interface" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Field Mapping" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract:0 +msgid "Refresh Validation Dates" +msgstr "" + +#. module: base +#: view:ir.model:0 +#: field:ir.model.fields,ttype:0 +msgid "Field Type" +msgstr "" + +#. module: base +#: field:res.country.state,code:0 +msgid "State Code" +msgstr "" + +#. module: base +#: field:ir.model.fields,on_delete:0 +msgid "On delete" +msgstr "" + +#. module: base +#: selection:res.lang,direction:0 +msgid "Left-to-Right" +msgstr "" + +#. module: base +#: view:res.lang:0 +#: field:res.lang,translatable:0 +msgid "Translatable" +msgstr "" + +#. module: base +#: model:res.country,name:base.vn +msgid "Vietnam" +msgstr "" + +#. module: base +#: field:res.config.users,signature:0 +#: view:res.users:0 +#: field:res.users,signature:0 +msgid "Signature" +msgstr "" + +#. module: base +#: code:addons/fields.py:456 +#: code:addons/fields.py:654 +#: code:addons/fields.py:656 +#: code:addons/fields.py:658 +#: code:addons/fields.py:660 +#: code:addons/fields.py:662 +#: code:addons/fields.py:664 +#, python-format +msgid "Not Implemented" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_widget_user +msgid "res.widget.user" +msgstr "" + +#. module: base +#: field:res.partner.category,complete_name:0 +msgid "Full Name" +msgstr "" + +#. module: base +#: view:base.module.configuration:0 +msgid "_Ok" +msgstr "" + +#. module: base +#: help:ir.filters,user_id:0 +msgid "False means for every user" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:198 +#, python-format +msgid "The name of the module must be unique !" +msgstr "" + +#. module: base +#: model:res.country,name:base.mz +msgid "Mozambique" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_project_long_term +msgid "Long Term Planning" +msgstr "" + +#. module: base +#: field:ir.actions.server,message:0 +#: view:partner.sms.send:0 +#: field:partner.wizard.spam,text:0 +#: field:res.log,name:0 +msgid "Message" +msgstr "" + +#. module: base +#: field:ir.actions.act_window.view,multi:0 +msgid "On Multiple Doc." +msgstr "" + +#. module: base +#: view:res.partner:0 +#: field:res.partner,user_id:0 +msgid "Salesman" +msgstr "" + +#. module: base +#: field:res.partner,address:0 +#: view:res.partner.address:0 +msgid "Contacts" +msgstr "" + +#. module: base +#: code:addons/orm.py:3199 +#, python-format +msgid "" +"Unable to delete this document because it is used as a default property" +msgstr "" + +#. module: base +#: view:res.widget.wizard:0 +msgid "Add" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_window +#: model:ir.ui.menu,name:base.menu_view_base_module_upgrade +msgid "Apply Scheduled Upgrades" +msgstr "" + +#. module: base +#: view:res.widget:0 +msgid "Widgets" +msgstr "" + +#. module: base +#: model:res.country,name:base.cz +msgid "Czech Republic" +msgstr "" + +#. module: base +#: view:res.widget.wizard:0 +msgid "Widget Wizard" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.act_ir_actions_todo_form +msgid "" +"The configuration wizards are used to help you configure a new instance of " +"OpenERP. They are launched during the installation of new modules, but you " +"can choose to restart some wizards manually from this menu." +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:206 +#, python-format +msgid "" +"Please use the change password wizard (in User Preferences or User menu) to " +"change your own password." +msgstr "" + +#. module: base +#: code:addons/orm.py:1350 +#, python-format +msgid "Insufficient fields for Calendar View!" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Integer" +msgstr "" + +#. module: base +#: help:ir.actions.report.xml,report_rml:0 +msgid "" +"The path to the main report file (depending on Report Type) or NULL if the " +"content is in another data field" +msgstr "" + +#. module: base +#: help:res.config.users,company_id:0 +#: help:res.users,company_id:0 +msgid "The company this user is currently working for." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_wizard_ir_model_menu_create +msgid "wizard.ir.model.menu.create" +msgstr "" + +#. module: base +#: view:workflow.transition:0 +msgid "Transition" +msgstr "" + +#. module: base +#: field:res.groups,menu_access:0 +msgid "Access Menu" +msgstr "" + +#. module: base +#: model:res.country,name:base.na +msgid "Namibia" +msgstr "" + +#. module: base +#: model:res.country,name:base.mn +msgid "Mongolia" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Created Menus" +msgstr "" + +#. module: base +#: selection:ir.ui.view,type:0 +msgid "mdx" +msgstr "" + +#. module: base +#: model:res.country,name:base.bi +msgid "Burundi" +msgstr "" + +#. module: base +#: view:base.language.install:0 +#: view:base.module.import:0 +#: view:base.module.update:0 +#: view:publisher_warranty.contract.wizard:0 +#: view:res.request:0 +#: wizard_button:server.action.create,init,end:0 +#: wizard_button:server.action.create,step_1,end:0 +msgid "Close" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (MX) / Español (MX)" +msgstr "" + +#. module: base +#: view:res.log:0 +msgid "My Logs" +msgstr "" + +#. module: base +#: model:res.country,name:base.bt +msgid "Bhutan" +msgstr "" + +#. module: base +#: help:ir.sequence,number_next:0 +msgid "Next number of this sequence" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_11 +msgid "Textile Suppliers" +msgstr "" + +#. module: base +#: selection:ir.actions.url,target:0 +msgid "This Window" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract:0 +msgid "Publisher Warranty Contracts" +msgstr "" + +#. module: base +#: help:res.log,name:0 +msgid "The logging message." +msgstr "" + +#. module: base +#: field:base.language.export,format:0 +msgid "File Format" +msgstr "" + +#. module: base +#: field:res.lang,iso_code:0 +msgid "ISO code" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_config_view +msgid "res.config.view" +msgstr "" + +#. module: base +#: view:res.log:0 +#: field:res.log,read:0 +msgid "Read" +msgstr "" + +#. module: base +#: sql_constraint:res.country:0 +msgid "The name of the country must be unique !" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_country_state +msgid "" +"If you are working on the American market, you can manage the different " +"federal states you are working on from here. Each state is attached to one " +"country." +msgstr "" + +#. module: base +#: view:workflow.workitem:0 +msgid "Workflow Workitems" +msgstr "" + +#. module: base +#: model:res.country,name:base.vc +msgid "Saint Vincent & Grenadines" +msgstr "" + +#. module: base +#: field:partner.sms.send,password:0 +#: field:res.config.users,password:0 +#: field:res.users,password:0 +msgid "Password" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_model_fields +#: view:ir.model:0 +#: field:ir.model,field_id:0 +#: model:ir.model,name:base.model_ir_model_fields +#: view:ir.model.fields:0 +#: model:ir.ui.menu,name:base.ir_model_model_fields +msgid "Fields" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_employee_form +msgid "Employees" +msgstr "" + +#. module: base +#: help:res.log,read:0 +msgid "" +"If this log item has been read, get() should not send it to the client" +msgstr "" + +#. module: base +#: field:res.company,rml_header2:0 +#: field:res.company,rml_header3:0 +msgid "RML Internal Header" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,search_view_id:0 +msgid "Search View Ref." +msgstr "" + +#. module: base +#: field:ir.module.module,installed_version:0 +msgid "Latest version" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.res_partner_canal-act +msgid "" +"Track from where is coming your leads and opportunities by creating specific " +"channels that will be maintained at the creation of a document in the " +"system. Some examples of channels can be: Website, Phone Call, Reseller, etc." +msgstr "" + +#. module: base +#: model:res.partner.bank.type.field,name:base.bank_normal_field +msgid "acc_number" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_address_form +#: model:ir.ui.menu,name:base.menu_partner_address_form +msgid "Addresses" +msgstr "" + +#. module: base +#: model:res.country,name:base.mm +msgid "Myanmar" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Chinese (CN) / 简体ä¸æ–‡" +msgstr "" + +#. module: base +#: field:res.bank,street:0 +#: field:res.partner.address,street:0 +#: field:res.partner.bank,street:0 +msgid "Street" +msgstr "" + +#. module: base +#: model:res.country,name:base.yu +msgid "Yugoslavia" +msgstr "" + +#. module: base +#: field:ir.model.data,name:0 +msgid "XML Identifier" +msgstr "" + +#. module: base +#: model:res.country,name:base.ca +msgid "Canada" +msgstr "" + +#. module: base +#: selection:ir.module.module.dependency,state:0 +msgid "Unknown" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_users_my +msgid "Change My Preferences" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:164 +#, python-format +msgid "Invalid model name in the action definition." +msgstr "" + +#. module: base +#: field:partner.sms.send,text:0 +msgid "SMS Message" +msgstr "" + +#. module: base +#: model:res.country,name:base.cm +msgid "Cameroon" +msgstr "" + +#. module: base +#: model:res.country,name:base.bf +msgid "Burkina Faso" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,state:0 +msgid "Skipped" +msgstr "" + +#. module: base +#: selection:ir.model.fields,state:0 +msgid "Custom Field" +msgstr "" + +#. module: base +#: field:ir.module.module,web:0 +msgid "Has a web component" +msgstr "" + +#. module: base +#: model:res.country,name:base.cc +msgid "Cocos (Keeling) Islands" +msgstr "" + +#. module: base +#: selection:base.language.install,state:0 +#: selection:base.module.import,state:0 +#: selection:base.module.update,state:0 +msgid "init" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "11. %U or %W ==> 48 (49th week)" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_bank_type_field +msgid "Bank type fields" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Dutch / Nederlands" +msgstr "" + +#. module: base +#: code:addons/base/res/res_config.py:384 +#, python-format +msgid "" +"\n" +"\n" +"This addon is already installed on your system" +msgstr "" + +#. module: base +#: help:ir.cron,interval_number:0 +msgid "Repeat every x." +msgstr "" + +#. module: base +#: wizard_view:server.action.create,step_1:0 +#: wizard_field:server.action.create,step_1,report:0 +msgid "Select Report" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "1cm 28cm 20cm 28cm" +msgstr "" + +#. module: base +#: field:ir.module.module,maintainer:0 +msgid "Maintainer" +msgstr "" + +#. module: base +#: field:ir.sequence,suffix:0 +msgid "Suffix" +msgstr "" + +#. module: base +#: model:res.country,name:base.mo +msgid "Macau" +msgstr "" + +#. module: base +#: model:ir.actions.report.xml,name:base.res_partner_address_report +msgid "Labels" +msgstr "" + +#. module: base +#: field:partner.wizard.spam,email_from:0 +msgid "Sender's email" +msgstr "" + +#. module: base +#: field:ir.default,field_name:0 +msgid "Object Field" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (PE) / Español (PE)" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "French (CH) / Français (CH)" +msgstr "" + +#. module: base +#: help:res.config.users,action_id:0 +#: help:res.users,action_id:0 +msgid "" +"If specified, this action will be opened at logon for this user, in addition " +"to the standard menu." +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Client Actions" +msgstr "" + +#. module: base +#: code:addons/orm.py:1806 +#, python-format +msgid "The exists method is not implemented on this object !" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:336 +#, python-format +msgid "" +"You try to upgrade a module that depends on the module: %s.\n" +"But this module is not available in your system." +msgstr "" + +#. module: base +#: field:workflow.transition,act_to:0 +msgid "Destination Activity" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Connect Events to Actions" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_update_translations +msgid "base.update.translations" +msgstr "" + +#. module: base +#: field:ir.module.category,parent_id:0 +#: field:res.partner.category,parent_id:0 +msgid "Parent Category" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Integer Big" +msgstr "" + +#. module: base +#: selection:res.partner.address,type:0 +#: selection:res.partner.title,domain:0 +#: view:res.users:0 +msgid "Contact" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_ui_menu +msgid "ir.ui.menu" +msgstr "" + +#. module: base +#: model:res.country,name:base.us +msgid "United States" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Cancel Uninstall" +msgstr "" + +#. module: base +#: view:res.bank:0 +#: view:res.partner:0 +#: view:res.partner.address:0 +msgid "Communication" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "RML Report" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_server_object_lines +msgid "ir.server.object.lines" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:531 +#, python-format +msgid "Module %s: Invalid Quality Certificate" +msgstr "" + +#. module: base +#: model:res.country,name:base.kw +msgid "Kuwait" +msgstr "" + +#. module: base +#: field:workflow.workitem,inst_id:0 +msgid "Instance" +msgstr "" + +#. module: base +#: help:ir.actions.report.xml,attachment:0 +msgid "" +"This is the filename of the attachment used to store the printing result. " +"Keep empty to not save the printed reports. You can use a python expression " +"with the object and time variables." +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Many2One" +msgstr "" + +#. module: base +#: model:res.country,name:base.ng +msgid "Nigeria" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:250 +#, python-format +msgid "For selection fields, the Selection Options must be given!" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_sms_send +msgid "SMS Send" +msgstr "" + +#. module: base +#: field:res.company,user_ids:0 +msgid "Accepted Users" +msgstr "" + +#. module: base +#: field:ir.ui.menu,web_icon_data:0 +msgid "Web Icon Image" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Values for Event Type" +msgstr "" + +#. module: base +#: selection:ir.model.fields,select_level:0 +msgid "Always Searchable" +msgstr "" + +#. module: base +#: model:res.country,name:base.hk +msgid "Hong Kong" +msgstr "" + +#. module: base +#: help:ir.actions.server,name:0 +msgid "Easy to Refer action by name e.g. One Sales Order -> Many Invoices" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_address_form +msgid "" +"Customers (also called Partners in other areas of the system) helps you " +"manage your address book of companies whether they are prospects, customers " +"and/or suppliers. The partner form allows you to track and record all the " +"necessary information to interact with your partners from the company " +"address to their contacts as well as pricelists, and much more. If you " +"installed the CRM, with the history tab, you can track all the interactions " +"with a partner such as opportunities, emails, or sales orders issued." +msgstr "" + +#. module: base +#: model:res.country,name:base.ph +msgid "Philippines" +msgstr "" + +#. module: base +#: model:res.country,name:base.ma +msgid "Morocco" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "2. %a ,%A ==> Fri, Friday" +msgstr "" + +#. module: base +#: field:res.widget,content:0 +msgid "Content" +msgstr "" + +#. module: base +#: help:ir.rule,global:0 +msgid "If no group is specified the rule is global and applied to everyone" +msgstr "" + +#. module: base +#: model:res.country,name:base.td +msgid "Chad" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow_transition +msgid "workflow.transition" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%a - Abbreviated weekday name." +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Introspection report on objects" +msgstr "" + +#. module: base +#: model:res.country,name:base.pf +msgid "Polynesia (French)" +msgstr "" + +#. module: base +#: model:res.country,name:base.dm +msgid "Dominica" +msgstr "" + +#. module: base +#: sql_constraint:publisher_warranty.contract:0 +msgid "" +"Your publisher warranty contract is already subscribed in the system !" +msgstr "" + +#. module: base +#: help:ir.cron,nextcall:0 +msgid "Next planned execution date for this scheduler" +msgstr "" + +#. module: base +#: help:res.config.users,view:0 +#: help:res.users,view:0 +msgid "Choose between the simplified interface and the extended one" +msgstr "" + +#. module: base +#: model:res.country,name:base.np +msgid "Nepal" +msgstr "" + +#. module: base +#: code:addons/orm.py:2307 +#, python-format +msgid "" +"Invalid value for reference field \"%s\" (last part must be a non-zero " +"integer): \"%s\"" +msgstr "" + +#. module: base +#: help:ir.cron,args:0 +msgid "Arguments to be passed to the method. e.g. (uid,)" +msgstr "" + +#. module: base +#: help:ir.ui.menu,groups_id:0 +msgid "" +"If you have groups, the visibility of this menu will be based on these " +"groups. If this field is empty, OpenERP will compute visibility based on the " +"related object's read access." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_ui_view_custom +#: model:ir.ui.menu,name:base.menu_action_ui_view_custom +#: view:ir.ui.view.custom:0 +msgid "Customized Views" +msgstr "" + +#. module: base +#: view:partner.sms.send:0 +msgid "Bulk SMS send" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Seconde: %(sec)s" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_view_base_module_update +msgid "Update Modules List" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:255 +#, python-format +msgid "" +"Unable to upgrade module \"%s\" because an external dependency is not met: %s" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:257 +#, python-format +msgid "" +"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)" +msgstr "" + +#. module: base +#: view:ir.actions.configuration.wizard:0 +msgid "Continue" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Thai / ภาษาไทย" +msgstr "" + +#. module: base +#: code:addons/orm.py:158 +#, python-format +msgid "Object %s does not exists" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Slovenian / slovenÅ¡Äina" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,attachment_use:0 +msgid "Reload from Attachment" +msgstr "" + +#. module: base +#: model:res.country,name:base.bv +msgid "Bouvet Island" +msgstr "" + +#. module: base +#: field:ir.attachment,name:0 +msgid "Attachment Name" +msgstr "" + +#. module: base +#: field:base.language.export,data:0 +#: field:base.language.import,data:0 +msgid "File" +msgstr "" + +#. module: base +#: view:res.config.users:0 +msgid "Add User" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_view_base_module_upgrade_install +msgid "Module Upgrade Install" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_configuration_wizard +msgid "ir.actions.configuration.wizard" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%b - Abbreviated month name." +msgstr "" + +#. module: base +#: field:res.partner,supplier:0 +#: view:res.partner.address:0 +#: field:res.partner.address,is_supplier_add:0 +#: model:res.partner.category,name:base.res_partner_category_8 +msgid "Supplier" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +#: selection:ir.actions.server,state:0 +msgid "Multi Actions" +msgstr "" + +#. module: base +#: view:base.language.export:0 +#: view:base.language.import:0 +#: view:wizard.ir.model.menu.create:0 +msgid "_Close" +msgstr "" + +#. module: base +#: field:multi_company.default,company_dest_id:0 +msgid "Default Company" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (EC) / Español (EC)" +msgstr "" + +#. module: base +#: help:ir.ui.view,xml_id:0 +msgid "ID of the view defined in xml file" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_module_import +#: model:ir.ui.menu,name:base.menu_view_base_module_import +msgid "Import Module" +msgstr "" + +#. module: base +#: model:res.country,name:base.as +msgid "American Samoa" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,res_model:0 +msgid "Model name of the object to open in the view window" +msgstr "" + +#. module: base +#: field:res.log,secondary:0 +msgid "Secondary Log" +msgstr "" + +#. module: base +#: field:ir.model.fields,selectable:0 +msgid "Selectable" +msgstr "" + +#. module: base +#: view:res.request.link:0 +msgid "Request Link" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: selection:ir.attachment,type:0 +#: field:ir.module.module,url:0 +msgid "URL" +msgstr "" + +#. module: base +#: help:res.country,name:0 +msgid "The full name of the country." +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +msgid "Iteration" +msgstr "" + +#. module: base +#: code:addons/orm.py:3448 +#: code:addons/orm.py:3532 +#, python-format +msgid "UserError" +msgstr "" + +#. module: base +#: model:res.country,name:base.ae +msgid "United Arab Emirates" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_crm_case_job_req_main +msgid "Recruitment" +msgstr "" + +#. module: base +#: model:res.country,name:base.re +msgid "Reunion (French)" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:321 +#, python-format +msgid "" +"New column name must still start with x_ , because it is a custom field!" +msgstr "" + +#. module: base +#: view:ir.model.access:0 +#: view:ir.rule:0 +#: field:ir.rule,global:0 +msgid "Global" +msgstr "" + +#. module: base +#: model:res.country,name:base.mp +msgid "Northern Mariana Islands" +msgstr "" + +#. module: base +#: model:res.country,name:base.sb +msgid "Solomon Islands" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:490 +#: code:addons/orm.py:1897 +#: code:addons/orm.py:2972 +#: code:addons/orm.py:3165 +#: code:addons/orm.py:3365 +#: code:addons/orm.py:3817 +#, python-format +msgid "AccessError" +msgstr "" + +#. module: base +#: view:res.request:0 +msgid "Waiting" +msgstr "" + +#. module: base +#: code:addons/__init__.py:834 +#, python-format +msgid "Could not load base module" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "8. %I:%M:%S %p ==> 06:25:20 PM" +msgstr "" + +#. module: base +#: code:addons/orm.py:1803 +#, python-format +msgid "The copy method is not implemented on this object !" +msgstr "" + +#. module: base +#: field:res.log,create_date:0 +msgid "Creation Date" +msgstr "" + +#. module: base +#: view:ir.translation:0 +#: model:ir.ui.menu,name:base.menu_translation +msgid "Translations" +msgstr "" + +#. module: base +#: field:ir.sequence,padding:0 +msgid "Number padding" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "Report" +msgstr "" + +#. module: base +#: model:res.country,name:base.ua +msgid "Ukraine" +msgstr "" + +#. module: base +#: model:res.country,name:base.to +msgid "Tonga" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_module_category +#: view:ir.module.category:0 +msgid "Module Category" +msgstr "" + +#. module: base +#: view:partner.wizard.ean.check:0 +msgid "Ignore" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Reference Guide" +msgstr "" + +#. module: base +#: view:ir.ui.view:0 +msgid "Architecture" +msgstr "" + +#. module: base +#: model:res.country,name:base.ml +msgid "Mali" +msgstr "" + +#. module: base +#: help:res.config.users,email:0 +#: help:res.users,email:0 +msgid "" +"If an email is provided, the user will be sent a message welcoming him.\n" +"\n" +"Warning: if \"email_from\" and \"smtp_server\" aren't configured, it won't " +"be possible to email new users." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Flemish (BE) / Vlaams (BE)" +msgstr "" + +#. module: base +#: field:ir.cron,interval_number:0 +msgid "Interval Number" +msgstr "" + +#. module: base +#: model:res.country,name:base.tk +msgid "Tokelau" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_xsl:0 +msgid "XSL path" +msgstr "" + +#. module: base +#: model:res.country,name:base.bn +msgid "Brunei Darussalam" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +#: field:ir.actions.act_window,view_type:0 +#: field:ir.actions.act_window.view,view_mode:0 +#: field:ir.ui.view,type:0 +#: field:wizard.ir.model.menu.create.line,view_type:0 +msgid "View Type" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.next_id_2 +msgid "User Interface" +msgstr "" + +#. module: base +#: field:ir.attachment,create_date:0 +msgid "Date Created" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_todo +msgid "ir.actions.todo" +msgstr "" + +#. module: base +#: code:addons/base/res/res_config.py:94 +#, python-format +msgid "Couldn't find previous ir.actions.todo" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +msgid "General Settings" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_administration_shortcut +msgid "Custom Shortcuts" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Vietnamese / Tiếng Việt" +msgstr "" + +#. module: base +#: model:res.country,name:base.dz +msgid "Algeria" +msgstr "" + +#. module: base +#: model:res.country,name:base.be +msgid "Belgium" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_osv_memory_autovacuum +msgid "osv_memory.autovacuum" +msgstr "" + +#. module: base +#: field:base.language.export,lang:0 +#: field:base.language.install,lang:0 +#: field:base.update.translations,lang:0 +#: field:ir.translation,lang:0 +#: field:res.config.users,context_lang:0 +#: field:res.partner,lang:0 +#: field:res.users,context_lang:0 +msgid "Language" +msgstr "" + +#. module: base +#: model:res.country,name:base.gm +msgid "Gambia" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_company_form +#: model:ir.model,name:base.model_res_company +#: model:ir.ui.menu,name:base.menu_action_res_company_form +#: model:ir.ui.menu,name:base.menu_res_company_global +#: view:res.company:0 +#: field:res.config.users,company_ids:0 +#: view:res.users:0 +#: field:res.users,company_ids:0 +msgid "Companies" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%H - Hour (24-hour clock) [00,23]." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_widget +msgid "res.widget" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:258 +#, python-format +msgid "Model %s does not exist!" +msgstr "" + +#. module: base +#: code:addons/base/res/res_lang.py:159 +#, python-format +msgid "You cannot delete the language which is User's Preferred Language !" +msgstr "" + +#. module: base +#: code:addons/fields.py:103 +#, python-format +msgid "Not implemented get_memory method !" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +#: field:ir.actions.server,code:0 +#: selection:ir.actions.server,state:0 +msgid "Python Code" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_module_import.py:67 +#, python-format +msgid "Can not create the module file: %s !" +msgstr "" + +#. module: base +#: model:ir.module.module,description:base.module_meta_information +msgid "The kernel of OpenERP, needed for all installation." +msgstr "" + +#. module: base +#: view:base.language.install:0 +#: view:base.module.import:0 +#: view:base.module.update:0 +#: view:base.module.upgrade:0 +#: view:base.update.translations:0 +#: view:partner.clear.ids:0 +#: view:partner.sms.send:0 +#: view:partner.wizard.spam:0 +#: view:publisher_warranty.contract.wizard:0 +#: view:res.widget.wizard:0 +msgid "Cancel" +msgstr "" + +#. module: base +#: selection:base.language.export,format:0 +msgid "PO File" +msgstr "" + +#. module: base +#: model:res.country,name:base.nt +msgid "Neutral Zone" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Hindi / हिंदी" +msgstr "" + +#. module: base +#: view:ir.model:0 +msgid "Custom" +msgstr "" + +#. module: base +#: view:res.request:0 +msgid "Current" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_9 +msgid "Components Supplier" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_users +#: field:ir.default,uid:0 +#: model:ir.ui.menu,name:base.menu_action_res_users +#: model:ir.ui.menu,name:base.menu_users +#: view:res.groups:0 +#: field:res.groups,users:0 +#: view:res.users:0 +msgid "Users" +msgstr "" + +#. module: base +#: field:ir.module.module,published_version:0 +msgid "Published Version" +msgstr "" + +#. module: base +#: model:res.country,name:base.is +msgid "Iceland" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_action_window +#: model:ir.ui.menu,name:base.menu_ir_action_window +msgid "Window Actions" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%I - Hour (12-hour clock) [01,12]." +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract.wizard,state:0 +msgid "Finished" +msgstr "" + +#. module: base +#: model:res.country,name:base.de +msgid "Germany" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Week of the year: %(woy)s" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_14 +msgid "Bad customers" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Reports :" +msgstr "" + +#. module: base +#: model:res.country,name:base.gy +msgid "Guyana" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,view_type:0 +msgid "" +"View type: set to 'tree' for a hierarchical tree view, or 'form' for other " +"views" +msgstr "" + +#. module: base +#: code:addons/base/res/res_config.py:421 +#, python-format +msgid "Click 'Continue' to configure the next addon..." +msgstr "" + +#. module: base +#: field:ir.actions.server,record_id:0 +msgid "Create Id" +msgstr "" + +#. module: base +#: model:res.country,name:base.hn +msgid "Honduras" +msgstr "" + +#. module: base +#: help:res.config.users,menu_tips:0 +#: help:res.users,menu_tips:0 +msgid "" +"Check out this box if you want to always display tips on each menu action" +msgstr "" + +#. module: base +#: model:res.country,name:base.eg +msgid "Egypt" +msgstr "" + +#. module: base +#: field:ir.rule,perm_read:0 +msgid "Apply For Read" +msgstr "" + +#. module: base +#: help:ir.actions.server,model_id:0 +msgid "" +"Select the object on which the action will work (read, write, create)." +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:629 +#, python-format +msgid "Please specify server option --email-from !" +msgstr "" + +#. module: base +#: field:base.language.import,name:0 +msgid "Language Name" +msgstr "" + +#. module: base +#: selection:ir.property,type:0 +msgid "Boolean" +msgstr "" + +#. module: base +#: view:ir.model:0 +msgid "Fields Description" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: view:ir.cron:0 +#: view:ir.model.access:0 +#: view:ir.model.data:0 +#: view:ir.model.fields:0 +#: view:ir.module.module:0 +#: view:ir.rule:0 +#: view:ir.ui.view:0 +#: view:ir.values:0 +#: view:res.partner:0 +#: view:res.partner.address:0 +#: view:workflow.activity:0 +msgid "Group By..." +msgstr "" + +#. module: base +#: view:ir.model.fields:0 +#: field:ir.model.fields,readonly:0 +#: field:res.partner.bank.type.field,readonly:0 +msgid "Readonly" +msgstr "" + +#. module: base +#: field:ir.actions.act_window.view,view_id:0 +#: field:ir.default,page:0 +#: selection:ir.translation,type:0 +#: field:wizard.ir.model.menu.create.line,view_id:0 +msgid "View" +msgstr "" + +#. module: base +#: selection:ir.module.module,state:0 +#: selection:ir.module.module.dependency,state:0 +msgid "To be installed" +msgstr "" + +#. module: base +#: help:ir.actions.act_window,display_menu_tip:0 +msgid "" +"It gives the status if the tip has to be displayed or not when a user " +"executes an action" +msgstr "" + +#. module: base +#: view:ir.model:0 +#: model:ir.module.module,shortdesc:base.module_meta_information +#: field:res.currency,base:0 +msgid "Base" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Telugu / తెలà±à°—à±" +msgstr "" + +#. module: base +#: model:res.country,name:base.lr +msgid "Liberia" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: view:ir.model:0 +#: view:res.groups:0 +#: view:res.partner:0 +#: field:res.partner,comment:0 +#: model:res.widget,title:base.note_widget +msgid "Notes" +msgstr "" + +#. module: base +#: field:ir.config_parameter,value:0 +#: field:ir.property,value_binary:0 +#: field:ir.property,value_datetime:0 +#: field:ir.property,value_float:0 +#: field:ir.property,value_integer:0 +#: field:ir.property,value_reference:0 +#: field:ir.property,value_text:0 +#: selection:ir.server.object.lines,type:0 +#: field:ir.server.object.lines,value:0 +#: view:ir.values:0 +#: field:ir.values,value:0 +#: field:ir.values,value_unpickle:0 +msgid "Value" +msgstr "" + +#. module: base +#: field:ir.sequence,code:0 +#: field:ir.sequence.type,code:0 +#: selection:ir.translation,type:0 +#: field:res.bank,code:0 +#: field:res.partner.bank.type,code:0 +msgid "Code" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_config_installer +msgid "res.config.installer" +msgstr "" + +#. module: base +#: model:res.country,name:base.mc +msgid "Monaco" +msgstr "" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Minutes" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Help" +msgstr "" + +#. module: base +#: help:res.config.users,menu_id:0 +#: help:res.users,menu_id:0 +msgid "" +"If specified, the action will replace the standard menu for this user." +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +msgid "Write Object" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_fundrising +msgid "Fund Raising" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_sequence_type +#: model:ir.ui.menu,name:base.menu_ir_sequence_type +msgid "Sequence Codes" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (CO) / Español (CO)" +msgstr "" + +#. module: base +#: view:base.module.configuration:0 +msgid "" +"All pending configuration wizards have been executed. You may restart " +"individual wizards via the list of configuration wizards." +msgstr "" + +#. module: base +#: wizard_button:server.action.create,step_1,create:0 +msgid "Create" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Current Year with Century: %(year)s" +msgstr "" + +#. module: base +#: field:ir.exports,export_fields:0 +msgid "Export ID" +msgstr "" + +#. module: base +#: model:res.country,name:base.fr +msgid "France" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_log +msgid "res.log" +msgstr "" + +#. module: base +#: help:ir.translation,module:0 +#: help:ir.translation,xml_id:0 +msgid "Maps to the ir_model_data for which this translation is provided." +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: field:workflow.activity,flow_stop:0 +msgid "Flow Stop" +msgstr "" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Weeks" +msgstr "" + +#. module: base +#: model:res.country,name:base.af +msgid "Afghanistan, Islamic State of" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_module_import.py:67 +#, python-format +msgid "Error !" +msgstr "" + +#. module: base +#: model:res.partner.bank.type.field,name:base.bank_normal_field_contry +msgid "country_id" +msgstr "" + +#. module: base +#: field:ir.cron,interval_type:0 +msgid "Interval Unit" +msgstr "" + +#. module: base +#: field:publisher_warranty.contract,kind:0 +#: field:workflow.activity,kind:0 +msgid "Kind" +msgstr "" + +#. module: base +#: code:addons/orm.py:3775 +#, python-format +msgid "This method does not exist anymore" +msgstr "" + +#. module: base +#: field:res.bank,fax:0 +#: field:res.partner.address,fax:0 +msgid "Fax" +msgstr "" + +#. module: base +#: field:res.lang,thousands_sep:0 +msgid "Thousands Separator" +msgstr "" + +#. module: base +#: field:res.request,create_date:0 +msgid "Created Date" +msgstr "" + +#. module: base +#: help:ir.actions.server,loop_action:0 +msgid "" +"Select the action that will be executed. Loop action will not be avaliable " +"inside loop." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Chinese (TW) / æ£é«”å—" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_request +msgid "res.request" +msgstr "" + +#. module: base +#: view:ir.model:0 +msgid "In Memory" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +msgid "Todo" +msgstr "" + +#. module: base +#: field:ir.attachment,datas:0 +msgid "File Content" +msgstr "" + +#. module: base +#: model:res.country,name:base.pa +msgid "Panama" +msgstr "" + +#. module: base +#: model:res.partner.title,name:base.res_partner_title_ltd +msgid "Ltd" +msgstr "" + +#. module: base +#: help:workflow.transition,group_id:0 +msgid "" +"The group that a user must have to be authorized to validate this transition." +msgstr "" + +#. module: base +#: constraint:res.config.users:0 +#: constraint:res.users:0 +msgid "The chosen company is not in the allowed companies for this user" +msgstr "" + +#. module: base +#: model:res.country,name:base.gi +msgid "Gibraltar" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_name:0 +msgid "Service Name" +msgstr "" + +#. module: base +#: model:res.country,name:base.pn +msgid "Pitcairn Island" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "" +"We suggest to reload the menu tab to see the new menus (Ctrl+T then Ctrl+R)." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_rule +#: model:ir.ui.menu,name:base.menu_action_rule +msgid "Record Rules" +msgstr "" + +#. module: base +#: field:res.config.users,name:0 +#: field:res.users,name:0 +msgid "User Name" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Day of the year: %(doy)s" +msgstr "" + +#. module: base +#: view:ir.model:0 +#: view:ir.model.fields:0 +#: view:workflow.activity:0 +msgid "Properties" +msgstr "" + +#. module: base +#: help:ir.sequence,padding:0 +msgid "" +"OpenERP will automatically adds some '0' on the left of the 'Next Number' to " +"get the required padding size." +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%A - Full weekday name." +msgstr "" + +#. module: base +#: selection:ir.cron,interval_type:0 +msgid "Months" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,search_view:0 +msgid "Search View" +msgstr "" + +#. module: base +#: sql_constraint:res.lang:0 +msgid "The code of the language must be unique !" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_attachment +#: view:ir.actions.report.xml:0 +#: view:ir.attachment:0 +#: model:ir.ui.menu,name:base.menu_action_attachment +msgid "Attachments" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_base_partner +#: model:ir.ui.menu,name:base.menu_sale_config_sales +#: model:ir.ui.menu,name:base.menu_sales +msgid "Sales" +msgstr "" + +#. module: base +#: field:ir.actions.server,child_ids:0 +msgid "Other Actions" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,state:0 +#: view:res.config.users:0 +msgid "Done" +msgstr "" + +#. module: base +#: model:res.partner.title,name:base.res_partner_title_miss +msgid "Miss" +msgstr "" + +#. module: base +#: view:ir.model.access:0 +#: field:ir.model.access,perm_write:0 +#: view:ir.rule:0 +msgid "Write Access" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%m - Month number [01,12]." +msgstr "" + +#. module: base +#: field:res.bank,city:0 +#: field:res.partner,city:0 +#: field:res.partner.address,city:0 +#: field:res.partner.bank,city:0 +msgid "City" +msgstr "" + +#. module: base +#: model:res.country,name:base.qa +msgid "Qatar" +msgstr "" + +#. module: base +#: model:res.country,name:base.it +msgid "Italy" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +#: selection:ir.actions.todo,state:0 +msgid "To Do" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Estonian / Eesti keel" +msgstr "" + +#. module: base +#: field:res.config.users,email:0 +#: field:res.partner,email:0 +#: field:res.users,email:0 +msgid "E-mail" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "GPL-3 or later version" +msgstr "" + +#. module: base +#: field:workflow.activity,action:0 +msgid "Python Action" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "English (US)" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_model_data +#: view:ir.model.data:0 +#: model:ir.ui.menu,name:base.ir_model_data_menu +msgid "Object Identifiers" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_title_partner +msgid "" +"Manage the partner titles you want to have available in your system. The " +"partner titles is the legal status of the company: Private Limited, SA, etc." +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "To browse official translations, you can start with these links:" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:484 +#, python-format +msgid "" +"You can not read this document (%s) ! Be sure your user belongs to one of " +"these groups: %s." +msgstr "" + +#. module: base +#: view:res.bank:0 +#: field:res.config.users,address_id:0 +#: view:res.partner.address:0 +#: view:res.users:0 +#: field:res.users,address_id:0 +msgid "Address" +msgstr "" + +#. module: base +#: field:ir.module.module,latest_version:0 +msgid "Installed version" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Mongolian / монгол" +msgstr "" + +#. module: base +#: model:res.country,name:base.mr +msgid "Mauritania" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_translation +msgid "ir.translation" +msgstr "" + +#. module: base +#: view:base.module.update:0 +msgid "Module update result" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: field:workflow.workitem,act_id:0 +msgid "Activity" +msgstr "" + +#. module: base +#: view:res.partner:0 +#: view:res.partner.address:0 +msgid "Postal Address" +msgstr "" + +#. module: base +#: field:res.company,parent_id:0 +msgid "Parent Company" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (CR) / Español (CR)" +msgstr "" + +#. module: base +#: field:res.currency.rate,rate:0 +msgid "Rate" +msgstr "" + +#. module: base +#: model:res.country,name:base.cg +msgid "Congo" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "Examples" +msgstr "" + +#. module: base +#: field:ir.default,value:0 +msgid "Default Value" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_tools +msgid "Tools" +msgstr "" + +#. module: base +#: model:res.country,name:base.kn +msgid "Saint Kitts & Nevis Anguilla" +msgstr "" + +#. module: base +#: code:addons/base/res/res_currency.py:100 +#, python-format +msgid "" +"No rate found \n" +"for the currency: %s \n" +"at the date: %s" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_ui_view_custom +msgid "" +"Customized views are used when users reorganize the content of their " +"dashboard views (via web client)" +msgstr "" + +#. module: base +#: field:ir.model,name:0 +#: field:ir.model.fields,model:0 +#: field:ir.values,model:0 +msgid "Object Name" +msgstr "" + +#. module: base +#: help:ir.actions.server,srcmodel_id:0 +msgid "" +"Object in which you want to create / write the object. If it is empty then " +"refer to the Object field." +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: selection:ir.module.module,state:0 +#: selection:ir.module.module.dependency,state:0 +msgid "Not Installed" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +#: field:workflow.activity,out_transitions:0 +msgid "Outgoing Transitions" +msgstr "" + +#. module: base +#: field:ir.ui.menu,icon:0 +msgid "Icon" +msgstr "" + +#. module: base +#: help:ir.model.fields,model_id:0 +msgid "The model this field belongs to" +msgstr "" + +#. module: base +#: model:res.country,name:base.mq +msgid "Martinique (French)" +msgstr "" + +#. module: base +#: view:ir.sequence.type:0 +msgid "Sequences Type" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_request-act +#: model:ir.ui.menu,name:base.menu_res_request_act +#: model:ir.ui.menu,name:base.menu_resquest_ref +#: view:res.request:0 +msgid "Requests" +msgstr "" + +#. module: base +#: model:res.country,name:base.ye +msgid "Yemen" +msgstr "" + +#. module: base +#: selection:workflow.activity,split_mode:0 +msgid "Or" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_log_act_window +#: model:ir.ui.menu,name:base.menu_res_log_act_window +msgid "Client Logs" +msgstr "" + +#. module: base +#: model:res.country,name:base.al +msgid "Albania" +msgstr "" + +#. module: base +#: model:res.country,name:base.ws +msgid "Samoa" +msgstr "" + +#. module: base +#: code:addons/base/res/res_lang.py:161 +#, python-format +msgid "" +"You cannot delete the language which is Active !\n" +"Please de-activate the language first." +msgstr "" + +#. module: base +#: view:base.language.install:0 +#: view:base.module.import:0 +msgid "" +"Please be patient, this operation may take a few minutes (depending on the " +"number of modules currently installed)..." +msgstr "" + +#. module: base +#: field:ir.ui.menu,child_id:0 +msgid "Child IDs" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:713 +#: code:addons/base/ir/ir_actions.py:716 +#, python-format +msgid "Problem in configuration `Record Id` in Server Action!" +msgstr "" + +#. module: base +#: code:addons/orm.py:2306 +#: code:addons/orm.py:2316 +#, python-format +msgid "ValidateError" +msgstr "" + +#. module: base +#: view:base.module.import:0 +#: view:base.module.update:0 +msgid "Open Modules" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_res_bank_form +msgid "Manage bank records you want to be used in the system." +msgstr "" + +#. module: base +#: view:base.module.import:0 +msgid "Import module" +msgstr "" + +#. module: base +#: field:ir.actions.server,loop_action:0 +msgid "Loop Action" +msgstr "" + +#. module: base +#: help:ir.actions.report.xml,report_file:0 +msgid "" +"The path to the main report file (depending on Report Type) or NULL if the " +"content is in another field" +msgstr "" + +#. module: base +#: model:res.country,name:base.la +msgid "Laos" +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +#: field:res.config.users,user_email:0 +#: field:res.users,user_email:0 +msgid "Email" +msgstr "" + +#. module: base +#: field:res.config.users,action_id:0 +#: field:res.users,action_id:0 +msgid "Home Action" +msgstr "" + +#. module: base +#: code:addons/custom.py:558 +#, python-format +msgid "" +"The sum of the data (2nd field) is null.\n" +"We can't draw a pie chart !" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_lunch_reporting +#: model:ir.ui.menu,name:base.menu_project_report +#: model:ir.ui.menu,name:base.menu_report_association +#: model:ir.ui.menu,name:base.menu_report_marketing +#: model:ir.ui.menu,name:base.menu_reporting +#: model:ir.ui.menu,name:base.next_id_64 +#: model:ir.ui.menu,name:base.next_id_73 +#: model:ir.ui.menu,name:base.reporting_menu +msgid "Reporting" +msgstr "" + +#. module: base +#: model:res.country,name:base.tg +msgid "Togo" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "Other Proprietary" +msgstr "" + +#. module: base +#: selection:workflow.activity,kind:0 +msgid "Stop All" +msgstr "" + +#. module: base +#: code:addons/orm.py:412 +#, python-format +msgid "The read_group method is not implemented on this object !" +msgstr "" + +#. module: base +#: view:ir.model.data:0 +msgid "Updatable" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "3. %x ,%X ==> 12/05/08, 18:25:20" +msgstr "" + +#. module: base +#: selection:ir.model.fields,on_delete:0 +msgid "Cascade" +msgstr "" + +#. module: base +#: field:workflow.transition,group_id:0 +msgid "Group Required" +msgstr "" + +#. module: base +#: view:ir.actions.configuration.wizard:0 +msgid "Next Configuration Step" +msgstr "" + +#. module: base +#: field:res.groups,comment:0 +msgid "Comment" +msgstr "" + +#. module: base +#: model:res.country,name:base.ro +msgid "Romania" +msgstr "" + +#. module: base +#: help:ir.cron,doall:0 +msgid "" +"Enable this if you want to execute missed occurences as soon as the server " +"restarts." +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "Start update" +msgstr "" + +#. module: base +#: code:addons/base/publisher_warranty/publisher_warranty.py:144 +#, python-format +msgid "Contract validation error" +msgstr "" + +#. module: base +#: field:res.country.state,name:0 +msgid "State Name" +msgstr "" + +#. module: base +#: field:workflow.activity,join_mode:0 +msgid "Join Mode" +msgstr "" + +#. module: base +#: field:res.config.users,context_tz:0 +#: field:res.users,context_tz:0 +msgid "Timezone" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_report_xml +#: selection:ir.ui.menu,action:0 +msgid "ir.actions.report.xml" +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_miss +msgid "Mss" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_ui_view +msgid "ir.ui.view" +msgstr "" + +#. module: base +#: constraint:res.partner:0 +msgid "Error ! You can not create recursive associated members." +msgstr "" + +#. module: base +#: help:res.lang,code:0 +msgid "This field is used to set/get locales for user" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_2 +msgid "OpenERP Partners" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_hr_manager +msgid "HR Manager Dashboard" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:253 +#, python-format +msgid "" +"Unable to install module \"%s\" because an external dependency is not met: %s" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Search modules" +msgstr "" + +#. module: base +#: model:res.country,name:base.by +msgid "Belarus" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,name:0 +#: field:ir.actions.act_window_close,name:0 +#: field:ir.actions.actions,name:0 +#: field:ir.actions.server,name:0 +#: field:ir.actions.url,name:0 +#: field:ir.filters,name:0 +msgid "Action Name" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_res_users +msgid "" +"Create and manage users that will connect to the system. Users can be " +"deactivated should there be a period of time during which they will/should " +"not connect to the system. You can assign them groups in order to give them " +"specific access to the applications they need to use in the system." +msgstr "" + +#. module: base +#: selection:res.request,priority:0 +msgid "Normal" +msgstr "" + +#. module: base +#: field:res.bank,street2:0 +#: field:res.partner.address,street2:0 +msgid "Street2" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_view_base_module_update +msgid "Module Update" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_module_upgrade.py:95 +#, python-format +msgid "Following modules are not installed or unknown: %s" +msgstr "" + +#. module: base +#: view:ir.cron:0 +#: field:ir.cron,user_id:0 +#: view:ir.filters:0 +#: field:ir.filters,user_id:0 +#: field:ir.ui.view.custom,user_id:0 +#: field:ir.values,user_id:0 +#: field:res.log,user_id:0 +#: field:res.partner.event,user_id:0 +#: view:res.users:0 +#: field:res.widget.user,user_id:0 +msgid "User" +msgstr "" + +#. module: base +#: model:res.country,name:base.pr +msgid "Puerto Rico" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +msgid "Open Window" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,auto_search:0 +msgid "Auto Search" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,filter:0 +msgid "Filter" +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_madam +msgid "Ms." +msgstr "" + +#. module: base +#: model:res.country,name:base.ch +msgid "Switzerland" +msgstr "" + +#. module: base +#: model:res.country,name:base.gd +msgid "Grenada" +msgstr "" + +#. module: base +#: model:res.country,name:base.wf +msgid "Wallis and Futuna Islands" +msgstr "" + +#. module: base +#: selection:server.action.create,init,type:0 +msgid "Open Report" +msgstr "" + +#. module: base +#: field:res.currency,rounding:0 +msgid "Rounding factor" +msgstr "" + +#. module: base +#: view:base.language.install:0 +msgid "Load" +msgstr "" + +#. module: base +#: help:res.config.users,name:0 +#: help:res.users,name:0 +msgid "The new user's real name, used for searching and most listings" +msgstr "" + +#. module: base +#: code:addons/osv.py:154 +#: code:addons/osv.py:156 +#, python-format +msgid "Integrity Error" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_wizard_screen +msgid "ir.wizard.screen" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:223 +#, python-format +msgid "Size of the field can never be less than 1 !" +msgstr "" + +#. module: base +#: model:res.country,name:base.so +msgid "Somalia" +msgstr "" + +#. module: base +#: selection:publisher_warranty.contract,state:0 +msgid "Terminated" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_13 +msgid "Important customers" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "Update Terms" +msgstr "" + +#. module: base +#: field:partner.sms.send,mobile_to:0 +#: field:res.request,act_to:0 +#: field:res.request.history,act_to:0 +msgid "To" +msgstr "" + +#. module: base +#: view:ir.cron:0 +#: field:ir.cron,args:0 +msgid "Arguments" +msgstr "" + +#. module: base +#: code:addons/orm.py:716 +#, python-format +msgid "Database ID doesn't exist: %s : %s" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "GPL Version 2" +msgstr "" + +#. module: base +#: selection:ir.module.module,license:0 +msgid "GPL Version 3" +msgstr "" + +#. module: base +#: code:addons/orm.py:836 +#, python-format +msgid "key '%s' not found in selection field '%s'" +msgstr "" + +#. module: base +#: view:partner.wizard.ean.check:0 +msgid "Correct EAN13" +msgstr "" + +#. module: base +#: code:addons/orm.py:2317 +#, python-format +msgid "The value \"%s\" for the field \"%s\" is not in the selection" +msgstr "" + +#. module: base +#: field:res.partner,customer:0 +#: view:res.partner.address:0 +#: field:res.partner.address,is_customer_add:0 +#: model:res.partner.category,name:base.res_partner_category_0 +msgid "Customer" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (NI) / Español (NI)" +msgstr "" + +#. module: base +#: field:ir.module.module,shortdesc:0 +msgid "Short Description" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,context:0 +#: field:ir.filters,context:0 +msgid "Context Value" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Hour 00->24: %(h24)s" +msgstr "" + +#. module: base +#: field:ir.cron,nextcall:0 +msgid "Next Execution Date" +msgstr "" + +#. module: base +#: help:multi_company.default,field_id:0 +msgid "Select field property" +msgstr "" + +#. module: base +#: field:res.request.history,date_sent:0 +msgid "Date sent" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Month: %(month)s" +msgstr "" + +#. module: base +#: field:ir.actions.act_window.view,sequence:0 +#: field:ir.actions.server,sequence:0 +#: field:ir.actions.todo,sequence:0 +#: view:ir.cron:0 +#: view:ir.sequence:0 +#: field:ir.ui.menu,sequence:0 +#: view:ir.ui.view:0 +#: field:ir.ui.view,priority:0 +#: field:ir.ui.view_sc,sequence:0 +#: field:multi_company.default,sequence:0 +#: field:res.partner.bank,sequence:0 +#: field:res.widget.user,sequence:0 +#: field:wizard.ir.model.menu.create.line,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: base +#: model:res.country,name:base.tn +msgid "Tunisia" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_mrp_root +msgid "Manufacturing" +msgstr "" + +#. module: base +#: model:res.country,name:base.km +msgid "Comoros" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_server_action +#: view:ir.actions.server:0 +#: model:ir.ui.menu,name:base.menu_server_action +msgid "Server Actions" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Cancel Install" +msgstr "" + +#. module: base +#: field:ir.model.fields,selection:0 +msgid "Selection Options" +msgstr "" + +#. module: base +#: field:res.partner.category,parent_right:0 +msgid "Right parent" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "Legends for Date and Time Formats" +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +msgid "Copy Object" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:581 +#, python-format +msgid "" +"Group(s) cannot be deleted, because some user(s) still belong to them: %s !" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_country_state +#: model:ir.ui.menu,name:base.menu_country_state_partner +msgid "Fed. States" +msgstr "" + +#. module: base +#: view:ir.model:0 +#: view:res.groups:0 +msgid "Access Rules" +msgstr "" + +#. module: base +#: field:ir.default,ref_table:0 +msgid "Table Ref." +msgstr "" + +#. module: base +#: field:ir.actions.act_window,res_model:0 +#: field:ir.actions.report.xml,model:0 +#: field:ir.actions.server,model_id:0 +#: field:ir.actions.wizard,model:0 +#: field:ir.cron,model:0 +#: field:ir.default,field_tbl:0 +#: field:ir.filters,model_id:0 +#: field:ir.model,model:0 +#: view:ir.model.access:0 +#: field:ir.model.access,model_id:0 +#: view:ir.model.data:0 +#: field:ir.model.data,model:0 +#: view:ir.model.fields:0 +#: view:ir.rule:0 +#: field:ir.rule,model_id:0 +#: selection:ir.translation,type:0 +#: view:ir.ui.view:0 +#: field:ir.ui.view,model:0 +#: view:ir.values:0 +#: field:ir.values,model_id:0 +#: field:multi_company.default,object_id:0 +#: field:res.log,res_model:0 +#: field:res.request.link,object:0 +#: field:workflow.triggers,model:0 +msgid "Object" +msgstr "" + +#. module: base +#: code:addons/osv.py:151 +#, python-format +msgid "" +"\n" +"\n" +"[object with reference: %s - %s]" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_default +msgid "ir.default" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Minute: %(min)s" +msgstr "" + +#. module: base +#: view:base.update.translations:0 +#: model:ir.actions.act_window,name:base.action_wizard_update_translations +#: model:ir.ui.menu,name:base.menu_wizard_update_translations +msgid "Synchronize Translations" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.next_id_10 +msgid "Scheduler" +msgstr "" + +#. module: base +#: help:ir.cron,numbercall:0 +msgid "" +"Number of time the function is called,\n" +"a negative number indicates no limit" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:331 +#, python-format +msgid "" +"Changing the type of a column is not yet supported. Please drop it and " +"create it again!" +msgstr "" + +#. module: base +#: field:ir.ui.view_sc,user_id:0 +msgid "User Ref." +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:580 +#, python-format +msgid "Warning !" +msgstr "" + +#. module: base +#: model:res.widget,title:base.google_maps_widget +msgid "Google Maps" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_base_config +#: model:ir.ui.menu,name:base.menu_config +#: model:ir.ui.menu,name:base.menu_event_config +#: model:ir.ui.menu,name:base.menu_lunch_survey_root +#: model:ir.ui.menu,name:base.menu_marketing_config_association +#: model:ir.ui.menu,name:base.menu_marketing_config_root +#: view:res.company:0 +msgid "Configuration" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_publisher_warranty_contract_wizard +msgid "publisher_warranty.contract.wizard" +msgstr "" + +#. module: base +#: field:ir.actions.server,expression:0 +msgid "Loop Expression" +msgstr "" + +#. module: base +#: field:publisher_warranty.contract,date_start:0 +msgid "Starting Date" +msgstr "" + +#. module: base +#: help:res.partner,website:0 +msgid "Website of Partner" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_5 +msgid "Gold Partner" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner +#: field:res.company,partner_id:0 +#: view:res.partner.address:0 +#: field:res.partner.bank,partner_id:0 +#: field:res.partner.event,partner_id:0 +#: selection:res.partner.title,domain:0 +#: model:res.request.link,name:base.req_link_partner +msgid "Partner" +msgstr "" + +#. module: base +#: model:res.country,name:base.tr +msgid "Turkey" +msgstr "" + +#. module: base +#: model:res.country,name:base.fk +msgid "Falkland Islands" +msgstr "" + +#. module: base +#: model:res.country,name:base.lb +msgid "Lebanon" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +#: field:ir.actions.report.xml,report_type:0 +msgid "Report Type" +msgstr "" + +#. module: base +#: field:ir.actions.todo,state:0 +#: view:ir.module.module:0 +#: field:ir.module.module,state:0 +#: field:ir.module.module.dependency,state:0 +#: field:publisher_warranty.contract,state:0 +#: field:res.bank,state:0 +#: view:res.country.state:0 +#: field:res.partner.bank,state_id:0 +#: view:res.request:0 +#: field:res.request,state:0 +#: field:workflow.instance,state:0 +#: field:workflow.workitem,state:0 +msgid "State" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Galician / Galego" +msgstr "" + +#. module: base +#: model:res.country,name:base.no +msgid "Norway" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "4. %b, %B ==> Dec, December" +msgstr "" + +#. module: base +#: view:base.language.install:0 +#: model:ir.ui.menu,name:base.menu_view_base_language_install +msgid "Load an Official Translation" +msgstr "" + +#. module: base +#: view:res.currency:0 +msgid "Miscelleanous" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_10 +msgid "Open Source Service Company" +msgstr "" + +#. module: base +#: model:res.country,name:base.kg +msgid "Kyrgyz Republic (Kyrgyzstan)" +msgstr "" + +#. module: base +#: selection:res.request,state:0 +msgid "waiting" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_file:0 +msgid "Report file" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow_triggers +msgid "workflow.triggers" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:62 +#, python-format +msgid "Invalid search criterions" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +msgid "Created" +msgstr "" + +#. module: base +#: help:ir.actions.wizard,multi:0 +msgid "" +"If set to true, the wizard will not be displayed on the right toolbar of a " +"form view." +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "- type,name,res_id,src,value" +msgstr "" + +#. module: base +#: model:res.country,name:base.hm +msgid "Heard and McDonald Islands" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,view_id:0 +msgid "View Ref." +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Selection" +msgstr "" + +#. module: base +#: field:res.company,rml_header1:0 +msgid "Report Header" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,type:0 +#: field:ir.actions.act_window_close,type:0 +#: field:ir.actions.actions,type:0 +#: field:ir.actions.report.xml,type:0 +#: view:ir.actions.server:0 +#: field:ir.actions.server,state:0 +#: field:ir.actions.server,type:0 +#: field:ir.actions.url,type:0 +#: field:ir.actions.wizard,type:0 +msgid "Action Type" +msgstr "" + +#. module: base +#: code:addons/base/module/module.py:268 +#, python-format +msgid "" +"You try to install module '%s' that depends on module '%s'.\n" +"But the latter module is not available in your system." +msgstr "" + +#. module: base +#: view:base.language.import:0 +#: model:ir.actions.act_window,name:base.action_view_base_import_language +#: model:ir.ui.menu,name:base.menu_view_base_import_language +msgid "Import Translation" +msgstr "" + +#. module: base +#: field:res.partner.bank.type,field_ids:0 +msgid "Type fields" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +#: field:ir.module.module,category_id:0 +msgid "Category" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: selection:ir.attachment,type:0 +#: selection:ir.property,type:0 +msgid "Binary" +msgstr "" + +#. module: base +#: field:ir.actions.server,sms:0 +#: selection:ir.actions.server,state:0 +msgid "SMS" +msgstr "" + +#. module: base +#: model:res.country,name:base.cr +msgid "Costa Rica" +msgstr "" + +#. module: base +#: view:workflow.activity:0 +msgid "Conditions" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_other_form +msgid "Other Partners" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_currency_form +#: model:ir.ui.menu,name:base.menu_action_currency_form +#: view:res.currency:0 +msgid "Currencies" +msgstr "" + +#. module: base +#: sql_constraint:res.groups:0 +msgid "The name of the group must be unique !" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Hour 00->12: %(h12)s" +msgstr "" + +#. module: base +#: help:res.partner.address,active:0 +msgid "Uncheck the active field to hide the contact." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_widget_wizard +msgid "Add a widget for User" +msgstr "" + +#. module: base +#: model:res.country,name:base.dk +msgid "Denmark" +msgstr "" + +#. module: base +#: field:res.country,code:0 +msgid "Country Code" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow_instance +msgid "workflow.instance" +msgstr "" + +#. module: base +#: code:addons/orm.py:278 +#, python-format +msgid "Unknown attribute %s in %s " +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "10. %S ==> 20" +msgstr "" + +#. module: base +#: code:addons/fields.py:106 +#, python-format +msgid "undefined get method !" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Norwegian BokmÃ¥l / Norsk bokmÃ¥l" +msgstr "" + +#. module: base +#: help:res.config.users,new_password:0 +#: help:res.users,new_password:0 +msgid "" +"Only specify a value if you want to change the user password. This user will " +"have to logout and login again!" +msgstr "" + +#. module: base +#: model:res.partner.title,name:base.res_partner_title_madam +msgid "Madam" +msgstr "" + +#. module: base +#: model:res.country,name:base.ee +msgid "Estonia" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.dashboard +msgid "Dashboards" +msgstr "" + +#. module: base +#: help:ir.attachment,type:0 +msgid "Binary File or external URL" +msgstr "" + +#. module: base +#: field:res.config.users,new_password:0 +#: field:res.users,new_password:0 +msgid "Change password" +msgstr "" + +#. module: base +#: model:res.country,name:base.nl +msgid "Netherlands" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.next_id_4 +msgid "Low Level Objects" +msgstr "" + +#. module: base +#: view:res.company:0 +msgid "Your Logo - Use a size of about 450x150 pixels." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_values +msgid "ir.values" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Occitan (FR, post 1500) / Occitan" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.open_module_tree +msgid "" +"You can install new modules in order to activate new features, menu, reports " +"or data in your OpenERP instance. To install some modules, click on the " +"button \"Schedule for Installation\" from the form view, then click on " +"\"Apply Scheduled Upgrades\" to migrate your system." +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_emails +#: model:ir.ui.menu,name:base.menu_mail_gateway +msgid "Emails" +msgstr "" + +#. module: base +#: model:res.country,name:base.cd +msgid "Congo, The Democratic Republic of the" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Malayalam / മലയാളം" +msgstr "" + +#. module: base +#: view:res.request:0 +#: field:res.request,body:0 +#: field:res.request.history,req_id:0 +msgid "Request" +msgstr "" + +#. module: base +#: model:res.country,name:base.jp +msgid "Japan" +msgstr "" + +#. module: base +#: field:ir.cron,numbercall:0 +msgid "Number of Calls" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +#: field:base.module.upgrade,module_info:0 +msgid "Modules to update" +msgstr "" + +#. module: base +#: help:ir.actions.server,sequence:0 +msgid "" +"Important when you deal with multiple actions, the execution order will be " +"decided based on this, low number is higher priority." +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,header:0 +msgid "Add RML header" +msgstr "" + +#. module: base +#: model:res.country,name:base.gr +msgid "Greece" +msgstr "" + +#. module: base +#: field:res.request,trigger_date:0 +msgid "Trigger Date" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Croatian / hrvatski jezik" +msgstr "" + +#. module: base +#: field:base.language.install,overwrite:0 +msgid "Overwrite Existing Terms" +msgstr "" + +#. module: base +#: help:ir.actions.server,code:0 +msgid "Python code to be executed" +msgstr "" + +#. module: base +#: sql_constraint:res.country:0 +msgid "The code of the country must be unique !" +msgstr "" + +#. module: base +#: selection:ir.module.module.dependency,state:0 +msgid "Uninstallable" +msgstr "" + +#. module: base +#: view:res.partner.category:0 +msgid "Partner Category" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +#: selection:ir.actions.server,state:0 +msgid "Trigger" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_module_update +msgid "Update Module" +msgstr "" + +#. module: base +#: view:ir.model.fields:0 +#: field:ir.model.fields,translate:0 +msgid "Translate" +msgstr "" + +#. module: base +#: field:res.request.history,body:0 +msgid "Body" +msgstr "" + +#. module: base +#: view:partner.wizard.spam:0 +msgid "Send Email" +msgstr "" + +#. module: base +#: field:res.config.users,menu_id:0 +#: field:res.users,menu_id:0 +msgid "Menu Action" +msgstr "" + +#. module: base +#: help:ir.model.fields,selection:0 +msgid "" +"List of options for a selection field, specified as a Python expression " +"defining a list of (key, label) pairs. For example: " +"[('blue','Blue'),('yellow','Yellow')]" +msgstr "" + +#. module: base +#: selection:base.language.export,state:0 +msgid "choose" +msgstr "" + +#. module: base +#: help:ir.model,osv_memory:0 +msgid "" +"Indicates whether this object model lives in memory only, i.e. is not " +"persisted (osv.osv_memory)" +msgstr "" + +#. module: base +#: field:res.partner,child_ids:0 +#: field:res.request,ref_partner_id:0 +msgid "Partner Ref." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_supplier_form +#: model:ir.ui.menu,name:base.menu_procurement_management_supplier_name +#: view:res.partner:0 +msgid "Suppliers" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract.wizard:0 +msgid "Register" +msgstr "" + +#. module: base +#: field:res.request,ref_doc2:0 +msgid "Document Ref 2" +msgstr "" + +#. module: base +#: field:res.request,ref_doc1:0 +msgid "Document Ref 1" +msgstr "" + +#. module: base +#: model:res.country,name:base.ga +msgid "Gabon" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_model_data +msgid "ir.model.data" +msgstr "" + +#. module: base +#: view:ir.model:0 +#: view:ir.rule:0 +#: view:res.groups:0 +msgid "Access Rights" +msgstr "" + +#. module: base +#: model:res.country,name:base.gl +msgid "Greenland" +msgstr "" + +#. module: base +#: field:res.partner.bank,acc_number:0 +msgid "Account Number" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "1. %c ==> Fri Dec 5 18:25:20 2008" +msgstr "" + +#. module: base +#: model:res.country,name:base.nc +msgid "New Caledonia (French)" +msgstr "" + +#. module: base +#: model:res.country,name:base.cy +msgid "Cyprus" +msgstr "" + +#. module: base +#: view:base.module.import:0 +msgid "" +"This wizard helps you add a new language to you OpenERP system. After " +"loading a new language it becomes available as default interface language " +"for users and partners." +msgstr "" + +#. module: base +#: field:ir.actions.server,subject:0 +#: field:partner.wizard.spam,subject:0 +#: field:res.request,name:0 +msgid "Subject" +msgstr "" + +#. module: base +#: field:res.request,act_from:0 +#: field:res.request.history,act_from:0 +msgid "From" +msgstr "" + +#. module: base +#: view:res.users:0 +msgid "Preferences" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_consumers0 +msgid "Consumers" +msgstr "" + +#. module: base +#: view:res.config:0 +#: wizard_button:server.action.create,init,step_1:0 +msgid "Next" +msgstr "" + +#. module: base +#: help:ir.cron,function:0 +msgid "" +"Name of the method to be called on the object when this scheduler is " +"executed." +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:219 +#, python-format +msgid "" +"The Selection Options expression is must be in the [('key','Label'), ...] " +"format!" +msgstr "" + +#. module: base +#: view:ir.actions.report.xml:0 +msgid "Miscellaneous" +msgstr "" + +#. module: base +#: model:res.country,name:base.cn +msgid "China" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:516 +#, python-format +msgid "" +"--\n" +"%(name)s %(email)s\n" +msgstr "" + +#. module: base +#: model:res.country,name:base.eh +msgid "Western Sahara" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow +msgid "workflow" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_res_company_form +msgid "" +"Create and manage the companies that will be managed by OpenERP from here. " +"Shops or subsidiaries can be created and maintained from here." +msgstr "" + +#. module: base +#: model:res.country,name:base.id +msgid "Indonesia" +msgstr "" + +#. module: base +#: view:base.update.translations:0 +msgid "" +"This wizard will detect new terms to translate in the application, so that " +"you can then add translations manually or perform a complete export (as a " +"template for a new language example)." +msgstr "" + +#. module: base +#: help:multi_company.default,expression:0 +msgid "" +"Expression, must be True to match\n" +"use context.get or user (browse)" +msgstr "" + +#. module: base +#: model:res.country,name:base.bg +msgid "Bulgaria" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract.wizard:0 +msgid "Publisher warranty contract successfully registered!" +msgstr "" + +#. module: base +#: model:res.country,name:base.ao +msgid "Angola" +msgstr "" + +#. module: base +#: model:res.country,name:base.tf +msgid "French Southern Territories" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_currency +#: field:res.company,currency_id:0 +#: field:res.company,currency_ids:0 +#: view:res.currency:0 +#: field:res.currency,name:0 +#: field:res.currency.rate,currency_id:0 +msgid "Currency" +msgstr "" + +#. module: base +#: field:res.partner.canal,name:0 +msgid "Channel Name" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "5. %y, %Y ==> 08, 2008" +msgstr "" + +#. module: base +#: model:res.partner.title,shortcut:base.res_partner_title_ltd +msgid "ltd" +msgstr "" + +#. module: base +#: field:ir.values,res_id:0 +#: field:res.log,res_id:0 +msgid "Object ID" +msgstr "" + +#. module: base +#: view:res.company:0 +msgid "Landscape" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_administration +msgid "Administration" +msgstr "" + +#. module: base +#: view:base.module.update:0 +msgid "Click on Update below to start the process..." +msgstr "" + +#. module: base +#: model:res.country,name:base.ir +msgid "Iran" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_widget_user_act_window +#: model:ir.ui.menu,name:base.menu_res_widget_user_act_window +msgid "Widgets per User" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Slovak / Slovenský jazyk" +msgstr "" + +#. module: base +#: field:base.language.export,state:0 +#: field:ir.ui.menu,icon_pict:0 +#: field:publisher_warranty.contract.wizard,state:0 +msgid "unknown" +msgstr "" + +#. module: base +#: field:res.currency,symbol:0 +msgid "Symbol" +msgstr "" + +#. module: base +#: help:res.config.users,login:0 +#: help:res.users,login:0 +msgid "Used to log into the system" +msgstr "" + +#. module: base +#: view:base.update.translations:0 +msgid "Synchronize Translation" +msgstr "" + +#. module: base +#: field:ir.ui.view_sc,res_id:0 +msgid "Resource Ref." +msgstr "" + +#. module: base +#: model:res.country,name:base.ki +msgid "Kiribati" +msgstr "" + +#. module: base +#: model:res.country,name:base.iq +msgid "Iraq" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_association +msgid "Association" +msgstr "" + +#. module: base +#: model:res.country,name:base.cl +msgid "Chile" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_address_book +#: model:ir.ui.menu,name:base.menu_config_address_book +#: model:ir.ui.menu,name:base.menu_procurement_management_supplier +msgid "Address Book" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_sequence_type +msgid "ir.sequence.type" +msgstr "" + +#. module: base +#: selection:base.language.export,format:0 +msgid "CSV File" +msgstr "" + +#. module: base +#: field:res.company,account_no:0 +msgid "Account No." +msgstr "" + +#. module: base +#: code:addons/base/res/res_lang.py:157 +#, python-format +msgid "Base Language 'en_US' can not be deleted !" +msgstr "" + +#. module: base +#: selection:ir.model,state:0 +msgid "Base Object" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "Dependencies :" +msgstr "" + +#. module: base +#: field:ir.model.fields,field_description:0 +msgid "Field Label" +msgstr "" + +#. module: base +#: model:res.country,name:base.dj +msgid "Djibouti" +msgstr "" + +#. module: base +#: field:ir.translation,value:0 +msgid "Translation Value" +msgstr "" + +#. module: base +#: model:res.country,name:base.ag +msgid "Antigua and Barbuda" +msgstr "" + +#. module: base +#: code:addons/orm.py:3166 +#, python-format +msgid "" +"Operation prohibited by access rules, or performed on an already deleted " +"document (Operation: %s, Document type: %s)." +msgstr "" + +#. module: base +#: model:res.country,name:base.zr +msgid "Zaire" +msgstr "" + +#. module: base +#: field:ir.model.data,res_id:0 +#: field:ir.translation,res_id:0 +#: field:workflow.instance,res_id:0 +#: field:workflow.triggers,res_id:0 +msgid "Resource ID" +msgstr "" + +#. module: base +#: view:ir.cron:0 +#: field:ir.model,info:0 +msgid "Information" +msgstr "" + +#. module: base +#: view:res.widget.user:0 +msgid "User Widgets" +msgstr "" + +#. module: base +#: view:base.module.update:0 +msgid "Update Module List" +msgstr "" + +#. module: base +#: selection:res.partner.address,type:0 +msgid "Other" +msgstr "" + +#. module: base +#: view:res.request:0 +msgid "Reply" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Turkish / Türkçe" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_workflow_activity_form +#: model:ir.ui.menu,name:base.menu_workflow_activity +#: view:workflow:0 +#: field:workflow,activities:0 +msgid "Activities" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,auto_refresh:0 +msgid "Auto-Refresh" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:62 +#, python-format +msgid "The osv_memory field can only be compared with = and != operator." +msgstr "" + +#. module: base +#: selection:ir.ui.view,type:0 +msgid "Diagram" +msgstr "" + +#. module: base +#: help:multi_company.default,name:0 +msgid "Name it to easily find a record" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.grant_menu_access +#: model:ir.ui.menu,name:base.menu_grant_menu_access +msgid "Menu Items" +msgstr "" + +#. module: base +#: constraint:ir.rule:0 +msgid "Rules are not supported for osv_memory objects !" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_event_association +#: model:ir.ui.menu,name:base.menu_event_main +msgid "Events Organisation" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.ir_sequence_actions +#: model:ir.ui.menu,name:base.menu_custom_action +#: model:ir.ui.menu,name:base.menu_ir_sequence_actions +#: model:ir.ui.menu,name:base.next_id_6 +#: view:workflow.activity:0 +msgid "Actions" +msgstr "" + +#. module: base +#: selection:res.request,priority:0 +msgid "High" +msgstr "" + +#. module: base +#: field:ir.exports.line,export_id:0 +msgid "Export" +msgstr "" + +#. module: base +#: model:res.country,name:base.hr +msgid "Croatia" +msgstr "" + +#. module: base +#: help:res.bank,bic:0 +msgid "Bank Identifier Code" +msgstr "" + +#. module: base +#: model:res.country,name:base.tm +msgid "Turkmenistan" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_actions.py:597 +#: code:addons/base/ir/ir_actions.py:629 +#: code:addons/base/ir/ir_actions.py:713 +#: code:addons/base/ir/ir_actions.py:716 +#: code:addons/base/ir/ir_model.py:114 +#: code:addons/base/ir/ir_model.py:204 +#: code:addons/base/ir/ir_model.py:218 +#: code:addons/base/ir/ir_model.py:232 +#: code:addons/base/ir/ir_model.py:250 +#: code:addons/base/ir/ir_model.py:255 +#: code:addons/base/ir/ir_model.py:258 +#: code:addons/base/module/module.py:215 +#: code:addons/base/module/module.py:258 +#: code:addons/base/module/module.py:262 +#: code:addons/base/module/module.py:268 +#: code:addons/base/module/module.py:303 +#: code:addons/base/module/module.py:321 +#: code:addons/base/module/module.py:336 +#: code:addons/base/module/module.py:429 +#: code:addons/base/module/module.py:531 +#: code:addons/base/publisher_warranty/publisher_warranty.py:163 +#: code:addons/base/publisher_warranty/publisher_warranty.py:281 +#: code:addons/base/res/res_currency.py:100 +#: code:addons/base/res/res_user.py:57 +#: code:addons/base/res/res_user.py:66 +#: code:addons/custom.py:558 +#: code:addons/orm.py:3199 +#, python-format +msgid "Error" +msgstr "" + +#. module: base +#: model:res.country,name:base.pm +msgid "Saint Pierre and Miquelon" +msgstr "" + +#. module: base +#: help:ir.actions.report.xml,header:0 +msgid "Add or not the coporate RML header" +msgstr "" + +#. module: base +#: help:workflow.transition,act_to:0 +msgid "The destination activity." +msgstr "" + +#. module: base +#: view:base.module.update:0 +#: view:base.update.translations:0 +msgid "Update" +msgstr "" + +#. module: base +#: model:ir.actions.report.xml,name:base.ir_module_reference_print +msgid "Technical guide" +msgstr "" + +#. module: base +#: model:res.country,name:base.tz +msgid "Tanzania" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Danish / Dansk" +msgstr "" + +#. module: base +#: selection:ir.model.fields,select_level:0 +msgid "Advanced Search (deprecated)" +msgstr "" + +#. module: base +#: model:res.country,name:base.cx +msgid "Christmas Island" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Other Actions Configuration" +msgstr "" + +#. module: base +#: view:res.config.installer:0 +msgid "Install Modules" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.res_partner_canal-act +#: model:ir.model,name:base.model_res_partner_canal +#: model:ir.ui.menu,name:base.menu_res_partner_canal-act +#: view:res.partner.canal:0 +msgid "Channels" +msgstr "" + +#. module: base +#: view:ir.ui.view:0 +msgid "Extra Info" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.act_values_form_action +#: model:ir.ui.menu,name:base.menu_values_form_action +msgid "Client Events" +msgstr "" + +#. module: base +#: view:ir.module.module:0 +msgid "Schedule for Installation" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_partner_wizard_ean_check +msgid "Ean Check" +msgstr "" + +#. module: base +#: sql_constraint:res.config.users:0 +#: sql_constraint:res.users:0 +msgid "You can not have two users with the same login !" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_multi_company_default +msgid "Default multi company" +msgstr "" + +#. module: base +#: view:res.request:0 +msgid "Send" +msgstr "" + +#. module: base +#: field:res.config.users,menu_tips:0 +#: field:res.users,menu_tips:0 +msgid "Menu Tips" +msgstr "" + +#. module: base +#: field:ir.translation,src:0 +msgid "Source" +msgstr "" + +#. module: base +#: help:res.partner.address,partner_id:0 +msgid "Keep empty for a private address, not related to partner." +msgstr "" + +#. module: base +#: model:res.country,name:base.vu +msgid "Vanuatu" +msgstr "" + +#. module: base +#: view:res.company:0 +msgid "Internal Header/Footer" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_export_language.py:59 +#, python-format +msgid "" +"Save this document to a .tgz file. This archive containt UTF-8 %s files and " +"may be uploaded to launchpad." +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "Start configuration" +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "_Export" +msgstr "" + +#. module: base +#: field:base.language.install,state:0 +#: field:base.module.import,state:0 +#: field:base.module.update,state:0 +msgid "state" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Catalan / Català " +msgstr "" + +#. module: base +#: model:res.country,name:base.do +msgid "Dominican Republic" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Serbian (Cyrillic) / ÑрпÑки" +msgstr "" + +#. module: base +#: code:addons/orm.py:2161 +#, python-format +msgid "" +"Invalid group_by specification: \"%s\".\n" +"A group_by specification must be a list of valid fields." +msgstr "" + +#. module: base +#: model:res.country,name:base.sa +msgid "Saudi Arabia" +msgstr "" + +#. module: base +#: help:res.partner,supplier:0 +msgid "" +"Check this box if the partner is a supplier. If it's not checked, purchase " +"people will not see it when encoding a purchase order." +msgstr "" + +#. module: base +#: field:ir.model.fields,relation_field:0 +msgid "Relation Field" +msgstr "" + +#. module: base +#: view:res.partner.event:0 +msgid "Event Logs" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_module_configuration.py:37 +#, python-format +msgid "System Configuration done" +msgstr "" + +#. module: base +#: field:workflow.triggers,instance_id:0 +msgid "Destination Instance" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,multi:0 +#: field:ir.actions.wizard,multi:0 +msgid "Action on Multiple Doc." +msgstr "" + +#. module: base +#: view:base.language.export:0 +msgid "https://translations.launchpad.net/openobject" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,report_xml:0 +msgid "XML path" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,restart:0 +msgid "On Skip" +msgstr "" + +#. module: base +#: model:res.country,name:base.gn +msgid "Guinea" +msgstr "" + +#. module: base +#: model:res.country,name:base.lu +msgid "Luxembourg" +msgstr "" + +#. module: base +#: help:ir.values,key2:0 +msgid "" +"The kind of action or button in the client side that will trigger the action." +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_ui_menu.py:285 +#, python-format +msgid "Error ! You can not create recursive Menu." +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_publisher_warranty_contract_add_wizard +#: model:ir.ui.menu,name:base.menu_publisher_warranty_contract_add +#: view:publisher_warranty.contract.wizard:0 +msgid "Register a Contract" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "" +"3. If user belongs to several groups, the results from step 2 are combined " +"with logical OR operator" +msgstr "" + +#. module: base +#: code:addons/base/publisher_warranty/publisher_warranty.py:145 +#, python-format +msgid "Please check your publisher warranty contract name and validity." +msgstr "" + +#. module: base +#: model:res.country,name:base.sv +msgid "El Salvador" +msgstr "" + +#. module: base +#: field:res.bank,phone:0 +#: field:res.partner,phone:0 +#: field:res.partner.address,phone:0 +msgid "Phone" +msgstr "" + +#. module: base +#: field:ir.cron,active:0 +#: field:ir.sequence,active:0 +#: field:res.bank,active:0 +#: field:res.config.users,active:0 +#: field:res.currency,active:0 +#: field:res.lang,active:0 +#: field:res.partner,active:0 +#: field:res.partner.address,active:0 +#: field:res.partner.canal,active:0 +#: field:res.partner.category,active:0 +#: field:res.request,active:0 +#: field:res.users,active:0 +#: view:workflow.instance:0 +#: view:workflow.workitem:0 +msgid "Active" +msgstr "" + +#. module: base +#: model:res.country,name:base.th +msgid "Thailand" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_crm_config_lead +msgid "Leads & Opportunities" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Romanian / română" +msgstr "" + +#. module: base +#: view:res.log:0 +msgid "System Logs" +msgstr "" + +#. module: base +#: selection:workflow.activity,join_mode:0 +#: selection:workflow.activity,split_mode:0 +msgid "And" +msgstr "" + +#. module: base +#: field:ir.model.fields,relation:0 +msgid "Object Relation" +msgstr "" + +#. module: base +#: view:ir.rule:0 +#: view:res.partner:0 +msgid "General" +msgstr "" + +#. module: base +#: model:res.country,name:base.uz +msgid "Uzbekistan" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_act_window +#: selection:ir.ui.menu,action:0 +msgid "ir.actions.act_window" +msgstr "" + +#. module: base +#: field:ir.rule,perm_create:0 +msgid "Apply For Create" +msgstr "" + +#. module: base +#: model:res.country,name:base.vi +msgid "Virgin Islands (USA)" +msgstr "" + +#. module: base +#: model:res.country,name:base.tw +msgid "Taiwan" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_currency_rate +msgid "Currency Rate" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.grant_menu_access +msgid "" +"Manage and customize the items available and displayed in your OpenERP " +"system menu. You can delete an item by clicking on the box at the beginning " +"of each line and then delete it through the button that appeared. Items can " +"be assigned to specific groups in order to make them accessible to some " +"users within the system." +msgstr "" + +#. module: base +#: field:ir.ui.view,field_parent:0 +msgid "Child Field" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,usage:0 +#: field:ir.actions.act_window_close,usage:0 +#: field:ir.actions.actions,usage:0 +#: field:ir.actions.report.xml,usage:0 +#: field:ir.actions.server,usage:0 +#: field:ir.actions.wizard,usage:0 +msgid "Action Usage" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_workflow_workitem +msgid "workflow.workitem" +msgstr "" + +#. module: base +#: selection:ir.module.module,state:0 +msgid "Not Installable" +msgstr "" + +#. module: base +#: report:ir.module.reference.graph:0 +msgid "View :" +msgstr "" + +#. module: base +#: field:ir.model.fields,view_load:0 +msgid "View Auto-Load" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:232 +#, python-format +msgid "You cannot remove the field '%s' !" +msgstr "" + +#. module: base +#: field:ir.exports,resource:0 +#: view:ir.property:0 +#: field:ir.property,res_id:0 +msgid "Resource" +msgstr "" + +#. module: base +#: field:ir.ui.menu,web_icon:0 +msgid "Web Icon File" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Persian / Ùارس" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +msgid "View Ordering" +msgstr "" + +#. module: base +#: code:addons/base/module/wizard/base_module_upgrade.py:95 +#, python-format +msgid "Unmet dependency !" +msgstr "" + +#. module: base +#: view:base.language.import:0 +msgid "" +"Supported file formats: *.csv (Comma-separated values) or *.po (GetText " +"Portable Objects)" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:487 +#, python-format +msgid "" +"You can not delete this document (%s) ! Be sure your user belongs to one of " +"these groups: %s." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_base_module_configuration +msgid "base.module.configuration" +msgstr "" + +#. module: base +#: field:base.language.export,name:0 +#: field:ir.attachment,datas_fname:0 +msgid "Filename" +msgstr "" + +#. module: base +#: field:ir.model,access_ids:0 +#: view:ir.model.access:0 +msgid "Access" +msgstr "" + +#. module: base +#: model:res.country,name:base.sk +msgid "Slovak Republic" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.publisher_warranty +msgid "Publisher Warranty" +msgstr "" + +#. module: base +#: model:res.country,name:base.aw +msgid "Aruba" +msgstr "" + +#. module: base +#: model:res.country,name:base.ar +msgid "Argentina" +msgstr "" + +#. module: base +#: field:res.groups,name:0 +msgid "Group Name" +msgstr "" + +#. module: base +#: model:res.country,name:base.bh +msgid "Bahrain" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_12 +msgid "Segmentation" +msgstr "" + +#. module: base +#: view:ir.attachment:0 +#: field:ir.attachment,company_id:0 +#: field:ir.default,company_id:0 +#: field:ir.property,company_id:0 +#: field:ir.sequence,company_id:0 +#: field:ir.values,company_id:0 +#: view:res.company:0 +#: field:res.config.users,company_id:0 +#: field:res.currency,company_id:0 +#: field:res.partner,company_id:0 +#: field:res.partner.address,company_id:0 +#: view:res.users:0 +#: field:res.users,company_id:0 +msgid "Company" +msgstr "" + +#. module: base +#: view:res.users:0 +msgid "Email & Signature" +msgstr "" + +#. module: base +#: view:publisher_warranty.contract:0 +msgid "Publisher Warranty Contract" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Bulgarian / българÑки език" +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_aftersale +msgid "After-Sale Services" +msgstr "" + +#. module: base +#: view:ir.actions.todo:0 +msgid "Launch" +msgstr "" + +#. module: base +#: field:ir.actions.act_window,limit:0 +msgid "Limit" +msgstr "" + +#. module: base +#: help:ir.actions.server,wkf_model_id:0 +msgid "Workflow to be executed on this model." +msgstr "" + +#. module: base +#: model:res.country,name:base.jm +msgid "Jamaica" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_category_form +msgid "" +"Manage the partner categories in order to better classify them for tracking " +"and analysis purposes. A partner may belong to several categories and " +"categories have a hierarchy structure: a partner belonging to a category " +"also belong to his parent category." +msgstr "" + +#. module: base +#: model:res.country,name:base.az +msgid "Azerbaijan" +msgstr "" + +#. module: base +#: code:addons/base/res/partner/partner.py:250 +#, python-format +msgid "Warning" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Arabic / الْعَرَبيّة" +msgstr "" + +#. module: base +#: model:res.country,name:base.vg +msgid "Virgin Islands (British)" +msgstr "" + +#. module: base +#: view:ir.property:0 +#: model:ir.ui.menu,name:base.next_id_15 +msgid "Parameters" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Czech / ÄŒeÅ¡tina" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Trigger Configuration" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,help:base.action_partner_supplier_form +msgid "" +"You can access all information regarding your suppliers from the supplier " +"form: accounting data, history of emails, meetings, purchases, etc. You can " +"uncheck the 'Suppliers' filter button in order to search in all your " +"partners, including customers and prospects." +msgstr "" + +#. module: base +#: model:res.country,name:base.rw +msgid "Rwanda" +msgstr "" + +#. module: base +#: view:ir.sequence:0 +msgid "Day of the week (0:Monday): %(weekday)s" +msgstr "" + +#. module: base +#: model:res.country,name:base.ck +msgid "Cook Islands" +msgstr "" + +#. module: base +#: field:ir.model.data,noupdate:0 +msgid "Non Updatable" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Klingon" +msgstr "" + +#. module: base +#: model:res.country,name:base.sg +msgid "Singapore" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window,target:0 +msgid "Current Window" +msgstr "" + +#. module: base +#: view:ir.values:0 +msgid "Action Source" +msgstr "" + +#. module: base +#: view:res.config.view:0 +msgid "" +"If you use OpenERP for the first time we strongly advise you to select the " +"simplified interface, which has less features but is easier. You can always " +"switch later from the user preferences." +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_country +#: field:res.bank,country:0 +#: view:res.country:0 +#: field:res.country.state,country_id:0 +#: field:res.partner,country:0 +#: view:res.partner.address:0 +#: field:res.partner.address,country_id:0 +#: field:res.partner.bank,country_id:0 +msgid "Country" +msgstr "" + +#. module: base +#: field:ir.model.fields,complete_name:0 +#: field:ir.ui.menu,complete_name:0 +msgid "Complete Name" +msgstr "" + +#. module: base +#: field:ir.values,object:0 +msgid "Is Object" +msgstr "" + +#. module: base +#: view:ir.rule:0 +msgid "" +"1. Global rules are combined together with a logical AND operator, and with " +"the result of the following steps" +msgstr "" + +#. module: base +#: field:res.partner.category,name:0 +msgid "Category Name" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_15 +msgid "IT sector" +msgstr "" + +#. module: base +#: view:ir.actions.act_window:0 +msgid "Select Groups" +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%X - Appropriate time representation." +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Spanish (SV) / Español (SV)" +msgstr "" + +#. module: base +#: help:res.lang,grouping:0 +msgid "" +"The Separator Format should be like [,n] where 0 < n :starting from Unit " +"digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be " +"1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as " +"106,500. Provided ',' as the thousand separator in each case." +msgstr "" + +#. module: base +#: view:res.company:0 +msgid "Portrait" +msgstr "" + +#. module: base +#: code:addons/base/ir/ir_model.py:317 +#, python-format +msgid "Can only rename one column at a time!" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Wizard Button" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Report/Template" +msgstr "" + +#. module: base +#: selection:ir.actions.act_window.view,view_mode:0 +#: selection:ir.ui.view,type:0 +#: selection:wizard.ir.model.menu.create.line,view_type:0 +msgid "Graph" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_ir_actions_server +#: selection:ir.ui.menu,action:0 +msgid "ir.actions.server" +msgstr "" + +#. module: base +#: field:ir.actions.configuration.wizard,progress:0 +#: field:res.config,progress:0 +#: field:res.config.installer,progress:0 +#: field:res.config.users,progress:0 +#: field:res.config.view,progress:0 +msgid "Configuration Progress" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.act_ir_actions_todo_form +#: model:ir.ui.menu,name:base.menu_ir_actions_todo_form +#: model:ir.ui.menu,name:base.next_id_11 +msgid "Configuration Wizards" +msgstr "" + +#. module: base +#: field:res.lang,code:0 +msgid "Locale Code" +msgstr "" + +#. module: base +#: field:workflow.activity,split_mode:0 +msgid "Split Mode" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "Note that this operation might take a few minutes." +msgstr "" + +#. module: base +#: model:ir.ui.menu,name:base.menu_localisation +msgid "Localisation" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "Action to Launch" +msgstr "" + +#. module: base +#: view:ir.cron:0 +msgid "Execution" +msgstr "" + +#. module: base +#: field:ir.actions.server,condition:0 +#: field:workflow.transition,condition:0 +msgid "Condition" +msgstr "" + +#. module: base +#: help:ir.values,model_id:0 +msgid "This field is not used, it only helps you to select a good model." +msgstr "" + +#. module: base +#: field:ir.ui.view,name:0 +msgid "View Name" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Italian / Italiano" +msgstr "" + +#. module: base +#: field:ir.actions.report.xml,attachment:0 +msgid "Save As Attachment Prefix" +msgstr "" + +#. module: base +#: view:ir.actions.server:0 +msgid "" +"Only one client action will be executed, last client action will be " +"considered in case of multiple client actions." +msgstr "" + +#. module: base +#: view:res.lang:0 +msgid "%j - Day of the year [001,366]." +msgstr "" + +#. module: base +#: field:ir.actions.server,mobile:0 +msgid "Mobile No" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_partner_by_category +#: model:ir.actions.act_window,name:base.action_partner_category_form +#: model:ir.model,name:base.model_res_partner_category +#: model:ir.ui.menu,name:base.menu_partner_category_form +#: view:res.partner.category:0 +msgid "Partner Categories" +msgstr "" + +#. module: base +#: view:base.module.upgrade:0 +msgid "System Update" +msgstr "" + +#. module: base +#: selection:ir.translation,type:0 +msgid "Wizard Field" +msgstr "" + +#. module: base +#: help:ir.sequence,prefix:0 +msgid "Prefix value of the record for the sequence" +msgstr "" + +#. module: base +#: model:res.country,name:base.sc +msgid "Seychelles" +msgstr "" + +#. module: base +#: model:ir.model,name:base.model_res_partner_bank +#: view:res.partner.bank:0 +msgid "Bank Accounts" +msgstr "" + +#. module: base +#: model:res.country,name:base.sl +msgid "Sierra Leone" +msgstr "" + +#. module: base +#: view:res.company:0 +#: view:res.partner:0 +msgid "General Information" +msgstr "" + +#. module: base +#: model:res.country,name:base.tc +msgid "Turks and Caicos Islands" +msgstr "" + +#. module: base +#: field:res.partner.bank,owner_name:0 +msgid "Account Owner" +msgstr "" + +#. module: base +#: code:addons/base/res/res_user.py:256 +#, python-format +msgid "Company Switch Warning" +msgstr "" + +#. module: base +#: model:ir.actions.act_window,name:base.action_res_widget_wizard +msgid "Homepage Widgets Management" +msgstr "" + +#. module: base +#: field:workflow,osv:0 +#: field:workflow.instance,res_type:0 +msgid "Resource Object" +msgstr "" + +#. module: base +#: help:ir.sequence,number_increment:0 +msgid "The next number of the sequence will be incremented by this number" +msgstr "" + +#. module: base +#: field:ir.cron,function:0 +#: field:res.partner.address,function:0 +#: selection:workflow.activity,kind:0 +msgid "Function" +msgstr "" + +#. module: base +#: view:res.widget:0 +msgid "Search Widget" +msgstr "" + +#. module: base +#: selection:ir.actions.todo,restart:0 +msgid "Never" +msgstr "" + +#. module: base +#: selection:res.partner.address,type:0 +msgid "Delivery" +msgstr "" + +#. module: base +#: model:res.partner.title,name:base.res_partner_title_pvt_ltd +#: model:res.partner.title,shortcut:base.res_partner_title_pvt_ltd +msgid "Corp." +msgstr "" + +#. module: base +#: model:res.country,name:base.gw +msgid "Guinea Bissau" +msgstr "" + +#. module: base +#: view:workflow.instance:0 +msgid "Workflow Instances" +msgstr "" + +#. module: base +#: code:addons/base/res/partner/partner.py:261 +#, python-format +msgid "Partners: " +msgstr "" + +#. module: base +#: model:res.country,name:base.kp +msgid "North Korea" +msgstr "" + +#. module: base +#: selection:ir.actions.server,state:0 +msgid "Create Object" +msgstr "" + +#. module: base +#: view:ir.filters:0 +#: field:res.log,context:0 +msgid "Context" +msgstr "" + +#. module: base +#: field:res.bank,bic:0 +msgid "BIC/Swift code" +msgstr "" + +#. module: base +#: model:res.partner.category,name:base.res_partner_category_1 +msgid "Prospect" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Polish / JÄ™zyk polski" +msgstr "" + +#. module: base +#: field:ir.exports,name:0 +msgid "Export Name" +msgstr "" + +#. module: base +#: help:res.partner.address,type:0 +msgid "" +"Used to select automatically the right address according to the context in " +"sales and purchases documents." +msgstr "" + +#. module: base +#: model:res.country,name:base.lk +msgid "Sri Lanka" +msgstr "" + +#. module: base +#: selection:base.language.install,lang:0 +msgid "Russian / руÑÑкий Ñзык" +msgstr "" diff --git a/openerp/addons/base/ir/__init__.py b/openerp/addons/base/ir/__init__.py index 9b4eb96df5fb519b0ae0b16639b5c41778bbdc15..4a6bd3c614c5f3e55f7e27086ae54920f0bb5d36 100644 --- a/openerp/addons/base/ir/__init__.py +++ b/openerp/addons/base/ir/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- ############################################################################## -# +# # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). # @@ -15,7 +15,7 @@ # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# along with this program. If not, see <http://www.gnu.org/licenses/>. # ############################################################################## @@ -36,6 +36,7 @@ import ir_rule import wizard import ir_config_parameter import osv_memory_autovacuum +import ir_mail_server # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index adbab6487983ed73f5fdd8302321b7f37fdafcb2..2792259773d3b61a1f98e7df8d83da16371d9119 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -28,7 +28,7 @@ <group col="2" colspan="2"> <separator string="Values for Event Type" colspan="2"/> <label string="client_action_multi, client_action_relate" colspan="2"/> - <label string="tree_but_action, client_print_multi" colspan="2"/> + <label string="tree_but_open, client_print_multi" colspan="2"/> </group> <group col="2" colspan="2"> <separator colspan="2" string="Value"/> @@ -1274,7 +1274,7 @@ <record id="action_model_model" model="ir.actions.act_window"> - <field name="name">Objects</field> + <field name="name">Models</field> <field name="res_model">ir.model</field> <field name="view_type">form</field> <field name="context">{'manual':True}</field> @@ -1740,7 +1740,7 @@ <field name="name">Property multi-company</field> <field model="ir.model" name="model_id" ref="model_ir_property"/> <field eval="True" name="global"/> - <field name="domain_force">['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field> + <field name="domain_force">['|',('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field> </record> <!--server action view--> @@ -1766,7 +1766,9 @@ <page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}"> <separator colspan="4" string="Trigger Configuration"/> <field name="wkf_model_id" attrs="{'required':[('state','=','trigger')]}"/> - <field name="trigger_obj_id" context="{'key':''}" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','trigger')]}"/> + <field name="trigger_obj_id" context="{'key':''}" + domain="[('model_id','=',model_id),('ttype','in',['many2one','int'])]" + attrs="{'required':[('state','=','trigger')]}"/> <field name="trigger_name" attrs="{'required':[('state','=','trigger')]}"/> </page> <page string="Action to Launch" attrs="{'invisible':[('state','!=','client_action')]}"> @@ -1995,5 +1997,76 @@ <field name="sequence">5</field> </record> + <!-- ir.mail.server --> + <record model="ir.ui.view" id="ir_mail_server_form"> + <field name="name">ir.mail.server.form</field> + <field name="model">ir.mail_server</field> + <field name="type">form</field> + <field name="arch" type="xml"> + <form string="Outgoing Mail Servers"> + <group colspan="4"> + <field name="name"/> + <field name="sequence"/> + </group> + <notebook colspan="4"> + <page string="Configuration"> + <group col="2" colspan="4"> + <separator string="Connection Information" colspan="4"/> + <field name="smtp_host"/> + <field name="smtp_port"/> + <field name="smtp_debug"/> + </group> + <group col="2" colspan="4"> + <separator string="Security and Authentication" colspan="2"/> + <field name="smtp_encryption" on_change="on_change_encryption(smtp_encryption)"/> + <field name="smtp_user"/> + <field name="smtp_pass" password="True"/> + <button name="test_smtp_connection" type="object" string="Test Connection" icon="gtk-network" colspan="2"/> + </group> + </page> + </notebook> + </form> + </field> + </record> + + <record model="ir.ui.view" id="ir_mail_server_list"> + <field name="name">ir.mail.server.list</field> + <field name="model">ir.mail_server</field> + <field name="type">tree</field> + <field name="arch" type="xml"> + <tree string="Outgoing Mail Servers"> + <field name="sequence"/> + <field name="name"/> + <field name="smtp_host"/> + <field name="smtp_user"/> + <field name="smtp_encryption"/> + </tree> + </field> + </record> + + <record id="view_ir_mail_server_search" model="ir.ui.view"> + <field name="name">ir.mail.server.search</field> + <field name="model">ir.mail_server</field> + <field name="type">search</field> + <field name="arch" type="xml"> + <search string="Outgoing Mail Servers"> + <field name="name"/> + <field name="smtp_host"/> + <field name="smtp_user"/> + <field name="smtp_encryption"/> + </search> + </field> + </record> + + <record model="ir.actions.act_window" id="action_ir_mail_server_list"> + <field name="name">Outgoing Mail Servers</field> + <field name="res_model">ir.mail_server</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="view_id" ref="ir_mail_server_list" /> + <field name="search_view_id" ref="view_ir_mail_server_search"/> + </record> + <menuitem id="next_id_15" name="Parameters" parent="base.menu_config" groups="base.group_extended" /> + <menuitem id="menu_mail_servers" parent="base.next_id_15" action="action_ir_mail_server_list" sequence="15"/> </data> </openerp> diff --git a/openerp/addons/base/ir/ir_actions.py b/openerp/addons/base/ir/ir_actions.py index 3ce3d9c0335a20b1f73d67eb5917092f1a854ce0..a2e107e741e4a724bf466673c87353b35aaefd04 100644 --- a/openerp/addons/base/ir/ir_actions.py +++ b/openerp/addons/base/ir/ir_actions.py @@ -418,7 +418,10 @@ class server_object_lines(osv.osv): _columns = { 'server_id': fields.many2one('ir.actions.server', 'Object Mapping'), 'col1': fields.many2one('ir.model.fields', 'Destination', required=True), - 'value': fields.text('Value', required=True), + 'value': fields.text('Value', required=True, help="Expression containing a value specification. \n" + "When Formula type is selected, this field may be a Python expression " + " that can use the same values as for the condition field on the server action.\n" + "If Value type is selected, the value will be used directly without evaluation."), 'type': fields.selection([ ('value','Value'), ('equation','Formula') @@ -435,14 +438,15 @@ server_object_lines() class actions_server(osv.osv): def _select_signals(self, cr, uid, context=None): - cr.execute("SELECT distinct w.osv, t.signal FROM wkf w, wkf_activity a, wkf_transition t \ - WHERE w.id = a.wkf_id AND t.act_from = a.id OR t.act_to = a.id AND t.signal!='' \ - AND t.signal NOT IN (null, NULL)") + cr.execute("""SELECT distinct w.osv, t.signal FROM wkf w, wkf_activity a, wkf_transition t + WHERE w.id = a.wkf_id AND + (t.act_from = a.id OR t.act_to = a.id) AND + t.signal IS NOT NULL""") result = cr.fetchall() or [] res = [] for rs in result: if rs[0] is not None and rs[1] is not None: - line = rs[0], "%s - (%s)" % (rs[1], rs[0]) + line = rs[1], "%s - (%s)" % (rs[1], rs[0]) res.append(line) return res @@ -453,13 +457,15 @@ class actions_server(osv.osv): return [(r['model'], r['name']) for r in res] + [('','')] def change_object(self, cr, uid, ids, copy_object, state, context=None): - if state == 'object_copy': + if state == 'object_copy' and copy_object: + if context is None: + context = {} model_pool = self.pool.get('ir.model') model = copy_object.split(',')[0] mid = model_pool.search(cr, uid, [('model','=',model)]) return { - 'value':{'srcmodel_id':mid[0]}, - 'context':context + 'value': {'srcmodel_id': mid[0]}, + 'context': context } else: return {} @@ -469,8 +475,19 @@ class actions_server(osv.osv): _sequence = 'ir_actions_id_seq' _order = 'sequence,name' _columns = { - 'name': fields.char('Action Name', required=True, size=64, help="Easy to Refer action by name e.g. One Sales Order -> Many Invoices", translate=True), - 'condition' : fields.char('Condition', size=256, required=True, help="Condition that is to be tested before action is executed, e.g. object.list_price > object.cost_price"), + 'name': fields.char('Action Name', required=True, size=64, translate=True), + 'condition' : fields.char('Condition', size=256, required=True, + help="Condition that is tested before the action is executed, " + "and prevent execution if it is not verified.\n" + "Example: object.list_price > 5000\n" + "It is a Python expression that can use the following values:\n" + " - self: ORM model of the record on which the action is triggered\n" + " - object or obj: browse_record of the record on which the action is triggered\n" + " - pool: ORM model pool (i.e. self.pool)\n" + " - time: Python time module\n" + " - cr: database cursor\n" + " - uid: current user id\n" + " - context: current context"), 'state': fields.selection([ ('client_action','Client Action'), ('dummy','Dummy'), @@ -484,16 +501,20 @@ class actions_server(osv.osv): ('object_write','Write Object'), ('other','Multi Actions'), ], 'Action Type', required=True, size=32, help="Type of the Action that is to be executed"), - 'code':fields.text('Python Code', help="Python code to be executed"), + 'code':fields.text('Python Code', help="Python code to be executed if condition is met.\n" + "It is a Python block that can use the same values as for the condition field"), 'sequence': fields.integer('Sequence', help="Important when you deal with multiple actions, the execution order will be decided based on this, low number is higher priority."), 'model_id': fields.many2one('ir.model', 'Object', required=True, help="Select the object on which the action will work (read, write, create)."), 'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Action Window, Report, Wizard to be executed."), - 'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be used as the trigger."), - 'wkf_model_id': fields.many2one('ir.model', 'Workflow On', help="Workflow to be executed on this model."), - 'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="Select the object from the model on which the workflow will executed."), - 'email': fields.char('Email Address', size=512, help="Provides the fields that will be used to fetch the email address, e.g. when you select the invoice, then `object.invoice_address_id.email` is the field which gives the correct address"), - 'subject': fields.char('Subject', size=1024, translate=True, help="Specify the subject. You can use fields from the object, e.g. `Hello [[ object.partner_id.name ]]`"), - 'message': fields.text('Message', translate=True, help="Specify the message. You can use the fields from the object. e.g. `Dear [[ object.partner_id.name ]]`"), + 'trigger_name': fields.selection(_select_signals, string='Trigger Signal', size=128, help="The workflow signal to trigger"), + 'wkf_model_id': fields.many2one('ir.model', 'Target Object', help="The object that should receive the workflow signal (must have an associated workflow)"), + 'trigger_obj_id': fields.many2one('ir.model.fields','Relation Field', help="The field on the current object that links to the target object record (must be a many2one, or an integer field with the record ID)"), + 'email': fields.char('Email Address', size=512, help="Expression that returns the email address to send to. Can be based on the same values as for the condition field.\n" + "Example: object.invoice_address_id.email, or 'me@example.com'"), + 'subject': fields.char('Subject', size=1024, translate=True, help="Email subject, may contain expressions enclosed in double brackets based on the same values as those " + "available in the condition field, e.g. `Hello [[ object.partner_id.name ]]`"), + 'message': fields.text('Message', translate=True, help="Email contents, may contain expressions enclosed in double brackets based on the same values as those " + "available in the condition field, e.g. `Dear [[ object.partner_id.name ]]`"), 'mobile': fields.char('Mobile No', size=512, help="Provides fields that be used to fetch the mobile number, e.g. you select the invoice, then `object.invoice_address_id.mobile` is the field which gives the correct mobile number"), 'sms': fields.char('SMS', size=160, translate=True), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Other Actions'), @@ -512,12 +533,14 @@ class actions_server(osv.osv): 'condition': lambda *a: 'True', 'type': lambda *a: 'ir.actions.server', 'sequence': lambda *a: 5, - 'code': lambda *a: """# You can use the following variables -# - object or obj -# - time -# - cr -# - uid -# - ids + 'code': lambda *a: """# You can use the following variables: +# - self: ORM model of the record on which the action is triggered +# - object: browse_record of the record on which the action is triggered if there is one, otherwise None +# - pool: ORM model pool (i.e. self.pool) +# - time: Python time module +# - cr: database cursor +# - uid: current user id +# - context: current context # If you plan to return an action, assign: action = {...} """, } @@ -567,6 +590,7 @@ class actions_server(osv.osv): def merge_message(self, cr, uid, keystr, action, context=None): if context is None: context = {} + def merge(match): obj_pool = self.pool.get(action.model_id.model) id = context.get('active_id') @@ -602,15 +626,17 @@ class actions_server(osv.osv): user = self.pool.get('res.users').browse(cr, uid, uid) for action in self.browse(cr, uid, ids, context): obj = None + obj_pool = self.pool.get(action.model_id.model) if context.get('active_model') == action.model_id.model and context.get('active_id'): - obj_pool = self.pool.get(action.model_id.model) obj = obj_pool.browse(cr, uid, context['active_id'], context=context) cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval + 'self': obj_pool, 'object': obj, + 'obj': obj, + 'pool': self.pool, 'time': time, 'cr': cr, - 'pool': self.pool, + 'context': dict(context), # copy context to prevent side-effects of eval 'uid': uid, 'user': user } @@ -625,21 +651,9 @@ class actions_server(osv.osv): .read(cr, uid, action.action_id.id, context=context) if action.state=='code': - localdict = { - 'self': self.pool.get(action.model_id.model), - 'pool': self.pool, - 'context': dict(context), # copy context to prevent side-effects of eval - 'time': time, - 'ids': ids, - 'cr': cr, - 'uid': uid, - 'object':obj, - 'obj': obj, - 'user': user, - } - eval(action.code, localdict, mode="exec", nocopy=True) # nocopy allows to return 'action' - if 'action' in localdict: - return localdict['action'] + eval(action.code, cxt, mode="exec", nocopy=True) # nocopy allows to return 'action' + if 'action' in cxt: + return cxt['action'] if action.state == 'email': email_from = config['email_from'] @@ -652,7 +666,7 @@ class actions_server(osv.osv): if not address: logger.info('No partner email address specified, not sending any email.') continue - + if not email_from: logger.debug('--email-from command line option is not specified, using a fallback value instead.') if user.user_email: @@ -663,7 +677,10 @@ class actions_server(osv.osv): subject = self.merge_message(cr, uid, action.subject, action, context) body = self.merge_message(cr, uid, action.message, action, context) - if tools.email_send(email_from, [address], subject, body, debug=False, subtype='html') == True: + ir_mail_server = self.pool.get('ir.mail_server') + msg = ir_mail_server.build_email(email_from, [address], subject, body) + res_email = ir_mail_server.send_email(cr, uid, msg) + if res_email: logger.info('Email successfully sent to: %s', address) else: logger.warning('Failed to send email to: %s', address) @@ -671,10 +688,10 @@ class actions_server(osv.osv): if action.state == 'trigger': wf_service = netsvc.LocalService("workflow") model = action.wkf_model_id.model - obj_pool = self.pool.get(action.model_id.model) - res_id = self.pool.get(action.model_id.model).read(cr, uid, [context.get('active_id')], [action.trigger_obj_id.name]) - id = res_id [0][action.trigger_obj_id.name] - wf_service.trg_validate(uid, model, int(id), action.trigger_name, cr) + m2o_field_name = action.trigger_obj_id.name + target_id = obj_pool.read(cr, uid, context.get('active_id'), [m2o_field_name])[m2o_field_name] + target_id = target_id[0] if isinstance(target_id,tuple) else target_id + wf_service.trg_validate(uid, model, int(target_id), action.trigger_name, cr) if action.state == 'sms': #TODO: set the user and password from the system @@ -689,20 +706,9 @@ class actions_server(osv.osv): result = self.run(cr, uid, [act.id], context) if result: res.append(result) - return res if action.state == 'loop': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - 'cr': cr, - 'pool' : self.pool, - 'uid' : uid - } expr = eval(str(action.expression), cxt) context['object'] = obj for i in expr: @@ -714,13 +720,6 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - cxt = { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - } expr = eval(euq, cxt) else: expr = exp.value @@ -754,14 +753,7 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - expr = eval(euq, - { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - }) + expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr @@ -778,21 +770,11 @@ class actions_server(osv.osv): for exp in action.fields_lines: euq = exp.value if exp.type == 'equation': - obj_pool = self.pool.get(action.model_id.model) - obj = obj_pool.browse(cr, uid, context['active_id'], context=context) - expr = eval(euq, - { - 'context': dict(context), # copy context to prevent side-effects of eval - 'object': obj, - 'time': time, - }) + expr = eval(euq, cxt) else: expr = exp.value res[exp.col1.name] = expr - obj_pool = None - res_id = False - model = action.copy_object.split(',')[0] cid = action.copy_object.split(',')[1] obj_pool = self.pool.get(model) diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py index 95a4cd8cab01f71f2edec155d50e68de5c77ca62..0612c1861d88e980f45ad3a4caea0361b7ae062d 100644 --- a/openerp/addons/base/ir/ir_attachment.py +++ b/openerp/addons/base/ir/ir_attachment.py @@ -50,8 +50,7 @@ class ir_attachment(osv.osv): for model, mids in res_ids.items(): # ignore attachments that are not attached to a resource anymore when checking access rights # (resource was deleted but attachment was not) - cr.execute('select id from '+self.pool.get(model)._table+' where id in %s', (tuple(mids),)) - mids = [x[0] for x in cr.fetchall()] + mids = self.pool.get(model).exists(cr, uid, mids) ima.check(cr, uid, model, mode) self.pool.get(model).check_access_rule(cr, uid, mids, mode, context=context) diff --git a/openerp/addons/base/ir/ir_config_parameter.py b/openerp/addons/base/ir/ir_config_parameter.py index f8c0348e8f6d07090f4332722c733b8832bc5e17..981dfd2798e83f02d5e51ff8a4b29746ce0f2f22 100644 --- a/openerp/addons/base/ir/ir_config_parameter.py +++ b/openerp/addons/base/ir/ir_config_parameter.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). +# Copyright (C) 2011 OpenERP SA (<http://www.openerp.com>). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,7 +19,7 @@ # ############################################################################## """ -A module to store some configuration parameters relative to a whole database. +Store database-specific configuration parameters """ from osv import osv,fields @@ -36,23 +36,19 @@ _default_parameters = { } class ir_config_parameter(osv.osv): - """ An osv to old configuration parameters for a given database. - - To be short, it's just a global dictionary of strings stored in a table. """ - + """Per-database storage of configuration key-value pairs.""" + _name = 'ir.config_parameter' - + _columns = { - # The key of the configuration parameter. 'key': fields.char('Key', size=256, required=True, select=1), - # The value of the configuration parameter. 'value': fields.text('Value', required=True), } - + _sql_constraints = [ ('key_uniq', 'unique (key)', 'Key must be unique.') ] - + def init(self, cr): """ Initializes the parameters listed in _default_parameters. @@ -63,12 +59,12 @@ class ir_config_parameter(osv.osv): self.set_param(cr, 1, key, func()) def get_param(self, cr, uid, key, default=False, context=None): - """ Get the value of a parameter. - - @param key: The key of the parameter. - @type key: string - @return: The value of the parameter, False if it does not exist. - @rtype: string + """Retrieve the value for a given key. + + :param string key: The key of the parameter value to retrieve. + :param string default: default value if parameter is missing. + :return: The value of the parameter, or ``default`` if it does not exist. + :rtype: string """ ids = self.search(cr, uid, [('key','=',key)], context=context) if not ids: @@ -78,15 +74,13 @@ class ir_config_parameter(osv.osv): return value def set_param(self, cr, uid, key, value, context=None): - """ Set the value of a parameter. + """Sets the value of a parameter. - @param key: The key of the parameter. - @type key: string - @param value: The value of the parameter. - @type value: string - @return: Return the previous value of the parameter of False if it did - not existed. - @rtype: string + :param string key: The key of the parameter value to set. + :param string value: The value to set. + :return: the previous value of the parameter or False if it did + not exist. + :rtype: string """ ids = self.search(cr, uid, [('key','=',key)], context=context) if ids: @@ -97,5 +91,3 @@ class ir_config_parameter(osv.osv): else: self.create(cr, uid, {'key': key, 'value': value}, context=context) return False - -ir_config_parameter() diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py new file mode 100644 index 0000000000000000000000000000000000000000..96fa9f52a8820757394f2aa95531c8b19315b4d0 --- /dev/null +++ b/openerp/addons/base/ir/ir_mail_server.py @@ -0,0 +1,436 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2011 OpenERP S.A (<http://www.openerp.com>) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/> +# +############################################################################## + +from email.MIMEText import MIMEText +from email.MIMEBase import MIMEBase +from email.MIMEMultipart import MIMEMultipart +from email.Header import Header +from email.Utils import formatdate, make_msgid, COMMASPACE +from email import Encoders +import logging +import re +import smtplib + +from osv import osv +from osv import fields +from openerp.tools.translate import _ +from openerp.tools import html2text +from openerp.tools.func import wraps +import openerp.tools as tools + +# ustr was originally from tools.misc. +# it is moved to loglevels until we refactor tools. +from openerp.loglevels import ustr + +_logger = logging.getLogger('ir.mail_server') + +class MailDeliveryException(osv.except_osv): + """Specific exception subclass for mail delivery errors""" + def __init__(self, name, value, exc_type='warning'): + super(MailDeliveryException, self).__init__(name, value, exc_type=exc_type) + +class WriteToLogger(object): + """debugging helper: behave as a fd and pipe to logger at the given level""" + def __init__(self, logger, level=logging.DEBUG): + self.logger = logger + self.level = level + + def write(self, s): + self.logger.log(self.level, s) + + +def try_coerce_ascii(string_utf8): + """Attempts to decode the given utf8-encoded string + as ASCII after coercing it to UTF-8, then return + the confirmed 7-bit ASCII string. + + If the process fails (because the string + contains non-ASCII characters) returns ``None``. + """ + try: + string_utf8.decode('ascii') + except UnicodeDecodeError: + return + return string_utf8 + +def encode_header(header_text): + """Returns an appropriate representation of the given header value, + suitable for direct assignment as a header value in an + email.message.Message. RFC2822 assumes that headers contain + only 7-bit characters, so we ensure it is the case, using + RFC2047 encoding when needed. + + :param header_text: unicode or utf-8 encoded string with header value + :rtype: string | email.header.Header + :return: if ``header_text`` represents a plain ASCII string, + return the same 7-bit string, otherwise returns an email.header.Header + that will perform the appropriate RFC2047 encoding of + non-ASCII values. + """ + if not header_text: return "" + # convert anything to utf-8, suitable for testing ASCIIness, as 7-bit chars are + # encoded as ASCII in utf-8 + header_text_utf8 = tools.ustr(header_text).encode('utf-8') + header_text_ascii = try_coerce_ascii(header_text_utf8) + # if this header contains non-ASCII characters, + # we'll need to wrap it up in a message.header.Header + # that will take care of RFC2047-encoding it as + # 7-bit string. + return header_text_ascii if header_text_ascii\ + else Header(header_text_utf8, 'utf-8') + +name_with_email_pattern = re.compile(r'("[^<@>]+")\s*<([^ ,<@]+@[^> ,]+)>') +address_pattern = re.compile(r'([^ ,<@]+@[^> ,]+)') + +def extract_rfc2822_addresses(text): + """Returns a list of valid RFC2822 addresses + that can be found in ``source``, ignoring + malformed ones and non-ASCII ones. + """ + if not text: return [] + candidates = address_pattern.findall(tools.ustr(text).encode('utf-8')) + return filter(try_coerce_ascii, candidates) + +def encode_rfc2822_address_header(header_text): + """If ``header_text`` contains non-ASCII characters, + attempts to locate patterns of the form + ``"Name" <address@domain>`` and replace the + ``"Name"`` portion by the RFC2047-encoded + version, preserving the address part untouched. + """ + header_text_utf8 = tools.ustr(header_text).encode('utf-8') + header_text_ascii = try_coerce_ascii(header_text_utf8) + if header_text_ascii: + return header_text_ascii + # non-ASCII characters are present, attempt to + # replace all "Name" patterns with the RFC2047- + # encoded version + def replace(match_obj): + name, email = match_obj.group(1), match_obj.group(2) + name_encoded = str(Header(name, 'utf-8')) + return "%s <%s>" % (name_encoded, email) + header_text_utf8 = name_with_email_pattern.sub(replace, + header_text_utf8) + # try again after encoding + header_text_ascii = try_coerce_ascii(header_text_utf8) + if header_text_ascii: + return header_text_ascii + # fallback to extracting pure addresses only, which could + # still cause a failure downstream if the actual addresses + # contain non-ASCII characters + return COMMASPACE.join(extract_rfc2822_addresses(header_text_utf8)) + + +class ir_mail_server(osv.osv): + """Represents an SMTP server, able to send outgoing e-mails, with SSL and TLS capabilities.""" + _name = "ir.mail_server" + + _columns = { + 'name': fields.char('Description', size=64, required=True, select=True), + 'smtp_host': fields.char('Server Name', size=128, required=True, help="Hostname or IP of SMTP server"), + 'smtp_port': fields.integer('SMTP Port', size=5, required=True, help="SMTP Port. Usually 465 for SSL, and 25 or 587 for other cases."), + 'smtp_user': fields.char('Username', size=64, help="Optional username for SMTP authentication"), + 'smtp_pass': fields.char('Password', size=64, help="Optional password for SMTP authentication"), + 'smtp_encryption': fields.selection([('none','None'), + ('starttls','TLS (STARTTLS)'), + ('ssl','SSL/TLS')], + string='Connection Security', + help="Choose the connection encryption scheme:\n" + "- None: SMTP sessions are done in cleartext.\n" + "- TLS (STARTTLS): TLS encryption is requested at start of SMTP session (Recommended)\n" + "- SSL/TLS: SMTP sessions are encrypted with SSL/TLS through a dedicated port (default: 465)"), + 'smtp_debug': fields.boolean('Debugging', help="If enabled, the full output of SMTP sessions will " + "be written to the server log at DEBUG level" + "(this is very verbose and may include confidential info!)"), + 'sequence': fields.integer('Priority', help="When no specific mail server is requested for a mail, the highest priority one " + "is used. Default priority is 10 (smaller number = higher priority)"), + } + + _defaults = { + 'smtp_port': 25, + 'sequence': 10, + 'smtp_encryption': 'none', + } + + def __init__(self, *args, **kwargs): + # Make sure we pipe the smtplib outputs to our own DEBUG logger + if not isinstance(smtplib.stderr, WriteToLogger): + logpiper = WriteToLogger(_logger) + smtplib.stderr = logpiper + smtplib.stdout = logpiper + return super(ir_mail_server, self).__init__(*args,**kwargs) + + def name_get(self, cr, uid, ids, context=None): + return [(a["id"], "(%s)" % (a['name'])) for a in self.read(cr, uid, ids, ['name'], context=context)] + + def test_smtp_connection(self, cr, uid, ids, context=None): + for smtp_server in self.browse(cr, uid, ids, context=context): + smtp = False + try: + smtp = self.connect(smtp_server.smtp_host, smtp_server.smtp_port, user=smtp_server.smtp_user, + password=smtp_server.smtp_pass, encryption=smtp_server.smtp_encryption, + smtp_debug=smtp_server.smtp_debug) + except Exception, e: + raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e)) + finally: + try: + if smtp: smtp.quit() + except Exception: + # ignored, just a consequence of the previous exception + pass + raise osv.except_osv(_("Connection test succeeded!"), _("Everything seems properly set up!")) + + def connect(self, host, port, user=None, password=None, encryption=False, smtp_debug=False): + """Returns a new SMTP connection to the give SMTP server, authenticated + with ``user`` and ``password`` if provided, and encrypted as requested + by the ``encryption`` parameter. + + :param host: host or IP of SMTP server to connect to + :param int port: SMTP port to connect to + :param user: optional username to authenticate with + :param password: optional password to authenticate with + :param string encryption: optional: ``'ssl'`` | ``'starttls'`` + :param bool smtp_debug: toggle debugging of SMTP sessions (all i/o + will be output in logs) + """ + if encryption == 'ssl': + if not 'SMTP_SSL' in smtplib.__all__: + raise osv.except_osv( + _("SMTP-over-SSL mode unavailable"), + _("Your OpenERP Server does not support SMTP-over-SSL. You could use STARTTLS instead." + "If SSL is needed, an upgrade to Python 2.6 on the server-side should do the trick.")) + connection = smtplib.SMTP_SSL(host, port) + else: + connection = smtplib.SMTP(host, port) + connection.set_debuglevel(smtp_debug) + if encryption == 'starttls': + # starttls() will perform ehlo() if needed first + # and will discard the previous list of services + # after successfully performing STARTTLS command, + # (as per RFC 3207) so for example any AUTH + # capability that appears only on encrypted channels + # will be correctly detected for next step + connection.starttls() + + if user: + # Attempt authentication - will raise if AUTH service not supported + connection.login(user, password) + return connection + + def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, + attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None): + """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it. + + :param string email_from: sender email address + :param list email_to: list of recipient addresses (to be joined with commas) + :param string subject: email subject (no pre-encoding/quoting necessary) + :param string body: email body, according to the ``subtype`` (by default, plaintext). + If html subtype is used, the message will be automatically converted + to plaintext and wrapped in multipart/alternative. + :param string reply_to: optional value of Reply-To header + :param string object_id: optional tracking identifier, to be included in the message-id for + recognizing replies. Suggested format for object-id is "res_id-model", + e.g. "12345-crm.lead". + :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'), + must match the format of the ``body`` parameter. Default is 'plain', + making the content part of the mail "text/plain". + :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string + containing the bytes of the attachment + :param list email_cc: optional list of string values for CC header (to be joined with commas) + :param list email_bcc: optional list of string values for BCC header (to be joined with commas) + :param dict headers: optional map of headers to set on the outgoing mail (may override the + other headers, including Subject, Reply-To, Message-Id, etc.) + :rtype: email.message.Message (usually MIMEMultipart) + :return: the new RFC2822 email message + """ + email_from = email_from or tools.config.get('email_from') + assert email_from, "You must either provide a sender address explicitly or configure "\ + "a global sender address in the server configuration or with the "\ + "--email-from startup parameter." + + # Note: we must force all strings to to 8-bit utf-8 when crafting message, + # or use encode_header() for headers, which does it automatically. + + headers = headers or {} # need valid dict later + + if not email_cc: email_cc = [] + if not email_bcc: email_bcc = [] + if not body: body = u'' + + email_body_utf8 = ustr(body).encode('utf-8') + email_text_part = MIMEText(email_body_utf8 or '', _subtype=subtype, _charset='utf-8') + msg = MIMEMultipart() + + if not message_id: + if object_id: + message_id = tools.generate_tracking_message_id(object_id) + else: + message_id = make_msgid() + msg['Message-Id'] = encode_header(message_id) + if references: + msg['references'] = encode_header(references) + msg['Subject'] = encode_header(subject) + msg['From'] = encode_rfc2822_address_header(email_from) + del msg['Reply-To'] + if reply_to: + msg['Reply-To'] = encode_rfc2822_address_header(reply_to) + else: + msg['Reply-To'] = msg['From'] + msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to)) + if email_cc: + msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc)) + if email_bcc: + msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc)) + msg['Date'] = formatdate(localtime=True) + # Custom headers may override normal headers or provide additional ones + for key, value in headers.iteritems(): + msg[ustr(key).encode('utf-8')] = encode_header(value) + + if html2text and subtype == 'html': + # Always provide alternative text body if possible. + text_utf8 = tools.html2text(email_body_utf8.decode('utf-8')).encode('utf-8') + alternative_part = MIMEMultipart(_subtype="alternative") + alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='plain')) + alternative_part.attach(email_text_part) + msg.attach(alternative_part) + else: + msg.attach(email_text_part) + + if attachments: + for (fname, fcontent) in attachments: + filename_utf8 = ustr(fname).encode('utf-8') + part = MIMEBase('application', "octet-stream") + part.set_payload(fcontent) + Encoders.encode_base64(part) + # Force RFC2231 encoding for attachment filename + # See email.message.Message.add_header doc + part.add_header('Content-Disposition', 'attachment', + filename=('utf-8',None,filename_utf8)) + msg.attach(part) + return msg + + def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, + smtp_user=None, smtp_password=None, smtp_encryption='none', smtp_debug=False, + context=None): + """Sends an email directly (no queuing). + + No retries are done, the caller should handle MailDeliveryException in order to ensure that + the mail is never lost. + + If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. + If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). + If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. + If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, + and fails if not found. + + :param message: the email.message.Message to send. The envelope sender will be extracted from the + ``Return-Path`` or ``From`` headers. The envelope recipients will be + extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. + :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. + :param smtp_server: optional hostname of SMTP server to use + :param smtp_encryption: one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) + :param smtp_port: optional SMTP port, if mail_server_id is not passed + :param smtp_user: optional SMTP user, if mail_server_id is not passed + :param smtp_password: optional SMTP password to use, if mail_server_id is not passed + :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed + :param debug: whether to turn on the SMTP level debugging, output to DEBUG log level + :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises + MailDeliveryException and logs root cause. + """ + smtp_from = message['Return-Path'] or message['From'] + assert smtp_from, "The Return-Path or From header is required for any outbound e-mail" + + # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. + from_rfc2822 = extract_rfc2822_addresses(smtp_from) + assert len(from_rfc2822) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" + smtp_from = from_rfc2822[0] + email_to = message['To'] + email_cc = message['Cc'] + email_bcc = message['Bcc'] + smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) + assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" + + # Get SMTP Server Details from Mail Server + mail_server = None + if mail_server_id: + mail_server = self.browse(cr, uid, mail_server_id) + elif not smtp_server: + mail_server_ids = self.search(cr, uid, [], order='sequence', limit=1) + if mail_server_ids: + mail_server = self.browse(cr, uid, mail_server_ids[0]) + else: + # we were passed an explicit smtp_server or nothing at all + smtp_server = smtp_server or tools.config.get('smtp_server') + smtp_port = tools.config.get('smtp_port', 25) if smtp_port is None else smtp_port + smtp_user = smtp_user or tools.config.get('smtp_user') + smtp_password = smtp_password or tools.config.get('smtp_password') + + if mail_server: + smtp_server = mail_server.smtp_host + smtp_user = mail_server.smtp_user + smtp_password = mail_server.smtp_pass + smtp_port = mail_server.smtp_port + smtp_encryption = mail_server.smtp_encryption + smtp_debug = smtp_debug or mail_server.smtp_debug + + if not smtp_server: + raise osv.except_osv( + _("Missing SMTP Server"), + _("Please define at least one SMTP server, or provide the SMTP parameters explicitly.")) + + try: + message_id = message['Message-Id'] + + # Add email in Maildir if smtp_server contains maildir. + if smtp_server.startswith('maildir:/'): + from mailbox import Maildir + maildir_path = smtp_server[8:] + mdir = Maildir(maildir_path, factory=None, create = True) + mdir.add(message.as_string(True)) + return message_id + + try: + smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption, smtp_debug) + smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) + finally: + try: + # Close Connection of SMTP Server + smtp.quit() + except Exception: + # ignored, just a consequence of the previous exception + pass + except Exception, e: + msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % (smtp_server, e.__class__.__name__, e) + _logger.exception(msg) + raise MailDeliveryException(_("Mail delivery failed"), msg) + return message_id + + def on_change_encryption(self, cr, uid, ids, smtp_encryption): + if smtp_encryption == 'ssl': + result = {'value': {'smtp_port': 465}} + if not 'SMTP_SSL' in smtplib.__all__: + result['warning'] = {'title': _('Warning'), + 'message': _('Your server does not seem to support SSL, you may want to try STARTTLS instead')} + else: + result = {'value': {'smtp_port': 25}} + return result + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py index 1ae54af0cb9cdfdcd661037faf54dae28a113005..2e273f53b69c5ec806fee749d6773bbd846b6e09 100644 --- a/openerp/addons/base/ir/ir_model.py +++ b/openerp/addons/base/ir/ir_model.py @@ -56,7 +56,7 @@ def _in_modules(self, cr, uid, ids, field_name, arg, context=None): class ir_model(osv.osv): _name = 'ir.model' - _description = "Objects" + _description = "Models" _order = 'model' def _is_osv_memory(self, cr, uid, ids, field_name, arg, context=None): @@ -85,8 +85,8 @@ class ir_model(osv.osv): return res _columns = { - 'name': fields.char('Object Name', size=64, translate=True, required=True), - 'model': fields.char('Object', size=64, required=True, select=1), + 'name': fields.char('Model Description', size=64, translate=True, required=True), + 'model': fields.char('Model', size=64, required=True, select=1), 'info': fields.text('Information'), 'field_id': fields.one2many('ir.model.fields', 'model_id', 'Fields', required=True), 'state': fields.selection([('manual','Custom Object'),('base','Base Object')],'Type',readonly=True), @@ -97,12 +97,12 @@ class ir_model(osv.osv): 'modules': fields.function(_in_modules, method=True, type='char', size=128, string='In modules', help='List of modules in which the object is defined or inherited'), 'view_ids': fields.function(_view_ids, method=True, type='one2many', obj='ir.ui.view', string='Views'), } - + _defaults = { 'model': lambda *a: 'x_', 'state': lambda self,cr,uid,ctx=None: (ctx and ctx.get('manual',False)) and 'manual' or 'base', } - + def _check_model_name(self, cr, uid, ids, context=None): for model in self.browse(cr, uid, ids, context=context): if model.state=='manual': @@ -114,9 +114,13 @@ class ir_model(osv.osv): def _model_name_msg(self, cr, uid, ids, context=None): return _('The Object name must start with x_ and not contain any special character !') + _constraints = [ (_check_model_name, _model_name_msg, ['model']), ] + _sql_constraints = [ + ('obj_name_uniq', 'unique (model)', 'Each model must be unique!'), + ] # overridden to allow searching both on model name (model field) # and model description (name field) @@ -616,7 +620,7 @@ class ir_model_data(osv.osv): """Returns the id of the ir.model.data record corresponding to a given module and xml_id (cached) or raise a ValueError if not found""" ids = self.search(cr, uid, [('module','=',module), ('name','=', xml_id)]) if not ids: - raise ValueError('No references to %s.%s' % (module, xml_id)) + raise ValueError('No such external ID currently defined in the system: %s.%s' % (module, xml_id)) # the sql constraints ensure us we have only one result return ids[0] @@ -626,7 +630,7 @@ class ir_model_data(osv.osv): data_id = self._get_id(cr, uid, module, xml_id) res = self.read(cr, uid, data_id, ['model', 'res_id']) if not res['res_id']: - raise ValueError('No references to %s.%s' % (module, xml_id)) + raise ValueError('No such external ID currently defined in the system: %s.%s' % (module, xml_id)) return (res['model'], res['res_id']) def get_object(self, cr, uid, module, xml_id, context=None): diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index ab9de808cece2e29d0646030cb369ee11707d587..44f5d24823dee1e198e35726311ea2acf86d9102 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -108,8 +108,8 @@ class ir_translation(osv.osv): 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, uid, name, tt, lang, ids) cr.execute('delete from ir_translation ' \ 'where lang=%s ' \ diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index 90990834c9bae0c7811ebb806568a903e9fde196..c44ff7165190797686486dd6c68fd0b95ddac675 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -96,6 +96,19 @@ class view(osv.osv): if not cr.fetchone(): cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, type, inherit_id)') + def get_inheriting_views_arch(self, cr, uid, view_id, model, context=None): + """Retrieves the architecture of views that inherit from the given view. + + :param int view_id: id of the view whose inheriting views should be retrieved + :param str model: model identifier of the view's related model (for double-checking) + :rtype: list of tuples + :return: [(view_arch,view_id), ...] + """ + cr.execute("""SELECT arch, id FROM ir_ui_view WHERE inherit_id=%s AND model=%s + ORDER BY priority""", + (view_id, model)) + return cr.fetchall() + def write(self, cr, uid, ids, vals, context={}): if not isinstance(ids, (list, tuple)): ids = [ids] @@ -159,10 +172,10 @@ class view(osv.osv): label_string = "" if label: for lbl in eval(label): - if t.has_key(str(lbl)) and str(t[lbl])=='False': + if t.has_key(tools.ustr(lbl)) and tools.ustr(t[lbl])=='False': label_string = label_string + ' ' else: - label_string = label_string + " " + t[lbl] + label_string = label_string + " " + tools.ustr(t[lbl]) labels[str(t['id'])] = (a['id'],label_string) g = graph(nodes, transitions, no_ancester) g.process(start) diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index c2a59ada55eb236ccaf94f60ad6f21aa10b0a832..f079e5764c929f83370cf32168b464bb1f72390f 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -79,7 +79,10 @@ class ir_values(osv.osv): method=True, type='text', string='Value'), 'object': fields.boolean('Is Object'), 'key': fields.selection([('action','Action'),('default','Default')], 'Type', size=128, select=True), - 'key2' : fields.char('Event Type',help="The kind of action or button in the client side that will trigger the action.", size=128, select=True), + 'key2' : fields.char('Event Type', size=128, select=True, help="The kind of action or button on the client side " + "that will trigger the action. One of: " + "client_action_multi, client_action_relate, tree_but_open, " + "client_print_multi"), 'meta': fields.text('Meta Datas'), 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, method=True, type='text', string='Metadata'), diff --git a/openerp/addons/base/ir/wizard/__init__.py b/openerp/addons/base/ir/wizard/__init__.py index 99c6cdcd0de669a557889954a9e575b73333d9be..3f5495524f5244e84f370e54c77f15731128a994 100644 --- a/openerp/addons/base/ir/wizard/__init__.py +++ b/openerp/addons/base/ir/wizard/__init__.py @@ -20,6 +20,5 @@ ############################################################################## import wizard_menu import wizard_screen -import create_action # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/ir/wizard/create_action.py b/openerp/addons/base/ir/wizard/create_action.py deleted file mode 100644 index 335f7a5ce04a22cb48e5d3fc4d176743cb06e6c8..0000000000000000000000000000000000000000 --- a/openerp/addons/base/ir/wizard/create_action.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - ############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -# -############################################################################## - -import wizard -import pooler -import time - -action_type = '''<?xml version="1.0"?> -<form string="Select Action Type"> - <field name="type"/> -</form>''' - -action_type_fields = { - 'type': {'string':"Select Action Type",'type':'selection','required':True ,'selection':[('ir.actions.report.xml','Open Report')]}, -} - -report_action = '''<?xml version="1.0"?> -<form string="Select Report"> - <field name="report" colspan="4"/> -</form>''' - -report_action_fields = { - 'report': {'string':"Select Report",'type':'many2one','relation':'ir.actions.report.xml', 'required':True}, -} - -class create_action(wizard.interface): - - def _create_report_action(self, cr, uid, data, context={}): - pool = pooler.get_pool(cr.dbname) - - reports = pool.get('ir.actions.report.xml') - form = data['form'] - - rpt = reports.browse(cr, uid, form['report']) - - action = """action = {"type": "ir.actions.report.xml","model":"%s","report_name": "%s","ids": context["active_ids"]}""" % (rpt.model, rpt.report_name) - - obj = pool.get('ir.actions.server') - obj.write(cr, uid, data['ids'], {'code':action}) - - return {} - - states = { - 'init': { - 'actions': [], - 'result': {'type':'form', 'arch':action_type,'fields':action_type_fields, 'state':[('step_1','Next'),('end','Close')]} - }, - 'step_1': { - 'actions': [], - 'result': {'type':'form', 'arch':report_action,'fields':report_action_fields, 'state':[('create','Create'),('end','Close')]} - }, - 'create': { - 'actions': [_create_report_action], - 'result': {'type':'state', 'state':'end'} - }, - } -create_action('server.action.create') - - diff --git a/openerp/addons/base/ir/wizard/wizard_menu_view.xml b/openerp/addons/base/ir/wizard/wizard_menu_view.xml index 4d3e7e7a26eb9c073ef44dd525b2e050928766ed..d99138d00e6b763f7d49ed10c32c303908aa0b6b 100644 --- a/openerp/addons/base/ir/wizard/wizard_menu_view.xml +++ b/openerp/addons/base/ir/wizard/wizard_menu_view.xml @@ -21,12 +21,5 @@ </field> </record> <act_window context="{'model_id': active_id}" id="act_menu_create" name="Create Menu" res_model="wizard.ir.model.menu.create" target="new" view_mode="form"/> - <wizard - id="wizard_server_action_create" - model="ir.actions.server" - name="server.action.create" - string="Create Action" - menu="False" - /> </data> </openerp> diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index 034829b82b5780016be805d5efc29b412335984b..a35e4b5d1ceeeb71caf469c503fc58f5255cb70e 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -107,48 +107,59 @@ class module(osv.osv): view_obj = self.pool.get('ir.ui.view') report_obj = self.pool.get('ir.actions.report.xml') menu_obj = self.pool.get('ir.ui.menu') - mlist = self.browse(cr, uid, ids, context=context) - mnames = {} - for m in mlist: - # skip uninstalled modules below, - # no data to find anyway - if m.state in ('installed', 'to upgrade', 'to remove'): - mnames[m.name] = m.id - res[m.id] = { - 'menus_by_module':[], - 'reports_by_module':[], + + dmodels = [] + if field_name is None or 'views_by_module' in field_name: + dmodels.append('ir.ui.view') + if field_name is None or 'reports_by_module' in field_name: + dmodels.append('ir.actions.report.xml') + if field_name is None or 'menus_by_module' in field_name: + dmodels.append('ir.ui.menu') + assert dmodels, "no models for %s" % field_name + + for module_rec in self.browse(cr, uid, ids, context=context): + res[module_rec.id] = { + 'menus_by_module': [], + 'reports_by_module': [], 'views_by_module': [] } - if not mnames: - return res + # Skip uninstalled modules below, no data to find anyway. + if module_rec.state not in ('installed', 'to upgrade', 'to remove'): + continue + + # then, search and group ir.model.data records + imd_models = dict( [(m,[]) for m in dmodels]) + imd_ids = model_data_obj.search(cr,uid,[('module','=', module_rec.name), + ('model','in',tuple(dmodels))]) - view_id = model_data_obj.search(cr,uid,[('module','in', mnames.keys()), - ('model','in',('ir.ui.view','ir.actions.report.xml','ir.ui.menu'))]) - for data_id in model_data_obj.browse(cr,uid,view_id,context): - # We use try except, because views or menus may not exist + for imd_res in model_data_obj.read(cr, uid, imd_ids, ['model', 'res_id'], context=context): + imd_models[imd_res['model']].append(imd_res['res_id']) + + # For each one of the models, get the names of these ids. + # We use try except, because views or menus may not exist. try: - key = data_id.model - res_mod_dic = res[mnames[data_id.module]] - if key=='ir.ui.view': - v = view_obj.browse(cr,uid,data_id.res_id) + res_mod_dic = res[module_rec.id] + for v in view_obj.browse(cr, uid, imd_models.get('ir.ui.view', []), context=context): aa = v.inherit_id and '* INHERIT ' or '' res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')') - elif key=='ir.actions.report.xml': - res_mod_dic['reports_by_module'].append(report_obj.browse(cr,uid,data_id.res_id).name) - elif key=='ir.ui.menu': - res_mod_dic['menus_by_module'].append(menu_obj.browse(cr,uid,data_id.res_id).complete_name) + + for rx in report_obj.browse(cr, uid, imd_models.get('ir.actions.report.xml', []), context=context): + res_mod_dic['reports_by_module'].append(rx.name) + + for um in menu_obj.browse(cr, uid, imd_models.get('ir.ui.menu', []), context=context): + res_mod_dic['menus_by_module'].append(um.complete_name) except KeyError, e: self.__logger.warning( - 'Data not found for reference %s[%s:%s.%s]', data_id.model, - data_id.res_id, data_id.model, data_id.name, exc_info=True) - pass + 'Data not found for items of %s', module_rec.name) + except AttributeError, e: + self.__logger.warning( + 'Data not found for items of %s %s', module_rec.name, str(e)) except Exception, e: - self.__logger.warning('Unknown error while browsing %s[%s]', - data_id.model, data_id.res_id, exc_info=True) - pass + self.__logger.warning('Unknown error while fetching data of %s', + module_rec.name, exc_info=True) for key, value in res.iteritems(): - for k, v in res[key].iteritems() : + for k, v in res[key].iteritems(): res[key][k] = "\n".join(sorted(v)) return res @@ -437,12 +448,11 @@ class module(osv.osv): res.append(mod.url) if not download: continue - zipfile = urllib.urlopen(mod.url).read() + zip_content = urllib.urlopen(mod.url).read() fname = addons.get_module_path(str(mod.name)+'.zip', downloaded=True) try: - fp = file(fname, 'wb') - fp.write(zipfile) - fp.close() + with open(fname, 'wb') as fp: + fp.write(zip_content) except Exception: self.__logger.exception('Error when trying to create module ' 'file %s', fname) diff --git a/openerp/addons/base/module/wizard/base_import_language.py b/openerp/addons/base/module/wizard/base_import_language.py index d73cd0864a6689494e527352ac6f32f406d32560..fdb9a177d8b2881ca48df6f011a4bb8ee598a1ea 100644 --- a/openerp/addons/base/module/wizard/base_import_language.py +++ b/openerp/addons/base/module/wizard/base_import_language.py @@ -35,9 +35,12 @@ class base_language_import(osv.osv_memory): 'name': fields.char('Language Name',size=64 , required=True), 'code': fields.char('Code (eg:en__US)',size=5 , required=True), 'data': fields.binary('File', required=True), + 'overwrite': fields.boolean('Overwrite Existing Terms', + help="If you enable this option, existing translations (including custom ones) " + "will be overwritten and replaced by those in this file"), } - def import_lang(self, cr, uid, ids, context): + def import_lang(self, cr, uid, ids, context=None): """ Import Language @param cr: the current row, from the database cursor. @@ -45,8 +48,11 @@ class base_language_import(osv.osv_memory): @param ids: the ID or list of IDs @param context: A standard dictionary """ - + if context is None: + context = {} import_data = self.browse(cr, uid, ids)[0] + if import_data.overwrite: + context.update(overwrite=True) fileobj = TemporaryFile('w+') fileobj.write(base64.decodestring(import_data.data)) @@ -56,7 +62,7 @@ class base_language_import(osv.osv_memory): fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po' fileobj.seek(0) - tools.trans_load_data(cr, fileobj, fileformat, import_data.code, lang_name=import_data.name) + tools.trans_load_data(cr, fileobj, fileformat, import_data.code, lang_name=import_data.name, context=context) tools.trans_update_res_ids(cr) fileobj.close() return {} diff --git a/openerp/addons/base/module/wizard/base_import_language_view.xml b/openerp/addons/base/module/wizard/base_import_language_view.xml index d313afc40808ec815ca56cc18c20c57cc2bda18e..4a1d7e5b7586e64d476fabb943200cd21ef34e48 100644 --- a/openerp/addons/base/module/wizard/base_import_language_view.xml +++ b/openerp/addons/base/module/wizard/base_import_language_view.xml @@ -27,6 +27,7 @@ <field name="name" width="200"/> <field name="code"/> <field name="data" colspan="4"/> + <field name="overwrite"/> </group> <group colspan="8" col="8"> <separator string="" colspan="8"/> diff --git a/openerp/addons/base/module/wizard/base_module_import.py b/openerp/addons/base/module/wizard/base_module_import.py index 05c3b18198d41eb7b03d5c4f4ff8b5d12f24b65b..3ef9132af0ef4822937f381b98918ce55d7979dd 100644 --- a/openerp/addons/base/module/wizard/base_module_import.py +++ b/openerp/addons/base/module/wizard/base_module_import.py @@ -28,6 +28,8 @@ import base64 from tools.translate import _ from osv import osv, fields +ADDONS_PATH = tools.config['addons_path'].split(",")[-1] + class base_module_import(osv.osv_memory): """ Import Module """ @@ -37,7 +39,8 @@ class base_module_import(osv.osv_memory): _columns = { 'module_file': fields.binary('Module .ZIP file', required=True), - 'state':fields.selection([('init','init'),('done','done')], 'state', readonly=True), + 'state':fields.selection([('init','init'),('done','done')], + 'state', readonly=True), 'module_name': fields.char('Module Name', size=128), } @@ -48,26 +51,30 @@ 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 - - val = base64.decodestring(module_data) + zip_data = base64.decodestring(module_data) fp = StringIO() - fp.write(val) - fdata = zipfile.ZipFile(fp, 'r') - fname = fdata.namelist()[0] - module_name = os.path.split(fname)[0] - - ad = tools.config['addons_path'].split(",")[-1] + 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] - fname = os.path.join(ad, module_name+'.zip') + file_path = os.path.join(ADDONS_PATH, '%s.zip' % module_name) try: - fp = file(fname, 'wb') - fp.write(val) - fp.close() + zip_file = open(file_path, 'wb') except IOError: - raise osv.except_osv(_('Error !'), _('Can not create the module file: %s !') % (fname,) ) + 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) + 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 def action_module_open(self, cr, uid, ids, context): @@ -84,4 +91,4 @@ class base_module_import(osv.osv_memory): base_module_import() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/module/wizard/base_module_import_view.xml b/openerp/addons/base/module/wizard/base_module_import_view.xml index 8e43789b057f29a315093bdb9041f7ca2db5345f..0ca3e14ea96c2cd761b4727e6dc0c7b9255c2292 100644 --- a/openerp/addons/base/module/wizard/base_module_import_view.xml +++ b/openerp/addons/base/module/wizard/base_module_import_view.xml @@ -12,9 +12,10 @@ <group colspan="3" col="1"> <field name="config_logo" widget="image" width="220" height="130" nolabel="1" colspan="1"/> <newline/> - <label width="220" string="This wizard helps you add a new language to you OpenERP system. After loading a new language it becomes available as default interface language for users and partners."/> + <label width="220" string='This wizard helps you to import a new module to your OpenERP system. +After importing a new module you can install it by clicking on the button "Install" from the form view.'/> <label width="220"/> - <label width="220" string="Please be patient, this operation may take a few minutes (depending on the number of modules currently installed)..."/> + <label width="220" string="Please be patient, this operation may take a few minutes..."/> <field name="state" invisible="1"/> </group> <separator orientation="vertical" rowspan="5"/> diff --git a/openerp/addons/base/res/__init__.py b/openerp/addons/base/res/__init__.py index 9ce69f0c317495e861a4e3da9b42c6e94bcd2445..2b4da739f54433521eb58cb62b6ef0bd23359b6b 100644 --- a/openerp/addons/base/res/__init__.py +++ b/openerp/addons/base/res/__init__.py @@ -29,10 +29,10 @@ import res_bank import res_config import res_currency import res_company -import res_user +import res_users import res_request -import res_lang -import res_log +import res_lang +import res_log import res_widget import ir_property diff --git a/openerp/addons/base/res/ir_property_view.xml b/openerp/addons/base/res/ir_property_view.xml index af836a3c92e5149a38f0f532aa626b36f37dfe7e..67b3357a4df1a9af470bafad5e31d97798b5ea33 100644 --- a/openerp/addons/base/res/ir_property_view.xml +++ b/openerp/addons/base/res/ir_property_view.xml @@ -13,6 +13,7 @@ help="Parameters that are used by all resources." domain="[('res_id','=',False)]"/> <separator orientation="vertical"/> + <field name="fields_id" /> <field name="name"/> <field name="company_id" groups="base.group_multi_company"/> </search> diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 3ad0cfcfb55337dad3411968290ea23c02b63e2b..dc07b55a78efe695ed75ea379174053d3c4e045e 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -143,6 +143,9 @@ class res_company(osv.osv): 'vat': fields.related('partner_id', 'vat', string="Tax ID", type="char", size=32), 'company_registry': fields.char('Company Registry', size=64), } + _sql_constraints = [ + ('name_uniq', 'unique (name)', 'The company name must be unique !') + ] def _search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False, access_rights_uid=None): diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py index 3b7e427a9234e218ac5c8b0a1de3f5af0e6bb341..bb6a51a6bcba9fbae5f65ebfeb3684f545b5615e 100644 --- a/openerp/addons/base/res/res_currency.py +++ b/openerp/addons/base/res/res_currency.py @@ -62,15 +62,34 @@ class res_currency(osv.osv): 'active': fields.boolean('Active'), 'company_id':fields.many2one('res.company', 'Company'), 'date': fields.date('Date'), - 'base': fields.boolean('Base') - + 'base': fields.boolean('Base'), + 'position': fields.selection([('after','After Amount'),('before','Before Amount')], 'Symbol position', help="Determines where the currency symbol should be placed after or before the amount.") } _defaults = { 'active': lambda *a: 1, - 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'res.currency', context=c) + 'position' : 'after', } + _sql_constraints = [ + # this constraint does not cover all cases due to SQL NULL handling for company_id, + # so it is complemented with a unique index (see below). The constraint and index + # share the same prefix so that IntegrityError triggered by the index will be caught + # and reported to the user with the constraint's error message. + ('unique_name_company_id', 'unique (name, company_id)', 'The currency code must be unique per company!'), + ] _order = "name" + def init(self, cr): + # CONSTRAINT/UNIQUE INDEX on (name,company_id) + # /!\ The unique constraint 'unique_name_company_id' is not sufficient, because SQL92 + # only support field names in constraint definitions, and we need a function here: + # we need to special-case company_id to treat all NULL company_id as equal, otherwise + # we would allow duplicate "global" currencies (all having company_id == NULL) + cr.execute("""SELECT indexname FROM pg_indexes WHERE indexname = 'res_currency_unique_name_company_id_idx'""") + if not cr.fetchone(): + cr.execute("""CREATE UNIQUE INDEX res_currency_unique_name_company_id_idx + ON res_currency + (name, (COALESCE(company_id,-1)))""") + def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): res = super(osv.osv, self).read(cr, user, ids, fields, context, load) currency_rate_obj = self.pool.get('res.currency.rate') @@ -150,7 +169,7 @@ res_currency() class res_currency_rate_type(osv.osv): _name = "res.currency.rate.type" - _description = "Used to define the type of Currency Rates" + _description = "Currency Rate Type" _columns = { 'name': fields.char('Name', size=64, required=True, translate=True), } diff --git a/openerp/addons/base/res/res_currency_view.xml b/openerp/addons/base/res/res_currency_view.xml index 8d747c882b1e4ae010914c3e357e8f4480de0d78..7dab4c051f4846bbe9e085b2017ebf7dd564ffa6 100644 --- a/openerp/addons/base/res/res_currency_view.xml +++ b/openerp/addons/base/res/res_currency_view.xml @@ -2,6 +2,18 @@ <openerp> <data> + <record id="view_currency_search" model="ir.ui.view"> + <field name="name">res.currency.search</field> + <field name="model">res.currency</field> + <field name="type">search</field> + <field name="arch" type="xml"> + <search string="Currencies"> + <field name="name"/> + <field name="active"/> + </search> + </field> + </record> + <record id="view_currency_tree" model="ir.ui.view"> <field name="name">res.currency.tree</field> <field name="model">res.currency</field> @@ -9,12 +21,13 @@ <field name="arch" type="xml"> <tree string="Currencies"> <field name="name"/> - <field name="company_id" select="2" /> + <field name="company_id" groups="base.group_multi_company"/> <field name="rate_ids" invisible="1"/> <field name="date"/> <field name="rate"/> <field name="rounding"/> <field name="accuracy"/> + <field name="position"/> <field name="active"/> </tree> </field> @@ -25,23 +38,30 @@ <field name="type">form</field> <field name="arch" type="xml"> <form string="Currency"> - <group col="6" colspan="6"> - <field name="name" select="1"/> + <group col="6" colspan="4"> + <field name="name"/> <field name="rate"/> - <field name="company_id" select="2" groups="base.group_multi_company" /> - <field name="symbol"/> + <field name="company_id" groups="base.group_multi_company"/> </group> - <group col="2" colspan="2"> - <separator string="Price Accuracy" colspan="2"/> - <field name="rounding"/> - <field name="accuracy"/> - </group> + <group col="6" colspan="4"> + <group col="2" colspan="2"> + <separator string="Price Accuracy" colspan="2"/> + <field name="rounding"/> + <field name="accuracy"/> + </group> + + <group col="2" colspan="2"> + <separator string="Display" colspan="2"/> + <field name="symbol"/> + <field name="position"/> + </group> - <group col="2" colspan="2"> - <separator string="Miscelleanous" colspan="2"/> - <field name="base"/> - <field name="active" select="1"/> + <group col="2" colspan="2"> + <separator string="Miscelleanous" colspan="2"/> + <field name="base"/> + <field name="active" select="1"/> + </group> </group> <field colspan="4" mode="tree,form" name="rate_ids" nolabel="1" attrs="{'readonly':[('base','=',True)]}"> @@ -62,6 +82,7 @@ <field name="res_model">res.currency</field> <field name="view_type">form</field> <field name="view_mode">tree,form</field> + <field name="search_view_id" ref="view_currency_search"/> </record> <menuitem action="action_currency_form" id="menu_action_currency_form" parent="menu_localisation" sequence="3"/> diff --git a/openerp/addons/base/res/res_lang.py b/openerp/addons/base/res/res_lang.py index f6743a540622f44bbb37a8590887663648e988e2..50841241f8a548a6fbef0422654774608197f38a 100644 --- a/openerp/addons/base/res/res_lang.py +++ b/openerp/addons/base/res/res_lang.py @@ -194,7 +194,7 @@ class lang(osv.osv): trans_obj.unlink(cr, uid, trans_ids, context=context) return super(lang, self).unlink(cr, uid, ids, context=context) - def format(self, cr, uid, ids, percent, value, grouping=False, monetary=False): + 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] != '%': diff --git a/openerp/addons/base/res/res_partner_demo.xml b/openerp/addons/base/res/res_partner_demo.xml index e8d8d540422220d175c5b6e499cefdc639e5c24c..d3c4db106f9ba2e8ec87d1241a6a93ed86f8e9a0 100644 --- a/openerp/addons/base/res/res_partner_demo.xml +++ b/openerp/addons/base/res/res_partner_demo.xml @@ -90,67 +90,88 @@ <record id="res_partner_asus" model="res.partner"> <field name="name">ASUStek</field> - <field name="user_id" ref="user_demo"/> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="supplier">1</field> + <field eval="0" name="customer"/> <field name="address" eval="[]"/> + <field name="website">www.asustek.com</field> </record> <record id="res_partner_agrolait" model="res.partner"> <field name="name">Agrolait</field> - <field eval="[(6, 0, [ref('res_partner_category_8')])]" name="category_id"/> + <field eval="[(6, 0, [ref('base.res_partner_category_0')])]" name="category_id"/> + <field name="user_id" ref="base.user_root"/> <field name="address" eval="[]"/> + <field name="website">www.agrolait.com</field> </record> <record id="res_partner_c2c" model="res.partner"> <field name="name">Camptocamp</field> <field eval="[(6, 0, [ref('res_partner_category_10'), ref('res_partner_category_5')])]" name="category_id"/> <field name="supplier">1</field> + <field name="user_id" ref="base.user_root"/> <field name="address" eval="[]"/> + <field name="website">www.camptocamp.com</field> </record> <record id="res_partner_sednacom" model="res.partner"> - <field name="website">http://www.syleam.fr</field> + <field name="website">www.syleam.fr</field> <field name="name">Syleam</field> <field eval="[(6, 0, [ref('res_partner_category_5')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> </record> <record id="res_partner_thymbra" model="res.partner"> <field name="name">Thymbra</field> + <field name="user_id" ref="base.user_root"/> <field eval="[(6, 0, [ref('res_partner_category_4')])]" name="category_id"/> + <field name="website">www.thymbra.com/</field> </record> <record id="res_partner_desertic_hispafuentes" model="res.partner"> <field name="name">Axelor</field> <field eval="[(6, 0, [ref('res_partner_category_4')])]" name="category_id"/> <field name="supplier">1</field> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> + <field name="website">www.axelor.com/</field> </record> <record id="res_partner_tinyatwork" model="res.partner"> <field name="name">Tiny AT Work</field> + <field name="user_id" ref="base.user_root"/> <field eval="[(6, 0, [ref('res_partner_category_5'), ref('res_partner_category_10')])]" name="category_id"/> + <field name="website">www.tinyatwork.com/</field> </record> <record id="res_partner_2" model="res.partner"> <field name="name">Bank Wealthy and sons</field> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> + <field name="website">www.wealthyandsons.com/</field> </record> <record id="res_partner_3" model="res.partner"> <field name="name">China Export</field> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> + <field name="website">www.chinaexport.com/</field> </record> <record id="res_partner_4" model="res.partner"> <field name="name">Distrib PC</field> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="supplier">1</field> + <field eval="0" name="customer"/> <field name="address" eval="[]"/> + <field name="website">www.distribpc.com/</field> </record> <record id="res_partner_5" model="res.partner"> <field name="name">Ecole de Commerce de Liege</field> <field eval="[(6, 0, [ref('res_partner_category_1')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> + <field name="website">www.eci-liege.info//</field> </record> <record id="res_partner_6" model="res.partner"> <field name="name">Elec Import</field> <field name="user_id" ref="user_demo"/> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="supplier">1</field> + <field eval="0" name="customer"/> <field name="address" eval="[]"/> </record> <record id="res_partner_maxtor" model="res.partner"> @@ -159,6 +180,7 @@ <field name="user_id" ref="user_demo"/> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="supplier">1</field> + <field eval="0" name="customer"/> <field name="address" eval="[]"/> </record> <record id="res_partner_seagate" model="res.partner"> @@ -177,11 +199,11 @@ <field name="address" eval="[]"/> </record> <record id="res_partner_9" model="res.partner"> - <field name="website">http://balmerinc.com</field> + <field name="website">www.balmerinc.com</field> <field name="name">BalmerInc S.A.</field> <field eval="12000.00" name="credit_limit"/> <field name="ref">or</field> - <field name="user_id" ref="user_demo"/> + <field name="user_id" ref="base.user_root"/> <field eval="[(6, 0, [ref('res_partner_category_1')])]" name="category_id"/> <field name="address" eval="[]"/> </record> @@ -190,6 +212,7 @@ <field name="ean13">3020170000003</field> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> </record> <record id="res_partner_11" model="res.partner"> <field name="name">Leclerc</field> @@ -205,6 +228,7 @@ <field name="parent_id" ref="res_partner_10"/> <field eval="[(6, 0, [ref('res_partner_category_11')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> </record> <record id="res_partner_15" model="res.partner"> <field name="name">Magazin BML 1</field> @@ -219,6 +243,8 @@ <field name="name">Université de Liège</field> <field eval="[(6, 0, [ref('res_partner_category_9')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> + <field name="website">http://www.ulg.ac.be/</field> </record> <!-- @@ -230,16 +256,19 @@ <field model="res.users" name="user_id" search="[('name', '=', u'Thomas Lebrun')]"/> <field name="name">Dubois sprl</field> <field name="address" eval="[]"/> + <field name="website">http://www.dubois.be/</field> </record> <record id="res_partner_ericdubois0" model="res.partner"> <field name="name">Eric Dubois</field> <field name="address" eval="[]"/> + <field name="user_id" ref="user_demo"/> </record> <record id="res_partner_fabiendupont0" model="res.partner"> <field name="name">Fabien Dupont</field> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> </record> <record id="res_partner_lucievonck0" model="res.partner"> @@ -250,32 +279,41 @@ <record id="res_partner_notsotinysarl0" model="res.partner"> <field name="name">NotSoTiny SARL</field> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> + <field name="website">notsotiny.be</field> </record> <record id="res_partner_theshelvehouse0" model="res.partner"> <field name="name">The Shelve House</field> <field eval="[(6,0,[ref('res_partner_category_retailers0')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> </record> <record id="res_partner_vickingdirect0" model="res.partner"> <field name="name">Vicking Direct</field> <field eval="[(6,0,[ref('res_partner_category_miscellaneoussuppliers0')])]" name="category_id"/> <field name="supplier">1</field> + <field name="customer">0</field> <field name="address" eval="[]"/> + <field name="website">vicking-direct.be</field> </record> <record id="res_partner_woodywoodpecker0" model="res.partner"> <field name="name">Wood y Wood Pecker</field> <field eval="[(6,0,[ref('res_partner_category_woodsuppliers0')])]" name="category_id"/> <field name="supplier">1</field> + <field eval="0" name="customer"/> <field name="address" eval="[]"/> + <field name="website">woodywoodpecker.com</field> </record> <record id="res_partner_zerooneinc0" model="res.partner"> <field name="name">ZeroOne Inc</field> <field eval="[(6,0,[ref('res_partner_category_consumers0')])]" name="category_id"/> <field name="address" eval="[]"/> + <field name="user_id" ref="base.user_root"/> + <field name="website">http://www.zerooneinc.com/</field> </record> <!-- @@ -312,6 +350,7 @@ <field name="email">info@axelor.com</field> <field name="phone">+33 1 64 61 04 01</field> <field name="street">12 rue Albert Einstein</field> + <field name="type">default</field> <field name="partner_id" ref="res_partner_desertic_hispafuentes"/> </record> <record id="res_partner_address_3" model="res.partner.address"> @@ -329,6 +368,8 @@ <field name="zip">23410</field> <field model="res.country" name="country_id" search="[('name','=','Taiwan')]"/> <field name="street">31 Hong Kong street</field> + <field name="email">info@asustek.com</field> + <field name="phone">+ 1 64 61 04 01</field> <field name="type">default</field> <field name="partner_id" ref="res_partner_asus"/> </record> @@ -338,6 +379,8 @@ <field name="zip">23540</field> <field model="res.country" name="country_id" search="[('name','=','China')]"/> <field name="street">56 Beijing street</field> + <field name="email">info@maxtor.com</field> + <field name="phone">+ 11 8528 456 789</field> <field name="type">default</field> <field name="partner_id" ref="res_partner_maxtor"/> </record> @@ -348,6 +391,8 @@ <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">23 rue du Vieux Bruges</field> <field name="type">default</field> + <field name="email">info@elecimport.com</field> + <field name="phone">+ 32 025 897 456</field> <field name="partner_id" ref="res_partner_6"/> </record> <record id="res_partner_address_7" model="res.partner.address"> @@ -357,6 +402,8 @@ <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">42 rue de la Lesse</field> <field name="type">default</field> + <field name="email">info@distribpc.com</field> + <field name="phone">+ 32 081256987</field> <field name="partner_id" ref="res_partner_4"/> </record> <record id="res_partner_address_8" model="res.partner.address"> @@ -366,7 +413,10 @@ <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">69 rue de Chimay</field> <field name="type">default</field> + <field name="email">s.l@agrolait.be</field> + <field name="phone">003281588558</field> <field name="partner_id" ref="res_partner_agrolait"/> + <field name="title" ref="base.res_partner_title_madam"/> </record> <record id="res_partner_address_8delivery" model="res.partner.address"> <field name="city">Wavre</field> @@ -375,7 +425,10 @@ <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">71 rue de Chimay</field> <field name="type">delivery</field> + <field name="email">p.l@agrolait.be</field> + <field name="phone">003281588557</field> <field name="partner_id" ref="res_partner_agrolait"/> + <field name="title" ref="base.res_partner_title_sir"/> </record> <record id="res_partner_address_8invoice" model="res.partner.address"> <field name="city">Wavre</field> @@ -384,7 +437,10 @@ <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">69 rue de Chimay</field> <field name="type">invoice</field> + <field name="email">serge.l@agrolait.be</field> + <field name="phone">003281588556</field> <field name="partner_id" ref="res_partner_agrolait"/> + <field name="title" ref="base.res_partner_title_sir"/> </record> <record id="res_partner_address_9" model="res.partner.address"> <field name="city">Paris</field> @@ -393,7 +449,10 @@ <field model="res.country" name="country_id" search="[('name','=','France')]"/> <field name="street">1 rue Rockfeller</field> <field name="type">default</field> + <field name="email">a.g@wealthyandsons.com</field> + <field name="phone">003368978776</field> <field name="partner_id" ref="res_partner_2"/> + <field name="title" ref="base.res_partner_title_sir"/> </record> <record id="res_partner_address_11" model="res.partner.address"> <field name="city">Alencon</field> @@ -412,48 +471,84 @@ <field name="zip">6985</field> <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> <field name="street">2 Impasse de la Soif</field> + <field name="email">k.lesbrouffe@eci-liege.info</field> + <field name="phone">+32 421 52571</field> <field name="type">default</field> <field name="partner_id" ref="res_partner_5"/> </record> <record id="res_partner_address_zen" model="res.partner.address"> <field name="city">Shanghai</field> <field name="name">Zen</field> - <field name="zip">4785552</field> + <field name="zip">478552</field> <field model="res.country" name="country_id" search="[('name','=','China')]"/> <field name="street">52 Chop Suey street</field> <field name="type">default</field> + <field name="email">zen@chinaexport.com</field> + <field name="phone">+86-751-64845671</field> <field name="partner_id" ref="res_partner_3"/> </record> <record id="res_partner_address_12" model="res.partner.address"> <field name="type">default</field> - <field name="name">Centrale</field> + <field name="city">Grenoble</field> + <field name="name">Loïc Dupont</field> + <field name="zip">38100</field> + <field model="res.country" name="country_id" search="[('name','=','China')]"/> + <field name="street">Rue Lavoisier 145</field> + <field name="type">default</field> + <field name="email">l.dupont@tecsas.fr</field> + <field name="phone">+33-658-256545</field> <field name="partner_id" ref="res_partner_10"/> </record> <record id="res_partner_address_13" model="res.partner.address"> <field name="type">default</field> - <field name="name">Centrale d'achats 1</field> + <field name="name">Carl François</field> + <field name="city">Bruxelles</field> + <field name="zip">1000</field> + <field model="res.country" name="country_id" search="[('name','=','Belgium')]"/> + <field name="street">89 Chaussée de Waterloo</field> + <field name="email">carl.françois@bml.be</field> + <field name="phone">+32-258-256545</field> <field name="partner_id" ref="res_partner_14"/> </record> <record id="res_partner_address_14" model="res.partner.address"> <field name="type">default</field> - <field name="name">Shop 1</field> + <field name="name">Lucien Ferguson</field> + <field name="street">89 Chaussée de Liège</field> + <field name="city">Namur</field> + <field name="zip">5000</field> + <field name="email">lucien.ferguson@bml.be</field> + <field name="phone">+32-621-568978</field> <field name="partner_id" ref="res_partner_15"/> </record> <record id="res_partner_address_15" model="res.partner.address"> <field name="type">default</field> - <field name="name">Shop 2</field> + <field name="name">Marine Leclerc</field> + <field name="street">rue Grande</field> + <field name="city">Brest</field> + <field name="zip">29200</field> + <field name="email">marine@leclerc.fr</field> + <field name="phone">+33-298.334558</field> <field name="partner_id" ref="res_partner_11"/> </record> <record id="res_partner_address_16" model="res.partner.address"> - <field name="type">default</field> - <field name="name">Shop 3</field> + <field name="type">invoice</field> + <field name="name">Claude Leclerc</field> + <field name="street">rue Grande</field> + <field name="city">Brest</field> + <field name="zip">29200</field> + <field name="email">claude@leclerc.fr</field> + <field name="phone">+33-298.334598</field> <field name="partner_id" ref="res_partner_11"/> </record> <record id="res_partner_address_accent" model="res.partner.address"> <field name="type">default</field> - <field name="city">Liège</field> - <field name="street">Université de Liège</field> + <field name="name">Martine Ohio</field> + <field name="street">Place du 20Août</field> + <field name="city">Liège</field> + <field name="zip">4000</field> + <field name="email">martine.ohio@ulg.ac.be</field> + <field name="phone">+32-45895245</field> <field name="partner_id" ref="res_partner_accent"/> </record> <record id="res_partner_address_Camptocamp" model="res.partner.address"> @@ -472,6 +567,8 @@ <field name="zip">95014</field> <field model="res.country" name="country_id" search="[('name','=','United States')]"/> <field name="street">10200 S. De Anza Blvd</field> + <field name="email">info@seagate.com</field> + <field name="phone">+1 408 256987</field> <field name="type">default</field> <field name="partner_id" ref="res_partner_seagate"/> </record> @@ -552,7 +649,12 @@ <record id="res_partner_address_brussels0" model="res.partner.address"> <field eval="'Brussels'" name="city"/> - <field eval="'Brussels'" name="name"/> + <field eval="'Leen Vandenloep'" name="name"/> + <field eval="'Puurs'" name="city"/> + <field eval="'2870'" name="zip"/> + <field name="country_id" ref="base.be"/> + <field eval="'(+32).70.12.85.00'" name="phone"/> + <field eval="'Schoonmansveld 28'" name="street"/> <field name="partner_id" ref="res_partner_vickingdirect0"/> <field name="country_id" ref="base.be"/> </record> @@ -562,6 +664,7 @@ <field eval="'Kainuu'" name="city"/> <field eval="'Roger Pecker'" name="name"/> <field name="partner_id" ref="res_partner_woodywoodpecker0"/> + <field eval="'(+358).9.589 689'" name="phone"/> <field name="country_id" ref="base.fi"/> </record> @@ -597,10 +700,13 @@ <record id="res_partner_address_ericdubois0" model="res.partner.address"> <field eval="'Mons'" name="city"/> + <field eval="'Eric Dubois'" name="name"/> <field eval="'7000'" name="zip"/> <field name="partner_id" ref="res_partner_ericdubois0"/> <field name="country_id" ref="base.be"/> <field eval="'Chaussée de Binche, 27'" name="street"/> + <field eval="'e.dubois@gmail.com'" name="email"/> + <field eval="'(+32).758 958 789'" name="phone"/> </record> diff --git a/openerp/addons/base/res/res_user.py b/openerp/addons/base/res/res_users.py similarity index 97% rename from openerp/addons/base/res/res_user.py rename to openerp/addons/base/res/res_users.py index f2140b30f1d1d05c1bdc5bcddc66a1c7659baa7b..51be4adc747bfb2cc9bbfac75aceb0e4e54acced 100644 --- a/openerp/addons/base/res/res_user.py +++ b/openerp/addons/base/res/res_users.py @@ -147,25 +147,16 @@ class users(osv.osv): return cr.fetchall() def send_welcome_email(self, cr, uid, id, context=None): - logger= netsvc.Logger() - user = self.pool.get('res.users').read(cr, uid, id, context=context) - if not user.get('email'): - return False - if not tools.config.get('smtp_server'): - logger.notifyChannel('mails', netsvc.LOG_WARNING, - _('"smtp_server" needs to be set to send mails to users')) - return False - if not tools.config.get('email_from'): - logger.notifyChannel("mails", netsvc.LOG_WARNING, - _('"email_from" needs to be set to send welcome mails ' - 'to users')) - return False + if isinstance(id,list): id = id[0] + user = self.read(cr, uid, id, ['email','login','name', 'user_email'], context=context) + email = user['email'] or user['user_email'] - return tools.email_send(email_from=None, email_to=[user['email']], - subject=self.get_welcome_mail_subject( - cr, uid, context=context), - body=self.get_welcome_mail_body( - cr, uid, context=context) % user) + ir_mail_server = self.pool.get('ir.mail_server') + msg = ir_mail_server.build_email(email_from=None, # take config default + email_to=[email], + subject=self.get_welcome_mail_subject(cr, uid, context=context), + body=(self.get_welcome_mail_body(cr, uid, context=context) % user)) + return ir_mail_server.send_email(cr, uid, msg, context=context) def _set_interface_type(self, cr, uid, ids, name, value, arg, context=None): """Implementation of 'view' function field setter, sets the type of interface of the users. @@ -347,7 +338,7 @@ class users(osv.osv): } # User can write to a few of her own fields (but not her groups for example) - SELF_WRITEABLE_FIELDS = ['menu_tips','view', 'password', 'signature', 'action_id', 'company_id', 'user_email'] + SELF_WRITEABLE_FIELDS = ['menu_tips','view', 'password', 'signature', 'action_id', 'company_id', 'user_email', 'name'] def write(self, cr, uid, ids, values, context=None): if not hasattr(ids, '__iter__'): @@ -562,7 +553,7 @@ class users_implied(osv.osv): _inherit = 'res.users' def create(self, cr, uid, values, context=None): - groups = values.pop('groups_id') + groups = values.pop('groups_id', None) user_id = super(users_implied, self).create(cr, uid, values, context) if groups: # delegate addition of groups to add implied groups diff --git a/openerp/addons/base/res/wizard/__init__.py b/openerp/addons/base/res/wizard/__init__.py index 65869c366c4400dc6ce170bb115640bc3936a153..23156a24601f03f63166c1cb29f4f0eb529545d0 100644 --- a/openerp/addons/base/res/wizard/__init__.py +++ b/openerp/addons/base/res/wizard/__init__.py @@ -20,7 +20,7 @@ ############################################################################## import partner_sms_send -import partner_wizard_spam +import partner_wizard_massmail import partner_clear_ids import partner_wizard_ean_check diff --git a/openerp/addons/base/res/wizard/partner_wizard_spam.py b/openerp/addons/base/res/wizard/partner_wizard_massmail.py similarity index 57% rename from openerp/addons/base/res/wizard/partner_wizard_spam.py rename to openerp/addons/base/res/wizard/partner_wizard_massmail.py index 61ddd70aa45c807827b37cf0f042993722580ed2..c14101135c42fe24e4777309499cc35a58ea6622 100644 --- a/openerp/addons/base/res/wizard/partner_wizard_spam.py +++ b/openerp/addons/base/res/wizard/partner_wizard_massmail.py @@ -19,15 +19,16 @@ # ############################################################################## -import netsvc -import tools from osv import fields, osv import re +import logging -class partner_wizard_spam(osv.osv_memory): +_logger = logging.getLogger('mass.mailing') + +class partner_massmail_wizard(osv.osv_memory): """ Mass Mailing """ - _name = "partner.wizard.spam" + _name = "partner.massmail.wizard" _description = "Mass Mailing" _columns = { @@ -37,45 +38,45 @@ class partner_wizard_spam(osv.osv_memory): } def mass_mail_send(self, cr, uid, ids, context): - """ - Send Email + """Send the given mail to all partners whose ids + are present in ``context['active_ids']``, to + all addresses with an email set. - @param cr: the current row, from the database cursor. - @param uid: the current user’s ID for security checks. - @param ids: the ID or list of IDs - @param context: A standard dictionary + :param dict context: ``context['active_ids']`` + should contain the list of + ids of the partners who should + receive the mail. """ - nbr = 0 partner_pool = self.pool.get('res.partner') data = self.browse(cr, uid, ids[0], context=context) event_pool = self.pool.get('res.partner.event') - active_ids = context and context.get('active_ids', []) + assert context['active_model'] == 'res.partner', 'This wizard must be started on a list of Partners' + active_ids = context.get('active_ids', []) partners = partner_pool.browse(cr, uid, active_ids, context) - type_ = 'plain' + subtype = 'plain' if re.search('(<(pre)|[pubi].*>)', data.text): - type_ = 'html' + subtype = 'html' + ir_mail_server = self.pool.get('ir.mail_server') + emails_seen = set() for partner in partners: for adr in partner.address: - if adr.email: - name = adr.name or partner.name - to = '"%s" <%s>' % (name, adr.email) - #TODO: add some tests to check for invalid email addresses - #CHECKME: maybe we should use res.partner/email_send - tools.email_send(data.email_from, - [to], - data.subject, - data.text, - subtype=type_, - openobject_id="res.partner-%s"%partner.id) - nbr += 1 + if adr.email and not adr.email in emails_seen: + try: + emails_seen.add(adr.email) + name = adr.name or partner.name + to = '"%s" <%s>' % (name, adr.email) + msg = ir_mail_server.build_email(data.email_from, [to], data.subject, data.text, subtype=subtype) + if ir_mail_server.send_email(cr, uid, msg): + nbr += 1 + except Exception: + #ignore failed deliveries, will be logged anyway + pass event_pool.create(cr, uid, {'name': 'Email(s) sent through mass mailing', 'partner_id': partner.id, 'description': data.text }) - #TODO: log number of message sent + _logger.info('Mass-mailing wizard sent %s emails', nbr) return {'email_sent': nbr} -partner_wizard_spam() - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/wizard/partner_wizard_spam_view.xml b/openerp/addons/base/res/wizard/partner_wizard_massmail_view.xml similarity index 91% rename from openerp/addons/base/res/wizard/partner_wizard_spam_view.xml rename to openerp/addons/base/res/wizard/partner_wizard_massmail_view.xml index 0de26400f90720ff539f532e72b347ee121c8846..864550b439665207d314c90b9e3225aee01515df 100644 --- a/openerp/addons/base/res/wizard/partner_wizard_spam_view.xml +++ b/openerp/addons/base/res/wizard/partner_wizard_massmail_view.xml @@ -4,7 +4,7 @@ <record id="view_partner_mass_mail" model="ir.ui.view"> <field name="name">Mass Mailing</field> - <field name="model">partner.wizard.spam</field> + <field name="model">partner.massmail.wizard</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="Mass Mailing" col="4"> @@ -24,7 +24,7 @@ </record> <act_window name="Mass Mailing" - res_model="partner.wizard.spam" + res_model="partner.massmail.wizard" src_model="res.partner" view_mode="form" target="new" diff --git a/openerp/addons/base/rng/view.rng b/openerp/addons/base/rng/view.rng index 4512965f053faf5805a6df4aa98336bdad12c781..7c13afd8bfc6c9cd02cab7be47c154aa1cf2154d 100644 --- a/openerp/addons/base/rng/view.rng +++ b/openerp/addons/base/rng/view.rng @@ -212,6 +212,7 @@ <rng:optional><rng:attribute name="help"/></rng:optional> <rng:optional><rng:attribute name="width"/></rng:optional> <rng:optional><rng:attribute name="wrap"/></rng:optional> + <rng:optional><rng:attribute name="name"/></rng:optional> <rng:zeroOrMore> <rng:choice> <rng:ref name="notebook"/> diff --git a/openerp/addons/base/security/base_security.xml b/openerp/addons/base/security/base_security.xml index 00aca6613d6e9e6f397af5b6ab4c831a39006869..59f891bd83dc7da2665176d51576d360c10bb87e 100644 --- a/openerp/addons/base/security/base_security.xml +++ b/openerp/addons/base/security/base_security.xml @@ -42,28 +42,32 @@ <field name="groups_id" eval="[(6,0, [ref('group_system'), ref('group_erp_manager')])]"/> </record> - <record model="ir.rule" id="res_widget_user_rule"> - <field name="name">res.widget.user rule</field> - <field name="model_id" ref="model_res_widget_user"/> - <field name="global" eval="True"/> - <field name="domain_force">['|', ('user_id','=',user.id),('user_id','=',False)]</field> - </record> + </data> - <record model="ir.rule" id="res_partner_rule"> - <field name="name">res.partner company</field> - <field name="model_id" ref="model_res_partner"/> - <field name="global" eval="True"/> - <!-- Show partners from ancestors and descendants companies (or company-less), this is usually a better - default for multicompany setups. --> - <field name="domain_force">['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field> - </record> + <data noupdate="1"> - <record model="ir.rule" id="multi_company_default_rule"> - <field name="name">Multi_company_default company</field> - <field name="model_id" ref="model_multi_company_default"/> - <field name="global" eval="True"/> - <field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field> - </record> + <record model="ir.rule" id="res_widget_user_rule"> + <field name="name">res.widget.user rule</field> + <field name="model_id" ref="model_res_widget_user"/> + <field name="global" eval="True"/> + <field name="domain_force">['|', ('user_id','=',user.id),('user_id','=',False)]</field> + </record> + + <record model="ir.rule" id="res_partner_rule"> + <field name="name">res.partner company</field> + <field name="model_id" ref="model_res_partner"/> + <field name="global" eval="True"/> + <!-- Show partners from ancestors and descendants companies (or company-less), this is usually a better + default for multicompany setups. --> + <field name="domain_force">['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]</field> + </record> + + <record model="ir.rule" id="multi_company_default_rule"> + <field name="name">Multi_company_default company</field> + <field name="model_id" ref="model_multi_company_default"/> + <field name="global" eval="True"/> + <field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field> + </record> </data> </openerp> diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv index 8949052f89b403707d1555e03ff02a71c45ee460..659938a73a3815ea0b788ae374b977fe2f0458d8 100644 --- a/openerp/addons/base/security/ir.model.access.csv +++ b/openerp/addons/base/security/ir.model.access.csv @@ -48,6 +48,7 @@ "access_res_country_state_group_user","res_country_state group_user","model_res_country_state","group_partner_manager",1,1,1,1 "access_res_currency_group_all","res_currency group_all","model_res_currency",,1,0,0,0 "access_res_currency_rate_group_all","res_currency_rate group_all","model_res_currency_rate",,1,0,0,0 +"access_res_currency_rate_type_group_all","res_currency_rate_type group_all","model_res_currency_rate_type",,1,0,0,0 "access_res_currency_group_system","res_currency group_system","model_res_currency","group_system",1,1,1,1 "access_res_currency_rate_group_system","res_currency_rate group_system","model_res_currency_rate","group_system",1,1,1,1 "access_res_groups_group_erp_manager","res_groups group_erp_manager","model_res_groups","group_erp_manager",1,1,1,1 @@ -123,4 +124,6 @@ "access_res_widget_user","res.widget.user","model_res_widget",,1,0,0,0 "access_res_log_all","res.log","model_res_log",,1,1,1,1 "access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0 +"access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0 "access_ir_actions_todo_category","ir_actions_todo_category","model_ir_actions_todo_category","group_system",1,1,1,1 +"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0 diff --git a/openerp/addons/base/test/test_osv_expression.yml b/openerp/addons/base/test/test_osv_expression.yml index 3a5e41dacc795f579f3af29ef48f9538e842c310..43fea5c16cf89ffea95245306653e21cd0735a4f 100644 --- a/openerp/addons/base/test/test_osv_expression.yml +++ b/openerp/addons/base/test/test_osv_expression.yml @@ -177,6 +177,251 @@ res_ids = self.search(cr, uid, [('company_id.partner_id', 'not in', [])]) res_ids.sort() assert res_ids == all_ids, "Searching against empty set failed, returns %r" % res_ids +- + Test the '(not) like/in' behavior. res.partner and its parent_id column are used because + parent_id is a many2one, allowing to test the Null value, and there are actually some + null and non-null values in the demo data. +- + !python {model: res.partner }: | + partner_ids = self.search(cr, uid, []) + partner_ids.sort() + max_partner_id = max(partner_ids) + + # Grab test sample data without using a normal + # search domain, because we want to test these later, + # so we can't rely on them! + partners = self.browse(cr, uid, partner_ids) + with_parent = [] + without_parent = [] + with_website = [] + for x in partners: + if x.parent_id: + with_parent.append(x.id) + else: + without_parent.append(x.id) + if x.website: + with_website.append(x.id) + with_parent.sort() + without_parent.sort() + with_website.sort() + + # We treat null values differently than in SQL. For instance in SQL: + # SELECT id FROM res_partner WHERE parent_id NOT IN (0) + # will return only the records with non-null parent_id. + # SELECT id FROM res_partner WHERE parent_id IN (0) + # will return expectedly nothing (our ids always begin at 1). + # This means the union of those two results will give only some + # records, but not all present in database. + # + # When using domains and the ORM's search method, we think it is + # more intuitive that the union returns all the records, and that + # a domain like ('parent_id', 'not in', [0]) will return all + # the records. For instance, if you perform a search for the companies + # that don't have OpenERP has a parent company, you expect to find, + # among others, the companies that don't have parent company. + # + # ('parent_id', 'not in', [0]) must give the same result than + # ('parent_id', 'not in', []), i.e. a empty set or a set with non- + # existing values be treated similarly if we simply check that some + # existing value belongs to them. + + res_0 = self.search(cr, uid, [('parent_id', 'not like', 'probably_unexisting_name')]) # get all rows, included null parent_id + res_0.sort() + res_1 = self.search(cr, uid, [('parent_id', 'not in', [max_partner_id + 1])]) # get all rows, included null parent_id + res_1.sort() + res_2 = self.search(cr, uid, [('parent_id', 'not in', False)]) # get rows with not null parent_id, deprecated syntax + res_2.sort() + res_3 = self.search(cr, uid, [('parent_id', 'not in', [])]) # get all rows, included null parent_id + res_3.sort() + res_4 = self.search(cr, uid, [('parent_id', 'not in', [False])]) # get rows with not null parent_id + res_4.sort() + assert res_0 == partner_ids + assert res_1 == partner_ids + assert res_2 == with_parent + assert res_3 == partner_ids + assert res_4 == with_parent + # The results of these queries, when combined with queries 0..4 must + # give the whole set of ids. + res_5 = self.search(cr, uid, [('parent_id', 'like', 'probably_unexisting_name')]) + res_5.sort() + res_6 = self.search(cr, uid, [('parent_id', 'in', [max_partner_id + 1])]) + res_6.sort() + res_7 = self.search(cr, uid, [('parent_id', 'in', False)]) + res_7.sort() + res_8 = self.search(cr, uid, [('parent_id', 'in', [])]) + res_8.sort() + res_9 = self.search(cr, uid, [('parent_id', 'in', [False])]) + res_9.sort() + assert res_5 == [] + assert res_6 == [] + assert res_7 == without_parent + assert res_8 == [] + assert res_9 == without_parent + # These queries must return exactly the results than the queries 0..4, + # i.e. not ... in ... must be the same as ... not in ... . + res_10 = self.search(cr, uid, ['!', ('parent_id', 'like', 'probably_unexisting_name')]) + res_10.sort() + res_11 = self.search(cr, uid, ['!', ('parent_id', 'in', [max_partner_id + 1])]) + res_11.sort() + res_12 = self.search(cr, uid, ['!', ('parent_id', 'in', False)]) + res_12.sort() + res_13 = self.search(cr, uid, ['!', ('parent_id', 'in', [])]) + res_13.sort() + res_14 = self.search(cr, uid, ['!', ('parent_id', 'in', [False])]) + res_14.sort() + assert res_0 == res_10 + assert res_1 == res_11 + assert res_2 == res_12 + assert res_3 == res_13 + assert res_4 == res_14 + + # Testing many2one field is not enough, a regular char field is tested + # with in [] and must not return any result. + res_15 = self.search(cr, uid, [('website', 'in', [])]) + assert res_15 == [] + # not in [] must return everything. + res_16 = self.search(cr, uid, [('website', 'not in', [])]) + res_16.sort() + assert res_16 == partner_ids + + res_17 = self.search(cr, uid, [('website', 'not in', False)]) + res_17.sort() + assert res_17 == with_website +- + Property of the query (one2many not in False). +- + !python {model: res.currency }: | + ids = self.search(cr, uid, []) + referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)]) + companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', 'not in', False)])) + assert referenced_companies == companies +- + Property of the query (one2many in False). +- + !python {model: res.currency }: | + ids = self.search(cr, uid, []) + referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)]) + unreferenced_companies = set(self.pool.get('res.company').search(cr, uid, [])).difference(referenced_companies) + companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', 'in', False)])) + assert unreferenced_companies == companies +- + Equivalent queries. +- + !python {model: res.currency }: | + max_currency_id = max(self.search(cr, uid, [])) + res_0 = self.search(cr, uid, []) + res_1 = self.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')]) + res_2 = self.search(cr, uid, [('id', 'not in', [max_currency_id + 1003])]) + res_3 = self.search(cr, uid, [('id', 'not in', [])]) + res_4 = self.search(cr, uid, [('id', 'not in', False)]) + res_0.sort() + res_1.sort() + res_2.sort() + res_3.sort() + res_4.sort() + assert res_0 == res_1 + assert res_0 == res_2 + assert res_0 == res_3 + assert res_0 == res_4 +- + Equivalent queries, integer and string. +- + !python {model: res.partner }: | + all_ids = self.search(cr, uid, []) + if len(all_ids) > 1: + one = all_ids[0] + record = self.browse(cr, uid, one) + others = all_ids[1:] + res_1 = self.search(cr, uid, [('id', '=', one)]) + # self.search(cr, uid, [('id', '!=', others)]) # not permitted + res_2 = self.search(cr, uid, [('id', 'not in', others)]) + res_3 = self.search(cr, uid, ['!', ('id', '!=', one)]) + res_4 = self.search(cr, uid, ['!', ('id', 'in', others)]) + # res_5 = self.search(cr, uid, [('id', 'in', one)]) # TODO make it permitted, just like for child_of + res_6 = self.search(cr, uid, [('id', 'in', [one])]) + res_7 = self.search(cr, uid, [('name', '=', record.name)]) + res_8 = self.search(cr, uid, [('name', 'in', [record.name])]) + # res_9 = self.search(cr, uid, [('name', 'in', record.name)]) # TODO + assert [one] == res_1 + assert [one] == res_2 + assert [one] == res_3 + assert [one] == res_4 + #assert [one] == res_5 + assert [one] == res_6 + assert [one] == res_7 +- + Need a company with a parent_id. +- + !record {model: res.company, id: ymltest_company3}: + name: Acme 3 +- + Need a company with a parent_id. +- + !record {model: res.company, id: ymltest_company4}: + name: Acme 4 + parent_id: ymltest_company3 +- + Equivalent queries, one2many. +- + !python {model: res.company }: | + # Search the company via its one2many (the one2many must point back at the company). + company = self.browse(cr, uid, ref('ymltest_company3')) + max_currency_id = max(self.pool.get('res.currency').search(cr, uid, [])) + currency_ids1 = self.pool.get('res.currency').search(cr, uid, [('name', 'not like', 'probably_unexisting_name')]) + currency_ids2 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [max_currency_id + 1003])]) + currency_ids3 = self.pool.get('res.currency').search(cr, uid, [('id', 'not in', [])]) + assert currency_ids1 == currency_ids2 == currency_ids3, 'All 3 results should have be the same: all currencies' + default_company = self.browse(cr, uid, 1) + # one2many towards same model + res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child + res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child + # one2many towards another model + res_3 = self.search(cr, uid, [('currency_ids', 'in', [x.id for x in default_company.currency_ids])]) # companies having a currency of main company + res_4 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].id])]) # companies having first currency of main company + res_5 = self.search(cr, uid, [('currency_ids', 'in', default_company.currency_ids[0].id)]) # companies having first currency of main company + # res_6 = self.search(cr, uid, [('currency_ids', 'in', [default_company.currency_ids[0].name])]) # TODO + res_7 = self.search(cr, uid, [('currency_ids', '=', default_company.currency_ids[0].name)]) + res_8 = self.search(cr, uid, [('currency_ids', 'like', default_company.currency_ids[0].name)]) + res_9 = self.search(cr, uid, [('currency_ids', 'like', 'probably_unexisting_name')]) + # self.search(cr, uid, [('currency_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception + assert res_1 == [ref('ymltest_company3')] + assert res_2 == [ref('ymltest_company3')] + assert res_3 == [1] + assert res_4 == [1] + assert res_5 == [1] + assert res_7 == [1] + assert res_8 == [1] + assert res_9 == [] + + # get the companies referenced by some currency (this is normally the main company) + res_10 = self.search(cr, uid, [('currency_ids', 'not like', 'probably_unexisting_name')]) + res_11 = self.search(cr, uid, [('currency_ids', 'not in', [max_currency_id + 1])]) + res_12 = self.search(cr, uid, [('currency_ids', 'not in', False)]) + res_13 = self.search(cr, uid, [('currency_ids', 'not in', [])]) + res_10.sort() + res_11.sort() + res_12.sort() + res_13.sort() + assert res_10 == res_11 + assert res_10 == res_12 + assert res_10 == res_13 + + # child_of x returns x and its children (direct or not). + company = self.browse(cr, uid, ref('ymltest_company3')) + expected = [ref('ymltest_company3'), ref('ymltest_company4')] + expected.sort() + res_1 = self.search(cr, uid, [('id', 'child_of', [ref('ymltest_company3')])]) + res_1.sort() + res_2 = self.search(cr, uid, [('id', 'child_of', ref('ymltest_company3'))]) + res_2.sort() + res_3 = self.search(cr, uid, [('id', 'child_of', [company.name])]) + res_3.sort() + res_4 = self.search(cr, uid, [('id', 'child_of', company.name)]) + res_4.sort() + assert res_1 == expected + assert res_2 == expected + assert res_3 == expected + assert res_4 == expected - Verify that normalize_domain() works. - @@ -187,6 +432,72 @@ domain = [('x','in',['y','z']),('a.v','=','e'),'|','|',('a','=','b'),'!',('c','>','d'),('e','!=','f'),('g','=','h')] norm_domain = ['&','&','&'] + domain assert norm_domain == expression.normalize(domain), "Non-normalized domains should be properly normalized" +- + Unaccent. Create a company with an accent in its name. +- + !record {model: res.company, id: ymltest_unaccent_company}: + name: Hélène +- + Test the unaccent-enabled 'ilike'. +- + !python {model: res.company}: | + if self.pool.has_unaccent: + ids = self.search(cr, uid, [('name','ilike','Helene')], {}) + assert ids == [ref('ymltest_unaccent_company')] + ids = self.search(cr, uid, [('name','ilike','hélène')], {}) + assert ids == [ref('ymltest_unaccent_company')] + ids = self.search(cr, uid, [('name','not ilike','Helene')], {}) + assert ref('ymltest_unaccent_company') not in ids + ids = self.search(cr, uid, [('name','not ilike','hélène')], {}) + assert ref('ymltest_unaccent_company') not in ids +- + Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on an untranslated field. +- + !python {model: res.partner }: | + all_ids = self.search(cr, uid, [('name', '=like', 'A_e_or')]) + assert len(all_ids) == 1, "Must match one partner (Axelor), got %r"%all_ids + all_ids = self.search(cr, uid, [('name', '=ilike', 'm_____')]) + assert len(all_ids) == 1, "Must match *only* one partner (Maxtor), got %r"%all_ids +- + Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on translated field. +- + !python {model: res.country }: | + all_ids = self.search(cr, uid, [('name', '=like', 'Ind__')]) + assert len(all_ids) == 1, "Must match India only, got %r"%all_ids + all_ids = self.search(cr, uid, [('name', '=ilike', 'z%')]) + assert len(all_ids) == 3, "Must match only countries with names starting with Z (currently 3), got %r"%all_ids +- + Use the create_date column on res.country (which doesn't declare it in _columns). +- + !python {model: res.country }: | + ids = self.search(cr, uid, [('create_date', '<', '2001-01-01 12:00:00')]) + + +- + Verify that invalid expressions are refused, even for magic fields +- + !python {model: res.country }: | + try: + self.search(cr, uid, [('does_not_exist', '=', 'foo')]) + raise AssertionError('Invalid fields should not be accepted') + except ValueError: + pass + try: + self.search(cr, uid, [('create_date', '>>', 'foo')]) + raise AssertionError('Invalid operators should not be accepted') + except ValueError: + pass + import psycopg2 + try: + cr._default_log_exceptions = False + cr.execute('SAVEPOINT expression_failure_test') + self.search(cr, uid, [('create_date', '=', "1970-01-01'); --")]) + # if the above search gives no error, the operand was not escaped! + cr.execute('RELEASE SAVEPOINT expression_failure_test') + raise AssertionError('Operands should always be SQL escaped') + except psycopg2.DataError: + # Should give: 'DataError: invalid input syntax for type timestamp' or similar + cr.execute('ROLLBACK TO SAVEPOINT expression_failure_test') diff --git a/openerp/modules/db.py b/openerp/modules/db.py index 25ce7283c97e64a7c1630b964d011f1d93ab7810..6e6dd64b13cfdc66274127e2377a6c5a28412990 100644 --- a/openerp/modules/db.py +++ b/openerp/modules/db.py @@ -21,6 +21,7 @@ ############################################################################## import openerp.modules +import logging def is_initialized(cr): """ Check if a database has been initialized for the ORM. @@ -40,6 +41,10 @@ def initialize(cr): """ f = openerp.modules.get_module_resource('base', 'base.sql') + if not f: + m = "File not found: 'base.sql' (provided by module 'base')." + logging.getLogger('init').critical(m) + raise IOError(m) base_sql_file = openerp.tools.misc.file_open(f) try: cr.execute(base_sql_file.read()) @@ -118,4 +123,14 @@ def create_categories(cr, categories): categories = categories[1:] return p_id +def has_unaccent(cr): + """ Test if the database has an unaccent function. + + The unaccent is supposed to be provided by the PostgreSQL unaccent contrib + module but any similar function will be picked by OpenERP. + + """ + cr.execute("SELECT proname FROM pg_proc WHERE proname='unaccent'") + return len(cr.fetchall()) > 0 + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 4bc8e440b62e2f32f4171d7697f6da23d2736cc4..40986580d1bae63e2d47c7917be21c1c7d89069b 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -347,7 +347,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False): cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""") for (model, name) in cr.fetchall(): model_obj = pool.get(model) - if isinstance(model_obj, osv.osv.osv_memory): + if isinstance(model_obj, osv.osv.osv_memory) and not isinstance(model_obj, osv.osv.osv): logger.notifyChannel('init', netsvc.LOG_WARNING, 'In-memory object %s (%s) should not have explicit access rules!' % (model, name)) cr.execute("SELECT model from ir_model") diff --git a/openerp/modules/registry.py b/openerp/modules/registry.py index e88852a8c189259b40544fe8e99345be76cbb4a0..f35adadbf2ff35caa37dca6f4494f2a0de5a2f2d 100644 --- a/openerp/modules/registry.py +++ b/openerp/modules/registry.py @@ -22,10 +22,14 @@ """ Models registries. """ +import threading + +import logging import openerp.sql_db import openerp.osv.orm - +import openerp.modules.db +import openerp.tools.config class Registry(object): """ Model registry for a particular database. @@ -44,6 +48,14 @@ class Registry(object): self.db_name = db_name self.db = openerp.sql_db.db_connect(db_name) + cr = self.db.cursor() + has_unaccent = openerp.modules.db.has_unaccent(cr) + if openerp.tools.config['unaccent'] and not has_unaccent: + logger = logging.getLogger('unaccent') + logger.warning("The option --unaccent was given but no unaccent() function was found in database.") + self.has_unaccent = openerp.tools.config['unaccent'] and has_unaccent + cr.close() + def do_parent_store(self, cr): for o in self._init_parent: self.get(o)._parent_store_compute(cr) @@ -93,7 +105,6 @@ class Registry(object): for model in self.models.itervalues(): model.clear_caches() - class RegistryManager(object): """ Model registries manager. @@ -105,19 +116,20 @@ class RegistryManager(object): # Mapping between db name and model registry. # Accessed through the methods below. registries = {} + registries_lock = threading.RLock() @classmethod def get(cls, db_name, force_demo=False, status=None, update_module=False, pooljobs=True): """ Return a registry for a given database name.""" - - if db_name in cls.registries: - registry = cls.registries[db_name] - else: - registry = cls.new(db_name, force_demo, status, - update_module, pooljobs) - return registry + with cls.registries_lock: + if db_name in cls.registries: + registry = cls.registries[db_name] + else: + registry = cls.new(db_name, force_demo, status, + update_module, pooljobs) + return registry @classmethod @@ -128,42 +140,43 @@ class RegistryManager(object): The (possibly) previous registry for that database name is discarded. """ - import openerp.modules - registry = Registry(db_name) - - # Initializing a registry will call general code which will in turn - # call registries.get (this object) to obtain the registry being - # initialized. Make it available in the registries dictionary then - # remove it if an exception is raised. - cls.delete(db_name) - cls.registries[db_name] = registry - try: - # This should be a method on Registry - openerp.modules.load_modules(registry.db, force_demo, status, update_module) - except Exception: - del cls.registries[db_name] - raise - - cr = registry.db.cursor() - try: - registry.do_parent_store(cr) - registry.get('ir.actions.report.xml').register_all(cr) - cr.commit() - finally: - cr.close() - - if pooljobs: - registry.get('ir.cron').restart(registry.db.dbname) - - return registry + with cls.registries_lock: + registry = Registry(db_name) + + # Initializing a registry will call general code which will in turn + # call registries.get (this object) to obtain the registry being + # initialized. Make it available in the registries dictionary then + # remove it if an exception is raised. + cls.delete(db_name) + cls.registries[db_name] = registry + try: + # This should be a method on Registry + openerp.modules.load_modules(registry.db, force_demo, status, update_module) + except Exception: + del cls.registries[db_name] + raise + + cr = registry.db.cursor() + try: + registry.do_parent_store(cr) + registry.get('ir.actions.report.xml').register_all(cr) + cr.commit() + finally: + cr.close() + + if pooljobs: + registry.get('ir.cron').restart(registry.db.dbname) + + return registry @classmethod def delete(cls, db_name): """ Delete the registry linked to a given database. """ - if db_name in cls.registries: - del cls.registries[db_name] + with cls.registries_lock: + if db_name in cls.registries: + del cls.registries[db_name] @classmethod @@ -177,8 +190,9 @@ class RegistryManager(object): This method is given to spare you a ``RegistryManager.get(db_name)`` that would loads the given database if it was not already loaded. """ - if db_name in cls.registries: - cls.registries[db_name].clear_caches() + with cls.registries_lock: + if db_name in cls.registries: + cls.registries[db_name].clear_caches() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py index 54726a289f2e00f32379ae4ec6747d79d2d21eb0..ff2528db73db53aa21eff3f75f5393bea31ce209 100644 --- a/openerp/osv/expression.py +++ b/openerp/osv/expression.py @@ -20,17 +20,146 @@ # ############################################################################## +""" Domain expression processing + +The main duty of this module is to compile a domain expression into a SQL +query. A lot of things should be documented here, but as a first step in the +right direction, some tests in test_osv_expression.yml might give you some +additional information. + +For legacy reasons, a domain uses an inconsistent two-levels abstract syntax +(domains are regular Python data structures). At the first level, a domain +is an expression made of terms (sometimes called leaves) and (domain) operators +used in prefix notation. The available operators at this level are '!', '&', +and '|'. '!' is a unary 'not', '&' is a binary 'and', and '|' is a binary 'or'. +For instance, here is a possible domain. (<term> stands for an arbitrary term, +more on this later.) + + ['&', '!', <term1>, '|', <term2>, <term3>] + +It is equivalent to this pseudo code using infix notation: + + (not <term1>) and (<term2> or <term3>) + +The second level of syntax deals with the term representation. A term is +a triple of the form (left, operator, right). That is, a term uses an infix +notation, and the available operators, and possible left and right operands +differ with those of the previous level. Here is a possible term: + + ('company_id.name', '=', 'OpenERP') + +The left and right operand don't have the same possible values. The left +operand is field name (related to the model for which the domain applies). +Actually, the field name can use the dot-notation to traverse relationships. +The right operand is a Python value whose type should match the used operator +and field type. In the above example, a string is used because the name field +of a company has type string, and because we use the '=' operator. When +appropriate, a 'in' operator can be used, and thus the right operand should be +a list. + +Note: the non-uniform syntax could have been more uniform, but this would hide +an important limitation of the domain syntax. Say that the term representation +was ['=', 'company_id.name', 'OpenERP']. Used in a complete domain, this would +look like: + + ['!', ['=', 'company_id.name', 'OpenERP']] + +and you would be tempted to believe something like this would be possible: + + ['!', ['=', 'company_id.name', ['&', ..., ...]]] + +That is, a domain could be a valid operand. But this is not the case. A domain +is really limited to a two-level nature, and can not takes a recursive form: a +domain is not a valid second-level operand. + +Unaccent - Accent-insensitive search + +OpenERP will use the SQL function 'unaccent' when available for the 'ilike' and +'not ilike' operators, and enabled in the configuration. +Normally the 'unaccent' function is obtained from the PostgreSQL 'unaccent' +contrib module[0]. + + +..todo: The following explanation should be moved in some external installation + guide + +The steps to install the module might differ on specific PostgreSQL versions. +We give here some instruction for PostgreSQL 9.x on a Ubuntu system. + +Ubuntu doesn't come yet with PostgreSQL 9.x, so an alternative package source +is used. We use Martin Pitt's PPA available at ppa:pitti/postgresql[1]. See +[2] for instructions. Basically: + + > sudo add-apt-repository ppa:pitti/postgresql + > sudo apt-get update + +Once the package list is up-to-date, you have to install PostgreSQL 9.0 and +its contrib modules. + + > sudo apt-get install postgresql-9.0 postgresql-contrib-9.0 + +When you want to enable unaccent on some database: + + > psql9 <database> -f /usr/share/postgresql/9.0/contrib/unaccent.sql + +Here 'psql9' is an alias for the newly installed PostgreSQL 9.0 tool, together +with the correct port if necessary (for instance if PostgreSQL 8.4 is running +on 5432). (Other aliases can be used for createdb and dropdb.) + + > alias psql9='/usr/lib/postgresql/9.0/bin/psql -p 5433' + +You can check unaccent is working: + + > psql9 <database> -c"select unaccent('hélène')" + +Finally, to instruct OpenERP to really use the unaccent function, you have to +start the server specifying the --unaccent flag. + +[0] http://developer.postgresql.org/pgdocs/postgres/unaccent.html +[1] https://launchpad.net/~pitti/+archive/postgresql +[2] https://launchpad.net/+help/soyuz/ppa-sources-list.html + +""" + +import logging + from openerp.tools import flatten, reverse_enumerate import fields +import openerp.modules +from openerp.osv.orm import MAGIC_COLUMNS #.apidoc title: Domain Expressions +# Domain operators. NOT_OPERATOR = '!' OR_OPERATOR = '|' AND_OPERATOR = '&' +DOMAIN_OPERATORS = (NOT_OPERATOR, OR_OPERATOR, AND_OPERATOR) + +# List of available term operators. It is also possible to use the '<>' +# operator, which is strictly the same as '!='; the later should be prefered +# for consistency. This list doesn't contain '<>' as it is simpified to '!=' +# by the normalize_operator() function (so later part of the code deals with +# only one representation). +# An internal (i.e. not available to the user) 'inselect' operator is also +# used. In this case its right operand has the form (subselect, params). +TERM_OPERATORS = ('=', '!=', '<=', '<', '>', '>=', '=?', '=like', '=ilike', + 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', + 'child_of') -TRUE_DOMAIN = [(1,'=',1)] -FALSE_DOMAIN = [(0,'=',1)] +# A subset of the above operators, with a 'negative' semantic. When the +# expressions 'in NEGATIVE_TERM_OPERATORS' or 'not in NEGATIVE_TERM_OPERATORS' are used in the code +# below, this doesn't necessarily mean that any of those NEGATIVE_TERM_OPERATORS is +# legal in the processed term. +NEGATIVE_TERM_OPERATORS = ('!=', 'not like', 'not ilike', 'not in') + +TRUE_LEAF = (1, '=', 1) +FALSE_LEAF = (0, '=', 1) + +TRUE_DOMAIN = [TRUE_LEAF] +FALSE_DOMAIN = [FALSE_LEAF] + +_logger = logging.getLogger('expression') def normalize(domain): """Returns a normalized version of ``domain_expr``, where all implicit '&' operators @@ -45,10 +174,10 @@ def normalize(domain): op_arity = {NOT_OPERATOR: 1, AND_OPERATOR: 2, OR_OPERATOR: 2} for token in domain: if expected == 0: # more than expected, like in [A, B] - result[0:0] = ['&'] # put an extra '&' in front + result[0:0] = [AND_OPERATOR] # put an extra '&' in front expected = 1 result.append(token) - if isinstance(token, (list,tuple)): # domain term + if isinstance(token, (list, tuple)): # domain term expected -= 1 else: expected += op_arity.get(token, 0) - 1 @@ -57,7 +186,8 @@ def normalize(domain): def combine(operator, unit, zero, domains): """Returns a new domain expression where all domain components from ``domains`` - have been added together using the binary operator ``operator``. + have been added together using the binary operator ``operator``. The given + domains must be normalized. :param unit: the identity element of the domains "set" with regard to the operation performed by ``operator``, i.e the domain component ``i`` which, when @@ -69,6 +199,7 @@ def combine(operator, unit, zero, domains): combined with any domain ``x`` via ``operator``, yields ``z``. E.g. [(1,'=',1)] is the typical zero for OR_OPERATOR: as soon as you see it in a domain component the resulting domain is the zero. + :param domains: a list of normalized domains. """ result = [] count = 0 @@ -84,13 +215,130 @@ def combine(operator, unit, zero, domains): return result def AND(domains): - """ AND([D1,D2,...]) returns a domain representing D1 and D2 and ... """ + """AND([D1,D2,...]) returns a domain representing D1 and D2 and ... """ return combine(AND_OPERATOR, TRUE_DOMAIN, FALSE_DOMAIN, domains) def OR(domains): - """ OR([D1,D2,...]) returns a domain representing D1 or D2 or ... """ + """OR([D1,D2,...]) returns a domain representing D1 or D2 or ... """ return combine(OR_OPERATOR, FALSE_DOMAIN, TRUE_DOMAIN, domains) +def is_operator(element): + """Test whether an object is a valid domain operator. """ + return isinstance(element, basestring) and element in DOMAIN_OPERATORS + +# TODO change the share wizard to use this function. +def is_leaf(element, internal=False): + """ Test whether an object is a valid domain term. + + :param internal: allow or not the 'inselect' internal operator in the term. + This normally should be always left to False. + """ + INTERNAL_OPS = TERM_OPERATORS + ('inselect',) + return (isinstance(element, tuple) or isinstance(element, list)) \ + and len(element) == 3 \ + and (((not internal) and element[1] in TERM_OPERATORS + ('<>',)) \ + or (internal and element[1] in INTERNAL_OPS + ('<>',))) + +def normalize_leaf(left, operator, right): + """ Change a term's operator to some canonical form, simplifying later + processing. + """ + original = operator + operator = operator.lower() + if operator == '<>': + operator = '!=' + if isinstance(right, bool) and operator in ('in', 'not in'): + _logger.warning("The domain term '%s' should use the '=' or '!=' operator." % ((left, original, right),)) + operator = '=' if operator == 'in' else '!=' + if isinstance(right, (list, tuple)) and operator in ('=', '!='): + _logger.warning("The domain term '%s' should use the 'in' or 'not in' operator." % ((left, original, right),)) + operator = 'in' if operator == '=' else 'not in' + return left, operator, right + +def distribute_not(domain): + """ Distribute any '!' domain operators found inside a normalized domain. + + Because we don't use SQL semantic for processing a 'left not in right' + query (i.e. our 'not in' is not simply translated to a SQL 'not in'), + it means that a '! left in right' can not be simply processed + by __leaf_to_sql by first emitting code for 'left in right' then wrapping + the result with 'not (...)', as it would result in a 'not in' at the SQL + level. + + This function is thus responsible for pushing any '!' domain operators + inside the terms themselves. For example:: + + ['!','&',('user_id','=',4),('partner_id','in',[1,2])] + will be turned into: + ['|',('user_id','!=',4),('partner_id','not in',[1,2])] + + """ + def negate(leaf): + """Negates and returns a single domain leaf term, + using the opposite operator if possible""" + left, operator, right = leaf + mapping = { + '<': '>=', + '>': '<=', + '<=': '>', + '>=': '<', + '=': '!=', + '!=': '=', + } + if operator in ('in', 'like', 'ilike'): + operator = 'not ' + operator + return [(left, operator, right)] + if operator in ('not in', 'not like', 'not ilike'): + operator = operator[4:] + return [(left, operator, right)] + if operator in mapping: + operator = mapping[operator] + return [(left, operator, right)] + return [NOT_OPERATOR, (left, operator, right)] + def distribute_negate(domain): + """Negate the domain ``subtree`` rooted at domain[0], + leaving the rest of the domain intact, and return + (negated_subtree, untouched_domain_rest) + """ + if is_leaf(domain[0]): + return negate(domain[0]), domain[1:] + if domain[0] == AND_OPERATOR: + done1, todo1 = distribute_negate(domain[1:]) + done2, todo2 = distribute_negate(todo1) + return [OR_OPERATOR] + done1 + done2, todo2 + if domain[0] == OR_OPERATOR: + done1, todo1 = distribute_negate(domain[1:]) + done2, todo2 = distribute_negate(todo1) + return [AND_OPERATOR] + done1 + done2, todo2 + if not domain: + return [] + if domain[0] != NOT_OPERATOR: + return [domain[0]] + distribute_not(domain[1:]) + if domain[0] == NOT_OPERATOR: + done, todo = distribute_negate(domain[1:]) + return done + distribute_not(todo) + +def select_from_where(cr, select_field, from_table, where_field, where_ids, where_operator): + # todo: merge into parent query as sub-query + res = [] + if where_ids: + if where_operator in ['<','>','>=','<=']: + cr.execute('SELECT "%s" FROM "%s" WHERE "%s" %s %%s' % \ + (select_field, from_table, where_field, where_operator), + (where_ids[0],)) # TODO shouldn't this be min/max(where_ids) ? + res = [r[0] for r in cr.fetchall()] + else: # TODO where_operator is supposed to be 'in'? It is called with child_of... + for i in range(0, len(where_ids), cr.IN_MAX): + subids = where_ids[i:i+cr.IN_MAX] + cr.execute('SELECT "%s" FROM "%s" WHERE "%s" IN %%s' % \ + (select_field, from_table, where_field), (tuple(subids),)) + res.extend([r[0] for r in cr.fetchall()]) + return res + +def select_distinct_from_where_not_null(cr, select_field, from_table): + cr.execute('SELECT distinct("%s") FROM "%s" where "%s" is not null' % \ + (select_field, from_table, select_field)) + return [r[0] for r in cr.fetchall()] class expression(object): """ @@ -100,148 +348,124 @@ class expression(object): For more info: http://christophe-simonis-at-tiny.blogspot.com/2008/08/new-new-domain-notation.html """ - @classmethod - def _is_operator(cls, element): - return isinstance(element, (str, unicode)) and element in [AND_OPERATOR, OR_OPERATOR, NOT_OPERATOR] - - @classmethod - def _is_leaf(cls, element, internal=False): - OPS = ('=', '!=', '<>', '<=', '<', '>', '>=', '=?', '=like', '=ilike', 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', 'child_of') - INTERNAL_OPS = OPS + ('inselect',) - return (isinstance(element, tuple) or isinstance(element, list)) \ - and len(element) == 3 \ - and (((not internal) and element[1] in OPS) \ - or (internal and element[1] in INTERNAL_OPS)) - - def __execute_recursive_in(self, cr, s, f, w, ids, op, type): - # todo: merge into parent query as sub-query - res = [] - if ids: - if op in ['<','>','>=','<=']: - cr.execute('SELECT "%s"' \ - ' FROM "%s"' \ - ' WHERE "%s" %s %%s' % (s, f, w, op), (ids[0],)) - res.extend([r[0] for r in cr.fetchall()]) - else: - for i in range(0, len(ids), cr.IN_MAX): - subids = ids[i:i+cr.IN_MAX] - cr.execute('SELECT "%s"' \ - ' FROM "%s"' \ - ' WHERE "%s" IN %%s' % (s, f, w),(tuple(subids),)) - res.extend([r[0] for r in cr.fetchall()]) - else: - cr.execute('SELECT distinct("%s")' \ - ' FROM "%s" where "%s" is not null' % (s, f, s)), - res.extend([r[0] for r in cr.fetchall()]) - return res - - def __init__(self, exp): - # check if the expression is valid - if not reduce(lambda acc, val: acc and (self._is_operator(val) or self._is_leaf(val)), exp, True): - raise ValueError('Bad domain expression: %r' % (exp,)) - self.__exp = exp + def __init__(self, cr, uid, exp, table, context): + self.has_unaccent = openerp.modules.registry.RegistryManager.get(cr.dbname).has_unaccent self.__field_tables = {} # used to store the table to use for the sql generation. key = index of the leaf self.__all_tables = set() self.__joins = [] self.__main_table = None # 'root' table. set by parse() - self.__DUMMY_LEAF = (1, '=', 1) # a dummy leaf that must not be parsed or sql generated + # assign self.__exp with the normalized, parsed domain. + self.parse(cr, uid, distribute_not(normalize(exp)), table, context) + # TODO used only for osv_memory @property def exp(self): return self.__exp[:] - def parse(self, cr, uid, table, context): - """ transform the leafs of the expression """ - if not self.__exp: - return self + def parse(self, cr, uid, exp, table, context): + """ transform the leaves of the expression """ + self.__exp = exp + self.__main_table = table + self.__all_tables.add(table) - def _rec_get(ids, table, parent=None, left='id', prefix=''): - if table._parent_store and (not table.pool._init): -# TODO: Improve where joins are implemented for many with '.', replace by: -# doms += ['&',(prefix+'.parent_left','<',o.parent_right),(prefix+'.parent_left','>=',o.parent_left)] + def child_of_domain(left, ids, left_model, parent=None, prefix=''): + """Returns a domain implementing the child_of operator for [(left,child_of,ids)], + either as a range using the parent_left/right tree lookup fields (when available), + or as an expanded [(left,in,child_ids)]""" + if left_model._parent_store and (not left_model.pool._init): + # TODO: Improve where joins are implemented for many with '.', replace by: + # doms += ['&',(prefix+'.parent_left','<',o.parent_right),(prefix+'.parent_left','>=',o.parent_left)] doms = [] - for o in table.browse(cr, uid, ids, context=context): + for o in left_model.browse(cr, uid, ids, context=context): if doms: doms.insert(0, OR_OPERATOR) doms += [AND_OPERATOR, ('parent_left', '<', o.parent_right), ('parent_left', '>=', o.parent_left)] if prefix: - return [(left, 'in', table.search(cr, uid, doms, context=context))] + return [(left, 'in', left_model.search(cr, uid, doms, context=context))] return doms else: - def rg(ids, table, parent): + def recursive_children(ids, model, parent_field): if not ids: return [] - ids2 = table.search(cr, uid, [(parent, 'in', ids)], context=context) - return ids + rg(ids2, table, parent) - return [(left, 'in', rg(ids, table, parent or table._parent_name))] - - def child_of_right_to_ids(value): - """ Normalize a single id, or a string, or a list of ids to a list of ids. + ids2 = model.search(cr, uid, [(parent_field, 'in', ids)], context=context) + return ids + recursive_children(ids2, model, parent_field) + return [(left, 'in', recursive_children(ids, left_model, parent or left_model._parent_name))] - This function is always used with _rec_get() above, so it should be - called directly from _rec_get instead of repeatedly before _rec_get. - - """ + def to_ids(value, field_obj): + """Normalize a single id or name, or a list of those, into a list of ids""" + names = [] if isinstance(value, basestring): - return [x[0] for x in field_obj.name_search(cr, uid, value, [], 'ilike', context=context, limit=None)] + names = [value] + if value and isinstance(value, (tuple, list)) and isinstance(value[0], basestring): + names = value + if names: + return flatten([[x[0] for x in field_obj.name_search(cr, uid, n, [], 'ilike', context=context, limit=None)] \ + for n in names]) elif isinstance(value, (int, long)): return [value] - else: - return list(value) - - self.__main_table = table - self.__all_tables.add(table) + return list(value) i = -1 while i + 1<len(self.__exp): i += 1 e = self.__exp[i] - if self._is_operator(e) or e == self.__DUMMY_LEAF: + if is_operator(e) or e == TRUE_LEAF or e == FALSE_LEAF: continue + + # check if the expression is valid + if not is_leaf(e): + raise ValueError("Invalid term %r in domain expression %r" % (e, exp)) + + # normalize the leaf's operator + e = normalize_leaf(*e) + self.__exp[i] = e left, operator, right = e - operator = operator.lower() - working_table = table - main_table = table - fargs = left.split('.', 1) - if fargs[0] in table._inherit_fields: + + working_table = table # The table containing the field (the name provided in the left operand) + field_path = left.split('.', 1) + + # If the field is _inherits'd, search for the working_table, + # and extract the field. + if field_path[0] in table._inherit_fields: while True: - field = main_table._columns.get(fargs[0], False) + field = working_table._columns.get(field_path[0]) if field: - working_table = main_table self.__field_tables[i] = working_table break - working_table = main_table.pool.get(main_table._inherit_fields[fargs[0]][0]) - if working_table not in self.__all_tables: - self.__joins.append('%s.%s=%s.%s' % (working_table._table, 'id', main_table._table, main_table._inherits[working_table._name])) - self.__all_tables.add(working_table) - main_table = working_table + next_table = working_table.pool.get(working_table._inherit_fields[field_path[0]][0]) + if next_table not in self.__all_tables: + self.__joins.append('%s."%s"=%s."%s"' % (next_table._table, 'id', working_table._table, working_table._inherits[next_table._name])) + self.__all_tables.add(next_table) + working_table = next_table + # Or (try to) directly extract the field. + else: + field = working_table._columns.get(field_path[0]) - field = working_table._columns.get(fargs[0], False) if not field: if left == 'id' and operator == 'child_of': - ids2 = child_of_right_to_ids(right) - dom = _rec_get(ids2, working_table) + ids2 = to_ids(right, table) + dom = child_of_domain(left, ids2, working_table) self.__exp = self.__exp[:i] + dom + self.__exp[i+1:] + else: + # field could not be found in model columns, it's probably invalid, unless + # it's one of the _log_access special fields + # TODO: make these fields explicitly available in self.columns instead! + if (field_path[0] not in MAGIC_COLUMNS) and (left not in MAGIC_COLUMNS): + raise ValueError("Invalid field %r in domain expression %r" % (left, exp)) continue field_obj = table.pool.get(field._obj) - if len(fargs) > 1: + if len(field_path) > 1: if field._type == 'many2one': - right = field_obj.search(cr, uid, [(fargs[1], operator, right)], context=context) - if right == []: - self.__exp[i] = ( 'id', '=', 0 ) - else: - self.__exp[i] = (fargs[0], 'in', right) + right = field_obj.search(cr, uid, [(field_path[1], operator, right)], context=context) + self.__exp[i] = (field_path[0], 'in', right) # Making search easier when there is a left operand as field.o2m or field.m2m - if field._type in ['many2many','one2many']: - right = field_obj.search(cr, uid, [(fargs[1], operator, right)], context=context) - right1 = table.search(cr, uid, [(fargs[0],'in', right)], context=context) - if right1 == []: - self.__exp[i] = ( 'id', '=', 0 ) - else: - self.__exp[i] = ('id', 'in', right1) + if field._type in ['many2many', 'one2many']: + right = field_obj.search(cr, uid, [(field_path[1], operator, right)], context=context) + right1 = table.search(cr, uid, [(field_path[0], 'in', right)], context=context) + self.__exp[i] = ('id', 'in', right1) - if not isinstance(field,fields.property): + if not isinstance(field, fields.property): continue if field._properties and not field.store: @@ -249,16 +473,16 @@ class expression(object): if not field._fnct_search: # the function field doesn't provide a search function and doesn't store # values in the database, so we must ignore it : we generate a dummy leaf - self.__exp[i] = self.__DUMMY_LEAF + self.__exp[i] = TRUE_LEAF else: subexp = field.search(cr, uid, table, left, [self.__exp[i]], context=context) if not subexp: - self.__exp[i] = self.__DUMMY_LEAF + self.__exp[i] = TRUE_LEAF else: # we assume that the expression is valid # we create a dummy leaf for forcing the parsing of the resulting expression self.__exp[i] = AND_OPERATOR - self.__exp.insert(i + 1, self.__DUMMY_LEAF) + self.__exp.insert(i + 1, TRUE_LEAF) for j, se in enumerate(subexp): self.__exp.insert(i + 2 + j, se) # else, the value of the field is store in the database, so we search on it @@ -266,11 +490,11 @@ class expression(object): elif field._type == 'one2many': # Applying recursivity on field(one2many) if operator == 'child_of': - ids2 = child_of_right_to_ids(right) + ids2 = to_ids(right, field_obj) if field._obj != working_table._name: - dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj) + dom = child_of_domain(left, ids2, field_obj, prefix=field._obj) else: - dom = _rec_get(ids2, working_table, parent=left) + dom = child_of_domain('id', ids2, working_table, parent=left) self.__exp = self.__exp[:i] + dom + self.__exp[i+1:] else: @@ -282,7 +506,7 @@ class expression(object): if ids2: operator = 'in' else: - if not isinstance(right,list): + if not isinstance(right, list): ids2 = [right] else: ids2 = right @@ -290,22 +514,16 @@ class expression(object): if operator in ['like','ilike','in','=']: #no result found with given search criteria call_null = False - self.__exp[i] = ('id','=',0) - else: - call_null = True - operator = 'in' # operator changed because ids are directly related to main object + self.__exp[i] = FALSE_LEAF else: - call_null = False - o2m_op = 'in' - if operator in ['not like','not ilike','not in','<>','!=']: - o2m_op = 'not in' - self.__exp[i] = ('id', o2m_op, self.__execute_recursive_in(cr, field._fields_id, field_obj._table, 'id', ids2, operator, field._type)) + ids2 = select_from_where(cr, field._fields_id, field_obj._table, 'id', ids2, operator) + if ids2: + call_null = False + self.__exp[i] = ('id', 'in', ids2) if call_null: - o2m_op = 'not in' - if operator in ['not like','not ilike','not in','<>','!=']: - o2m_op = 'in' - self.__exp[i] = ('id', o2m_op, self.__execute_recursive_in(cr, field._fields_id, field_obj._table, 'id', [], operator, field._type) or [0]) + o2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in' + self.__exp[i] = ('id', o2m_op, select_distinct_from_where_not_null(cr, field._fields_id, field_obj._table)) elif field._type == 'many2many': #FIXME @@ -313,10 +531,10 @@ class expression(object): def _rec_convert(ids): if field_obj == table: return ids - return self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, ids, operator, field._type) + return select_from_where(cr, field._id1, field._rel, field._id2, ids, operator) - ids2 = child_of_right_to_ids(right) - dom = _rec_get(ids2, field_obj) + ids2 = to_ids(right, field_obj) + dom = child_of_domain('id', ids2, field_obj) ids2 = field_obj.search(cr, uid, dom, context=context) self.__exp[i] = ('id', 'in', _rec_convert(ids2)) else: @@ -335,34 +553,28 @@ class expression(object): if operator in ['like','ilike','in','=']: #no result found with given search criteria call_null_m2m = False - self.__exp[i] = ('id','=',0) + self.__exp[i] = FALSE_LEAF else: - call_null_m2m = True operator = 'in' # operator changed because ids are directly related to main object else: call_null_m2m = False - m2m_op = 'in' - if operator in ['not like','not ilike','not in','<>','!=']: - m2m_op = 'not in' + m2m_op = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in' + self.__exp[i] = ('id', m2m_op, select_from_where(cr, field._id1, field._rel, field._id2, res_ids, operator) or [0]) - self.__exp[i] = ('id', m2m_op, self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, res_ids, operator, field._type) or [0]) if call_null_m2m: - m2m_op = 'not in' - if operator in ['not like','not ilike','not in','<>','!=']: - m2m_op = 'in' - self.__exp[i] = ('id', m2m_op, self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, [], operator, field._type) or [0]) + m2m_op = 'in' if operator in NEGATIVE_TERM_OPERATORS else 'not in' + self.__exp[i] = ('id', m2m_op, select_distinct_from_where_not_null(cr, field._id1, field._rel)) elif field._type == 'many2one': if operator == 'child_of': - ids2 = child_of_right_to_ids(right) - self.__operator = 'in' + ids2 = to_ids(right, field_obj) if field._obj != working_table._name: - dom = _rec_get(ids2, field_obj, left=left, prefix=field._obj) + dom = child_of_domain(left, ids2, field_obj, prefix=field._obj) else: - dom = _rec_get(ids2, working_table, parent=left) + dom = child_of_domain('id', ids2, working_table, parent=left) self.__exp = self.__exp[:i] + dom + self.__exp[i+1:] else: - def _get_expression(field_obj,cr, uid, left, right, operator, context=None): + def _get_expression(field_obj, cr, uid, left, right, operator, context=None): if context is None: context = {} c = context.copy() @@ -370,46 +582,35 @@ class expression(object): #Special treatment to ill-formed domains operator = ( operator in ['<','>','<=','>='] ) and 'in' or operator - dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in','<>':'not in'} - if isinstance(right,tuple): + dict_op = {'not in':'!=','in':'=','=':'in','!=':'not in'} + if isinstance(right, tuple): right = list(right) - if (not isinstance(right,list)) and operator in ['not in','in']: + if (not isinstance(right, list)) and operator in ['not in','in']: operator = dict_op[operator] - elif isinstance(right,list) and operator in ['<>','!=','=']: #for domain (FIELD,'=',['value1','value2']) + elif isinstance(right, list) and operator in ['!=','=']: #for domain (FIELD,'=',['value1','value2']) operator = dict_op[operator] - res_ids = field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c) - if not res_ids: - return ('id','=',0) - else: - right = map(lambda x: x[0], res_ids) - return (left, 'in', right) + res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)] + if operator in NEGATIVE_TERM_OPERATORS: + res_ids.append(False) # TODO this should not be appended if False was in 'right' + return (left, 'in', res_ids) m2o_str = False if right: if isinstance(right, basestring): # and not isinstance(field, fields.related): m2o_str = True - elif isinstance(right,(list,tuple)): + elif isinstance(right, (list, tuple)): m2o_str = True for ele in right: if not isinstance(ele, basestring): m2o_str = False break + if m2o_str: + self.__exp[i] = _get_expression(field_obj, cr, uid, left, right, operator, context=context) elif right == []: - m2o_str = False - if operator in ('not in', '!=', '<>'): - # (many2one not in []) should return all records - self.__exp[i] = self.__DUMMY_LEAF - else: - self.__exp[i] = ('id','=',0) - else: - new_op = '=' - if operator in ['not like','not ilike','not in','<>','!=']: - new_op = '!=' - #Is it ok to put 'left' and not 'id' ? - self.__exp[i] = (left,new_op,False) - - if m2o_str: - self.__exp[i] = _get_expression(field_obj,cr, uid, left, right, operator, context=context) + pass # Handled by __leaf_to_sql(). + else: # right is False + pass # Handled by __leaf_to_sql(). + else: # other field type # add the time part to datetime field when it's not there: @@ -425,127 +626,160 @@ class expression(object): self.__exp[i] = tuple(self.__exp[i]) if field.translate: - if operator in ('like', 'ilike', 'not like', 'not ilike'): + need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike') + sql_operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator) + if need_wildcard: right = '%%%s%%' % right - operator = operator == '=like' and 'like' or operator - - query1 = '( SELECT res_id' \ + subselect = '( SELECT res_id' \ ' FROM ir_translation' \ ' WHERE name = %s' \ ' AND lang = %s' \ ' AND type = %s' instr = ' %s' #Covering in,not in operators with operands (%s,%s) ,etc. - if operator in ['in','not in']: + if sql_operator in ['in','not in']: instr = ','.join(['%s'] * len(right)) - query1 += ' AND value ' + operator + ' ' +" (" + instr + ")" \ + subselect += ' AND value ' + sql_operator + ' ' +" (" + instr + ")" \ ') UNION (' \ ' SELECT id' \ ' FROM "' + working_table._table + '"' \ - ' WHERE "' + left + '" ' + operator + ' ' +" (" + instr + "))" + ' WHERE "' + left + '" ' + sql_operator + ' ' +" (" + instr + "))" else: - query1 += ' AND value ' + operator + instr + \ + subselect += ' AND value ' + sql_operator + instr + \ ') UNION (' \ ' SELECT id' \ ' FROM "' + working_table._table + '"' \ - ' WHERE "' + left + '" ' + operator + instr + ")" + ' WHERE "' + left + '" ' + sql_operator + instr + ")" - query2 = [working_table._name + ',' + left, + params = [working_table._name + ',' + left, context.get('lang', False) or 'en_US', 'model', right, right, ] - self.__exp[i] = ('id', 'inselect', (query1, query2)) - return self + self.__exp[i] = ('id', 'inselect', (subselect, params)) def __leaf_to_sql(self, leaf, table): - if leaf == self.__DUMMY_LEAF: - return ('(1=1)', []) left, operator, right = leaf - if operator == 'inselect': - query = '(%s.%s in (%s))' % (table._table, left, right[0]) + # final sanity checks - should never fail + assert operator in (TERM_OPERATORS + ('inselect',)), \ + "Invalid operator %r in domain term %r" % (operator, leaf) + assert leaf in (TRUE_LEAF, FALSE_LEAF) or left in table._all_columns \ + or left in MAGIC_COLUMNS, "Invalid field %r in domain term %r" % (left, leaf) + + if leaf == TRUE_LEAF: + query = 'TRUE' + params = [] + + elif leaf == FALSE_LEAF: + query = 'FALSE' + params = [] + + elif operator == 'inselect': + query = '(%s."%s" in (%s))' % (table._table, left, right[0]) params = right[1] + elif operator in ['in', 'not in']: - params = right and right[:] or [] - len_before = len(params) - for i in range(len_before)[::-1]: - if params[i] == False: - del params[i] - - len_after = len(params) - check_nulls = len_after != len_before - query = '(1=0)' - - if len_after: - if left == 'id': - instr = ','.join(['%s'] * len_after) - else: - instr = ','.join([table._columns[left]._symbol_set[0]] * len_after) - query = '(%s.%s %s (%s))' % (table._table, left, operator, instr) - else: - # the case for [field, 'in', []] or [left, 'not in', []] + # Two cases: right is a boolean or a list. The boolean case is an + # abuse and handled for backward compatibility. + if isinstance(right, bool): + _logger.warning("The domain term '%s' should use the '=' or '!=' operator." % (leaf,)) if operator == 'in': - query = '(%s.%s IS NULL)' % (table._table, left) + r = 'NOT NULL' if right else 'NULL' else: - query = '(%s.%s IS NOT NULL)' % (table._table, left) - if check_nulls: - query = '(%s OR %s.%s IS NULL)' % (query, table._table, left) - else: + r = 'NULL' if right else 'NOT NULL' + query = '(%s."%s" IS %s)' % (table._table, left, r) + params = [] + elif isinstance(right, (list, tuple)): + params = right[:] + check_nulls = False + for i in range(len(params))[::-1]: + if params[i] == False: + check_nulls = True + del params[i] + + if params: + if left == 'id': + instr = ','.join(['%s'] * len(params)) + else: + instr = ','.join([table._columns[left]._symbol_set[0]] * len(params)) + query = '(%s."%s" %s (%s))' % (table._table, left, operator, instr) + else: + # The case for (left, 'in', []) or (left, 'not in', []). + query = 'FALSE' if operator == 'in' else 'TRUE' + + if check_nulls and operator == 'in': + query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left) + elif not check_nulls and operator == 'not in': + query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left) + elif check_nulls and operator == 'not in': + query = '(%s AND %s."%s" IS NOT NULL)' % (query, table._table, left) # needed only for TRUE. + else: # Must not happen + raise ValueError("Invalid domain term %r" % (leaf,)) + + elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '='): + query = '(%s."%s" IS NULL or %s."%s" = false )' % (table._table, left, table._table, left) params = [] - if right == False and (leaf[0] in table._columns) and table._columns[leaf[0]]._type=="boolean" and (operator == '='): - query = '(%s.%s IS NULL or %s.%s = false )' % (table._table, left,table._table, left) - elif (((right == False) and (type(right)==bool)) or (right is None)) and (operator == '='): - query = '%s.%s IS NULL ' % (table._table, left) - elif right == False and (leaf[0] in table._columns) and table._columns[leaf[0]]._type=="boolean" and (operator in ['<>', '!=']): - query = '(%s.%s IS NOT NULL and %s.%s != false)' % (table._table, left,table._table, left) - elif (((right == False) and (type(right)==bool)) or right is None) and (operator in ['<>', '!=']): - query = '%s.%s IS NOT NULL' % (table._table, left) - elif (operator == '=?'): - op = '=' - if (right is False or right is None): - return ( 'TRUE',[]) - if left in table._columns: - format = table._columns[left]._symbol_set[0] - query = '(%s.%s %s %s)' % (table._table, left, op, format) - params = table._columns[left]._symbol_set[1](right) - else: - query = "(%s.%s %s '%%s')" % (table._table, left, op) - params = right + elif (right is False or right is None) and (operator == '='): + query = '%s."%s" IS NULL ' % (table._table, left) + params = [] + elif right == False and (left in table._columns) and table._columns[left]._type=="boolean" and (operator == '!='): + query = '(%s."%s" IS NOT NULL and %s."%s" != false)' % (table._table, left, table._table, left) + params = [] + + elif (right is False or right is None) and (operator == '!='): + query = '%s."%s" IS NOT NULL' % (table._table, left) + params = [] + + elif (operator == '=?'): + if (right is False or right is None): + # '=?' is a short-circuit that makes the term TRUE if right is None or False + query = 'TRUE' + params = [] else: - if left == 'id': - query = '%s.id %s %%s' % (table._table, operator) + # '=?' behaves like '=' in other cases + query, params = self.__leaf_to_sql((left, '=', right), table) + + elif left == 'id': + query = '%s.id %s %%s' % (table._table, operator) + params = right + + else: + need_wildcard = operator in ('like', 'ilike', 'not like', 'not ilike') + sql_operator = {'=like':'like','=ilike':'ilike'}.get(operator,operator) + + if left in table._columns: + format = need_wildcard and '%s' or table._columns[left]._symbol_set[0] + if self.has_unaccent and sql_operator in ('ilike', 'not ilike'): + query = '(unaccent(%s."%s") %s unaccent(%s))' % (table._table, left, sql_operator, format) + else: + query = '(%s."%s" %s %s)' % (table._table, left, sql_operator, format) + elif left in MAGIC_COLUMNS: + query = "(%s.\"%s\" %s %%s)" % (table._table, left, sql_operator) params = right + else: # Must not happen + raise ValueError("Invalid field %r in domain term %r" % (left, leaf)) + + add_null = False + if need_wildcard: + if isinstance(right, str): + str_utf8 = right + elif isinstance(right, unicode): + str_utf8 = right.encode('utf-8') else: - like = operator in ('like', 'ilike', 'not like', 'not ilike') - - op = {'=like':'like','=ilike':'ilike'}.get(operator,operator) - if left in table._columns: - format = like and '%s' or table._columns[left]._symbol_set[0] - query = '(%s.%s %s %s)' % (table._table, left, op, format) - else: - query = "(%s.%s %s '%s')" % (table._table, left, op, right) - - add_null = False - if like: - if isinstance(right, str): - str_utf8 = right - elif isinstance(right, unicode): - str_utf8 = right.encode('utf-8') - else: - str_utf8 = str(right) - params = '%%%s%%' % str_utf8 - add_null = not str_utf8 - elif left in table._columns: - params = table._columns[left]._symbol_set[1](right) + str_utf8 = str(right) + params = '%%%s%%' % str_utf8 + add_null = not str_utf8 + elif left in table._columns: + params = table._columns[left]._symbol_set[1](right) - if add_null: - query = '(%s OR %s IS NULL)' % (query, left) + if add_null: + query = '(%s OR %s."%s" IS NULL)' % (query, table._table, left) if isinstance(params, basestring): params = [params] @@ -555,25 +789,26 @@ class expression(object): def to_sql(self): stack = [] params = [] + # Process the domain from right to left, using a stack, to generate a SQL expression. for i, e in reverse_enumerate(self.__exp): - if self._is_leaf(e, internal=True): + if is_leaf(e, internal=True): table = self.__field_tables.get(i, self.__main_table) q, p = self.__leaf_to_sql(e, table) params.insert(0, p) stack.append(q) + elif e == NOT_OPERATOR: + stack.append('(NOT (%s))' % (stack.pop(),)) else: - if e == NOT_OPERATOR: - stack.append('(NOT (%s))' % (stack.pop(),)) - else: - ops = {AND_OPERATOR: ' AND ', OR_OPERATOR: ' OR '} - q1 = stack.pop() - q2 = stack.pop() - stack.append('(%s %s %s)' % (q1, ops[e], q2,)) + ops = {AND_OPERATOR: ' AND ', OR_OPERATOR: ' OR '} + q1 = stack.pop() + q2 = stack.pop() + stack.append('(%s %s %s)' % (q1, ops[e], q2,)) - query = ' AND '.join(reversed(stack)) + assert len(stack) == 1 + query = stack[0] joins = ' AND '.join(self.__joins) if joins: - query = '(%s) AND (%s)' % (joins, query) + query = '(%s) AND %s' % (joins, query) return (query, flatten(params)) def get_tables(self): diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 7a8f460f5cb6e5eec998a353ccbd8989ee765811..ccc1d740403b24b6538ff8ad456d1a43ae8b304a 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -55,7 +55,7 @@ def _symbol_set(symb): class _column(object): """ Base of all fields, a database column - + An instance of this object is a *description* of a database column. It will not hold any data, but only provide the methods to manipulate data of an ORM record or even prepare/update the database to hold such a field of data. @@ -675,7 +675,7 @@ class many2many(_column): if not cr.fetchone(): cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, act[1])) elif act[0] == 5: - cr.execute('update '+self._rel+' set '+self._id2+'=null where '+self._id2+'=%s', (id,)) + cr.execute('delete from '+self._rel+' where ' + self._id1 + ' = %s', (id,)) elif act[0] == 6: d1, d2,tables = obj.pool.get('ir.rule').domain_get(cr, user, obj._name, context=context) @@ -1295,7 +1295,7 @@ class property(function): def _fnct_read(self, obj, cr, uid, ids, prop_names, obj_dest, context=None): prop = obj.pool.get('ir.property') - # get the default values (for res_id = False) for the property fields + # get the default values (for res_id = False) for the property fields default_val = self._get_defaults(obj, cr, uid, prop_names, context) # build the dictionary that will be returned @@ -1417,12 +1417,16 @@ class column_info(object): :attr parent_column: the name of the column containing the m2o relationship to the parent model that contains this column, None for local columns. + :attr original_parent: if the column is inherited, name of the original + parent model that contains it i.e in case of multilevel + inheritence, None for local columns. """ - def __init__(self, name, column, parent_model=None, parent_column=None): + def __init__(self, name, column, parent_model=None, parent_column=None, original_parent=None): self.name = name self.column = column self.parent_model = parent_model self.parent_column = parent_column + self.original_parent = original_parent # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index b87672c012d4a034390b236fb0dd9ad447e2f5f2..37dd1010d2fcd0730bea93657db5fc2dcf8a13e5 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -38,7 +38,7 @@ - classicals (varchar, integer, boolean, ...) - relations (one2many, many2one, many2many) - functions - + """ import calendar @@ -165,7 +165,7 @@ def modifiers_tests(): test_modifiers({}, '{}') test_modifiers({"invisible": True}, '{"invisible": true}') test_modifiers({"invisible": False}, '{}') - + def check_object_name(name): """ Check if the given name is a valid openerp object name. @@ -212,6 +212,19 @@ def last_day_of_current_month(): def intersect(la, lb): return filter(lambda x: x in lb, la) +def fix_import_export_id_paths(fieldname): + """ + Fixes the id fields in import and exports, and splits field paths + on '/'. + + :param str fieldname: name of the field to import/export + :return: split field name + :rtype: list of str + """ + fixed_db_id = re.sub(r'([^/])\.id', r'\1/.id', fieldname) + fixed_external_id = re.sub(r'([^/]):id', r'\1/id', fixed_db_id) + return fixed_external_id.split('/') + class except_orm(Exception): def __init__(self, name, value): self.name = name @@ -252,7 +265,7 @@ class browse_null(object): # class browse_record_list(list): """ Collection of browse objects - + Such an instance will be returned when doing a ``browse([ids..])`` and will be iterable, yielding browse() objects """ @@ -267,9 +280,9 @@ class browse_record_list(list): class browse_record(object): """ An object that behaves like a row of an object's table. It has attributes after the columns of the corresponding object. - + Examples:: - + uobj = pool.get('res.users') user_rec = uobj.browse(cr, uid, 104) name = user_rec.name @@ -326,9 +339,12 @@ class browse_record(object): col = self._table._inherit_fields[name][2] elif hasattr(self._table, str(name)): attr = getattr(self._table, name) - if isinstance(attr, (types.MethodType, types.LambdaType, types.FunctionType)): - return lambda *args, **argv: attr(self._cr, self._uid, [self._id], *args, **argv) + def function_proxy(*args, **kwargs): + if 'context' not in kwargs and self._context: + kwargs.update(context=self._context) + return attr(self._cr, self._uid, [self._id], *args, **kwargs) + return function_proxy else: return attr else: @@ -475,6 +491,16 @@ class browse_record(object): __repr__ = __str__ + def refresh(self): + """Force refreshing this browse_record's data and all the data of the + records that belong to the same cache, by emptying the cache completely, + preserving only the record identifiers (for prefetching optimizations). + """ + for model, model_cache in self._cache.iteritems(): + # only preserve the ids of the records that were in the cache + cached_ids = dict([(i, {'id': i}) for i in model_cache.keys()]) + self._cache[model].clear() + self._cache[model].update(cached_ids) def get_pg_type(f): """ @@ -587,22 +613,32 @@ class orm_template(object): _order = 'id' _sequence = None _description = None + + # structure: + # { 'parent_model': 'm2o_field', ... } _inherits = {} - # Mapping from inherits'd field name to triple (m, r, f) - # where m is the model from which it is inherits'd, - # r is the (local) field towards m, - # and f is the _column object itself. + + # Mapping from inherits'd field name to triple (m, r, f, n) where m is the + # model from which it is inherits'd, r is the (local) field towards m, f + # is the _column object itself, and n is the original (i.e. top-most) + # parent model. + # Example: + # { 'field_name': ('parent_model', 'm2o_field_to_reach_parent', + # field_column_obj, origina_parent_model), ... } _inherit_fields = {} + # Mapping field name/column_info object # This is similar to _inherit_fields but: # 1. includes self fields, # 2. uses column_info instead of a triple. _all_columns = {} + _table = None _invalids = set() _log_create = False CONCURRENCY_CHECK_FIELD = '__last_update' + def log(self, cr, uid, id, message, secondary=False, context=None): if context and context.get('disable_log'): return True @@ -770,7 +806,7 @@ class orm_template(object): 'You may need to add a dependency on the parent class\' module.' % (name, parent_name)) nattr = {} for s in attributes: - new = copy.copy(getattr(pool.get(parent_name), s)) + new = copy.copy(getattr(pool.get(parent_name), s, {})) if s == '_columns': # Don't _inherit custom fields. for c in new.keys(): @@ -872,7 +908,7 @@ class orm_template(object): elif field_type == 'integer': return 0 elif field_type == 'boolean': - return False + return 'False' return '' def selection_field(in_field): @@ -984,11 +1020,7 @@ class orm_template(object): cols = self._columns.copy() for f in self._inherit_fields: cols.update({f: self._inherit_fields[f][2]}) - def fsplit(fieldname): - fixed_db_id = re.sub(r'([^/])\.id', r'\1/.id', fieldname) - fixed_external_id = re.sub(r'([^/]):id', r'\1/id', fixed_db_id) - return fixed_external_id.split('/') - fields_to_export = map(fsplit, fields_to_export) + fields_to_export = map(fix_import_export_id_paths, fields_to_export) datas = [] for row in self.browse(cr, uid, ids, context): datas += self.__export_row(cr, uid, row, fields_to_export, context) @@ -1024,10 +1056,7 @@ class orm_template(object): """ if not context: context = {} - def _replace_field(x): - x = re.sub('([a-z0-9A-Z_])\\.id$', '\\1/.id', x) - return x.replace(':id','/id').split('/') - fields = map(_replace_field, fields) + fields = map(fix_import_export_id_paths, fields) logger = netsvc.Logger() ir_model_data_obj = self.pool.get('ir.model.data') @@ -1089,7 +1118,7 @@ class orm_template(object): if line[i] and skip: return False continue - + #set the mode for m2o, o2m, m2m : xml_id/id/name if len(field) == len(prefix)+1: mode = False @@ -1102,7 +1131,7 @@ class orm_template(object): for db_id in line.split(config.get('csv_internal_sep')): res.append(_get_id(relation, db_id, current_module, mode)) return [(6,0,res)] - + # ID of the record using a XML ID if field[len(prefix)]=='id': try: @@ -1126,9 +1155,9 @@ class orm_template(object): relation_obj = self.pool.get(relation) newfd = relation_obj.fields_get( cr, uid, context=context ) pos = position - + res = many_ids(line[i], relation, current_module, mode) - + first = 0 while pos < len(datas): res2 = process_liness(self, datas, prefix + [field[len(prefix)]], current_module, relation_obj._name, newfd, pos, first) @@ -1138,15 +1167,15 @@ class orm_template(object): nbrmax = max(nbrmax, pos) warning += w2 first += 1 - + if data_res_id2: res.append((4, data_res_id2)) - + if (not newrow) or not reduce(lambda x, y: x or y, newrow.values(), 0): break res.append( (data_res_id2 and 1 or 0, data_res_id2 or 0, newrow) ) - + elif fields_def[field[len(prefix)]]['type']=='many2one': relation = fields_def[field[len(prefix)]]['relation'] @@ -1175,7 +1204,7 @@ class orm_template(object): else: res = line[i] - + row[field[len(prefix)]] = res or False result = (row, nbrmax, warning, data_res_id, xml_id) @@ -1189,7 +1218,7 @@ class orm_template(object): position = 0 while position<len(datas): res = {} - + (res, position, warning, res_id, xml_id) = \ process_liness(self, datas, [], current_module, self._name, fields_def, position=position) if len(warning): @@ -1201,7 +1230,7 @@ class orm_template(object): current_module, res, mode=mode, xml_id=xml_id, noupdate=noupdate, res_id=res_id, context=context) except Exception, e: - return (-1, res, 'Line ' + str(position) +' : ' + str(e), '') + return (-1, res, 'Line ' + str(position) + ' : ' + tools.ustr(e), '') if config.get('import_partial', False) and filename and (not (position%100)): data = pickle.load(file(config.get('import_partial'))) @@ -1556,7 +1585,7 @@ class orm_template(object): field = model_fields.get(node.get('name')) if field: transfer_field_to_modifiers(field, modifiers) - + elif node.tag in ('form', 'tree'): result = self.view_header_get(cr, user, False, node.tag, context) @@ -1887,22 +1916,20 @@ class orm_template(object): raise_view_error("Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, inherit_id) return source - def apply_view_inheritance(source, inherit_id): + def apply_view_inheritance(cr, user, source, inherit_id): """ Apply all the (directly and indirectly) inheriting views. :param source: a parent architecture to modify (with parent modifications already applied) - :param inherit_id: the database id of the parent view + :param inherit_id: the database view_id of the parent view :return: a modified source where all the modifying architecture are applied """ - # get all views which inherit from (ie modify) this view - cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name)) - sql_inherit = cr.fetchall() - for (inherit, id) in sql_inherit: - source = apply_inheritance_specs(source, inherit, id) - source = apply_view_inheritance(source, id) + sql_inherit = self.pool.get('ir.ui.view').get_inheriting_views_arch(cr, user, inherit_id, self._name) + for (view_arch, view_id) in sql_inherit: + source = apply_inheritance_specs(source, view_arch, view_id) + source = apply_view_inheritance(cr, user, source, view_id) return source result = {'type': view_type, 'model': self._name} @@ -1945,7 +1972,7 @@ class orm_template(object): result['view_id'] = sql_res['id'] source = etree.fromstring(encode(sql_res['arch'])) - result['arch'] = apply_view_inheritance(source, result['view_id']) + result['arch'] = apply_view_inheritance(cr, user, source, result['view_id']) result['name'] = sql_res['name'] result['field_parent'] = sql_res['field_parent'] or False @@ -2097,19 +2124,15 @@ class orm_template(object): raise NotImplementedError(_('The search method is not implemented on this object !')) def name_get(self, cr, user, ids, context=None): + """Returns the preferred display value (text representation) for the records with the + given ``ids``. By default this will be the value of the ``name`` column, unless + the model implements a custom behavior. + Can sometimes be seen as the inverse function of :meth:`~.name_search`, but it is not + guaranteed to be. + + :rtype: list(tuple) + :return: list of pairs ``(id,text_repr)`` for all records with the given ``ids``. """ - - :param cr: database cursor - :param user: current user id - :type user: integer - :param ids: list of ids - :param context: context arguments, like lang, time zone - :type context: dictionary - :return: tuples with the text representation of requested objects for to-many relationships - - """ - if not context: - context = {} if not ids: return [] if isinstance(ids, (int, long)): @@ -2118,38 +2141,39 @@ class orm_template(object): [self._rec_name], context, load='_classic_write')] def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100): - """ - Search for records and their display names according to a search domain. - - :param cr: database cursor - :param user: current user id - :param name: object name to search - :param args: list of tuples specifying search criteria [('field_name', 'operator', 'value'), ...] - :param operator: operator for search criterion - :param context: context arguments, like lang, time zone - :type context: dictionary - :param limit: optional max number of records to return - :return: list of object names matching the search criteria, used to provide completion for to-many relationships - - This method is equivalent of :py:meth:`~osv.osv.osv.search` on **name** + :py:meth:`~osv.osv.osv.name_get` on the result. - See :py:meth:`~osv.osv.osv.search` for an explanation of the possible values for the search domain specified in **args**. - + """Search for records that have a display name matching the given ``name`` pattern if compared + with the given ``operator``, while also matching the optional search domain (``args``). + This is used for example to provide suggestions based on a partial value for a relational + field. + Sometimes be seen as the inverse function of :meth:`~.name_get`, but it is not + guaranteed to be. + + This method is equivalent to calling :meth:`~.search` with a search domain based on ``name`` + and then :meth:`~.name_get` on the result of the search. + + :param list args: optional search domain (see :meth:`~.search` for syntax), + specifying further restrictions + :param str operator: domain operator for matching the ``name`` pattern, such as ``'like'`` + or ``'='``. + :param int limit: optional max number of records to return + :rtype: list + :return: list of pairs ``(id,text_repr)`` for all matching records. """ return self._name_search(cr, user, name, args, operator, context, limit) def name_create(self, cr, uid, name, context=None): - """ - Creates a new record by calling :py:meth:`~osv.osv.osv.create` with only one - value provided: the name of the new record (``_rec_name`` field). - The new record will also be initialized with any default values applicable - to this model, or provided through the context. The usual behavior of - :py:meth:`~osv.osv.osv.create` applies. - Similarly, this method may raise an exception if the model has multiple - required fields and some do not have default values. - - :param name: name of the record to create - - :return: the :py:meth:`~osv.osv.osv.name_get` value for the newly-created record. + """Creates a new record by calling :meth:`~.create` with only one + value provided: the name of the new record (``_rec_name`` field). + The new record will also be initialized with any default values applicable + to this model, or provided through the context. The usual behavior of + :meth:`~.create` applies. + Similarly, this method may raise an exception if the model has multiple + required fields and some do not have default values. + + :param name: name of the record to create + + :rtype: tuple + :return: the :meth:`~.name_get` pair value for the newly-created record. """ rec_id = self.create(cr, uid, {self._rec_name: name}, context); return self.name_get(cr, uid, [rec_id], context)[0] @@ -2172,7 +2196,19 @@ class orm_template(object): def copy(self, cr, uid, id, default=None, context=None): raise NotImplementedError(_('The copy method is not implemented on this object !')) - def exists(self, cr, uid, id, context=None): + def exists(self, cr, uid, ids, context=None): + """Checks whether the given id or ids exist in this model, + and return the list of ids that do. This is simple to use for + a truth test on a browse_record:: + + if record.exists(): + pass + + :param ids: id or list of ids to check for existence + :type ids: int or [int] + :return: the list of ids that currently exist, out of + the given `ids` + """ raise NotImplementedError(_('The exists method is not implemented on this object !')) def read_string(self, cr, uid, id, langs, fields=None, context=None): @@ -2259,6 +2295,16 @@ class orm_template(object): except AttributeError: pass + def check_access_rule(self, cr, uid, ids, operation, context=None): + """Verifies that the operation given by ``operation`` is allowed for the user + according to ir.rules. + + :param operation: one of ``write``, ``unlink`` + :raise except_orm: * if current ir.rules do not permit this operation. + :return: None if the operation is allowed + """ + raise NotImplementedError(_('The check_access_rule method is not implemented on this object !')) + class orm_memory(orm_template): _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists'] @@ -2414,8 +2460,7 @@ class orm_memory(orm_template): args = [('active', '=', 1)] if args: import expression - e = expression.expression(args) - e.parse(cr, user, self, context) + e = expression.expression(cr, user, args, self, context) res = e.exp return res or [] @@ -2445,6 +2490,9 @@ class orm_memory(orm_template): break f = True for arg in result: + if len(arg) != 3: + # Amazing hack: orm_memory handles only simple domains. + continue if arg[1] == '=': val = eval('data[arg[0]]'+'==' +' arg[2]', locals()) elif arg[1] in ['<', '>', 'in', 'not in', '<=', '>=', '<>']: @@ -2488,8 +2536,28 @@ class orm_memory(orm_template): # nothing to check in memory... pass - def exists(self, cr, uid, id, context=None): - return id in self.datas + def exists(self, cr, uid, ids, context=None): + if isinstance(ids, (long,int)): + ids = [ids] + return [id for id in ids if id in self.datas] + + def check_access_rule(self, cr, uid, ids, operation, context=None): + # ir.rules do not currently apply for orm.memory instances, + # only the implicit visibility=owner one. + for id in ids: + self._check_access(uid, id, operation) + +# Definition of log access columns, automatically added to models if +# self._log_access is True +LOG_ACCESS_COLUMNS = { + 'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL', + 'create_date': 'TIMESTAMP', + 'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL', + 'write_date': 'TIMESTAMP' +} +# special columns automatically created by the ORM +MAGIC_COLUMNS = ['id'] + LOG_ACCESS_COLUMNS.keys() + \ + ['internal.create_uid', 'internal.date_access'] # for osv_memory only class orm(orm_template): _sql_constraints = [] @@ -2497,6 +2565,7 @@ class orm(orm_template): _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists'] __logger = logging.getLogger('orm') __schema = logging.getLogger('orm.schema') + def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False): """ Get the list of records in list view grouped by the given ``groupby`` fields @@ -2617,20 +2686,22 @@ class orm(orm_template): del d['id'] return data - def _inherits_join_add(self, parent_model_name, query): + def _inherits_join_add(self, current_table, parent_model_name, query): """ Add missing table SELECT and JOIN clause to ``query`` for reaching the parent table (no duplicates) - + :param current_table: current model object :param parent_model_name: name of the parent model for which the clauses should be added :param query: query object on which the JOIN should be added """ - inherits_field = self._inherits[parent_model_name] + inherits_field = current_table._inherits[parent_model_name] parent_model = self.pool.get(parent_model_name) parent_table_name = parent_model._table quoted_parent_table_name = '"%s"' % parent_table_name if quoted_parent_table_name not in query.tables: query.tables.append(quoted_parent_table_name) - query.where_clause.append('("%s".%s = %s.id)' % (self._table, inherits_field, parent_table_name)) + query.where_clause.append('(%s.%s = %s.id)' % (current_table._table, inherits_field, parent_table_name)) + + def _inherits_join_calc(self, field, query): """ @@ -2645,7 +2716,7 @@ class orm(orm_template): while field in current_table._inherit_fields and not field in current_table._columns: parent_model_name = current_table._inherit_fields[field][0] parent_table = self.pool.get(parent_model_name) - self._inherits_join_add(parent_model_name, query) + self._inherits_join_add(current_table, parent_model_name, query) current_table = parent_table return '"%s".%s' % (current_table._table, field) @@ -2707,7 +2778,7 @@ class orm(orm_template): pass if not val_id: raise except_orm(_('ValidateError'), - _('Invalid value for reference field "%s" (last part must be a non-zero integer): "%s"') % (field, value)) + _('Invalid value for reference field "%s.%s" (last part must be a non-zero integer): "%s"') % (self._table, field, value)) val = val_model else: val = value @@ -2717,13 +2788,13 @@ class orm(orm_template): elif val in dict(self._columns[field].selection(self, cr, uid, context=context)): return raise except_orm(_('ValidateError'), - _('The value "%s" for the field "%s" is not in the selection') % (value, field)) + _('The value "%s" for the field "%s.%s" is not in the selection') % (value, self._table, field)) def _check_removed_columns(self, cr, log=False): # iterate on the database columns to drop the NOT NULL constraints # of fields which were required but have been removed (or will be added by another module) columns = [c for c in self._columns if not (isinstance(self._columns[c], fields.function) and not self._columns[c].store)] - columns += ('id', 'write_uid', 'write_date', 'create_uid', 'create_date') # openerp access columns + columns += MAGIC_COLUMNS cr.execute("SELECT a.attname, a.attnotnull" " FROM pg_class c, pg_attribute a" " WHERE c.relname=%s" @@ -2790,7 +2861,7 @@ class orm(orm_template): column_data = self._select_column_data(cr) for k, f in self._columns.iteritems(): - if k in ('id', 'write_uid', 'write_date', 'create_uid', 'create_date'): + if k in MAGIC_COLUMNS: continue # Don't update custom (also called manual) fields if f.manual and not update_custom_fields: @@ -2883,7 +2954,7 @@ class orm(orm_template): cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, k)) cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s"' % (self._table, k, newname)) cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1])) - cr.execute("COMMENT ON COLUMN %s.%s IS '%s'" % (self._table, k, f.string.replace("'", "''"))) + cr.execute("COMMENT ON COLUMN %s.\"%s\" IS %%s" % (self._table, k), (f.string,)) self.__schema.debug("Table '%s': column '%s' has changed type (DB=%s, def=%s), data moved to column %s !", self._table, k, f_pg_type, f._type, newname) @@ -2970,7 +3041,7 @@ class orm(orm_template): if not isinstance(f, fields.function) or f.store: # add the missing field cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1])) - cr.execute("COMMENT ON COLUMN %s.%s IS '%s'" % (self._table, k, f.string.replace("'", "''"))) + cr.execute("COMMENT ON COLUMN %s.\"%s\" IS %%s" % (self._table, k), (f.string,)) self.__schema.debug("Table '%s': added column '%s' with definition=%s", self._table, k, get_pg_type(f)[1]) @@ -3053,7 +3124,7 @@ class orm(orm_template): def _create_table(self, cr): cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITHOUT OIDS' % (self._table,)) - cr.execute("COMMENT ON TABLE \"%s\" IS '%s'" % (self._table, self._description.replace("'", "''"))) + cr.execute(("COMMENT ON TABLE \"%s\" IS %%s" % self._table), (self._description,)) self.__schema.debug("Table '%s': created", self._table) @@ -3092,23 +3163,17 @@ class orm(orm_template): def _add_log_columns(self, cr): - logs = { - 'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL', - 'create_date': 'TIMESTAMP', - 'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL', - 'write_date': 'TIMESTAMP' - } - for k in logs: + for field, field_def in LOG_ACCESS_COLUMNS.iteritems(): cr.execute(""" SELECT c.relname FROM pg_class c, pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid - """, (self._table, k)) + """, (self._table, field)) if not cr.rowcount: - cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, logs[k])) + cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, field, field_def)) cr.commit() self.__schema.debug("Table '%s': added column '%s' with definition=%s", - self._table, k, logs[k]) + self._table, field, field_def) def _select_column_data(self, cr): @@ -3263,7 +3328,7 @@ class orm(orm_template): if f == order: ok = False if ok: - self.pool._store_function[object].append( (self._name, store_field, fnct, fields2, order, length)) + 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: @@ -3336,9 +3401,9 @@ class orm(orm_template): for table in self._inherits: other = self.pool.get(table) for col in other._columns.keys(): - res[col] = (table, self._inherits[table], other._columns[col]) + res[col] = (table, self._inherits[table], other._columns[col], table) for col in other._inherit_fields.keys(): - res[col] = (table, self._inherits[table], other._inherit_fields[col][2]) + res[col] = (table, self._inherits[table], other._inherit_fields[col][2], other._inherit_fields[col][3]) self._inherit_fields = res self._all_columns = self._get_column_infos() self._inherits_reload_src() @@ -3349,8 +3414,8 @@ class orm(orm_template): inherited field via _inherits) to a ``column_info`` struct giving detailed columns """ result = {} - for k, (parent, m2o, col) in self._inherit_fields.iteritems(): - result[k] = fields.column_info(k, col, parent, m2o) + for k, (parent, m2o, col, original_parent) in self._inherit_fields.iteritems(): + result[k] = fields.column_info(k, col, parent, m2o, original_parent) for k, col in self._columns.iteritems(): result[k] = fields.column_info(k, col) return result @@ -3454,7 +3519,7 @@ class orm(orm_template): res = [] if len(fields_pre): def convert_field(f): - f_qual = "%s.%s" % (self._table, f) # need fully-qualified references in case len(tables) > 1 + f_qual = '%s."%s"' % (self._table, f) # need fully-qualified references in case len(tables) > 1 if f in ('create_date', 'write_date'): return "date_trunc('second', %s) as %s" % (f_qual, f) if f == self.CONCURRENCY_CHECK_FIELD: @@ -4059,7 +4124,7 @@ class orm(orm_template): upd_todo = [] for v in vals.keys(): if v in self._inherit_fields: - (table, col, col_detail) = self._inherit_fields[v] + (table, col, col_detail, original_parent) = self._inherit_fields[v] tocreate[table][v] = vals[v] del vals[v] else: @@ -4206,44 +4271,52 @@ class orm(orm_template): :return: [(priority, model_name, [record_ids,], [function_fields,])] """ - # FIXME: rewrite, cleanup, use real variable names - # e.g.: http://pastie.org/1222060 - result = {} - fncts = self.pool._store_function.get(self._name, []) - for fnct in range(len(fncts)): - if fncts[fnct][3]: - ok = False - if not fields: - ok = True - for f in (fields or []): - if f in fncts[fnct][3]: - ok = True - break - if not ok: - continue + if fields is None: fields = [] + stored_functions = self.pool._store_function.get(self._name, []) - result.setdefault(fncts[fnct][0], {}) + # use indexed names for the details of the stored_functions: + model_name_, func_field_to_compute_, id_mapping_fnct_, trigger_fields_, priority_ = range(5) + # only keep functions that should be triggered for the ``fields`` + # being written to. + 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 - ids2 = fncts[fnct][2](self, cr, ROOT_USER_ID, ids, context) - for id in filter(None, ids2): - result[fncts[fnct][0]].setdefault(id, []) - result[fncts[fnct][0]][id].append(fnct) - dict = {} - for object in result: - k2 = {} - for id, fnct in result[object].items(): - k2.setdefault(tuple(fnct), []) - k2[tuple(fnct)].append(id) - for fnct, id in k2.items(): - dict.setdefault(fncts[fnct[0]][4], []) - dict[fncts[fnct[0]][4]].append((fncts[fnct[0]][4], object, id, map(lambda x: fncts[x][1], fnct))) - result2 = [] - tmp = dict.keys() - tmp.sort() - for k in tmp: - result2 += dict[k] - return result2 + target_ids = [id for id in function[id_mapping_fnct_](self, cr, ROOT_USER_ID, ids, context) if id] + + # the compound key must consider the priority and model name + key = (function[priority_], function[model_name_]) + for target_id in target_ids: + mapping.setdefault(key, {}).setdefault(target_id,set()).add(tuple(function)) + + # 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) ], ... } + # } + + # 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 = {} + # 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])) + ordered_keys = call_map.keys() + ordered_keys.sort() + result = [] + if ordered_keys: + result = reduce(operator.add, (call_map[k] for k in ordered_keys)) + return result def _store_set_values(self, cr, uid, ids, fields, context): """Calls the fields.function's "implementation function" for all ``fields``, on records with ``ids`` (taking care of @@ -4355,8 +4428,7 @@ class orm(orm_template): if domain: import expression - e = expression.expression(domain) - e.parse(cr, user, self, context) + e = expression.expression(cr, user, domain, self, context) tables = e.get_tables() where_clause, where_params = e.to_sql() where_clause = where_clause and [where_clause] or [] @@ -4381,7 +4453,7 @@ class orm(orm_template): if parent_model and child_object: # as inherited rules are being applied, we need to add the missing JOIN # to reach the parent table (if it was not JOINed yet in the query) - child_object._inherits_join_add(parent_model, query) + child_object._inherits_join_add(child_object, parent_model, query) query.where_clause += added_clause query.where_clause_params += added_params for table in added_tables: @@ -4470,7 +4542,7 @@ class orm(orm_template): else: continue # ignore non-readable or "non-joinable" fields elif order_field in self._inherit_fields: - parent_obj = self.pool.get(self._inherit_fields[order_field][0]) + parent_obj = self.pool.get(self._inherit_fields[order_field][3]) order_column = parent_obj._columns[order_field] if order_column._classic_read: inner_clause = self._inherits_join_calc(order_field, query) @@ -4577,7 +4649,7 @@ class orm(orm_template): for f in fields: ftype = fields[f]['type'] - if self._log_access and f in ('create_date', 'create_uid', 'write_date', 'write_uid'): + if self._log_access and f in LOG_ACCESS_COLUMNS: del data[f] if f in default: @@ -4614,9 +4686,13 @@ class orm(orm_template): # force a clean recompute! for parent_column in ['parent_left', 'parent_right']: data.pop(parent_column, None) - - for v in self._inherits: - del data[self._inherits[v]] + # Remove _inherits field's from data recursively, missing parents will + # be created by create() (so that copy() copy everything). + def remove_ids(inherits_dict): + for parent_table in inherits_dict: + del data[inherits_dict[parent_table]] + remove_ids(self.pool.get(parent_table)._inherits) + remove_ids(self._inherits) return data def copy_translations(self, cr, uid, old_id, new_id, context=None): @@ -4690,9 +4766,9 @@ class orm(orm_template): def exists(self, cr, uid, ids, context=None): if type(ids) in (int, long): ids = [ids] - query = 'SELECT count(1) FROM "%s"' % (self._table) + query = 'SELECT id FROM "%s"' % (self._table) cr.execute(query + "WHERE ID IN %s", (tuple(ids),)) - return cr.fetchone()[0] == len(ids) + return [x[0] for x in cr.fetchall()] def check_recursion(self, cr, uid, ids, context=None, parent=None): warnings.warn("You are using deprecated %s.check_recursion(). Please use the '_check_recursion()' instead!" % \ diff --git a/openerp/report/interface.py b/openerp/report/interface.py index 110110fb1a99a77ce6a1247fed202eb610b2dc5a..9a97c4456711e5cc85ac5f16ac8c294dfe5e0c8a 100644 --- a/openerp/report/interface.py +++ b/openerp/report/interface.py @@ -231,6 +231,7 @@ class report_rml(report_int): def _get_path(self): ret = [] ret.append(self.tmpl.replace(os.path.sep, '/').rsplit('/',1)[0]) # Same dir as the report rml + ret.append('addons') ret.append(tools.config['root_path']) return ret diff --git a/openerp/report/preprocess.py b/openerp/report/preprocess.py index c84ce66b4721dee9c0fb1ed3a5cf57b1efa252d5..b339e078d817aea56d50b75b9f5ea73974e1dfcf 100644 --- a/openerp/report/preprocess.py +++ b/openerp/report/preprocess.py @@ -65,7 +65,10 @@ class report(object): if type =='html2html': match = html_parents if txt.group(3): - match = [txt.group(3)] + group_3 = txt.group(3) + if group_3.startswith("'") or group_3.startswith('"'): + group_3 = group_3[1:-1] + match = [group_3] n = node while n.tag not in match: n = n.getparent() diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py index a770a19ec270c631a66cf80740341254d60e5ecf..0067bf300f27fe3adb94a641b28ce3b3dc989c06 100644 --- a/openerp/report/render/rml2pdf/trml2pdf.py +++ b/openerp/report/render/rml2pdf/trml2pdf.py @@ -447,14 +447,14 @@ class _rml_canvas(object): self._logger.debug("Image %s used", node.get('name')) s = StringIO(image_data) else: + newtext = node.text if self.localcontext: - res = utils._regex.findall(node.text) + res = utils._regex.findall(newtext) for key in res: - newtext = eval(key, {}, self.localcontext) - node.text = newtext or '' + newtext = eval(key, {}, self.localcontext) or '' image_data = None - if node.text: - image_data = base64.decodestring(node.text) + if newtext: + image_data = base64.decodestring(newtext) if image_data: s = StringIO(image_data) else: diff --git a/openerp/report/report_sxw.py b/openerp/report/report_sxw.py index 210a54760c48490910210d1f62c6dd0f41ad5c1f..98de86b01a83dc6abceccdaa94490c8c540cb7df 100644 --- a/openerp/report/report_sxw.py +++ b/openerp/report/report_sxw.py @@ -68,6 +68,9 @@ rml2sxw = { 'para': 'p', } +def get_date_length(date_format=DT_FORMAT): + return len((datetime.now()).strftime(date_format)) + class _format(object): def set_value(self, cr, uid, name, object, field, lang_obj): self.object = object @@ -78,7 +81,7 @@ class _format(object): class _float_format(float, _format): def __init__(self,value): super(_float_format, self).__init__() - self.val = value + self.val = value or 0.0 def __str__(self): digits = 2 @@ -86,17 +89,17 @@ class _float_format(float, _format): digits = self._field.digits[1] if hasattr(self, 'lang_obj'): return self.lang_obj.format('%.' + str(digits) + 'f', self.name, True) - return self.val + return str(self.val) class _int_format(int, _format): def __init__(self,value): super(_int_format, self).__init__() - self.val = value and str(value) or str(0) + self.val = value or 0 def __str__(self): if hasattr(self,'lang_obj'): return self.lang_obj.format('%.d', self.name, True) - return self.val + return str(self.val) class _date_format(str, _format): def __init__(self,value): @@ -106,7 +109,7 @@ class _date_format(str, _format): def __str__(self): if self.val: if getattr(self,'name', None): - date = datetime.strptime(self.name, DT_FORMAT) + date = datetime.strptime(self.name[:get_date_length()], DT_FORMAT) return date.strftime(str(self.lang_obj.date_format)) return self.val @@ -264,7 +267,7 @@ class rml_parse(object): d = obj._field.digits[1] or DEFAULT_DIGITS return d - def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False, dp=False): + def formatLang(self, value, digits=None, date=False, date_time=False, grouping=True, monetary=False, dp=False, currency_obj=False): """ Assuming 'Account' decimal.precision=3: formatLang(value) -> digits=2 (default) @@ -296,13 +299,19 @@ class rml_parse(object): date_format = date_format + " " + self.lang_dict['time_format'] parse_format = DHM_FORMAT if not isinstance(value, time.struct_time): - return time.strftime(date_format, time.strptime(value, parse_format)) + return time.strftime(date_format, time.strptime(value[:get_date_length(parse_format)], parse_format)) else: date = datetime(*value.timetuple()[:6]) return date.strftime(date_format) - return self.lang_dict['lang_obj'].format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary) + res = self.lang_dict['lang_obj'].format('%.' + str(digits) + 'f', value, grouping=grouping, monetary=monetary) + if currency_obj: + if currency_obj.position == 'after': + res='%s %s'%(res,currency_obj.symbol) + elif currency_obj and currency_obj.position == 'before': + res='%s %s'%(currency_obj.symbol, res) + return res def repeatIn(self, lst, name,nodes_parent=False): ret_lst = [] diff --git a/openerp/sql_db.py b/openerp/sql_db.py index 79606b9101c996a98a11e7f66c0e1c730fe9c337..8038c39486dfdde265c40797c3ff7cc30cc814a7 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -183,6 +183,8 @@ class Cursor(object): self.__caller = False self.__closer = False + self._default_log_exceptions = True + def __del__(self): if not self.__closed: # Oops. 'self' has not been closed explicitly. @@ -199,7 +201,7 @@ class Cursor(object): self._close(True) @check - def execute(self, query, params=None, log_exceptions=True): + def execute(self, query, params=None, log_exceptions=None): if '%d' in query or '%f' in query: self.__logger.warn(query) self.__logger.warn("SQL queries cannot contain %d or %f anymore. " @@ -212,11 +214,11 @@ class Cursor(object): params = params or None res = self._obj.execute(query, params) except psycopg2.ProgrammingError, pe: - if log_exceptions: + if self._default_log_exceptions or log_exceptions: self.__logger.error("Programming error: %s, in query %s", pe, query) raise except Exception: - if log_exceptions: + if self._default_log_exceptions or log_exceptions: self.__logger.exception("bad query: %s", self._obj.query or query) raise diff --git a/openerp/tools/config.py b/openerp/tools/config.py index f5a45dd67a0883338853c70edaa6a10a2e27440a..69155f99966d1e3619dc1bd0afee0e3076ba62f6 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -254,6 +254,8 @@ class configmanager(object): "osv_memory tables. This is a decimal value expressed in hours, " "and the default is 1 hour.", type="float") + group.add_option("--unaccent", dest="unaccent", my_default=False, action="store_true", + help="Use the unaccent function provided by the database when available.") parser.add_option_group(group) # Copy all optparse options (i.e. MyOption) into self.options. @@ -356,7 +358,7 @@ class configmanager(object): 'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog', 'list_db', 'xmlrpcs', 'test_file', 'test_disable', 'test_commit', 'test_report_directory', - 'osv_memory_count_limit', 'osv_memory_age_limit', + 'osv_memory_count_limit', 'osv_memory_age_limit', 'unaccent', ] for arg in keys: diff --git a/openerp/tools/misc.py b/openerp/tools/misc.py index b1d23e746304ee03c4d4e2eb9cabc5b1b82c465f..dbccbe5b2174f5a3046245200e4f2c3113a024f1 100644 --- a/openerp/tools/misc.py +++ b/openerp/tools/misc.py @@ -45,6 +45,7 @@ from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email.Header import Header from email.Utils import formatdate, COMMASPACE +from email import Utils from email import Encoders from itertools import islice, izip from lxml import etree @@ -59,6 +60,7 @@ except ImportError: html2text = None import openerp.loglevels as loglevels +import openerp.pooler as pooler from config import config from cache import * @@ -280,15 +282,7 @@ email_re = re.compile(r""" """, re.VERBOSE) res_re = re.compile(r"\[([0-9]+)\]", re.UNICODE) command_re = re.compile("^Set-([a-z]+) *: *(.+)$", re.I + re.UNICODE) -reference_re = re.compile("<.*-openobject-(\\d+)@(.*)>", re.UNICODE) - -priorities = { - '1': '1 (Highest)', - '2': '2 (High)', - '3': '3 (Normal)', - '4': '4 (Low)', - '5': '5 (Lowest)', - } +reference_re = re.compile("<.*-open(?:object|erp)-(\\d+).*@(.*)>", re.UNICODE) def html2plaintext(html, body_id=None, encoding='utf-8'): """ From an HTML text, convert the HTML to plain text. @@ -354,150 +348,51 @@ def html2plaintext(html, body_id=None, encoding='utf-8'): return html -def generate_tracking_message_id(openobject_id): +def generate_tracking_message_id(res_id): """Returns a string that can be used in the Message-ID RFC822 header field Used to track the replies related to a given object thanks to the "In-Reply-To" or "References" fields that Mail User Agents will set. """ - return "<%s-openobject-%s@%s>" % (time.time(), openobject_id, socket.gethostname()) + return "<%s-openerp-%s@%s>" % (time.time(), res_id, socket.gethostname()) -def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False, debug=False): - """ Low-level method to send directly a Message through the configured smtp server. - - :param smtp_from: RFC-822 envelope FROM (not displayed to recipient) - :param smtp_to_list: RFC-822 envelope RCPT_TOs (not displayed to recipient) - :param message: an email.message.Message to send - :param debug: True if messages should be output to stderr before being sent, - and smtplib.SMTP put into debug mode. - :return: True if the mail was delivered successfully to the smtp, - else False (+ exception logged) +def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, + attachments=None, message_id=None, references=None, openobject_id=False, debug=False, subtype='plain', headers=None, + smtp_server=None, smtp_port=None, ssl=False, smtp_user=None, smtp_password=None, cr=None, uid=None): + """Low-level function for sending an email (deprecated). + + :deprecate: since OpenERP 6.1, please use ir.mail_server.send_email() instead. + :param email_from: A string used to fill the `From` header, if falsy, + config['email_from'] is used instead. Also used for + the `Reply-To` header if `reply_to` is not provided + :param email_to: a sequence of addresses to send the mail to. """ - class WriteToLogger(object): - def __init__(self): - self.logger = loglevels.Logger() - def write(self, s): - self.logger.notifyChannel('email_send', loglevels.LOG_DEBUG, s) - - if openobject_id: - message['Message-Id'] = generate_tracking_message_id(openobject_id) + # If not cr, get cr from current thread database + if not cr: + db_name = getattr(threading.currentThread(), 'dbname', None) + if db_name: + cr = pooler.get_db_only(db_name).cursor() + else: + raise Exception("No database cursor found, please pass one explicitly") + # Send Email try: - smtp_server = config['smtp_server'] - - if smtp_server.startswith('maildir:/'): - from mailbox import Maildir - maildir_path = smtp_server[8:] - mdir = Maildir(maildir_path,factory=None, create = True) - mdir.add(message.as_string(True)) - return True - - oldstderr = smtplib.stderr - if not ssl: ssl = config.get('smtp_ssl', False) - s = smtplib.SMTP() - try: - # in case of debug, the messages are printed to stderr. - if debug: - smtplib.stderr = WriteToLogger() - - s.set_debuglevel(int(bool(debug))) # 0 or 1 - s.connect(smtp_server, config['smtp_port']) - if ssl: - s.ehlo() - s.starttls() - s.ehlo() - - if config['smtp_user'] or config['smtp_password']: - s.login(config['smtp_user'], config['smtp_password']) - - s.sendmail(smtp_from, smtp_to_list, message.as_string()) - finally: - try: - s.quit() - if debug: - smtplib.stderr = oldstderr - except Exception: - # ignored, just a consequence of the previous exception - pass - + mail_server_pool = pooler.get_pool(cr.dbname).get('ir.mail_server') + res = False + # Pack Message into MIME Object + email_msg = mail_server_pool.build_email(email_from, email_to, subject, body, email_cc, email_bcc, reply_to, + attachments, message_id, references, openobject_id, subtype, headers=headers) + + res = mail_server_pool.send_email(cr, uid or 1, email_msg, mail_server_id=None, + smtp_server=smtp_server, smtp_port=smtp_port, smtp_user=smtp_user, smtp_password=smtp_password, + smtp_encryption=('ssl' if ssl else None), debug=debug) except Exception: - _logger.error('could not deliver email', exc_info=True) + _log.exception("tools.email_send failed to deliver email") return False - - return True - - -def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, - attach=None, openobject_id=False, ssl=False, debug=False, subtype='plain', x_headers=None, priority='3'): - - """Send an email. - - @param email_from A string used to fill the `From` header, if falsy, - config['email_from'] is used instead. Also used for - the `Reply-To` header if `reply_to` is not provided - - @param email_to a sequence of addresses to send the mail to. - """ - if x_headers is None: - x_headers = {} - - - - if not (email_from or config['email_from']): - raise ValueError("Sending an email requires either providing a sender " - "address or having configured one") - - if not email_from: email_from = config.get('email_from', False) - email_from = ustr(email_from).encode('utf-8') - - if not email_cc: email_cc = [] - if not email_bcc: email_bcc = [] - if not body: body = u'' - - email_body = ustr(body).encode('utf-8') - email_text = MIMEText(email_body or '',_subtype=subtype,_charset='utf-8') - - msg = MIMEMultipart() - - msg['Subject'] = Header(ustr(subject), 'utf-8') - msg['From'] = email_from - del msg['Reply-To'] - if reply_to: - msg['Reply-To'] = reply_to - else: - msg['Reply-To'] = msg['From'] - msg['To'] = COMMASPACE.join(email_to) - if email_cc: - msg['Cc'] = COMMASPACE.join(email_cc) - if email_bcc: - msg['Bcc'] = COMMASPACE.join(email_bcc) - msg['Date'] = formatdate(localtime=True) - - msg['X-Priority'] = priorities.get(priority, '3 (Normal)') - - # Add dynamic X Header - for key, value in x_headers.iteritems(): - msg['%s' % key] = str(value) - - if html2text and subtype == 'html': - text = html2text(email_body.decode('utf-8')).encode('utf-8') - alternative_part = MIMEMultipart(_subtype="alternative") - alternative_part.attach(MIMEText(text, _charset='utf-8', _subtype='plain')) - alternative_part.attach(email_text) - msg.attach(alternative_part) - else: - msg.attach(email_text) - - if attach: - for (fname,fcontent) in attach: - part = MIMEBase('application', "octet-stream") - part.set_payload( fcontent ) - Encoders.encode_base64(part) - part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,)) - msg.attach(part) - - return _email_send(email_from, flatten([email_to, email_cc, email_bcc]), msg, openobject_id=openobject_id, ssl=ssl, debug=debug) + finally: + cr.close() + return res #---------------------------------------------------------- # SMS @@ -1089,10 +984,7 @@ def detect_server_timezone(): return 'UTC' def get_server_timezone(): - # timezone detection is safe in multithread, so lazy init is ok here - if (not config['timezone']): - config['timezone'] = detect_server_timezone() - return config['timezone'] + return "UTC" DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d" diff --git a/openerp/workflow/wkf_service.py b/openerp/workflow/wkf_service.py index c74a0ad25c1ab6da357dd41ff1db8f8d7b0f0b9d..a8d829aa5468c9cba328b1616d77b1f65e8e4560 100644 --- a/openerp/workflow/wkf_service.py +++ b/openerp/workflow/wkf_service.py @@ -27,6 +27,16 @@ import openerp.netsvc as netsvc import openerp.pooler as pooler class workflow_service(netsvc.Service): + """ + Sometimes you might want to fire a signal or re-evaluate the current state + of a workflow using the service's API. You can access the workflow services + using: + + >>> import netsvc + >>> wf_service = netsvc.LocalService("workflow") + + """ + def __init__(self, name='workflow'): netsvc.Service.__init__(self, name) self.wkf_on_create_cache={} @@ -35,12 +45,31 @@ class workflow_service(netsvc.Service): self.wkf_on_create_cache[cr.dbname]={} def trg_write(self, uid, res_type, res_id, cr): + """ + Reevaluates the specified workflow instance. Thus if any condition for + a transition have been changed in the backend, then running ``trg_write`` + will move the workflow over that transition. + + :param res_type: the model name + :param res_id: the model instance id the workflow belongs to + :param cr: a database cursor + """ ident = (uid,res_type,res_id) cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id or None,res_type or None, 'active')) for (id,) in cr.fetchall(): instance.update(cr, id, ident) def trg_trigger(self, uid, res_type, res_id, cr): + """ + Activate a trigger. + + If a workflow instance is waiting for a trigger from another model, then this + trigger can be activated if its conditions are met. + + :param res_type: the model name + :param res_id: the model instance id the workflow belongs to + :param cr: a database cursor + """ cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (res_id,res_type)) res = cr.fetchall() for (instance_id,) in res: @@ -49,10 +78,24 @@ class workflow_service(netsvc.Service): instance.update(cr, instance_id, ident) def trg_delete(self, uid, res_type, res_id, cr): + """ + Delete a workflow instance + + :param res_type: the model name + :param res_id: the model instance id the workflow belongs to + :param cr: a database cursor + """ ident = (uid,res_type,res_id) instance.delete(cr, ident) def trg_create(self, uid, res_type, res_id, cr): + """ + Create a new workflow instance + + :param res_type: the model name + :param res_id: the model instance id to own the created worfklow instance + :param cr: a database cursor + """ ident = (uid,res_type,res_id) self.wkf_on_create_cache.setdefault(cr.dbname, {}) if res_type in self.wkf_on_create_cache[cr.dbname]: @@ -65,6 +108,14 @@ class workflow_service(netsvc.Service): instance.create(cr, ident, wkf_id) def trg_validate(self, uid, res_type, res_id, signal, cr): + """ + Fire a signal on a given workflow instance + + :param res_type: the model name + :param res_id: the model instance id the workflow belongs to + :signal: the signal name to be fired + :param cr: a database cursor + """ result = False ident = (uid,res_type,res_id) # ids of all active workflow instances for a corresponding resource (id, model_nam) @@ -74,10 +125,19 @@ class workflow_service(netsvc.Service): result = result or res2 return result - # make all workitems which are waiting for a (subflow) workflow instance - # for the old resource point to the (first active) workflow instance for - # the new resource def trg_redirect(self, uid, res_type, res_id, new_rid, cr): + """ + Re-bind a workflow instance to another instance of the same model. + + Make all workitems which are waiting for a (subflow) workflow instance + for the old resource point to the (first active) workflow instance for + the new resource. + + :param res_type: the model name + :param res_id: the model instance id the workflow belongs to + :param new_rid: the model instance id to own the worfklow instance + :param cr: a database cursor + """ # get ids of wkf instances for the old resource (res_id) #CHECKME: shouldn't we get only active instances? cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (res_id, res_type)) diff --git a/setup.nsi b/setup.nsi index f9c962ae38363d0e6f24e67aaf4cc18de3ef26f8..0ea37b0f9e6c9db35a81c00df19bd37ee70fd7ba 100644 --- a/setup.nsi +++ b/setup.nsi @@ -210,6 +210,7 @@ Section OpenERP_Server SectionOpenERP_Server WriteIniStr "$INSTDIR\openerp-server.conf" "options" "db_user" $TextPostgreSQLUsername WriteIniStr "$INSTDIR\openerp-server.conf" "options" "db_password" $TextPostgreSQLPassword WriteIniStr "$INSTDIR\openerp-server.conf" "options" "db_port" $TextPostgreSQLPort + WriteIniStr "$INSTDIR\openerp-server.conf" "options" "pg_path" "$INSTDIR\PostgreSQL\bin" nsExec::Exec '"$INSTDIR\openerp-server.exe" --stop-after-init --logfile "$INSTDIR\openerp-server.log" -s' nsExec::Exec '"$INSTDIR\service\OpenERPServerService.exe" -auto -install' diff --git a/setup.py b/setup.py index e36662b16ccd346b54b1c533342b4f507f427cef..58424dbad12b1bffeecd7466849fb2e1b21ba752 100755 --- a/setup.py +++ b/setup.py @@ -89,7 +89,7 @@ if os.name == 'nt': "pydot", "asyncore","asynchat", "reportlab", "vobject", "HTMLParser", "select", "mako", "poplib", "imaplib", "smtplib", "email", "yaml", "DAV", - "uuid", "commands", "openerp", + "uuid", "commands", "openerp", "simplejson", "vatnumber" ], "excludes" : ["Tkconstants","Tkinter","tcl"], } @@ -165,6 +165,7 @@ setup(name = name, 'pywebdav', 'feedparser', 'simplejson >= 2.0', + 'vatnumber', # required by base_vat module ], extras_require = { 'SSL' : ['pyopenssl'],