diff --git a/addons/account/account.py b/addons/account/account.py index 031a803d64c..9b728ff36e0 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -28,7 +28,7 @@ import time import openerp from openerp import SUPERUSER_ID from openerp import tools -from openerp.osv import fields, osv +from openerp.osv import fields, osv, expression from openerp.tools.translate import _ from openerp.tools.float_utils import float_round @@ -579,15 +579,18 @@ class account_account(osv.osv): except: pass if name: - ids = self.search(cr, user, [('code', '=like', name+"%")]+args, limit=limit) - if not ids: - ids = self.search(cr, user, [('shortcut', '=', name)]+ args, limit=limit) - if not ids: - ids = self.search(cr, user, [('name', operator, name)]+ args, limit=limit) - if not ids and len(name.split()) >= 2: - #Separating code and name of account for searching - operand1,operand2 = name.split(' ',1) #name can contain spaces e.g. OpenERP S.A. - ids = self.search(cr, user, [('code', operator, operand1), ('name', operator, operand2)]+ args, limit=limit) + if operator not in expression.NEGATIVE_TERM_OPERATORS: + ids = self.search(cr, user, ['|', ('code', '=like', name+"%"), '|', ('shortcut', '=', name), ('name', operator, name)]+args, limit=limit) + if not ids and len(name.split()) >= 2: + #Separating code and name of account for searching + operand1,operand2 = name.split(' ',1) #name can contain spaces e.g. OpenERP S.A. + ids = self.search(cr, user, [('code', operator, operand1), ('name', operator, operand2)]+ args, limit=limit) + else: + ids = self.search(cr, user, ['&','!', ('code', '=like', name+"%"), ('name', operator, name)]+args, limit=limit) + # as negation want to restric, do if already have results + if ids and len(name.split()) >= 2: + operand1,operand2 = name.split(' ',1) #name can contain spaces e.g. OpenERP S.A. + ids = self.search(cr, user, [('code', operator, operand1), ('name', operator, operand2), ('id', 'in', ids)]+ args, limit=limit) else: ids = self.search(cr, user, args, context=context, limit=limit) return self.name_get(cr, user, ids, context=context) @@ -1573,11 +1576,6 @@ class account_move(osv.osv): obj_analytic_line = self.pool.get('account.analytic.line') obj_move_line = self.pool.get('account.move.line') for move in self.browse(cr, uid, ids, context): - # Unlink old analytic lines on move_lines - for obj_line in move.line_id: - for obj in obj_line.analytic_lines: - obj_analytic_line.unlink(cr,uid,obj.id) - journal = move.journal_id amount = 0 line_ids = [] diff --git a/addons/account/account_move_line.py b/addons/account/account_move_line.py index d5c453ee9c7..cb242942656 100644 --- a/addons/account/account_move_line.py +++ b/addons/account/account_move_line.py @@ -193,6 +193,8 @@ class account_move_line(osv.osv): if obj_line.analytic_account_id: if not obj_line.journal_id.analytic_journal_id: raise osv.except_osv(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal!") % (obj_line.journal_id.name, )) + if obj_line.analytic_lines: + acc_ana_line_obj.unlink(cr,uid,[obj.id for obj in obj_line.analytic_lines]) vals_line = self._prepare_analytic_line(cr, uid, obj_line, context=context) acc_ana_line_obj.create(cr, uid, vals_line) return True @@ -1207,20 +1209,6 @@ class account_move_line(osv.osv): if not ok: raise osv.except_osv(_('Bad Account!'), _('You cannot use this general account in this journal, check the tab \'Entry Controls\' on the related journal.')) - if vals.get('analytic_account_id',False): - if journal.analytic_journal_id: - vals['analytic_lines'] = [(0,0, { - 'name': vals['name'], - 'date': vals.get('date', time.strftime('%Y-%m-%d')), - 'account_id': vals.get('analytic_account_id', False), - 'unit_amount': vals.get('quantity', 1.0), - 'amount': vals.get('debit', 0.0) or vals.get('credit', 0.0), - 'general_account_id': vals.get('account_id', False), - 'journal_id': journal.analytic_journal_id.id, - 'ref': vals.get('ref', False), - 'user_id': uid - })] - result = super(account_move_line, self).create(cr, uid, vals, context=context) # CREATE Taxes if vals.get('account_tax_id', False): diff --git a/addons/account/data/account_data.xml b/addons/account/data/account_data.xml index 8119e9f1002..723ec6da155 100644 --- a/addons/account/data/account_data.xml +++ b/addons/account/data/account_data.xml @@ -3,9 +3,15 @@ + SAL Sales sale + + PUR + Purchases + purchase + - - + + _usertemplate diff --git a/addons/auth_signup/i18n/zh_TW.po b/addons/auth_signup/i18n/zh_TW.po index b16d2be5abf..506ef4fac35 100644 --- a/addons/auth_signup/i18n/zh_TW.po +++ b/addons/auth_signup/i18n/zh_TW.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-12-21 17:05+0000\n" -"PO-Revision-Date: 2013-09-19 09:40+0000\n" -"Last-Translator: FULL NAME \n" +"PO-Revision-Date: 2013-12-29 09:17+0000\n" +"Last-Translator: Andy Cheng \n" "Language-Team: Chinese (Traditional) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2013-09-20 05:38+0000\n" -"X-Generator: Launchpad (build 16765)\n" +"X-Launchpad-Export-Date: 2013-12-30 04:39+0000\n" +"X-Generator: Launchpad (build 16877)\n" #. module: auth_signup #: field:res.partner,signup_type:0 @@ -66,19 +66,19 @@ msgstr "" #. module: auth_signup #: model:email.template,subject:auth_signup.reset_password_email msgid "Password reset" -msgstr "" +msgstr "密碼重設" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/js/auth_signup.js:120 #, python-format msgid "Please enter a password and confirm it." -msgstr "" +msgstr "請輸入密碼並確認" #. module: auth_signup #: view:res.users:0 msgid "Send an email to the user to (re)set their password." -msgstr "" +msgstr "寄出密碼重設電子郵件給該使用者" #. module: auth_signup #. openerp-web @@ -86,23 +86,23 @@ msgstr "" #: code:addons/auth_signup/static/src/xml/auth_signup.xml:29 #, python-format msgid "Sign Up" -msgstr "" +msgstr "註冊" #. module: auth_signup #: selection:res.users,state:0 msgid "New" -msgstr "" +msgstr "新增" #. module: auth_signup #: code:addons/auth_signup/res_users.py:258 #, python-format msgid "Mail sent to:" -msgstr "" +msgstr "信件已寄給:" #. module: auth_signup #: field:res.users,state:0 msgid "Status" -msgstr "" +msgstr "狀態" #. module: auth_signup #: model:email.template,body_html:auth_signup.reset_password_email @@ -122,29 +122,29 @@ msgstr "" #: code:addons/auth_signup/static/src/js/auth_signup.js:114 #, python-format msgid "Please enter a name." -msgstr "" +msgstr "請輸入名字" #. module: auth_signup #: model:ir.model,name:auth_signup.model_res_users msgid "Users" -msgstr "" +msgstr "使用者" #. module: auth_signup #: field:res.partner,signup_url:0 msgid "Signup URL" -msgstr "" +msgstr "註冊網址" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/js/auth_signup.js:117 #, python-format msgid "Please enter a username." -msgstr "" +msgstr "請輸入使用者名稱。" #. module: auth_signup #: selection:res.users,state:0 msgid "Active" -msgstr "" +msgstr "啟用" #. module: auth_signup #: code:addons/auth_signup/res_users.py:270 @@ -159,26 +159,26 @@ msgstr "" #: code:addons/auth_signup/static/src/xml/auth_signup.xml:12 #, python-format msgid "Username" -msgstr "" +msgstr "使用者名稱" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/xml/auth_signup.xml:8 #, python-format msgid "Name" -msgstr "" +msgstr "名稱" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/js/auth_signup.js:173 #, python-format msgid "Please enter a username or email address." -msgstr "" +msgstr "請輸入使用者名稱或電子郵件地址" #. module: auth_signup #: selection:res.users,state:0 msgid "Resetting Password" -msgstr "" +msgstr "重設密碼中" #. module: auth_signup #. openerp-web @@ -202,7 +202,7 @@ msgstr "" #: code:addons/auth_signup/static/src/xml/auth_signup.xml:25 #, python-format msgid "Log in" -msgstr "" +msgstr "登入" #. module: auth_signup #: field:res.partner,signup_valid:0 @@ -220,7 +220,7 @@ msgstr "" #: code:addons/auth_signup/static/src/js/auth_signup.js:173 #, python-format msgid "Login" -msgstr "" +msgstr "登入" #. module: auth_signup #. openerp-web @@ -242,36 +242,36 @@ msgstr "" #: code:addons/auth_signup/static/src/js/auth_signup.js:170 #, python-format msgid "No database selected !" -msgstr "" +msgstr "未選定資料庫!" #. module: auth_signup #: view:res.users:0 msgid "Reset Password" -msgstr "" +msgstr "重設密碼" #. module: auth_signup #: field:base.config.settings,auth_signup_reset_password:0 msgid "Enable password reset from Login page" -msgstr "" +msgstr "於登入頁面啟用密碼重設" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/xml/auth_signup.xml:30 #, python-format msgid "Back to Login" -msgstr "" +msgstr "返回登入畫面" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/xml/auth_signup.xml:22 #, python-format msgid "Sign up" -msgstr "" +msgstr "註冊" #. module: auth_signup #: model:ir.model,name:auth_signup.model_res_partner msgid "Partner" -msgstr "" +msgstr "業務夥伴" #. module: auth_signup #: field:res.partner,signup_token:0 diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py index 66f7913c966..a9469e4de0d 100644 --- a/addons/auth_signup/res_users.py +++ b/addons/auth_signup/res_users.py @@ -234,8 +234,6 @@ class res_users(osv.Model): # create a copy of the template user (attached to a specific partner_id if given) values['active'] = True - if 'alias_name' not in values: # allow behavior change via inheritance (like using the name) - values['alias_name'] = False context = dict(context or {}, no_reset_password=True) return self.copy(cr, uid, template_user_id, values, context=context) diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 59d61ba5b67..0d98030e800 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -23,6 +23,7 @@ from datetime import datetime, timedelta import time import logging +import openerp from openerp import SUPERUSER_ID from openerp.osv import fields, osv from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT @@ -222,6 +223,7 @@ class base_action_rule(osv.osv): def create(self, cr, uid, vals, context=None): res_id = super(base_action_rule, self).create(cr, uid, vals, context=context) self._register_hook(cr, [res_id]) + openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return res_id def write(self, cr, uid, ids, vals, context=None): @@ -229,6 +231,7 @@ class base_action_rule(osv.osv): ids = [ids] super(base_action_rule, self).write(cr, uid, ids, vals, context=context) self._register_hook(cr, ids) + openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) return True def onchange_model_id(self, cr, uid, ids, model_id, context=None): diff --git a/addons/base_action_rule/i18n/he.po b/addons/base_action_rule/i18n/he.po new file mode 100644 index 00000000000..49d917c2665 --- /dev/null +++ b/addons/base_action_rule/i18n/he.po @@ -0,0 +1,313 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:37+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: base_action_rule +#: selection:base.action.rule.lead.test,state:0 +msgid "In Progress" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "" +"- In this same \"Search\" view, select the menu \"Save Current Filter\", " +"enter the name (Ex: Create the 01/01/2012) and add the option \"Share with " +"all users\"" +msgstr "" + +#. module: base_action_rule +#: model:ir.model,name:base_action_rule.model_base_action_rule +msgid "Action Rules" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Select a filter or a timer as condition." +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule.lead.test,user_id:0 +msgid "Responsible" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,server_action_ids:0 +msgid "Examples: email reminders, call object service, etc." +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,act_followers:0 +msgid "Add Followers" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,act_user_id:0 +msgid "Set Responsible" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,trg_date_range:0 +msgid "" +"Delay after the trigger date.You can put a negative number if you need a " +"delay before thetrigger date, like sending a reminder 15 minutes before a " +"meeting." +msgstr "" + +#. module: base_action_rule +#: model:ir.model,name:base_action_rule.model_base_action_rule_lead_test +msgid "base.action.rule.lead.test" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule.lead.test,state:0 +msgid "Closed" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule.lead.test,state:0 +msgid "New" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,trg_date_range:0 +msgid "Delay after trigger date" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Conditions" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule.lead.test,state:0 +msgid "Pending" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule.lead.test,state:0 +msgid "Status" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,filter_pre_id:0 +msgid "Before Update Filter" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Action Rule" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,filter_id:0 +msgid "" +"If present, this condition must be satisfied after the update of the record." +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Fields to Change" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "The filter must therefore be available in this page." +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,filter_id:0 +msgid "After Update Filter" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule,trg_date_range_type:0 +msgid "Hours" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "To create a new filter:" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,active:0 +#: field:base.action.rule.lead.test,active:0 +msgid "Active" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Delay After Trigger Date" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "" +"An action rule is checked when you create or modify the \"Related Document " +"Model\". The precondition filter is checked right before the modification " +"while the postcondition filter is checked after the modification. A " +"precondition filter will therefore not work during a creation." +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Filter Condition" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "" +"- Go to your \"Related Document Model\" page and set the filter parameters " +"in the \"Search\" view (Example of filter based on Leads/Opportunities: " +"Creation Date \"is equal to\" 01/01/2012)" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,name:0 +msgid "Rule Name" +msgstr "" + +#. module: base_action_rule +#: model:ir.actions.act_window,name:base_action_rule.base_action_rule_act +#: model:ir.ui.menu,name:base_action_rule.menu_base_action_rule_form +msgid "Automated Actions" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,sequence:0 +msgid "Gives the sequence order when displaying a list of rules." +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule,trg_date_range_type:0 +msgid "Months" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule,trg_date_range_type:0 +msgid "Days" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Timer" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,trg_date_range_type:0 +msgid "Delay type" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Server actions to run" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,active:0 +msgid "When unchecked, the rule is hidden and will not be executed." +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule.lead.test,state:0 +msgid "Cancelled" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,model:0 +msgid "Model" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,last_run:0 +msgid "Last Run" +msgstr "" + +#. module: base_action_rule +#: selection:base.action.rule,trg_date_range_type:0 +msgid "Minutes" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,model_id:0 +msgid "Related Document Model" +msgstr "" + +#. module: base_action_rule +#: help:base.action.rule,filter_pre_id:0 +msgid "" +"If present, this condition must be satisfied before the update of the record." +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +msgid "Actions" +msgstr "" + +#. module: base_action_rule +#: model:ir.actions.act_window,help:base_action_rule.base_action_rule_act +msgid "" +"

\n" +" Click to setup a new automated action rule. \n" +"

\n" +" Use automated actions to automatically trigger actions for\n" +" various screens. Example: a lead created by a specific user " +"may\n" +" be automatically set to a specific sales team, or an\n" +" opportunity which still has status pending after 14 days " +"might\n" +" trigger an automatic reminder email.\n" +"

\n" +" " +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,create_date:0 +msgid "Create Date" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule.lead.test,date_action_last:0 +msgid "Last Action" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule.lead.test,partner_id:0 +msgid "Partner" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule,trg_date_id:0 +msgid "Trigger Date" +msgstr "" + +#. module: base_action_rule +#: view:base.action.rule:0 +#: field:base.action.rule,server_action_ids:0 +msgid "Server Actions" +msgstr "" + +#. module: base_action_rule +#: field:base.action.rule.lead.test,name:0 +msgid "Subject" +msgstr "" diff --git a/addons/base_setup/i18n/he.po b/addons/base_setup/i18n/he.po new file mode 100644 index 00000000000..4c4b3037c71 --- /dev/null +++ b/addons/base_setup/i18n/he.po @@ -0,0 +1,370 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:38+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Emails Integration" +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Guest" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Contacts" +msgstr "" + +#. module: base_setup +#: model:ir.model,name:base_setup.model_base_config_settings +msgid "base.config.settings" +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_auth_oauth:0 +msgid "" +"Use external authentication providers, sign in with google, facebook, ..." +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "" +"OpenERP allows to automatically create leads (or others documents)\n" +" from incoming emails. You can automatically " +"synchronize emails with OpenERP\n" +" using regular POP/IMAP accounts, using a direct " +"email integration script for your\n" +" email server, or by manually pushing emails to " +"OpenERP using specific\n" +" plugins for your preferred email application." +msgstr "" + +#. module: base_setup +#: field:sale.config.settings,module_sale:0 +msgid "SALE" +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Member" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Portal access" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Authentication" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Quotations and Sales Orders" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +#: model:ir.actions.act_window,name:base_setup.action_general_configuration +#: model:ir.ui.menu,name:base_setup.menu_general_configuration +msgid "General Settings" +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Donor" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Email" +msgstr "" + +#. module: base_setup +#: field:sale.config.settings,module_crm:0 +msgid "CRM" +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Patient" +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_base_import:0 +msgid "Allow users to import data from CSV files" +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_multi_company:0 +msgid "Manage multiple companies" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "On Mail Client" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "--db-filter=YOUR_DATABAE" +msgstr "" + +#. module: base_setup +#: field:sale.config.settings,module_web_linkedin:0 +msgid "Get contacts automatically from linkedIn" +msgstr "" + +#. module: base_setup +#: field:sale.config.settings,module_plugin_thunderbird:0 +msgid "Enable Thunderbird plug-in" +msgstr "" + +#. module: base_setup +#: view:base.setup.terminology:0 +msgid "res_config_contents" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Customer Features" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Import / Export" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Sale Features" +msgstr "" + +#. module: base_setup +#: field:sale.config.settings,module_plugin_outlook:0 +msgid "Enable Outlook plug-in" +msgstr "" + +#. module: base_setup +#: view:base.setup.terminology:0 +msgid "" +"You can use this wizard to change the terminologies for customers in the " +"whole application." +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Tenant" +msgstr "" + +#. module: base_setup +#: help:base.config.settings,module_share:0 +msgid "Share or embbed any screen of openerp." +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Customer" +msgstr "" + +#. module: base_setup +#: help:sale.config.settings,module_web_linkedin:0 +msgid "" +"When you create a new contact (person or company), you will be able to load " +"all the data from LinkedIn (photos, address, etc)." +msgstr "" + +#. module: base_setup +#: help:base.config.settings,module_multi_company:0 +msgid "" +"Work in multi-company environments, with appropriate security access between " +"companies.\n" +" This installs the module multi_company." +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "" +"The public portal is accessible only if you are in a single database mode. " +"You can\n" +" launch the OpenERP Server with the option" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "" +"You will find more options in your company details: address for the header " +"and footer, overdue payments texts, etc." +msgstr "" + +#. module: base_setup +#: model:ir.model,name:base_setup.model_sale_config_settings +msgid "sale.config.settings" +msgstr "" + +#. module: base_setup +#: field:base.setup.terminology,partner:0 +msgid "How do you call a Customer" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "" +"When you send a document to a customer\n" +" (quotation, invoice), your customer will " +"be\n" +" able to signup to get all his " +"documents,\n" +" read your company news, check his " +"projects,\n" +" etc." +msgstr "" + +#. module: base_setup +#: model:ir.model,name:base_setup.model_base_setup_terminology +msgid "base.setup.terminology" +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Client" +msgstr "" + +#. module: base_setup +#: help:base.config.settings,module_portal_anonymous:0 +msgid "Enable the public part of openerp, openerp becomes a public website." +msgstr "" + +#. module: base_setup +#: help:sale.config.settings,module_plugin_thunderbird:0 +msgid "" +"The plugin allows you archive email and its attachments to the selected\n" +" OpenERP objects. You can select a partner, or a lead and\n" +" attach the selected mail as a .eml file in\n" +" the attachment of a selected record. You can create " +"documents for CRM Lead,\n" +" Partner from the selected emails.\n" +" This installs the module plugin_thunderbird." +msgstr "" + +#. module: base_setup +#: selection:base.setup.terminology,partner:0 +msgid "Partner" +msgstr "" + +#. module: base_setup +#: model:ir.actions.act_window,name:base_setup.action_partner_terminology_config_form +msgid "Use another word to say \"Customer\"" +msgstr "" + +#. module: base_setup +#: model:ir.actions.act_window,name:base_setup.action_sale_config +#: view:sale.config.settings:0 +msgid "Configure Sales" +msgstr "" + +#. module: base_setup +#: help:sale.config.settings,module_plugin_outlook:0 +msgid "" +"The Outlook plugin allows you to select an object that you would like to " +"add\n" +" to your email and its attachments from MS Outlook. You can " +"select a partner,\n" +" or a lead object and archive a selected\n" +" email into an OpenERP mail message with attachments.\n" +" This installs the module plugin_outlook." +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Options" +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_portal:0 +msgid "Activate the customer portal" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "" +"to do so.\n" +" Once activated, the login page will be " +"replaced by the public website." +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_share:0 +msgid "Allow documents sharing" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "(company news, jobs, contact form, etc.)" +msgstr "" + +#. module: base_setup +#: field:base.config.settings,module_portal_anonymous:0 +msgid "Activate the public portal" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Configure outgoing email servers" +msgstr "" + +#. module: base_setup +#: view:sale.config.settings:0 +msgid "Social Network Integration" +msgstr "" + +#. module: base_setup +#: help:base.config.settings,module_portal:0 +msgid "Give your customers access to their documents." +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +#: view:sale.config.settings:0 +msgid "Cancel" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +#: view:sale.config.settings:0 +msgid "Apply" +msgstr "" + +#. module: base_setup +#: view:base.setup.terminology:0 +msgid "Specify Your Terminology" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +#: view:sale.config.settings:0 +msgid "or" +msgstr "" + +#. module: base_setup +#: view:base.config.settings:0 +msgid "Configure your company data" +msgstr "" diff --git a/addons/base_setup/i18n/zh_TW.po b/addons/base_setup/i18n/zh_TW.po index 929f62ca24d..634a16c7697 100644 --- a/addons/base_setup/i18n/zh_TW.po +++ b/addons/base_setup/i18n/zh_TW.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: OpenERP Server 6.0dev\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-12-21 17:05+0000\n" -"PO-Revision-Date: 2011-11-07 12:53+0000\n" -"Last-Translator: Walter Cheuk \n" +"PO-Revision-Date: 2013-12-29 15:39+0000\n" +"Last-Translator: Andy Cheng \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: 2013-09-12 05:22+0000\n" -"X-Generator: Launchpad (build 16761)\n" +"X-Launchpad-Export-Date: 2013-12-30 04:39+0000\n" +"X-Generator: Launchpad (build 16877)\n" #. module: base_setup #: view:sale.config.settings:0 @@ -189,7 +189,7 @@ msgstr "客戶" msgid "" "When you create a new contact (person or company), you will be able to load " "all the data from LinkedIn (photos, address, etc)." -msgstr "" +msgstr "當建立新的聯絡人時(個人或公司),你就可以從 LinkedIn 載入所有資料(照片、地址等)。" #. module: base_setup #: help:base.config.settings,module_multi_company:0 @@ -212,7 +212,7 @@ msgstr "" msgid "" "You will find more options in your company details: address for the header " "and footer, overdue payments texts, etc." -msgstr "" +msgstr "您可在貴公司的詳細資訊中找到更多選項,如表頭和頁尾的地址、付款過期通知等等。" #. module: base_setup #: model:ir.model,name:base_setup.model_sale_config_settings diff --git a/addons/base_setup/res_config.py b/addons/base_setup/res_config.py index 06c57f2df5a..8ddec7df111 100644 --- a/addons/base_setup/res_config.py +++ b/addons/base_setup/res_config.py @@ -68,7 +68,7 @@ class base_config_settings(osv.osv_memory): def set_base_defaults(self, cr, uid, ids, context=None): ir_model_data = self.pool.get('ir.model.data') - wizard = self.browse(cr, uid, ids)[0] + wizard = self.browse(cr, uid, ids, context)[0] if wizard.font: user = self.pool.get('res.users').browse(cr, uid, uid, context) font_name = wizard.font.name @@ -76,7 +76,7 @@ class base_config_settings(osv.osv_memory): return {} def act_discover_fonts(self, cr, uid, ids, context=None): - return self.pool.get("res.font").discover_fonts(cr, uid, ids, context) + return self.pool.get("res.font").font_scan(cr, uid, context=context) # Preferences wizard for Sales & CRM. # It is defined here because it is inherited independently in modules sale, crm, diff --git a/addons/base_setup/res_config_view.xml b/addons/base_setup/res_config_view.xml index fab2f48e8ab..f8f3efd8171 100644 --- a/addons/base_setup/res_config_view.xml +++ b/addons/base_setup/res_config_view.xml @@ -94,7 +94,7 @@
+ + Leads Analysis + crm.lead.report + form + {"search_default_month":1} + tree,graph + [('type','=', 'lead'),('section_id', '=', active_id)] + Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis. + + + + Opportunities Analysis + crm.lead.report + form + {"search_default_month":1} + tree,graph + [('type','=', 'opportunity'), ('section_id', '=', active_id)] + Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline. + + @@ -99,13 +117,25 @@ +
+
+ + + +
diff --git a/addons/crm/crm_demo.xml b/addons/crm/crm_demo.xml index 2858250e86a..82bdcd8fcd9 100644 --- a/addons/crm/crm_demo.xml +++ b/addons/crm/crm_demo.xml @@ -6,14 +6,20 @@
+ + + + Indirect Sales IM + Marketing SPD + diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 1fcd7311a79..1107234b928 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -411,7 +411,7 @@ on_change="on_change_partner_id(partner_id)" string="Customer" context="{'default_name': partner_name, 'default_email': email_from, 'default_phone': phone}"/> - + diff --git a/addons/crm/i18n/he.po b/addons/crm/i18n/he.po new file mode 100644 index 00000000000..1f496821c20 --- /dev/null +++ b/addons/crm/i18n/he.po @@ -0,0 +1,3014 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:04+0000\n" +"PO-Revision-Date: 2013-12-26 23:09+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-27 05:22+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: crm +#: view:crm.lead.report:0 +msgid "# Leads" +msgstr "" + +#. module: crm +#: help:sale.config.settings,fetchmail_lead:0 +msgid "" +"Allows you to configure your incoming mail server, and create leads from " +"incoming emails." +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:898 +#: selection:crm.case.stage,type:0 +#: view:crm.lead:0 +#: selection:crm.lead,type:0 +#: view:crm.lead.report:0 +#: selection:crm.lead.report,type:0 +#, python-format +msgid "Lead" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,title:0 +msgid "Title" +msgstr "" + +#. module: crm +#: model:ir.actions.server,message:crm.action_email_reminder_lead +msgid "" +"Warning unprocessed incoming lead is more than 5 day old.\n" +"Name: [[object.name ]]\n" +"ID: [[object.id ]]\n" +"Description: [[object.description]]\n" +" " +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,action:0 +#: field:crm.phonecall2phonecall,action:0 +msgid "Action" +msgstr "" + +#. module: crm +#: model:ir.actions.server,name:crm.action_set_team_sales_department +msgid "Set team to Sales Department" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner.mass:0 +msgid "Select Opportunities" +msgstr "" + +#. module: crm +#: model:res.groups,name:crm.group_fund_raising +#: field:sale.config.settings,group_fund_raising:0 +msgid "Manage Fund Raising" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: field:crm.phonecall.report,delay_close:0 +msgid "Delay to close" +msgstr "" + +#. module: crm +#: view:crm.case.stage:0 +#: field:crm.case.stage,name:0 +msgid "Stage Name" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,user_id:0 +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +msgid "Salesperson" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_lead_report +msgid "CRM Lead Analysis" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,day:0 +msgid "Day" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Company Name" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor6 +msgid "Training" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_lead_categ_action +#: model:ir.ui.menu,name:crm.menu_crm_lead_categ +msgid "Sales Tags" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Exp. Closing" +msgstr "" + +#. module: crm +#: help:crm.case.section,message_unread:0 +#: help:crm.lead,message_unread:0 +#: help:crm.phonecall,message_unread:0 +msgid "If checked new messages require your attention." +msgstr "" + +#. module: crm +#: help:crm.lead.report,creation_day:0 +msgid "Creation day" +msgstr "" + +#. module: crm +#: field:crm.segmentation.line,name:0 +msgid "Rule Name" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_phonecall.py:280 +#, python-format +msgid "It's only possible to convert one phonecall at a time." +msgstr "" + +#. module: crm +#: view:crm.case.resource.type:0 +#: view:crm.lead:0 +#: field:crm.lead,type_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,type_id:0 +#: model:ir.model,name:crm.model_crm_case_resource_type +msgid "Campaign" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Search Opportunities" +msgstr "" + +#. module: crm +#: help:crm.lead.report,deadline_month:0 +msgid "Expected closing month" +msgstr "" + +#. module: crm +#: help:crm.case.section,message_summary:0 +#: help:crm.lead,message_summary:0 +#: help:crm.phonecall,message_summary:0 +msgid "" +"Holds the Chatter summary (number of messages, ...). This summary is " +"directly in html format in order to be inserted in kanban views." +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:640 +#: code:addons/crm/crm_lead.py:761 +#: code:addons/crm/crm_phonecall.py:280 +#, python-format +msgid "Warning!" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,partner_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,partner_id:0 +#: field:crm.opportunity2phonecall,partner_id:0 +#: view:crm.phonecall:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,partner_id:0 +#: field:crm.phonecall2phonecall,partner_id:0 +#: model:ir.model,name:crm.model_res_partner +#: model:process.node,name:crm.process_node_partner0 +msgid "Partner" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +#: model:ir.actions.act_window,name:crm.phonecall_to_phonecall_act +msgid "Schedule Other Call" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_phonecall.py:209 +#: view:crm.phonecall:0 +#, python-format +msgid "Phone Call" +msgstr "" + +#. module: crm +#: field:crm.lead,opt_out:0 +msgid "Opt-Out" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,state_id:0 +msgid "State" +msgstr "" + +#. module: crm +#: field:res.partner,meeting_count:0 +msgid "# Meetings" +msgstr "" + +#. module: crm +#: model:ir.actions.server,name:crm.action_email_reminder_lead +msgid "Reminder to User" +msgstr "" + +#. module: crm +#: field:crm.segmentation,segmentation_line:0 +msgid "Criteria" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Excluded Answers :" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_merge_opportunity +msgid "Merge opportunities" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: model:ir.actions.act_window,name:crm.action_report_crm_lead +#: model:ir.ui.menu,name:crm.menu_report_crm_leads_tree +msgid "Leads Analysis" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:1010 +#, python-format +msgid "%s a call for the %s." +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_case_resource_type_act +#: model:ir.ui.menu,name:crm.menu_crm_case_resource_type_act +msgid "Campaigns" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,categ_ids:0 +#: model:ir.ui.menu,name:crm.menu_crm_case_phonecall-act +msgid "Categories" +msgstr "" + +#. module: crm +#: help:crm.lead,opt_out:0 +msgid "" +"If opt-out is checked, this contact has refused to receive emails or " +"unsubscribed to a campaign." +msgstr "" + +#. module: crm +#: model:process.transition,name:crm.process_transition_leadpartner0 +msgid "Prospect Partner" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:1002 +#, python-format +msgid "No Subject" +msgstr "" + +#. module: crm +#: field:crm.lead,contact_name:0 +msgid "Contact Name" +msgstr "" + +#. module: crm +#: help:crm.segmentation,categ_id:0 +msgid "" +"The partner category that will be added to partners that match the " +"segmentation criterions after computation." +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_segmentation_tree-act +msgid "" +"

\n" +" Click to define a new customer segmentation.\n" +"

\n" +" Create specific categories which you can assign to your\n" +" contacts to better manage your interactions with them. The\n" +" segmentation tool is able to assign categories to contacts\n" +" according to criteria you set.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,contact_name:0 +#: field:crm.phonecall,partner_id:0 +#: field:crm.phonecall2phonecall,contact_name:0 +msgid "Contact" +msgstr "" + +#. module: crm +#: help:crm.case.section,change_responsible:0 +msgid "" +"When escalating to this team override the salesman with the team leader." +msgstr "" + +#. module: crm +#: model:process.transition,name:crm.process_transition_opportunitymeeting0 +msgid "Opportunity Meeting" +msgstr "" + +#. module: crm +#: help:crm.lead.report,delay_close:0 +#: help:crm.phonecall.report,delay_close:0 +msgid "Number of Days to close the case" +msgstr "" + +#. module: crm +#: model:process.node,note:crm.process_node_opportunities0 +msgid "When a real project/opportunity is detected" +msgstr "" + +#. module: crm +#: field:res.partner,opportunity_ids:0 +msgid "Leads and Opportunities" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.relate_partner_opportunities +msgid "" +"

\n" +" Click to create an opportunity related to this customer.\n" +"

\n" +" Use opportunities to keep track of your sales pipeline, " +"follow\n" +" up potential sales and better forecast your future " +"revenues.\n" +"

\n" +" You will be able to plan meetings and phone calls from\n" +" opportunities, convert them into quotations, attach related\n" +" documents, track all discussions, and much more.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead7 +#: view:crm.lead:0 +msgid "Dead" +msgstr "" + +#. module: crm +#: field:crm.case.section,message_unread:0 +#: view:crm.lead:0 +#: field:crm.lead,message_unread:0 +#: field:crm.phonecall,message_unread:0 +msgid "Unread Messages" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +#: field:crm.segmentation.line,segmentation_id:0 +#: model:ir.actions.act_window,name:crm.crm_segmentation-act +msgid "Segmentation" +msgstr "" + +#. module: crm +#: selection:crm.lead2opportunity.partner,action:0 +#: selection:crm.lead2opportunity.partner.mass,action:0 +#: selection:crm.partner.binding,action:0 +msgid "Link to an existing customer" +msgstr "" + +#. module: crm +#: field:crm.lead,write_date:0 +msgid "Update Date" +msgstr "" + +#. module: crm +#: field:crm.case.section,user_id:0 +msgid "Team Leader" +msgstr "" + +#. module: crm +#: help:crm.case.stage,probability:0 +msgid "" +"This percentage depicts the default/average probability of the Case for this " +"stage to be a success" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.opportunity2phonecall,categ_id:0 +#: field:crm.phonecall,categ_id:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,categ_id:0 +#: field:crm.phonecall2phonecall,categ_id:0 +msgid "Category" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "#Opportunities" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:640 +#, python-format +msgid "" +"Please select more than one element (lead or opportunity) from the list view." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Leads that are assigned to one of the sale teams I manage, or to me" +msgstr "" + +#. module: crm +#: field:crm.lead,partner_address_email:0 +msgid "Partner Contact Email" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_section_act +msgid "" +"

\n" +" Click to define a new sales team.\n" +"

\n" +" Use sales team to organize your different salespersons or\n" +" departments into separate teams. Each team will work in\n" +" its own list of opportunities.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: model:process.transition,note:crm.process_transition_opportunitymeeting0 +msgid "Normal or phone meeting for opportunity" +msgstr "" + +#. module: crm +#: field:crm.lead,state:0 +#: field:crm.lead.report,state:0 +#: field:crm.phonecall,state:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,state:0 +msgid "Status" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner:0 +msgid "Create Opportunity" +msgstr "" + +#. module: crm +#: view:sale.config.settings:0 +msgid "Configure" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Escalate" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Mailings" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,description:crm.mt_lead_stage +msgid "Stage changed" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "June" +msgstr "" + +#. module: crm +#: selection:crm.segmentation,state:0 +msgid "Not Running" +msgstr "" + +#. module: crm +#: field:crm.lead.report,planned_revenue:0 +msgid "Planned Revenue" +msgstr "" + +#. module: crm +#: field:crm.lead,planned_revenue:0 +msgid "Expected Revenue" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "October" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Included Answers :" +msgstr "" + +#. module: crm +#: help:crm.phonecall,state:0 +msgid "" +"The status is set to 'Todo', when a case is created. " +" If the case is in progress the status is set to 'Open'. " +" When the call is over, the status is set to 'Held'. " +" If the call needs to be done then the status is set " +"to 'Not Held'." +msgstr "" + +#. module: crm +#: field:crm.case.section,message_summary:0 +#: field:crm.lead,message_summary:0 +#: field:crm.phonecall,message_summary:0 +msgid "Summary" +msgstr "" + +#. module: crm +#: view:crm.merge.opportunity:0 +msgid "Merge" +msgstr "" + +#. module: crm +#: model:email.template,subject:crm.email_template_opportunity_mail +msgid "Opportunity ${object.name | h})" +msgstr "" + +#. module: crm +#: view:crm.case.categ:0 +msgid "Case Category" +msgstr "" + +#. module: crm +#: field:crm.lead,partner_address_name:0 +msgid "Partner Contact Name" +msgstr "" + +#. module: crm +#: model:ir.actions.server,subject:crm.action_email_reminder_lead +msgid "" +"Reminder on Lead: [[object.id ]] [[object.partner_id and 'of ' " +"+object.partner_id.name or '']]" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Profiling Options" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "#Phone calls" +msgstr "" + +#. module: crm +#: sql_constraint:crm.case.section:0 +msgid "The code of the sales team must be unique !" +msgstr "" + +#. module: crm +#: help:crm.lead,email_from:0 +msgid "Email address of the contact" +msgstr "" + +#. module: crm +#: selection:crm.case.stage,state:0 +#: view:crm.lead:0 +#: selection:crm.lead,state:0 +msgid "In Progress" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_phonecall_categ_action +msgid "" +"

\n" +" Click to add a new category.\n" +"

\n" +" Create specific phone call categories to better define the type " +"of\n" +" calls tracked in the system.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: help:crm.case.section,reply_to:0 +msgid "" +"The email address put in the 'Reply-To' of all emails sent by OpenERP about " +"cases in this sales team" +msgstr "" + +#. module: crm +#: field:crm.lead.report,creation_month:0 +msgid "Creation Month" +msgstr "" + +#. module: crm +#: field:crm.case.section,resource_calendar_id:0 +#: model:ir.ui.menu,name:crm.menu_action_resource_calendar_form +msgid "Working Time" +msgstr "" + +#. module: crm +#: view:crm.segmentation.line:0 +msgid "Partner Segmentation Lines" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.action_report_crm_phonecall +#: model:ir.ui.menu,name:crm.menu_report_crm_phonecalls_tree +msgid "Phone Calls Analysis" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Leads Form" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +#: model:ir.model,name:crm.model_crm_segmentation +msgid "Partner Segmentation" +msgstr "" + +#. module: crm +#: field:crm.lead,company_currency:0 +msgid "Currency" +msgstr "" + +#. module: crm +#: field:crm.lead.report,probable_revenue:0 +msgid "Probable Revenue" +msgstr "" + +#. module: crm +#: help:crm.lead.report,creation_month:0 +msgid "Creation month" +msgstr "" + +#. module: crm +#: help:crm.segmentation,name:0 +msgid "The name of the segmentation." +msgstr "" + +#. module: crm +#: field:crm.case.stage,probability:0 +msgid "Probability (%)" +msgstr "" + +#. module: crm +#: sql_constraint:crm.lead:0 +msgid "The probability of closing the deal should be between 0% and 100%!" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Leads Generation" +msgstr "" + +#. module: crm +#: view:board.board:0 +msgid "Statistics Dashboard" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:878 +#: model:crm.case.stage,name:crm.stage_lead2 +#: selection:crm.case.stage,type:0 +#: view:crm.lead:0 +#: selection:crm.lead,type:0 +#: view:crm.lead.report:0 +#: selection:crm.lead.report,type:0 +#: field:crm.meeting,opportunity_id:0 +#: field:res.partner,opportunity_count:0 +#, python-format +msgid "Opportunity" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead7 +msgid "Television" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.action_crm_send_mass_convert +msgid "Convert to opportunities" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_sale_config_settings +msgid "sale.config.settings" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Stop Process" +msgstr "" + +#. module: crm +#: field:crm.case.section,alias_id:0 +msgid "Alias" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Search Phonecalls" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "" +"Leads/Opportunities that are assigned to one of the sale teams I manage" +msgstr "" + +#. module: crm +#: field:calendar.attendee,categ_id:0 +msgid "Event Type" +msgstr "" + +#. module: crm +#: field:crm.segmentation,exclusif:0 +msgid "Exclusive" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:600 +#, python-format +msgid "From %s : %s" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner.mass:0 +msgid "Convert to Opportunities" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner:0 +#: view:crm.lead2opportunity.partner.mass:0 +#: view:crm.merge.opportunity:0 +#: view:crm.opportunity2phonecall:0 +#: view:crm.phonecall2phonecall:0 +msgid "or" +msgstr "" + +#. module: crm +#: field:crm.lead.report,create_date:0 +#: field:crm.phonecall.report,create_date:0 +msgid "Create Date" +msgstr "" + +#. module: crm +#: field:crm.lead,ref2:0 +msgid "Reference 2" +msgstr "" + +#. module: crm +#: help:crm.case.stage,section_ids:0 +msgid "" +"Link between stages and sales teams. When set, this limitate the current " +"stage to the selected sales teams." +msgstr "" + +#. module: crm +#: view:crm.case.stage:0 +#: field:crm.case.stage,requirements:0 +msgid "Requirements" +msgstr "" + +#. module: crm +#: field:crm.lead,zip:0 +msgid "Zip" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Unassigned Phonecalls" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.lead2opportunity.partner:0 +#: field:crm.lead2opportunity.partner,opportunity_ids:0 +#: field:crm.lead2opportunity.partner.mass,opportunity_ids:0 +#: model:ir.actions.act_window,name:crm.crm_case_category_act_oppor11 +#: model:ir.actions.act_window,name:crm.relate_partner_opportunities +#: model:ir.ui.menu,name:crm.menu_crm_opportunities +#: model:process.node,name:crm.process_node_opportunities0 +#: view:res.partner:0 +msgid "Opportunities" +msgstr "" + +#. module: crm +#: field:crm.segmentation,categ_id:0 +msgid "Partner Category" +msgstr "" + +#. module: crm +#: field:crm.lead,probability:0 +msgid "Success Rate (%)" +msgstr "" + +#. module: crm +#: field:crm.segmentation,sales_purchase_active:0 +msgid "Use The Sales Purchase Rules" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_phone2 +msgid "Outbound" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Mark Won" +msgstr "" + +#. module: crm +#: model:ir.filters,name:crm.filter_usa_lead +msgid "Leads from USA" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Mark Lost" +msgstr "" + +#. module: crm +#: model:ir.filters,name:crm.filter_draft_lead +msgid "Draft Leads" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "March" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Send Email" +msgstr "" + +#. module: crm +#: code:addons/crm/wizard/crm_lead_to_opportunity.py:89 +#, python-format +msgid "Warning !" +msgstr "" + +#. module: crm +#: field:crm.lead,day_open:0 +msgid "Days to Open" +msgstr "" + +#. module: crm +#: field:crm.lead,mobile:0 +#: field:crm.phonecall,partner_mobile:0 +msgid "Mobile" +msgstr "" + +#. module: crm +#: field:crm.lead,ref:0 +msgid "Reference" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "" +"Opportunities that are assigned to either me or one of the sale teams I " +"manage" +msgstr "" + +#. module: crm +#: help:crm.case.section,resource_calendar_id:0 +msgid "Used to compute open days" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.act_crm_opportunity_crm_meeting_new +#: model:ir.actions.act_window,name:crm.crm_meeting_partner +#: view:res.partner:0 +#: field:res.partner,meeting_ids:0 +msgid "Meetings" +msgstr "" + +#. module: crm +#: field:crm.lead,date_action_next:0 +#: field:crm.lead,title_action:0 +#: field:crm.phonecall,date_action_next:0 +msgid "Next Action" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:780 +#, python-format +msgid "Partner set to %s." +msgstr "" + +#. module: crm +#: selection:crm.lead.report,state:0 +#: selection:crm.phonecall,state:0 +#: selection:crm.phonecall.report,state:0 +msgid "Draft" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Partner Segmentations" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Show only opportunity" +msgstr "" + +#. module: crm +#: field:crm.lead,name:0 +msgid "Subject" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "New Leads" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Show Sales Team" +msgstr "" + +#. module: crm +#: help:sale.config.settings,module_crm_claim:0 +msgid "" +"Allows you to track your customers/suppliers claims and grievances.\n" +" This installs the module crm_claim." +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead6 +#: view:crm.lead:0 +msgid "Won" +msgstr "" + +#. module: crm +#: field:crm.lead.report,delay_expected:0 +msgid "Overpassed Deadline" +msgstr "" + +#. module: crm +#: model:crm.case.section,name:crm.section_sales_department +msgid "Sales Department" +msgstr "" + +#. module: crm +#: field:crm.case.stage,type:0 +#: field:crm.lead,type:0 +#: field:crm.lead.report,type:0 +#: view:crm.opportunity2phonecall:0 +msgid "Type" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Compute Segmentation" +msgstr "" + +#. module: crm +#: selection:crm.lead,priority:0 +#: selection:crm.lead.report,priority:0 +#: selection:crm.phonecall,priority:0 +#: selection:crm.phonecall.report,priority:0 +msgid "Lowest" +msgstr "" + +#. module: crm +#: field:crm.lead,create_date:0 +#: view:crm.phonecall:0 +#: field:crm.phonecall,create_date:0 +#: field:crm.phonecall.report,creation_date:0 +msgid "Creation Date" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:715 +#, python-format +msgid "Lead converted into an Opportunity" +msgstr "" + +#. module: crm +#: selection:crm.segmentation.line,expr_name:0 +msgid "Purchase Amount" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Year of call" +msgstr "" + +#. module: crm +#: view:crm.case.stage:0 +#: view:crm.lead:0 +#: field:crm.lead,stage_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,stage_id:0 +msgid "Stage" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Phone Calls that are assigned to me" +msgstr "" + +#. module: crm +#: field:crm.lead,user_login:0 +msgid "User Login" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Phone calls which are in pending state" +msgstr "" + +#. module: crm +#: view:crm.case.section:0 +#: field:crm.case.section,stage_ids:0 +#: view:crm.case.stage:0 +#: model:ir.actions.act_window,name:crm.crm_case_stage_act +#: model:ir.actions.act_window,name:crm.crm_lead_stage_act +#: model:ir.ui.menu,name:crm.menu_crm_lead_stage_act +msgid "Stages" +msgstr "" + +#. module: crm +#: help:sale.config.settings,module_crm_helpdesk:0 +msgid "" +"Allows you to communicate with Customer, process Customer query, and " +"provide better help and support. This installs the module crm_helpdesk." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Delete" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,description:crm.mt_lead_create +msgid "Opportunity created" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "í" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "September" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_category_act_oppor11 +msgid "" +"

\n" +" Click to create a new opportunity.\n" +"

\n" +" OpenERP helps you keep track of your sales pipeline to follow\n" +" up potential sales and better forecast your future revenues.\n" +"

\n" +" You will be able to plan meetings and phone calls from\n" +" opportunities, convert them into quotations, attach related\n" +" documents, track all discussions, and much more.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: field:crm.segmentation,partner_id:0 +msgid "Max Partner ID processed" +msgstr "" + +#. module: crm +#: help:crm.case.stage,on_change:0 +msgid "" +"Setting this stage will change the probability automatically on the " +"opportunity." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "oe_kanban_text_red" +msgstr "" + +#. module: crm +#: model:ir.ui.menu,name:crm.menu_crm_payment_mode_act +msgid "Payment Modes" +msgstr "" + +#. module: crm +#: field:crm.lead.report,opening_date:0 +#: field:crm.phonecall.report,opening_date:0 +msgid "Opening Date" +msgstr "" + +#. module: crm +#: help:crm.phonecall,duration:0 +msgid "Duration in Minutes" +msgstr "" + +#. module: crm +#: field:crm.case.channel,name:0 +msgid "Channel Name" +msgstr "" + +#. module: crm +#: help:crm.lead.report,deadline_day:0 +msgid "Expected closing day" +msgstr "" + +#. module: crm +#: help:crm.case.section,active:0 +msgid "" +"If the active field is set to true, it will allow you to hide the sales team " +"without removing it." +msgstr "" + +#. module: crm +#: help:crm.case.stage,case_default:0 +msgid "" +"If you check this field, this stage will be proposed by default on each " +"sales team. It will not assign this stage to existing teams." +msgstr "" + +#. module: crm +#: help:crm.case.stage,type:0 +msgid "" +"This field is used to distinguish stages related to Leads from stages " +"related to Opportunities, or to specify stages available for both types." +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_lead_create +#: model:mail.message.subtype,name:crm.mt_salesteam_lead +msgid "Lead Created" +msgstr "" + +#. module: crm +#: help:crm.segmentation,sales_purchase_active:0 +msgid "" +"Check if you want to use this tab as part of the segmentation rule. If not " +"checked, the criteria beneath will be ignored" +msgstr "" + +#. module: crm +#: field:crm.segmentation,state:0 +msgid "Execution Status" +msgstr "" + +#. module: crm +#: view:crm.opportunity2phonecall:0 +msgid "Log call" +msgstr "" + +#. module: crm +#: field:crm.lead,day_close:0 +msgid "Days to Close" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:1057 +#: field:crm.case.section,complete_name:0 +#, python-format +msgid "unknown" +msgstr "" + +#. module: crm +#: field:crm.case.section,message_is_follower:0 +#: field:crm.lead,message_is_follower:0 +#: field:crm.phonecall,message_is_follower:0 +msgid "Is a Follower" +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,date:0 +#: view:crm.phonecall:0 +#: field:crm.phonecall,date:0 +#: field:crm.phonecall2phonecall,date:0 +msgid "Date" +msgstr "" + +#. module: crm +#: model:crm.case.section,name:crm.crm_case_section_4 +msgid "Online Support" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +msgid "Extended Filters..." +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Phone calls which are in closed state" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Search" +msgstr "" + +#. module: crm +#: help:crm.lead,state:0 +msgid "" +"The Status is set to 'Draft', when a case is created. If the case is in " +"progress the Status is set to 'Open'. When the case is over, the Status is " +"set to 'Done'. If the case needs to be reviewed then the Status is set to " +"'Pending'." +msgstr "" + +#. module: crm +#: model:crm.case.section,name:crm.crm_case_section_1 +msgid "Sales Marketing Department" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Date of call" +msgstr "" + +#. module: crm +#: help:crm.lead,section_id:0 +msgid "" +"When sending mails, the default email address is taken from the sales team." +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "" +"Phone Calls Assigned to the current user or with a team having the current " +"user as team leader" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Segmentation Description" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Lead Description" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:581 +#, python-format +msgid "Merged opportunities" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor7 +msgid "Consulting" +msgstr "" + +#. module: crm +#: field:crm.case.section,code:0 +msgid "Code" +msgstr "" + +#. module: crm +#: view:sale.config.settings:0 +msgid "Features" +msgstr "" + +#. module: crm +#: field:crm.case.section,child_ids:0 +msgid "Child Teams" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Phone calls which are in draft and open state" +msgstr "" + +#. module: crm +#: field:crm.lead2opportunity.partner.mass,user_ids:0 +msgid "Salesmen" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "References" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner:0 +#: view:crm.lead2opportunity.partner.mass:0 +#: view:crm.merge.opportunity:0 +#: view:crm.opportunity2phonecall:0 +#: view:crm.phonecall:0 +#: view:crm.phonecall2phonecall:0 +msgid "Cancel" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Opportunities Assigned to Me or My Team(s)" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor4 +msgid "Information" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Leads/Opportunities which are in pending state" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "To Do" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,description:crm.mt_lead_lost +msgid "Opportunity lost" +msgstr "" + +#. module: crm +#: field:crm.lead2opportunity.partner,action:0 +#: field:crm.lead2opportunity.partner.mass,action:0 +#: field:crm.partner.binding,action:0 +msgid "Related Customer" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor8 +msgid "Other" +msgstr "" + +#. module: crm +#: field:crm.phonecall,opportunity_id:0 +#: model:ir.model,name:crm.model_crm_lead +msgid "Lead/Opportunity" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.action_merge_opportunities +#: model:ir.actions.act_window,name:crm.merge_opportunity_act +msgid "Merge leads/opportunities" +msgstr "" + +#. module: crm +#: help:crm.case.stage,sequence:0 +msgid "Used to order stages. Lower is better." +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_phonecall_categ_action +msgid "Phonecall Categories" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Leads/Opportunities which are in open state" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_res_users +msgid "Users" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_lead_stage +msgid "Stage Changed" +msgstr "" + +#. module: crm +#: field:crm.case.stage,section_ids:0 +msgid "Sections" +msgstr "" + +#. module: crm +#: constraint:crm.case.section:0 +msgid "Error ! You cannot create recursive Sales team." +msgstr "" + +#. module: crm +#: selection:crm.opportunity2phonecall,action:0 +#: selection:crm.phonecall2phonecall,action:0 +msgid "Log a call" +msgstr "" + +#. module: crm +#: selection:crm.segmentation.line,expr_name:0 +msgid "Sale Amount" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +#: model:ir.actions.act_window,name:crm.act_crm_opportunity_crm_phonecall_new +msgid "Phone calls" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.action_report_crm_opportunity +msgid "" +"Opportunities Analysis gives you an instant access to your opportunities " +"with information such as the expected revenue, planned cost, missed " +"deadlines or the number of interactions per opportunity. This report is " +"mainly used by the sales manager in order to do the periodic review with the " +"teams of the sales pipeline." +msgstr "" + +#. module: crm +#: field:crm.case.categ,name:0 +#: field:crm.payment.mode,name:0 +#: field:crm.segmentation,name:0 +msgid "Name" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Leads/Opportunities that are assigned to me" +msgstr "" + +#. module: crm +#: field:crm.lead.report,date_closed:0 +#: field:crm.phonecall.report,date_closed:0 +msgid "Close Date" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "My Case(s)" +msgstr "" + +#. module: crm +#: help:crm.case.section,message_ids:0 +#: help:crm.lead,message_ids:0 +#: help:crm.phonecall,message_ids:0 +msgid "Messages and communication history" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Show Countries" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.phonecall:0 +msgid "Creation" +msgstr "" + +#. module: crm +#: selection:crm.lead,priority:0 +#: selection:crm.lead.report,priority:0 +#: selection:crm.phonecall,priority:0 +#: selection:crm.phonecall.report,priority:0 +msgid "High" +msgstr "" + +#. module: crm +#: model:process.node,note:crm.process_node_partner0 +msgid "Convert to prospect to business partner" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_payment_mode +msgid "CRM Payment Mode" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Leads/Opportunities which are in done state" +msgstr "" + +#. module: crm +#: field:crm.lead.report,delay_close:0 +msgid "Delay to Close" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.lead.report:0 +#: view:crm.phonecall:0 +#: view:crm.phonecall.report:0 +msgid "Group By..." +msgstr "" + +#. module: crm +#: view:crm.merge.opportunity:0 +msgid "Merge Leads/Opportunities" +msgstr "" + +#. module: crm +#: field:crm.case.section,parent_id:0 +msgid "Parent Team" +msgstr "" + +#. module: crm +#: selection:crm.lead2opportunity.partner,action:0 +#: selection:crm.lead2opportunity.partner.mass,action:0 +#: selection:crm.partner.binding,action:0 +msgid "Do not link to a customer" +msgstr "" + +#. module: crm +#: field:crm.lead,date_action:0 +msgid "Next Action Date" +msgstr "" + +#. module: crm +#: help:crm.case.stage,state:0 +msgid "" +"The status of your document will automatically change regarding the selected " +"stage. For example, if a stage is related to the status 'Close', when your " +"document reaches this stage, it is automatically closed." +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner.mass:0 +msgid "Assign opportunities to" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_phone1 +msgid "Inbound" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Month of call" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_phonecall.py:290 +#, python-format +msgid "Partner has been created." +msgstr "" + +#. module: crm +#: field:sale.config.settings,module_crm_claim:0 +msgid "Manage Customer Claims" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.action_report_crm_lead +msgid "" +"Leads Analysis allows you to check different CRM related information like " +"the treatment delays or number of leads per state. You can sort out your " +"leads analysis by different groups to get accurate grained analysis." +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor3 +msgid "Services" +msgstr "" + +#. module: crm +#: selection:crm.lead,priority:0 +#: selection:crm.lead.report,priority:0 +#: selection:crm.phonecall,priority:0 +#: selection:crm.phonecall.report,priority:0 +msgid "Highest" +msgstr "" + +#. module: crm +#: help:crm.lead.report,creation_year:0 +msgid "Creation year" +msgstr "" + +#. module: crm +#: view:crm.case.section:0 +#: field:crm.lead,description:0 +msgid "Notes" +msgstr "" + +#. module: crm +#: field:crm.segmentation.line,expr_value:0 +msgid "Value" +msgstr "" + +#. module: crm +#: field:crm.lead,partner_name:0 +msgid "Customer Name" +msgstr "" + +#. module: crm +#: field:crm.case.section,reply_to:0 +msgid "Reply-To" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Display" +msgstr "" + +#. module: crm +#: view:board.board:0 +msgid "Opportunities by Stage" +msgstr "" + +#. module: crm +#: model:process.transition,note:crm.process_transition_leadpartner0 +msgid "Prospect is converting to business partner" +msgstr "" + +#. module: crm +#: view:crm.case.channel:0 +#: model:ir.actions.act_window,name:crm.crm_case_channel_action +#: model:ir.model,name:crm.model_crm_case_channel +#: model:ir.ui.menu,name:crm.menu_crm_case_channel +msgid "Channels" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +#: selection:crm.phonecall,state:0 +#: view:crm.phonecall.report:0 +#: selection:crm.phonecall.report,state:0 +msgid "Held" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Extra Info" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Fund Raising" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Edit..." +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead5 +msgid "Google Adwords" +msgstr "" + +#. module: crm +#: view:crm.case.section:0 +msgid "Select Stages for this Sales Team" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,priority:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,priority:0 +#: field:crm.phonecall,priority:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,priority:0 +msgid "Priority" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_lead2opportunity_partner +msgid "Lead To Opportunity Partner" +msgstr "" + +#. module: crm +#: help:crm.lead,partner_id:0 +msgid "Linked partner (optional). Usually created when converting the lead." +msgstr "" + +#. module: crm +#: field:crm.lead,payment_mode:0 +#: view:crm.payment.mode:0 +#: model:ir.actions.act_window,name:crm.action_crm_payment_mode +msgid "Payment Mode" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_lead2opportunity_partner_mass +msgid "Mass Lead To Opportunity Partner" +msgstr "" + +#. module: crm +#: view:sale.config.settings:0 +msgid "On Mail Server" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.open_board_statistical_dash +#: model:ir.ui.menu,name:crm.menu_board_statistics_dash +msgid "CRM" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_segmentation_tree-act +#: model:ir.ui.menu,name:crm.menu_crm_segmentation-act +msgid "Contacts Segmentation" +msgstr "" + +#. module: crm +#: model:process.node,note:crm.process_node_meeting0 +msgid "Schedule a normal or phone meeting" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead1 +msgid "Telesales" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Leads Assigned to Me or My Team(s)" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_segmentation_line +msgid "Segmentation line" +msgstr "" + +#. module: crm +#: view:crm.opportunity2phonecall:0 +#: view:crm.phonecall2phonecall:0 +msgid "Planned Date" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Expected Revenues" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Referrer" +msgstr "" + +#. module: crm +#: help:crm.lead,type:0 +#: help:crm.lead.report,type:0 +msgid "Type is used to separate Leads and Opportunities" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "July" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Lead / Customer" +msgstr "" + +#. module: crm +#: model:crm.case.section,name:crm.crm_case_section_2 +msgid "Support Department" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Show only lead" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_case_section_act +#: model:ir.model,name:crm.model_crm_case_section +#: model:ir.ui.menu,name:crm.menu_crm_case_section_act +msgid "Sales Teams" +msgstr "" + +#. module: crm +#: field:crm.case.stage,case_default:0 +msgid "Default to New Sales Team" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Team" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Leads/Opportunities which are in New state" +msgstr "" + +#. module: crm +#: selection:crm.phonecall,state:0 +#: view:crm.phonecall.report:0 +msgid "Not Held" +msgstr "" + +#. module: crm +#: field:crm.lead.report,probability:0 +msgid "Probability" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,month:0 +msgid "Month" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: model:ir.actions.act_window,name:crm.crm_case_category_act_leads_all +#: model:ir.ui.menu,name:crm.menu_crm_leads +#: model:process.node,name:crm.process_node_leads0 +msgid "Leads" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:579 +#, python-format +msgid "Merged leads" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor5 +msgid "Design" +msgstr "" + +#. module: crm +#: selection:crm.lead2opportunity.partner,name:0 +#: selection:crm.lead2opportunity.partner.mass,name:0 +msgid "Merge with existing opportunities" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +#: selection:crm.phonecall.report,state:0 +msgid "Todo" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_lead_convert_to_opportunity +#: model:mail.message.subtype,name:crm.mt_salesteam_lead_opportunity +msgid "Lead to Opportunity" +msgstr "" + +#. module: crm +#: field:crm.lead,user_email:0 +msgid "User Email" +msgstr "" + +#. module: crm +#: help:crm.lead,partner_name:0 +msgid "" +"The name of the future partner company that will be created while converting " +"the lead into opportunity" +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,note:0 +#: field:crm.phonecall2phonecall,note:0 +msgid "Note" +msgstr "" + +#. module: crm +#: selection:crm.lead,priority:0 +#: selection:crm.lead.report,priority:0 +#: selection:crm.phonecall,priority:0 +#: selection:crm.phonecall.report,priority:0 +msgid "Low" +msgstr "" + +#. module: crm +#: selection:crm.case.stage,state:0 +#: field:crm.lead,date_closed:0 +#: selection:crm.lead,state:0 +#: view:crm.lead.report:0 +#: selection:crm.lead.report,state:0 +#: field:crm.phonecall,date_closed:0 +msgid "Closed" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Open Opportunities" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead2 +msgid "Email Campaign - Services" +msgstr "" + +#. module: crm +#: selection:crm.case.stage,state:0 +#: selection:crm.lead,state:0 +#: view:crm.lead.report:0 +#: selection:crm.lead.report,state:0 +#: selection:crm.phonecall.report,state:0 +msgid "Pending" +msgstr "" + +#. module: crm +#: model:process.transition,name:crm.process_transition_leadopportunity0 +msgid "Prospect Opportunity" +msgstr "" + +#. module: crm +#: field:crm.lead,email_cc:0 +msgid "Global CC" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +#: model:ir.actions.act_window,name:crm.crm_case_categ_phone0 +#: model:ir.ui.menu,name:crm.menu_crm_case_phone +#: model:ir.ui.menu,name:crm.menu_crm_config_phonecall +msgid "Phone Calls" +msgstr "" + +#. module: crm +#: view:crm.case.stage:0 +msgid "Stage Search" +msgstr "" + +#. module: crm +#: help:crm.lead.report,delay_open:0 +#: help:crm.phonecall.report,delay_open:0 +msgid "Number of Days to open the case" +msgstr "" + +#. module: crm +#: field:crm.lead,phone:0 +#: field:crm.opportunity2phonecall,phone:0 +#: view:crm.phonecall:0 +#: field:crm.phonecall,partner_phone:0 +#: field:crm.phonecall2phonecall,phone:0 +msgid "Phone" +msgstr "" + +#. module: crm +#: field:crm.case.channel,active:0 +#: field:crm.case.section,active:0 +#: field:crm.lead,active:0 +#: field:crm.phonecall,active:0 +msgid "Active" +msgstr "" + +#. module: crm +#: selection:crm.segmentation.line,operator:0 +msgid "Mandatory Expression" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Send Mail" +msgstr "" + +#. module: crm +#: selection:crm.lead2opportunity.partner,action:0 +#: selection:crm.lead2opportunity.partner.mass,action:0 +#: selection:crm.partner.binding,action:0 +msgid "Create a new customer" +msgstr "" + +#. module: crm +#: field:crm.lead.report,deadline_day:0 +msgid "Exp. Closing Day" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor2 +msgid "Software" +msgstr "" + +#. module: crm +#: field:crm.case.section,change_responsible:0 +msgid "Reassign Escalated" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: model:ir.actions.act_window,name:crm.action_report_crm_opportunity +#: model:ir.ui.menu,name:crm.menu_report_crm_opportunities_tree +msgid "Opportunities Analysis" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Misc" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.lead.report:0 +#: selection:crm.lead.report,state:0 +msgid "Open" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,city:0 +msgid "City" +msgstr "" + +#. module: crm +#: selection:crm.case.stage,type:0 +msgid "Both" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Call Done" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +#: field:crm.phonecall,user_id:0 +msgid "Responsible" +msgstr "" + +#. module: crm +#: model:crm.case.section,name:crm.crm_case_section_3 +msgid "Direct Marketing" +msgstr "" + +#. module: crm +#: model:crm.case.categ,name:crm.categ_oppor1 +msgid "Product" +msgstr "" + +#. module: crm +#: field:crm.lead.report,creation_year:0 +msgid "Creation Year" +msgstr "" + +#. module: crm +#: view:crm.lead2opportunity.partner.mass:0 +msgid "Conversion Options" +msgstr "" + +#. module: crm +#: view:crm.case.section:0 +msgid "" +"Follow this salesteam to automatically track the events associated to users " +"of this team." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Address" +msgstr "" + +#. module: crm +#: help:crm.case.section,alias_id:0 +msgid "" +"The email address associated with this team. New emails received will " +"automatically create new leads assigned to the team." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Unassigned Opportunities" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Search Leads" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,delay_open:0 +msgid "Delay to open" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_case_categ_phone_outgoing0 +#: model:ir.ui.menu,name:crm.menu_crm_case_phone_outbound +msgid "Scheduled Calls" +msgstr "" + +#. module: crm +#: field:crm.lead,id:0 +msgid "ID" +msgstr "" + +#. module: crm +#: help:crm.lead,type_id:0 +msgid "" +"From which campaign (seminar, marketing campaign, mass mailing, ...) did " +"this contact come from?" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_calendar_attendee +msgid "Attendee information" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Segmentation Test" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Continue Process" +msgstr "" + +#. module: crm +#: selection:crm.lead2opportunity.partner,name:0 +#: selection:crm.lead2opportunity.partner.mass,name:0 +#: model:ir.actions.act_window,name:crm.action_crm_lead2opportunity_partner +msgid "Convert to opportunity" +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,user_id:0 +#: field:crm.phonecall2phonecall,user_id:0 +msgid "Assign To" +msgstr "" + +#. module: crm +#: field:crm.lead,date_action_last:0 +#: field:crm.phonecall,date_action_last:0 +msgid "Last Action" +msgstr "" + +#. module: crm +#: field:crm.phonecall,duration:0 +#: field:crm.phonecall.report,duration:0 +msgid "Duration" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_categ_phone_outgoing0 +msgid "" +"

\n" +" Click to schedule a call \n" +"

\n" +" OpenERP allows you to easily define all the calls to be done\n" +" by your sales team and follow up based on their summary.\n" +"

\n" +" You can use the import feature to massively import a new list " +"of\n" +" prospects to qualify.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: help:crm.case.stage,fold:0 +msgid "" +"This stage is not visible, for example in status bar or kanban view, when " +"there are no records in that stage to display." +msgstr "" + +#. module: crm +#: field:crm.lead.report,nbr:0 +#: field:crm.phonecall.report,nbr:0 +msgid "# of Cases" +msgstr "" + +#. module: crm +#: help:crm.phonecall,section_id:0 +msgid "Sales team to which Case belongs to." +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead6 +msgid "Banner Ads" +msgstr "" + +#. module: crm +#: field:crm.merge.opportunity,opportunity_ids:0 +msgid "Leads/Opportunities" +msgstr "" + +#. module: crm +#: field:crm.lead,fax:0 +msgid "Fax" +msgstr "" + +#. module: crm +#: field:crm.lead,company_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,company_id:0 +#: field:crm.phonecall,company_id:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,company_id:0 +msgid "Company" +msgstr "" + +#. module: crm +#: selection:crm.segmentation,state:0 +msgid "Running" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,description:crm.mt_lead_convert_to_opportunity +msgid "Lead converted into an opportunity" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Unassigned Leads" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,description:crm.mt_lead_won +msgid "Opportunity won" +msgstr "" + +#. module: crm +#: field:crm.case.categ,object_id:0 +msgid "Object Name" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Phone Calls Assigned to Me or My Team(s)" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Reset" +msgstr "" + +#. module: crm +#: view:sale.config.settings:0 +msgid "After-Sale Services" +msgstr "" + +#. module: crm +#: field:crm.case.section,message_ids:0 +#: field:crm.lead,message_ids:0 +#: field:crm.phonecall,message_ids:0 +msgid "Messages" +msgstr "" + +#. module: crm +#: help:crm.lead,channel_id:0 +msgid "Communication channel (mail, direct, phone, ...)" +msgstr "" + +#. module: crm +#: field:crm.opportunity2phonecall,name:0 +#: field:crm.phonecall2phonecall,name:0 +msgid "Call summary" +msgstr "" + +#. module: crm +#: selection:crm.case.stage,state:0 +#: selection:crm.lead,state:0 +#: selection:crm.lead.report,state:0 +#: selection:crm.phonecall,state:0 +#: selection:crm.phonecall.report,state:0 +msgid "Cancelled" +msgstr "" + +#. module: crm +#: field:crm.lead,color:0 +msgid "Color Index" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.action_report_crm_phonecall +msgid "" +"From this report, you can analyse the performance of your sales team, based " +"on their phone calls. You can group or filter the information according to " +"several criteria and drill down the information, by adding more groups in " +"the report." +msgstr "" + +#. module: crm +#: field:crm.case.stage,fold:0 +msgid "Fold by Default" +msgstr "" + +#. module: crm +#: field:crm.case.stage,state:0 +msgid "Related Status" +msgstr "" + +#. module: crm +#: field:crm.phonecall,name:0 +msgid "Call Summary" +msgstr "" + +#. module: crm +#: field:crm.segmentation.line,expr_operator:0 +msgid "Operator" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: model:ir.actions.act_window,name:crm.opportunity2phonecall_act +msgid "Schedule/Log Call" +msgstr "" + +#. module: crm +#: view:crm.merge.opportunity:0 +msgid "Select Leads/Opportunities" +msgstr "" + +#. module: crm +#: selection:crm.phonecall,state:0 +msgid "Confirmed" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_partner_binding +msgid "Handle partner binding or generation in CRM wizards." +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.act_oppor_stage_user +msgid "Planned Revenue By User and Stage" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Confirm" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Unread messages" +msgstr "" + +#. module: crm +#: field:crm.phonecall.report,section_id:0 +msgid "Section" +msgstr "" + +#. module: crm +#: selection:crm.segmentation.line,operator:0 +msgid "Optional Expression" +msgstr "" + +#. module: crm +#: field:crm.case.section,message_follower_ids:0 +#: field:crm.lead,message_follower_ids:0 +#: field:crm.phonecall,message_follower_ids:0 +msgid "Followers" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_category_act_leads_all +msgid "" +"

\n" +" Click to create an unqualified lead.\n" +"

\n" +" Use leads if you need a qualification step before creating an\n" +" opportunity or a customer. It can be a business card you " +"received,\n" +" a contact form filled in your website, or a file of unqualified\n" +" prospects you import, etc.\n" +"

\n" +" Once qualified, the lead can be converted into a business\n" +" opportunity and/or a new customer in your address book.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: field:sale.config.settings,fetchmail_lead:0 +msgid "Create leads from incoming mails" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,email_from:0 +#: field:crm.phonecall,email_from:0 +msgid "Email" +msgstr "" + +#. module: crm +#: view:crm.case.channel:0 +#: view:crm.lead:0 +#: field:crm.lead,channel_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,channel_id:0 +msgid "Channel" +msgstr "" + +#. module: crm +#: view:crm.opportunity2phonecall:0 +#: view:crm.phonecall2phonecall:0 +msgid "Schedule Call" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +msgid "My Sales Team(s)" +msgstr "" + +#. module: crm +#: help:crm.segmentation,exclusif:0 +msgid "" +"Check if the category is limited to partners that match the segmentation " +"criterions. \n" +"If checked, remove the category from partners that doesn't match " +"segmentation criterions" +msgstr "" + +#. module: crm +#: model:process.transition,note:crm.process_transition_leadopportunity0 +msgid "Creating business opportunities from Leads" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead3 +msgid "Email Campaign - Products" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_categ_phone_incoming0 +msgid "" +"

\n" +" Click to log the summary of a phone call. \n" +"

\n" +" OpenERP allows you to log inbound calls on the fly to track the\n" +" history of the communication with a customer or to inform " +"another\n" +" team member.\n" +"

\n" +" In order to follow up on the call, you can trigger a request " +"for\n" +" another call, a meeting or an opportunity.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: model:process.node,note:crm.process_node_leads0 +msgid "Very first contact with new prospect" +msgstr "" + +#. module: crm +#: view:res.partner:0 +msgid "Calls" +msgstr "" + +#. module: crm +#: field:crm.case.stage,on_change:0 +msgid "Change Probability Automatically" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "My Phone Calls" +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead3 +msgid "Qualification" +msgstr "" + +#. module: crm +#: field:crm.lead2opportunity.partner,name:0 +#: field:crm.lead2opportunity.partner.mass,name:0 +msgid "Conversion Action" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_lead_categ_action +msgid "" +"

\n" +" Click to define a new sales tag.\n" +"

\n" +" Create specific tags that fit your company's activities\n" +" to better classify and analyse your leads and " +"opportunities.\n" +" Such categories could for instance reflect your product\n" +" structure or the different types of sales you do.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "August" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_lead_lost +#: model:mail.message.subtype,name:crm.mt_salesteam_lead_lost +msgid "Opportunity Lost" +msgstr "" + +#. module: crm +#: field:crm.lead.report,deadline_month:0 +msgid "Exp. Closing Month" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "December" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Date of Call" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,date_deadline:0 +msgid "Expected Closing" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_opportunity2phonecall +msgid "Opportunity to Phonecall" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Sales Purchase" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Schedule Meeting" +msgstr "" + +#. module: crm +#: field:crm.lead.report,deadline_year:0 +msgid "Ex. Closing Year" +msgstr "" + +#. module: crm +#: model:ir.actions.client,name:crm.action_client_crm_menu +msgid "Open Sale Menu" +msgstr "" + +#. module: crm +#: field:crm.lead,date_open:0 +#: field:crm.phonecall,date_open:0 +msgid "Opened" +msgstr "" + +#. module: crm +#: view:crm.case.section:0 +#: field:crm.case.section,member_ids:0 +msgid "Team Members" +msgstr "" + +#. module: crm +#: view:crm.opportunity2phonecall:0 +#: view:crm.phonecall2phonecall:0 +msgid "Schedule/Log a Call" +msgstr "" + +#. module: crm +#: field:crm.lead,planned_cost:0 +msgid "Planned Costs" +msgstr "" + +#. module: crm +#: help:crm.lead,date_deadline:0 +msgid "Estimate of the date on which the opportunity will be won." +msgstr "" + +#. module: crm +#: help:crm.lead,email_cc:0 +msgid "" +"These email addresses will be added to the CC field of all inbound and " +"outbound emails for this record before being sent. Separate multiple email " +"addresses with a comma" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_case_categ_phone_incoming0 +#: model:ir.ui.menu,name:crm.menu_crm_case_phone_inbound +msgid "Logged Calls" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_lead_won +#: model:mail.message.subtype,name:crm.mt_salesteam_lead_won +msgid "Opportunity Won" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,name:crm.crm_case_section_act_tree +msgid "Cases by Sales Team" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.phonecall:0 +#: model:ir.model,name:crm.model_crm_meeting +#: model:process.node,name:crm.process_node_meeting0 +msgid "Meeting" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_case_categ +msgid "Category of Case" +msgstr "" + +#. module: crm +#: view:board.board:0 +msgid "Planned Revenue by Stage and User" +msgstr "" + +#. module: crm +#: selection:crm.lead,priority:0 +#: selection:crm.lead.report,priority:0 +#: selection:crm.phonecall,priority:0 +#: selection:crm.phonecall.report,priority:0 +msgid "Normal" +msgstr "" + +#. module: crm +#: field:crm.lead,street2:0 +msgid "Street2" +msgstr "" + +#. module: crm +#: field:sale.config.settings,module_crm_helpdesk:0 +msgid "Manage Helpdesk and Support" +msgstr "" + +#. module: crm +#: field:crm.lead.report,delay_open:0 +msgid "Delay to Open" +msgstr "" + +#. module: crm +#: field:crm.lead.report,user_id:0 +#: field:crm.phonecall.report,user_id:0 +msgid "User" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "November" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: model:ir.actions.act_window,name:crm.act_opportunity_stage +msgid "Opportunities By Stage" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "January" +msgstr "" + +#. module: crm +#: model:process.process,name:crm.process_process_contractprocess0 +msgid "Contract" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead4 +msgid "Twitter Ads" +msgstr "" + +#. module: crm +#: field:crm.lead.report,creation_day:0 +msgid "Creation Day" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +msgid "Planned Revenues" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Exp.Closing" +msgstr "" + +#. module: crm +#: help:crm.lead.report,deadline_year:0 +msgid "Expected closing year" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_case_stage +msgid "Stage of case" +msgstr "" + +#. module: crm +#: selection:crm.opportunity2phonecall,action:0 +#: selection:crm.phonecall2phonecall,action:0 +msgid "Schedule a call" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Categorization" +msgstr "" + +#. module: crm +#: view:crm.phonecall2phonecall:0 +msgid "Log Call" +msgstr "" + +#. module: crm +#: help:sale.config.settings,group_fund_raising:0 +msgid "Allows you to trace and manage your activities for fund raising." +msgstr "" + +#. module: crm +#: field:crm.meeting,phonecall_id:0 +#: model:ir.model,name:crm.model_crm_phonecall +msgid "Phonecall" +msgstr "" + +#. module: crm +#: view:crm.phonecall.report:0 +msgid "Phone calls that are assigned to one of the sale teams I manage" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Create date" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "at" +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead1 +#: selection:crm.case.stage,state:0 +#: view:crm.lead:0 +#: selection:crm.lead,state:0 +#: view:crm.lead.report:0 +msgid "New" +msgstr "" + +#. module: crm +#: field:crm.lead,function:0 +msgid "Function" +msgstr "" + +#. module: crm +#: field:crm.case.section,note:0 +#: field:crm.phonecall,description:0 +#: field:crm.segmentation,description:0 +msgid "Description" +msgstr "" + +#. module: crm +#: field:crm.case.categ,section_id:0 +#: field:crm.case.resource.type,section_id:0 +#: view:crm.case.section:0 +#: field:crm.case.section,name:0 +#: field:crm.lead,section_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,section_id:0 +#: field:crm.lead2opportunity.partner.mass,section_id:0 +#: field:crm.opportunity2phonecall,section_id:0 +#: field:crm.payment.mode,section_id:0 +#: view:crm.phonecall:0 +#: field:crm.phonecall,section_id:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall2phonecall,section_id:0 +#: field:res.partner,section_id:0 +msgid "Sales Team" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "May" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_case_channel_action +msgid "" +"

\n" +" Click to define a new channel.\n" +"

\n" +" Use channels to track the soure of your leads and " +"opportunities. Channels\n" +" are mostly used in reporting to analyse sales performance\n" +" related to marketing efforts.\n" +"

\n" +" Some examples of channels: company website, phone call\n" +" campaign, reseller, etc.\n" +"

\n" +" " +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "Internal Notes" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +msgid "New Opportunities" +msgstr "" + +#. module: crm +#: field:crm.segmentation.line,operator:0 +msgid "Mandatory / Optional" +msgstr "" + +#. module: crm +#: field:crm.lead,street:0 +msgid "Street" +msgstr "" + +#. module: crm +#: field:crm.lead,referred:0 +msgid "Referred By" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Reset to Todo" +msgstr "" + +#. module: crm +#: field:crm.case.section,working_hours:0 +msgid "Working Hours" +msgstr "" + +#. module: crm +#: code:addons/crm/crm_lead.py:986 +#: view:crm.lead:0 +#: field:crm.lead2opportunity.partner,partner_id:0 +#: field:crm.lead2opportunity.partner.mass,partner_id:0 +#: field:crm.partner.binding,partner_id:0 +#, python-format +msgid "Customer" +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "February" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +msgid "Schedule a Meeting" +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead8 +#: view:crm.lead:0 +msgid "Lost" +msgstr "" + +#. module: crm +#: code:addons/crm/wizard/crm_lead_to_opportunity.py:89 +#, python-format +msgid "Closed/Cancelled leads cannot be converted into opportunities." +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: field:crm.lead,country_id:0 +#: view:crm.lead.report:0 +#: field:crm.lead.report,country_id:0 +msgid "Country" +msgstr "" + +#. module: crm +#: view:crm.lead:0 +#: view:crm.lead2opportunity.partner:0 +#: view:crm.lead2opportunity.partner.mass:0 +#: view:crm.phonecall:0 +msgid "Convert to Opportunity" +msgstr "" + +#. module: crm +#: help:crm.phonecall,email_from:0 +msgid "These people will receive email." +msgstr "" + +#. module: crm +#: selection:crm.lead.report,creation_month:0 +#: selection:crm.lead.report,deadline_month:0 +#: selection:crm.phonecall.report,month:0 +msgid "April" +msgstr "" + +#. module: crm +#: field:crm.case.resource.type,name:0 +msgid "Campaign Name" +msgstr "" + +#. module: crm +#: view:crm.segmentation:0 +msgid "Profiling" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_phonecall_report +msgid "Phone calls by user and section" +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead5 +msgid "Negotiation" +msgstr "" + +#. module: crm +#: model:ir.model,name:crm.model_crm_phonecall2phonecall +msgid "Phonecall To Phonecall" +msgstr "" + +#. module: crm +#: field:crm.case.stage,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: crm +#: field:crm.segmentation.line,expr_name:0 +msgid "Control Variable" +msgstr "" + +#. module: crm +#: model:crm.case.stage,name:crm.stage_lead4 +msgid "Proposition" +msgstr "" + +#. module: crm +#: view:crm.phonecall:0 +#: field:res.partner,phonecall_ids:0 +msgid "Phonecalls" +msgstr "" + +#. module: crm +#: view:crm.lead.report:0 +#: view:crm.phonecall.report:0 +#: field:crm.phonecall.report,name:0 +msgid "Year" +msgstr "" + +#. module: crm +#: model:crm.case.resource.type,name:crm.type_lead8 +msgid "Newsletter" +msgstr "" + +#. module: crm +#: model:mail.message.subtype,name:crm.mt_salesteam_lead_stage +msgid "Opportunity Stage Changed" +msgstr "" + +#. module: crm +#: model:ir.actions.act_window,help:crm.crm_lead_stage_act +msgid "" +"

\n" +" Click to set a new stage in your lead/opportunity pipeline.\n" +"

\n" +" Stages will allow salespersons to easily track how a " +"specific\n" +" lead or opportunity is positioned in the sales cycle.\n" +"

\n" +" " +msgstr "" diff --git a/addons/crm/report/crm_lead_report_view.xml b/addons/crm/report/crm_lead_report_view.xml index 95cf1d4b7b0..c7220fe66f2 100644 --- a/addons/crm/report/crm_lead_report_view.xml +++ b/addons/crm/report/crm_lead_report_view.xml @@ -66,9 +66,6 @@ crm.lead.report - - - - @@ -168,9 +165,9 @@ Leads Analysis crm.lead.report form - {'search_default_year': 1,'search_default_lead': 1, "search_default_user":1, "search_default_this_month":1, 'group_by_no_leaf':1, 'group_by':[]} + {'search_default_year': 1, "search_default_user":1, "search_default_month":1, 'group_by_no_leaf':1, 'group_by':[]} tree,graph - [] + [('type','=', 'lead')] Leads Analysis allows you to check different CRM related information like the treatment delays or number of leads per state. You can sort out your leads analysis by different groups to get accurate grained analysis.
@@ -190,8 +187,9 @@ Opportunities Analysis crm.lead.report form - {"search_default_year":1,"search_default_opportunity":1, "search_default_user":1,"search_default_this_month":1,'group_by_no_leaf':1,'group_by':[]} + {"search_default_year":1, "search_default_user":1,"search_default_month":1,'group_by_no_leaf':1,'group_by':[]} tree,graph + [('type','=', 'opportunity')] Opportunities Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, missed deadlines or the number of interactions per opportunity. This report is mainly used by the sales manager in order to do the periodic review with the teams of the sales pipeline. diff --git a/addons/crm/security/crm_security.xml b/addons/crm/security/crm_security.xml index ef7eb8b24db..efc335391f8 100644 --- a/addons/crm/security/crm_security.xml +++ b/addons/crm/security/crm_security.xml @@ -91,5 +91,19 @@ + + Personal Leads Analysis + + ['|',('user_id','=',user.id),('user_id','=',False)] + + + + + All Leads Analysis + + [(1,'=',1)] + + +
diff --git a/addons/crm/static/src/css/Makefile b/addons/crm/static/src/css/Makefile new file mode 100644 index 00000000000..a2ced24a13d --- /dev/null +++ b/addons/crm/static/src/css/Makefile @@ -0,0 +1,2 @@ +crm.css: crm.sass + sass --trace -t expanded crm.sass:crm.css diff --git a/addons/crm/static/src/css/crm.css b/addons/crm/static/src/css/crm.css index cce8248bc8b..8999f758e41 100644 --- a/addons/crm/static/src/css/crm.css +++ b/addons/crm/static/src/css/crm.css @@ -1,67 +1,62 @@ +@charset "utf-8"; .openerp .oe_kanban_view .oe_kanban_crm_salesteams { - /* Customize width and height of kanban according bootstrap3 */ - width: 357px; - min-height: 254px !important; - /* End of customize */ + /* Customize width and height of kanban according bootstrap3 */ + width: 357px; + min-height: 254px !important; + /* End of customize */ + cursor: default; } -.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars { - text-align: right; - margin: -5px 0 -10px 0; -} - -.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars img { - width: 30px; - height: 30px; - padding-left: 0px; - margin-top: 3px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - border-radius: 2px; - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); - -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); -} - .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list { - position: relative; - margin: 10px 0 10px 9px; /* Improved margin to set alignment of list items according bootstrap3 */ + position: relative; + /* Improved margin to set alignment of list items according bootstrap3 */ + margin: 10px 0 10px 9px; + min-height: 10px; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div { - width: 160px; - height: 22px; - margin: 0 !important; - position: relative; - display: inline-block; -} -.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a:hover { - text-decoration: underline !important; + width: 160px; + height: 22px; + margin: 0 !important; + position: relative; + display: inline-block; + float: left; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div a:nth-child(2n) { - position: absolute; - left: 90px; - top: 0; + position: absolute; + left: 90px; + top: 0; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list div:nth-child(2n) a:nth-child(2n) { - left: 110px; + left: 110px; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a:hover { + text-decoration: underline !important; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center { - text-align: center; - margin: 3px 0; + text-align: center; + margin: 3px 0; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_sum { - margin: 0; - font-size: 40px; + margin: 0; + font-size: 40px; } .openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_subsum { - font-size: 10px; + font-size: 10px; } - -.openerp .oe_kanban_view .oe_justgage { - color: black; - display: inline-block; +.openerp .oe_kanban_view .oe_salesteams_help { + display: inline-block; +} +.openerp .oe_kanban_view .oe_kanban_salesteams_avatars { + margin-top: 20px; +} +.openerp .oe_kanban_view .oe_kanban_salesteams_avatars img { + width: 30px; + height: 30px; + padding-left: 0px; + margin-top: 3px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); } - -.openerp .oe_kanban_view .oe_sparkline_bar { - height: 20px; - width: 36px; -} \ No newline at end of file diff --git a/addons/crm/static/src/css/crm.sass b/addons/crm/static/src/css/crm.sass new file mode 100644 index 00000000000..5c70981e52f --- /dev/null +++ b/addons/crm/static/src/css/crm.sass @@ -0,0 +1,55 @@ +@charset "utf-8" + +.openerp + .oe_kanban_view + .oe_kanban_crm_salesteams + /* Customize width and height of kanban according bootstrap3 */ + width: 357px + min-height: 254px !important + /* End of customize */ + cursor: default + .oe_items_list + position: relative + /* Improved margin to set alignment of list items according bootstrap3 */ + margin: 10px 0 10px 9px + min-height: 10px + div + width: 160px + height: 22px + margin: 0 !important + position: relative + display: inline-block + float: left + a:nth-child(2n) + position: absolute + left: 90px + top: 0 + div:nth-child(2n) + a:nth-child(2n) + left: 110px + a:hover + text-decoration: underline !important + .oe_center + text-align: center + margin: 3px 0 + .oe_sum + margin: 0 + font-size: 40px + .oe_subsum + font-size: 10px + .oe_salesteams_help + display: inline-block + .oe_kanban_salesteams_avatars + margin-top: 20px + .oe_kanban_salesteams_avatars + img + width: 30px + height: 30px + padding-left: 0px + margin-top: 3px + -moz-border-radius: 2px + -webkit-border-radius: 2px + border-radius: 2px + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) diff --git a/addons/crm/static/src/js/crm_case_section.js b/addons/crm/static/src/js/crm_case_section.js index deb21d38de2..02f42288880 100644 --- a/addons/crm/static/src/js/crm_case_section.js +++ b/addons/crm/static/src/js/crm_case_section.js @@ -1,4 +1,40 @@ openerp.crm = function(openerp) { + openerp.web_kanban.KanbanView.include({ + crm_display_members_names: function() { + /* + * Set avatar title for members. + * In kanban views, many2many fields only return a list of ids. + * We can implement return value of m2m fields like [(1,"Adminstration"),...]. + */ + var self = this; + var members_ids = []; + + // Collect members ids + self.$el.find('img[data-member_id]').each(function() { + members_ids.push($(this).data('member_id')); + }); + + // Find their matching names + var dataset = new openerp.web.DataSetSearch(self, 'res.users', self.session.context, [['id', 'in', _.uniq(members_ids)]]); + dataset.read_slice(['id', 'name']).done(function(result) { + _.each(result, function(v, k) { + // Set the proper value in the DOM + self.$el.find('img[data-member_id=' + v.id + ']').attr('title', v.name).tipsy({ + offset: 10 + }); + }); + }); + }, + on_groups_started: function() { + var self = this; + self._super.apply(self, arguments); + + if (self.dataset.model === 'crm.case.section') { + self.crm_display_members_names(); + } + }, + }); + openerp.web_kanban.KanbanRecord.include({ on_card_clicked: function() { if (this.view.dataset.model === 'crm.case.section') { @@ -8,5 +44,4 @@ openerp.crm = function(openerp) { } }, }); - }; diff --git a/addons/crm_helpdesk/i18n/he.po b/addons/crm_helpdesk/i18n/he.po new file mode 100644 index 00000000000..c7bc290288f --- /dev/null +++ b/addons/crm_helpdesk/i18n/he.po @@ -0,0 +1,708 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:48+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,delay_close:0 +msgid "Delay to Close" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,nbr:0 +msgid "# of Cases" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: view:crm.helpdesk.report:0 +msgid "Group By..." +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,email_from:0 +msgid "Destination email for email gateway" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "March" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,message_unread:0 +msgid "Unread Messages" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,company_id:0 +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,company_id:0 +msgid "Company" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,email_cc:0 +msgid "Watchers Emails" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Salesperson" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,priority:0 +#: selection:crm.helpdesk.report,priority:0 +msgid "Highest" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,day:0 +msgid "Day" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Date of helpdesk requests" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Notes" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,message_ids:0 +msgid "Messages" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "My company" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,state:0 +#: selection:crm.helpdesk.report,state:0 +msgid "Cancelled" +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,message_unread:0 +msgid "If checked new messages require your attention." +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,name:crm_helpdesk.action_report_crm_helpdesk +#: model:ir.ui.menu,name:crm_helpdesk.menu_report_crm_helpdesks_tree +msgid "Helpdesk Analysis" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,date_closed:0 +msgid "Close Date" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,ref:0 +msgid "Reference" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,date_action_next:0 +msgid "Next Action" +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,message_summary:0 +msgid "" +"Holds the Chatter summary (number of messages, ...). This summary is " +"directly in html format in order to be inserted in kanban views." +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Helpdesk Supports" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Extra Info" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,partner_id:0 +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,partner_id:0 +msgid "Partner" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Estimates" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,section_id:0 +msgid "Section" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,priority:0 +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,priority:0 +msgid "Priority" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,message_follower_ids:0 +msgid "Followers" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: selection:crm.helpdesk,state:0 +#: view:crm.helpdesk.report:0 +msgid "New" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk_report +msgid "Helpdesk report after Sales Services" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,email_from:0 +msgid "Email" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,channel_id:0 +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,channel_id:0 +msgid "Channel" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,priority:0 +#: selection:crm.helpdesk.report,priority:0 +msgid "Lowest" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "# Mails" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "My Sales Team(s)" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,create_date:0 +#: field:crm.helpdesk.report,create_date:0 +msgid "Creation Date" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Reset to Draft" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,date_deadline:0 +#: field:crm.helpdesk.report,date_deadline:0 +msgid "Deadline" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "July" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,name:crm_helpdesk.crm_helpdesk_categ_action +msgid "Helpdesk Categories" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.ui.menu,name:crm_helpdesk.menu_crm_case_helpdesk-act +msgid "Categories" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "New Helpdesk Request" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Dates" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Month of helpdesk requests" +msgstr "" + +#. module: crm_helpdesk +#: code:addons/crm_helpdesk/crm_helpdesk.py:104 +#, python-format +msgid "No Subject" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "" +"Helpdesk requests that are assigned to me or to one of the sale teams I " +"manage" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "#Helpdesk" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "All pending Helpdesk Request" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Year of helpdesk requests" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "September" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "December" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,month:0 +msgid "Month" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,write_date:0 +msgid "Update Date" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Query" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,ref2:0 +msgid "Reference 2" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,categ_id:0 +#: field:crm.helpdesk.report,categ_id:0 +msgid "Category" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Responsible User" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Helpdesk Support" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,planned_cost:0 +#: field:crm.helpdesk.report,planned_cost:0 +msgid "Planned Costs" +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,channel_id:0 +msgid "Communication channel." +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,email_cc:0 +msgid "" +"These email addresses will be added to the CC field of all inbound and " +"outbound emails for this record before being sent. Separate multiple email " +"addresses with a comma" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Search Helpdesk" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,state:0 +msgid "Draft" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,priority:0 +#: selection:crm.helpdesk.report,priority:0 +msgid "Low" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,date_closed:0 +#: selection:crm.helpdesk,state:0 +#: view:crm.helpdesk.report:0 +#: selection:crm.helpdesk.report,state:0 +msgid "Closed" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: selection:crm.helpdesk,state:0 +#: selection:crm.helpdesk.report,state:0 +msgid "Pending" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,state:0 +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,state:0 +msgid "Status" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "August" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,priority:0 +#: selection:crm.helpdesk.report,priority:0 +msgid "Normal" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Escalate" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "June" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,id:0 +msgid "ID" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,help:crm_helpdesk.crm_case_helpdesk_act111 +msgid "" +"

\n" +" Click to create a new request. \n" +"

\n" +" Helpdesk and Support allow you to track your interventions.\n" +"

\n" +" Use the OpenERP Issues system to manage your support\n" +" activities. Issues can be connected to the email gateway: " +"new\n" +" emails may create issues, each of them automatically gets " +"the\n" +" history of the conversation with the customer.\n" +"

\n" +" " +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,planned_revenue:0 +msgid "Planned Revenue" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,message_is_follower:0 +msgid "Is a Follower" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,user_id:0 +msgid "User" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,active:0 +msgid "Active" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "November" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Extended Filters..." +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,name:crm_helpdesk.crm_case_helpdesk_act111 +msgid "Helpdesk Requests" +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,section_id:0 +msgid "" +"Responsible sales team. Define Responsible user and Email account for mail " +"gateway." +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "October" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "January" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,message_summary:0 +msgid "Summary" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,date:0 +msgid "Date" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Misc" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "My Company" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "General" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "References" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Communication" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Cancel" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Close" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: view:crm.helpdesk.report:0 +#: selection:crm.helpdesk.report,state:0 +msgid "Open" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Helpdesk Support Tree" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,state:0 +msgid "In Progress" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Categorization" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +#: model:ir.model,name:crm_helpdesk.model_crm_helpdesk +#: model:ir.ui.menu,name:crm_helpdesk.menu_config_helpdesk +msgid "Helpdesk" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,user_id:0 +msgid "Responsible" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "Search" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,delay_expected:0 +msgid "Overpassed Deadline" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,description:0 +msgid "Description" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "May" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,probability:0 +msgid "Probability (%)" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk.report,email:0 +msgid "# Emails" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,help:crm_helpdesk.action_report_crm_helpdesk +msgid "" +"Have a general overview of all support requests by sorting them with " +"specific criteria such as the processing time, number of requests answered, " +"emails sent and costs." +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "February" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,name:0 +msgid "Name" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +#: field:crm.helpdesk.report,name:0 +msgid "Year" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.ui.menu,name:crm_helpdesk.menu_help_support_main +msgid "Helpdesk and Support" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk.report,month:0 +msgid "April" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk.report:0 +msgid "My Case(s)" +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,state:0 +msgid "" +"The status is set to 'Draft', when a case is created. " +" \n" +"If the case is in progress the status is set to 'Open'. " +" \n" +"When the case is over, the status is set to 'Done'. " +" \n" +"If the case needs to be reviewed then the status is set to 'Pending'." +msgstr "" + +#. module: crm_helpdesk +#: help:crm.helpdesk,message_ids:0 +msgid "Messages and communication history" +msgstr "" + +#. module: crm_helpdesk +#: model:ir.actions.act_window,help:crm_helpdesk.crm_helpdesk_categ_action +msgid "" +"Create and manage helpdesk categories to better manage and classify your " +"support requests." +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Request Date" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Open Helpdesk Request" +msgstr "" + +#. module: crm_helpdesk +#: selection:crm.helpdesk,priority:0 +#: selection:crm.helpdesk.report,priority:0 +msgid "High" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +#: field:crm.helpdesk,section_id:0 +#: view:crm.helpdesk.report:0 +msgid "Sales Team" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,date_action_last:0 +msgid "Last Action" +msgstr "" + +#. module: crm_helpdesk +#: view:crm.helpdesk:0 +msgid "Assigned to Me or My Sales Team(s)" +msgstr "" + +#. module: crm_helpdesk +#: field:crm.helpdesk,duration:0 +msgid "Duration" +msgstr "" diff --git a/addons/document/document.py b/addons/document/document.py index 5fc62578b1d..eb51ad5ac57 100644 --- a/addons/document/document.py +++ b/addons/document/document.py @@ -32,6 +32,7 @@ import psycopg2 import openerp from openerp import tools +from openerp import SUPERUSER_ID from openerp.osv import fields, osv from openerp.osv.orm import except_orm import openerp.report.interface @@ -322,7 +323,7 @@ class document_directory(osv.osv): ressource_parent_type_id=vals.get('ressource_parent_type_id',False) ressource_id=vals.get('ressource_id',0) if op=='write': - for directory in self.browse(cr, uid, ids): + for directory in self.browse(cr, SUPERUSER_ID, ids): if not name: name=directory.name if not parent_id: @@ -336,7 +337,7 @@ class document_directory(osv.osv): if len(res): return False if op=='create': - res=self.search(cr,uid,[('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)]) + res = self.search(cr, SUPERUSER_ID, [('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)]) if len(res): return False return True diff --git a/addons/document/i18n/he.po b/addons/document/i18n/he.po new file mode 100644 index 00000000000..644f64141fd --- /dev/null +++ b/addons/document/i18n/he.po @@ -0,0 +1,758 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:49+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: document +#: field:document.directory,parent_id:0 +msgid "Parent Directory" +msgstr "" + +#. module: document +#: code:addons/document/document.py:350 +#, python-format +msgid "Directory name contains special characters!" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Search Document Directory" +msgstr "" + +#. module: document +#: help:document.directory,resource_field:0 +msgid "" +"Field to be used as name on resource directories. If empty, the \"name\" " +"will be used." +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Group By..." +msgstr "" + +#. module: document +#: view:ir.attachment:0 +msgid "Modification" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Resources" +msgstr "" + +#. module: document +#: field:document.directory,file_ids:0 +#: view:report.document.user:0 +msgid "Files" +msgstr "" + +#. module: document +#: field:document.directory.content.type,mimetype:0 +msgid "Mime Type" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "March" +msgstr "" + +#. module: document +#: field:document.directory.dctx,expr:0 +msgid "Expression" +msgstr "" + +#. module: document +#: view:document.directory:0 +#: field:document.directory,company_id:0 +msgid "Company" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_document_directory_content +msgid "Directory Content" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +msgid "My Document(s)" +msgstr "" + +#. module: document +#: model:ir.ui.menu,name:document.menu_document_management_configuration +msgid "Document Management" +msgstr "" + +#. module: document +#: help:document.directory.dctx,expr:0 +msgid "" +"A python expression used to evaluate the field.\n" +"You can use 'dir_id' for current dir, 'res_id', 'res_model' as a reference " +"to the current record, in dynamic folders" +msgstr "" + +#. module: document +#: help:document.directory.dctx,field:0 +msgid "The name of the field." +msgstr "" + +#. module: document +#: code:addons/document/document.py:340 +#: code:addons/document/document.py:345 +#, python-format +msgid "Directory name must be unique!" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +msgid "Filter on my documents" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +#: field:ir.attachment,index_content:0 +msgid "Indexed Content" +msgstr "" + +#. module: document +#: help:document.directory,resource_find_all:0 +msgid "" +"If true, all attachments that match this resource will be located. If " +"false, only ones that have this as parent." +msgstr "" + +#. module: document +#: view:document.directory:0 +#: model:ir.actions.act_window,name:document.action_document_directory_form +#: model:ir.ui.menu,name:document.menu_document_directories +msgid "Directories" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_report_document_user +msgid "Files details by Users" +msgstr "" + +#. module: document +#: field:document.directory,resource_find_all:0 +msgid "Find all resources" +msgstr "" + +#. module: document +#: selection:document.directory,type:0 +msgid "Folders per resource" +msgstr "" + +#. module: document +#: field:document.directory.content,suffix:0 +msgid "Suffix" +msgstr "" + +#. module: document +#: field:report.document.user,change_date:0 +msgid "Modified Date" +msgstr "" + +#. module: document +#: view:document.configuration:0 +msgid "Knowledge Application Configuration" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +#: field:ir.attachment,partner_id:0 +msgid "Partner" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.act_res_partner_document +#: model:ir.actions.act_window,name:document.zoom_directory +msgid "Related Documents" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,help:document.action_document_file_form +msgid "" +"

\n" +" Click to create a new document. \n" +"

\n" +" The Documents repository gives you access to all attachments, " +"such\n" +" as mails, project documents, invoices etc.\n" +"

\n" +" " +msgstr "" + +#. module: document +#: code:addons/document/document.py:340 +#: code:addons/document/document.py:345 +#: code:addons/document/document.py:350 +#, python-format +msgid "ValidateError" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_ir_actions_report_xml +msgid "ir.actions.report.xml" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_document_file_form +#: model:ir.ui.menu,name:document.menu_document_doc +#: model:ir.ui.menu,name:document.menu_document_files +msgid "Documents" +msgstr "" + +#. module: document +#: field:document.directory,ressource_type_id:0 +msgid "Resource model" +msgstr "" + +#. module: document +#: field:report.document.file,file_size:0 +#: field:report.document.user,file_size:0 +msgid "File Size" +msgstr "" + +#. module: document +#: field:document.directory.content.type,name:0 +#: field:ir.attachment,file_type:0 +msgid "Content Type" +msgstr "" + +#. module: document +#: view:document.directory:0 +#: field:document.directory,type:0 +msgid "Type" +msgstr "" + +#. module: document +#: sql_constraint:ir.attachment:0 +msgid "The filename must be unique in a directory !" +msgstr "" + +#. module: document +#: code:addons/document/document.py:110 +#: code:addons/document/document.py:310 +#, python-format +msgid "%s (copy)" +msgstr "" + +#. module: document +#: help:document.directory,ressource_type_id:0 +msgid "" +"Select an object here and there will be one folder per record of that " +"resource." +msgstr "" + +#. module: document +#: help:document.directory,domain:0 +msgid "" +"Use a domain if you want to apply an automatic filter on visible resources." +msgstr "" + +#. module: document +#: constraint:document.directory:0 +msgid "Error! You cannot create recursive directories." +msgstr "" + +#. module: document +#: field:document.directory,resource_field:0 +msgid "Name field" +msgstr "" + +#. module: document +#: field:document.directory,dctx_ids:0 +msgid "Context fields" +msgstr "" + +#. module: document +#: view:document.directory:0 +#: field:report.document.user,type:0 +msgid "Directory Type" +msgstr "" + +#. module: document +#: field:document.directory.content,report_id:0 +msgid "Report" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "July" +msgstr "" + +#. module: document +#: field:document.directory.content.type,code:0 +msgid "Extension" +msgstr "" + +#. module: document +#: field:document.directory,content_ids:0 +msgid "Virtual Files" +msgstr "" + +#. module: document +#: code:addons/document/document.py:576 +#, python-format +msgid "Error at doc write!" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Generated Files" +msgstr "" + +#. module: document +#: view:document.configuration:0 +msgid "" +"When executing this wizard, it will configure your directories automatically " +"according to modules installed." +msgstr "" + +#. module: document +#: field:document.directory.content,directory_id:0 +#: field:document.directory.dctx,dir_id:0 +#: model:ir.actions.act_window,name:document.action_document_file_directory_form +#: view:ir.attachment:0 +#: field:ir.attachment,parent_id:0 +#: model:ir.model,name:document.model_document_directory +#: field:report.document.user,directory:0 +msgid "Directory" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Security" +msgstr "" + +#. module: document +#: field:document.directory,write_uid:0 +#: field:ir.attachment,write_uid:0 +msgid "Last Modification User" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_view_files_by_user_graph +#: view:report.document.user:0 +msgid "Files by User" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +msgid "on" +msgstr "" + +#. module: document +#: field:document.directory,domain:0 +msgid "Domain" +msgstr "" + +#. module: document +#: field:document.directory,write_date:0 +#: field:ir.attachment,write_date:0 +msgid "Date Modified" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_report_document_file +msgid "Files details by Directory" +msgstr "" + +#. module: document +#: view:report.document.user:0 +msgid "All users files" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_view_size_month +#: view:report.document.file:0 +msgid "File Size by Month" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "December" +msgstr "" + +#. module: document +#: selection:document.directory,type:0 +msgid "Static Directory" +msgstr "" + +#. module: document +#: field:report.document.file,month:0 +#: field:report.document.user,month:0 +msgid "Month" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Define words in the context, for all child directories and files" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Static" +msgstr "" + +#. module: document +#: field:report.document.user,user:0 +msgid "unknown" +msgstr "" + +#. module: document +#: view:document.directory:0 +#: field:document.directory,user_id:0 +#: view:ir.attachment:0 +#: field:ir.attachment,user_id:0 +#: field:report.document.user,user_id:0 +msgid "Owner" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "PDF Report" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Contents" +msgstr "" + +#. module: document +#: field:document.directory,create_date:0 +#: field:report.document.user,create_date:0 +msgid "Date Created" +msgstr "" + +#. module: document +#: help:document.directory.content,include_name:0 +msgid "" +"Check this field if you want that the name of the file to contain the record " +"name.\n" +"If set, the directory will have to be a resource one." +msgstr "" + +#. module: document +#: view:document.configuration:0 +#: model:ir.actions.act_window,name:document.action_config_auto_directory +msgid "Configure Directories" +msgstr "" + +#. module: document +#: field:document.directory.content,include_name:0 +msgid "Include Record Name" +msgstr "" + +#. module: document +#: field:ir.actions.report.xml,model_id:0 +msgid "Model Id" +msgstr "" + +#. module: document +#: help:document.directory,ressource_tree:0 +msgid "" +"Check this if you want to use the same tree structure as the object selected " +"in the system." +msgstr "" + +#. module: document +#: help:document.directory,ressource_id:0 +msgid "" +"Along with Parent Model, this ID attaches this folder to a specific record " +"of Parent Model." +msgstr "" + +#. module: document +#. openerp-web +#: code:addons/document/static/src/js/document.js:6 +#, python-format +msgid "Attachment(s)" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "August" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Dynamic context" +msgstr "" + +#. module: document +#: sql_constraint:document.directory:0 +msgid "Directory cannot be parent of itself!" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "June" +msgstr "" + +#. module: document +#: field:document.directory,group_ids:0 +msgid "Groups" +msgstr "" + +#. module: document +#: field:document.directory.content.type,active:0 +msgid "Active" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "November" +msgstr "" + +#. module: document +#: help:document.directory,ressource_parent_type_id:0 +msgid "" +"If you put an object here, this directory template will appear bellow all of " +"these objects. Such directories are \"attached\" to the specific model or " +"record, just like attachments. Don't put a parent directory if you select a " +"parent model." +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Definition" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "October" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Seq." +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_view_all_document_tree1 +msgid "All Users files" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "January" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Document Directory" +msgstr "" + +#. module: document +#: sql_constraint:document.directory:0 +msgid "The directory name must be unique !" +msgstr "" + +#. module: document +#: view:ir.attachment:0 +msgid "Attachments" +msgstr "" + +#. module: document +#: field:document.directory,create_uid:0 +msgid "Creator" +msgstr "" + +#. module: document +#: view:document.configuration:0 +msgid "" +"OpenERP's Document Management System supports mapping virtual folders with " +"documents. The virtual folder of a document can be used to manage the files " +"attached to the document, or to print and download any report. This tool " +"will create directories automatically according to modules installed." +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_view_files_by_month_graph +#: view:report.document.user:0 +msgid "Files by Month" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "September" +msgstr "" + +#. module: document +#: field:document.directory.content,prefix:0 +msgid "Prefix" +msgstr "" + +#. module: document +#: field:document.directory,child_ids:0 +msgid "Children" +msgstr "" + +#. module: document +#: field:document.directory,ressource_id:0 +msgid "Resource ID" +msgstr "" + +#. module: document +#: field:document.directory.dctx,field:0 +msgid "Field" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_document_directory_dctx +msgid "Directory Dynamic Context" +msgstr "" + +#. module: document +#: field:document.directory,ressource_parent_type_id:0 +msgid "Parent Model" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "" +"These groups, however, do NOT apply to children directories, which must " +"define their own groups." +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "May" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "For each entry here, virtual files will appear in this folder." +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_ir_attachment +msgid "ir.attachment" +msgstr "" + +#. module: document +#: view:report.document.user:0 +msgid "Users File" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_document_configuration +msgid "Directory Configuration" +msgstr "" + +#. module: document +#: help:document.directory,type:0 +msgid "" +"Each directory can either have the type Static or be linked to another " +"resource. A static directory, as with Operating Systems, is the classic " +"directory that can contain a set of files. The directories linked to systems " +"resources automatically possess sub-directories for each of resource types " +"defined in the parent directory." +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "February" +msgstr "" + +#. module: document +#: field:document.directory,name:0 +msgid "Name" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "Fields" +msgstr "" + +#. module: document +#: selection:report.document.user,month:0 +msgid "April" +msgstr "" + +#. module: document +#: field:report.document.file,nbr:0 +#: field:report.document.user,nbr:0 +msgid "# of Files" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_document_directory_content_type +msgid "Directory Content Type" +msgstr "" + +#. module: document +#: view:document.directory:0 +msgid "" +"Only members of these groups will have access to this directory and its " +"files." +msgstr "" + +#. module: document +#. openerp-web +#: code:addons/document/static/src/js/document.js:17 +#, python-format +msgid "%s (%s)" +msgstr "" + +#. module: document +#: field:document.directory.content,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: document +#: field:document.directory.content,name:0 +msgid "Content Name" +msgstr "" + +#. module: document +#: field:report.document.user,datas_fname:0 +msgid "File Name" +msgstr "" + +#. module: document +#: field:document.directory,ressource_tree:0 +msgid "Tree Structure" +msgstr "" + +#. module: document +#: view:document.configuration:0 +msgid "res_config_contents" +msgstr "" + +#. module: document +#: model:ir.actions.act_window,name:document.action_document_directory_tree +#: model:ir.ui.menu,name:document.menu_document_directories_tree +msgid "Directories' Structure" +msgstr "" + +#. module: document +#: field:report.document.user,name:0 +msgid "Year" +msgstr "" + +#. module: document +#: model:ir.model,name:document.model_document_storage +msgid "Storage Media" +msgstr "" + +#. module: document +#: field:document.directory.content,extension:0 +msgid "Document Type" +msgstr "" diff --git a/addons/document/report/document_report.py b/addons/document/report/document_report.py index c9df78e4272..a4133f46387 100644 --- a/addons/document/report/document_report.py +++ b/addons/document/report/document_report.py @@ -31,7 +31,7 @@ class report_document_user(osv.osv): 'name': fields.char('Year', size=64,readonly=True), 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month',readonly=True), - 'user_id':fields.integer('Owner', readonly=True), + 'user_id': fields.many2one('res.users', 'Owner', readonly=True), 'user': fields.related('user_id', 'name', type='char', size=64, readonly=True), 'directory': fields.char('Directory',size=64,readonly=True), 'datas_fname': fields.char('File Name',size=64,readonly=True), diff --git a/addons/document/test/document_test2.yml b/addons/document/test/document_test2.yml index beff61d4d0f..0c6345ef6c4 100644 --- a/addons/document/test/document_test2.yml +++ b/addons/document/test/document_test2.yml @@ -58,6 +58,23 @@ !python {model: ir.attachment}: | ids = self.search(cr, uid, [('res_model', '=', 'res.country'), ('res_id', '=', ref("base.za"))]) assert ids == [ ref("attach_3rd")], ids +- + I test that I can't create duplicate directories (even when duplicates are hidden by a record rule) +- + !python {model: document.directory}: | + duplicate_detected = False + from openerp.osv.osv import except_osv + try: + demo_uid = ref('base.user_demo') + dir_vals = { + 'name': 'Testing (will be deleted!)', + 'parent_id': ref('document.dir_root') + } + new_dir_id = self.create(cr, demo_uid, dir_vals, context=None) + self.unlink(cr, uid, [new_dir_id], context=None) + except except_osv, e: + duplicate_detected = e.value == u'Directory name must be unique!' + assert duplicate_detected is True, 'Failed to detect duplicate directory' - I delete the attachments - diff --git a/addons/edi/i18n/he.po b/addons/edi/i18n/he.po new file mode 100644 index 00000000000..6d66ac0dc1e --- /dev/null +++ b/addons/edi/i18n/he.po @@ -0,0 +1,87 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:50+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: edi +#. openerp-web +#: code:addons/edi/static/src/js/edi.js:67 +#, python-format +msgid "Reason:" +msgstr "" + +#. module: edi +#. openerp-web +#: code:addons/edi/static/src/js/edi.js:60 +#, python-format +msgid "The document has been successfully imported!" +msgstr "" + +#. module: edi +#. openerp-web +#: code:addons/edi/static/src/js/edi.js:65 +#, python-format +msgid "Sorry, the document could not be imported." +msgstr "" + +#. module: edi +#: model:ir.model,name:edi.model_res_company +msgid "Companies" +msgstr "" + +#. module: edi +#: model:ir.model,name:edi.model_res_currency +msgid "Currency" +msgstr "" + +#. module: edi +#. openerp-web +#: code:addons/edi/static/src/js/edi.js:71 +#, python-format +msgid "Document Import Notification" +msgstr "" + +#. module: edi +#: code:addons/edi/models/edi.py:130 +#, python-format +msgid "Missing application." +msgstr "" + +#. module: edi +#: code:addons/edi/models/edi.py:131 +#, python-format +msgid "" +"The document you are trying to import requires the OpenERP `%s` application. " +"You can install it by connecting as the administrator and opening the " +"configuration assistant." +msgstr "" + +#. module: edi +#: code:addons/edi/models/edi.py:47 +#, python-format +msgid "'%s' is an invalid external ID" +msgstr "" + +#. module: edi +#: model:ir.model,name:edi.model_res_partner +msgid "Partner" +msgstr "" + +#. module: edi +#: model:ir.model,name:edi.model_edi_edi +msgid "EDI Subsystem" +msgstr "" diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index 6e19b1eb8aa..904481096d3 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -411,7 +411,17 @@ class email_template(osv.osv): # create a mail_mail based on values, without attachments values = self.generate_email(cr, uid, template_id, res_id, context=context) assert values.get('email_from'), 'email_from is missing or empty after template rendering, send_mail() cannot proceed' - del values['partner_to'] # TODO Properly use them. + + # process partner_to field that is a comma separated list of partner_ids -> recipient_ids + # NOTE: only usable if force_send is True, because otherwise the value is + # not stored on the mail_mail, and therefore lost -> fixed in v8 + values['recipient_ids'] = [] + partner_to = values.pop('partner_to', '') + if partner_to: + # placeholders could generate '', 3, 2 due to some empty field values + tpl_partner_ids = [pid for pid in partner_to.split(',') if pid] + values['recipient_ids'] += [(4, pid) for pid in self.pool['res.partner'].exists(cr, SUPERUSER_ID, tpl_partner_ids, context=context)] + attachment_ids = values.pop('attachment_ids', []) attachments = values.pop('attachments', []) msg_id = mail_mail.create(cr, uid, values, context=context) @@ -420,11 +430,11 @@ class email_template(osv.osv): # manage attachments for attachment in attachments: attachment_data = { - 'name': attachment[0], - 'datas_fname': attachment[0], - 'datas': attachment[1], - 'res_model': 'mail.message', - 'res_id': mail.mail_message_id.id, + 'name': attachment[0], + 'datas_fname': attachment[0], + 'datas': attachment[1], + 'res_model': 'mail.message', + 'res_id': mail.mail_message_id.id, } context.pop('default_type', None) attachment_ids.append(ir_attachment.create(cr, uid, attachment_data, context=context)) diff --git a/addons/email_template/i18n/he.po b/addons/email_template/i18n/he.po new file mode 100644 index 00000000000..2ce04ed39e5 --- /dev/null +++ b/addons/email_template/i18n/he.po @@ -0,0 +1,488 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:05+0000\n" +"PO-Revision-Date: 2013-12-30 18:51+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: email_template +#: field:email.template,email_from:0 +#: field:email_template.preview,email_from:0 +msgid "From" +msgstr "" + +#. module: email_template +#: field:mail.compose.message,template_id:0 +msgid "Template" +msgstr "" + +#. module: email_template +#: help:email.template,ref_ir_value:0 +#: help:email_template.preview,ref_ir_value:0 +msgid "Sidebar button to open the sidebar action" +msgstr "" + +#. module: email_template +#: field:res.partner,opt_out:0 +msgid "Opt-Out" +msgstr "" + +#. module: email_template +#: field:email.template,email_to:0 +#: field:email_template.preview,email_to:0 +msgid "To (Emails)" +msgstr "" + +#. module: email_template +#: field:email.template,mail_server_id:0 +#: field:email_template.preview,mail_server_id:0 +msgid "Outgoing Mail Server" +msgstr "" + +#. module: email_template +#: help:email.template,ref_ir_act_window:0 +#: help:email_template.preview,ref_ir_act_window:0 +msgid "" +"Sidebar action to make this template available on records of the related " +"document model" +msgstr "" + +#. module: email_template +#: field:email.template,model_object_field:0 +#: field:email_template.preview,model_object_field:0 +msgid "Field" +msgstr "" + +#. module: email_template +#: help:email.template,email_from:0 +#: help:email_template.preview,email_from:0 +msgid "Sender address (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Remove context action" +msgstr "" + +#. module: email_template +#: help:email.template,mail_server_id:0 +#: help:email_template.preview,mail_server_id:0 +msgid "" +"Optional preferred server for outgoing mails. If not set, the highest " +"priority one will be used." +msgstr "" + +#. module: email_template +#: field:email.template,report_name:0 +#: field:email_template.preview,report_name:0 +msgid "Report Filename" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Preview" +msgstr "" + +#. module: email_template +#: field:email.template,reply_to:0 +#: field:email_template.preview,reply_to:0 +msgid "Reply-To" +msgstr "" + +#. module: email_template +#: view:mail.compose.message:0 +msgid "Use template" +msgstr "" + +#. module: email_template +#: field:email.template,body_html:0 +#: field:email_template.preview,body_html:0 +msgid "Body" +msgstr "" + +#. module: email_template +#: code:addons/email_template/email_template.py:247 +#, python-format +msgid "%s (copy)" +msgstr "" + +#. module: email_template +#: help:email.template,user_signature:0 +#: help:email_template.preview,user_signature:0 +msgid "" +"If checked, the user's signature will be appended to the text version of the " +"message" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "SMTP Server" +msgstr "" + +#. module: email_template +#: view:mail.compose.message:0 +msgid "Save as new template" +msgstr "" + +#. module: email_template +#: help:email.template,sub_object:0 +#: help:email_template.preview,sub_object:0 +msgid "" +"When a relationship field is selected as first field, this field shows the " +"document model the relationship goes to." +msgstr "" + +#. module: email_template +#: model:ir.model,name:email_template.model_email_template +msgid "Email Templates" +msgstr "" + +#. module: email_template +#: help:email.template,report_name:0 +#: help:email_template.preview,report_name:0 +msgid "" +"Name to use for the generated report file (may contain placeholders)\n" +"The extension can be omitted and will then come from the report type." +msgstr "" + +#. module: email_template +#: field:email.template,ref_ir_act_window:0 +#: field:email_template.preview,ref_ir_act_window:0 +msgid "Sidebar action" +msgstr "" + +#. module: email_template +#: help:email.template,lang:0 +#: help:email_template.preview,lang:0 +msgid "" +"Optional translation language (ISO code) to select when sending out an " +"email. If not set, the english version will be used. This should usually be " +"a placeholder expression that provides the appropriate language code, e.g. " +"${object.partner_id.lang.code}." +msgstr "" + +#. module: email_template +#: field:email_template.preview,res_id:0 +msgid "Sample Document" +msgstr "" + +#. module: email_template +#: help:email.template,model_object_field:0 +#: help:email_template.preview,model_object_field:0 +msgid "" +"Select target field from the related document model.\n" +"If it is a relationship field you will be able to select a target field at " +"the destination of the relationship." +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Dynamic Value Builder" +msgstr "" + +#. module: email_template +#: model:ir.actions.act_window,name:email_template.wizard_email_template_preview +msgid "Template Preview" +msgstr "" + +#. module: email_template +#: view:mail.compose.message:0 +msgid "Save as a new template" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "" +"Display an option on related documents to open a composition wizard with " +"this template" +msgstr "" + +#. module: email_template +#: help:email.template,email_cc:0 +#: help:email_template.preview,email_cc:0 +msgid "Carbon copy recipients (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: help:email.template,email_to:0 +#: help:email_template.preview,email_to:0 +msgid "Comma-separated recipient addresses (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Advanced" +msgstr "" + +#. module: email_template +#: view:email_template.preview:0 +msgid "Preview of" +msgstr "" + +#. module: email_template +#: view:email_template.preview:0 +msgid "Using sample document" +msgstr "" + +#. module: email_template +#: view:email.template:0 +#: model:ir.actions.act_window,name:email_template.action_email_template_tree_all +#: model:ir.ui.menu,name:email_template.menu_email_templates +msgid "Templates" +msgstr "" + +#. module: email_template +#: field:email.template,name:0 +#: field:email_template.preview,name:0 +msgid "Name" +msgstr "" + +#. module: email_template +#: field:email.template,lang:0 +#: field:email_template.preview,lang:0 +msgid "Language" +msgstr "" + +#. module: email_template +#: model:ir.model,name:email_template.model_email_template_preview +msgid "Email Template Preview" +msgstr "" + +#. module: email_template +#: view:email_template.preview:0 +msgid "Email Preview" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "" +"Remove the contextual action to use this template on related documents" +msgstr "" + +#. module: email_template +#: field:email.template,copyvalue:0 +#: field:email_template.preview,copyvalue:0 +msgid "Placeholder Expression" +msgstr "" + +#. module: email_template +#: field:email.template,sub_object:0 +#: field:email_template.preview,sub_object:0 +msgid "Sub-model" +msgstr "" + +#. module: email_template +#: help:email.template,subject:0 +#: help:email_template.preview,subject:0 +msgid "Subject (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: help:email.template,reply_to:0 +#: help:email_template.preview,reply_to:0 +msgid "Preferred response address (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: field:email.template,ref_ir_value:0 +#: field:email_template.preview,ref_ir_value:0 +msgid "Sidebar Button" +msgstr "" + +#. module: email_template +#: field:email.template,report_template:0 +#: field:email_template.preview,report_template:0 +msgid "Optional report to print and attach" +msgstr "" + +#. module: email_template +#: help:email.template,null_value:0 +#: help:email_template.preview,null_value:0 +msgid "Optional value to use if the target field is empty" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Model" +msgstr "" + +#. module: email_template +#: model:ir.model,name:email_template.model_mail_compose_message +msgid "Email composition wizard" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Add context action" +msgstr "" + +#. module: email_template +#: help:email.template,model_id:0 +#: help:email_template.preview,model_id:0 +msgid "The kind of document with with this template can be used" +msgstr "" + +#. module: email_template +#: field:email.template,email_recipients:0 +#: field:email_template.preview,email_recipients:0 +msgid "To (Partners)" +msgstr "" + +#. module: email_template +#: field:email.template,auto_delete:0 +#: field:email_template.preview,auto_delete:0 +msgid "Auto Delete" +msgstr "" + +#. module: email_template +#: help:email.template,copyvalue:0 +#: help:email_template.preview,copyvalue:0 +msgid "" +"Final placeholder expression, to be copy-pasted in the desired template " +"field." +msgstr "" + +#. module: email_template +#: field:email.template,model:0 +#: field:email_template.preview,model:0 +msgid "Related Document Model" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Addressing" +msgstr "" + +#. module: email_template +#: help:email.template,email_recipients:0 +#: help:email_template.preview,email_recipients:0 +msgid "" +"Comma-separated ids of recipient partners (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: field:email.template,attachment_ids:0 +#: field:email_template.preview,attachment_ids:0 +msgid "Attachments" +msgstr "" + +#. module: email_template +#: code:addons/email_template/email_template.py:234 +#, python-format +msgid "Deletion of the action record failed." +msgstr "" + +#. module: email_template +#: field:email.template,email_cc:0 +#: field:email_template.preview,email_cc:0 +msgid "Cc" +msgstr "" + +#. module: email_template +#: field:email.template,model_id:0 +#: field:email_template.preview,model_id:0 +msgid "Applies to" +msgstr "" + +#. module: email_template +#: field:email.template,sub_model_object_field:0 +#: field:email_template.preview,sub_model_object_field:0 +msgid "Sub-field" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Email Details" +msgstr "" + +#. module: email_template +#: code:addons/email_template/email_template.py:199 +#, python-format +msgid "Send Mail (%s)" +msgstr "" + +#. module: email_template +#: help:res.partner,opt_out:0 +msgid "" +"If checked, this partner will not receive any automated email notifications, " +"such as the availability of invoices." +msgstr "" + +#. module: email_template +#: help:email.template,auto_delete:0 +#: help:email_template.preview,auto_delete:0 +msgid "Permanently delete this email after sending it, to save space" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Group by..." +msgstr "" + +#. module: email_template +#: help:email.template,sub_model_object_field:0 +#: help:email_template.preview,sub_model_object_field:0 +msgid "" +"When a relationship field is selected as first field, this field lets you " +"select the target field within the destination document model (sub-model)." +msgstr "" + +#. module: email_template +#: code:addons/email_template/email_template.py:234 +#, python-format +msgid "Warning" +msgstr "" + +#. module: email_template +#: field:email.template,user_signature:0 +#: field:email_template.preview,user_signature:0 +msgid "Add Signature" +msgstr "" + +#. module: email_template +#: model:ir.model,name:email_template.model_res_partner +msgid "Partner" +msgstr "" + +#. module: email_template +#: field:email.template,null_value:0 +#: field:email_template.preview,null_value:0 +msgid "Default Value" +msgstr "" + +#. module: email_template +#: help:email.template,attachment_ids:0 +#: help:email_template.preview,attachment_ids:0 +msgid "" +"You may attach files to this template, to be added to all emails created " +"from this template" +msgstr "" + +#. module: email_template +#: help:email.template,body_html:0 +#: help:email_template.preview,body_html:0 +msgid "Rich-text/HTML version of the message (placeholders may be used here)" +msgstr "" + +#. module: email_template +#: view:email.template:0 +msgid "Contents" +msgstr "" + +#. module: email_template +#: field:email.template,subject:0 +#: field:email_template.preview,subject:0 +msgid "Subject" +msgstr "" diff --git a/addons/email_template/tests/test_ir_actions.py b/addons/email_template/tests/test_ir_actions.py index d323ee36c1f..9b408a45316 100644 --- a/addons/email_template/tests/test_ir_actions.py +++ b/addons/email_template/tests/test_ir_actions.py @@ -33,7 +33,7 @@ class TestServerActionsEmail(TestServerActionsBase): 'name': 'TestTemplate', 'email_from': 'myself@example.com', 'email_to': 'brigitte@example.com', - 'partner_to': '[%s]' % self.test_partner_id, + 'partner_to': '%s' % self.test_partner_id, 'model_id': self.res_partner_model_id, 'subject': 'About ${object.name}', 'body_html': '

Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}

', diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py index ccc8a49b875..a43bbe79713 100644 --- a/addons/email_template/tests/test_mail.py +++ b/addons/email_template/tests/test_mail.py @@ -21,6 +21,7 @@ import base64 from openerp.addons.mail.tests.common import TestMail +from openerp.tools import mute_logger class test_message_compose(TestMail): @@ -200,3 +201,44 @@ class test_message_compose(TestMail): # Generate messsage with default email and partner on template mail_value = mail_compose.generate_email_for_composer(cr, uid, email_template_id, uid) self.assertEqual(set(mail_value['partner_ids']), set(send_to), 'mail.message partner_ids list created by template is incorrect') + + @mute_logger('openerp.osv.orm', 'openerp.osv.orm') + def test_10_email_templating(self): + """ Tests designed for the mail.compose.message wizard updated by email_template. """ + cr, uid, context = self.cr, self.uid, {} + + # create the email.template on mail.group model + group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0] + email_template = self.registry('email.template') + email_template_id = email_template.create(cr, uid, { + 'model_id': group_model_id, + 'name': 'Pigs Template', + 'email_from': 'Raoul Grosbedon ', + 'subject': '${object.name}', + 'body_html': '${object.description}', + 'user_signature': True, + 'email_to': 'b@b.b c@c.c', + 'email_cc': 'd@d.d', + 'partner_to': '${user.partner_id.id},%s,%s,-1' % (self.user_raoul.partner_id.id, self.user_bert.partner_id.id) + }) + + # not force send: email_recipients is not taken into account + msg_id = email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, context=context) + mail = self.mail_mail.browse(cr, uid, msg_id, context=context) + self.assertEqual(mail.subject, 'Pigs', 'email_template: send_mail: wrong subject') + self.assertEqual(mail.email_to, 'b@b.b c@c.c', 'email_template: send_mail: wrong email_to') + self.assertEqual(mail.email_cc, 'd@d.d', 'email_template: send_mail: wrong email_cc') + self.assertEqual( + set([partner.id for partner in mail.recipient_ids]), + set((self.partner_admin_id, self.user_raoul.partner_id.id, self.user_bert.partner_id.id)), + 'email_template: send_mail: wrong management of partner_to') + + # force send: take email_recipients into account + email_template.send_mail(cr, uid, email_template_id, self.group_pigs_id, force_send=True, context=context) + sent_emails = self._build_email_kwargs_list + email_to_lst = [ + ['b@b.b', 'c@c.c'], ['"Followers of Pigs" '], + ['"Followers of Pigs" '], ['"Followers of Pigs" ']] + self.assertEqual(len(sent_emails), 4, 'email_template: send_mail: 3 valid email recipients + email_to -> should send 4 emails') + for email in sent_emails: + self.assertIn(email['email_to'], email_to_lst, 'email_template: send_mail: wrong email_recipients') diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py index bae7a0d8f9c..cd417a19d3c 100644 --- a/addons/email_template/wizard/mail_compose_message.py +++ b/addons/email_template/wizard/mail_compose_message.py @@ -19,7 +19,7 @@ # ############################################################################## -from openerp import tools +from openerp import tools, SUPERUSER_ID from openerp.osv import osv, fields @@ -143,9 +143,9 @@ class mail_compose_message(osv.TransientModel): partner_ids.append(partner_id) partner_to = rendered_values.pop('partner_to', '') if partner_to: - for partner_id in partner_to.split(','): - if partner_id: # placeholders could generate '', 3, 2 due to some empty field values - partner_ids.append(int(partner_id)) + # placeholders could generate '', 3, 2 due to some empty field values + tpl_partner_ids = [pid for pid in partner_to.split(',') if pid] + partner_ids += self.pool['res.partner'].exists(cr, SUPERUSER_ID, tpl_partner_ids, context=context) return partner_ids def generate_email_for_composer_batch(self, cr, uid, template_id, res_ids, context=None): diff --git a/addons/fleet/i18n/lo.po b/addons/fleet/i18n/lo.po new file mode 100644 index 00000000000..bb3d220ffbe --- /dev/null +++ b/addons/fleet/i18n/lo.po @@ -0,0 +1,1912 @@ +# Lao translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:06+0000\n" +"PO-Revision-Date: 2013-12-19 15:15+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Lao \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-20 05:11+0000\n" +"X-Generator: Launchpad (build 16872)\n" + +#. module: fleet +#: selection:fleet.vehicle,fuel_type:0 +msgid "Hybrid" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_compact +msgid "Compact" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_1 +msgid "A/C Compressor Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,vin_sn:0 +msgid "Unique number written on the vehicle motor (VIN/SN number)" +msgstr "" + +#. module: fleet +#: selection:fleet.service.type,category:0 +#: view:fleet.vehicle.log.contract:0 +#: view:fleet.vehicle.log.services:0 +msgid "Service" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Monthly" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:62 +#, python-format +msgid "Unknown" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_20 +msgid "Engine/Drive Belt(s) Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Vehicle costs" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,fuel_type:0 +msgid "Diesel" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:421 +#, python-format +msgid "License Plate: from '%s' to '%s'" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_38 +msgid "Resurface Rotors" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +#: view:fleet.vehicle.model:0 +msgid "Group By..." +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_32 +msgid "Oil Pump Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_18 +msgid "Engine Belt Inspection" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,cost_frequency:0 +msgid "No" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,power:0 +msgid "Power in kW of the vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_2 +msgid "Depreciation and Interests" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,insurer_id:0 +#: field:fleet.vehicle.log.fuel,vendor_id:0 +#: field:fleet.vehicle.log.services,vendor_id:0 +msgid "Supplier" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_35 +msgid "Power Steering Hose Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Odometer details" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "Has Alert(s)" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.fuel,liter:0 +msgid "Liter" +msgstr "" + +#. module: fleet +#: model:ir.actions.client,name:fleet.action_fleet_menu +msgid "Open Fleet Menu" +msgstr "" + +#. module: fleet +#: view:board.board:0 +msgid "Fuel Costs" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_9 +msgid "Battery Inspection" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,company_id:0 +msgid "Company" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Invoice Date" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +msgid "Refueling Details" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:669 +#, python-format +msgid "%s contract(s) need(s) to be renewed and/or closed!" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Indicative Costs" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_16 +msgid "Charging System Diagnosis" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,car_value:0 +msgid "Value of the bought vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_44 +msgid "Tie Rod End Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_24 +msgid "Head Gasket(s) Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +#: selection:fleet.vehicle.cost,cost_type:0 +msgid "Services" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,odometer:0 +#: help:fleet.vehicle.cost,odometer:0 +#: help:fleet.vehicle.cost,odometer_id:0 +msgid "Odometer measure of the vehicle at the moment of this log" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +#: field:fleet.vehicle.log.contract,notes:0 +msgid "Terms and Conditions" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_kanban +msgid "Vehicles with alerts" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_costs_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_costs_menu +msgid "Vehicle Costs" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Total Cost" +msgstr "" + +#. module: fleet +#: selection:fleet.service.type,category:0 +msgid "Both" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,cost_id:0 +#: field:fleet.vehicle.log.fuel,cost_id:0 +#: field:fleet.vehicle.log.services,cost_id:0 +msgid "Automatically created field to link to parent fleet.vehicle.cost" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Terminate Contract" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,parent_id:0 +msgid "Parent cost to this current cost" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Frequency of the recuring cost" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_1 +msgid "Calculation Benefit In Kind" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,expiration_date:0 +msgid "" +"Date when the coverage of the contract expirates (by default, one year after " +"begin date)" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +#: field:fleet.vehicle.log.fuel,notes:0 +#: view:fleet.vehicle.log.services:0 +#: field:fleet.vehicle.log.services,notes:0 +msgid "Notes" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:47 +#, python-format +msgid "Operation not allowed!" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,message_ids:0 +msgid "Messages" +msgstr "" + +#. module: fleet +#: model:res.groups,name:fleet.group_fleet_user +msgid "User" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,vehicle_id:0 +msgid "Vehicle concerned by this log" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,cost_amount:0 +#: field:fleet.vehicle.log.fuel,cost_amount:0 +#: field:fleet.vehicle.log.services,cost_amount:0 +msgid "Amount" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,message_unread:0 +msgid "Unread Messages" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_6 +msgid "Air Filter Replacement" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_tag +msgid "fleet.vehicle.tag" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "show the services logs for this vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,contract_renewal_name:0 +msgid "Name of contract to renew soon" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_senior +msgid "Senior" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,state:0 +msgid "Choose wheter the contract is still valid or not" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,transmission:0 +msgid "Automatic" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,message_unread:0 +msgid "If checked new messages require your attention." +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:414 +#, python-format +msgid "Driver: from '%s' to '%s'" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "and" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.model.brand,image_medium:0 +msgid "Medium-sized photo" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_34 +msgid "Oxygen Sensor Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.services:0 +msgid "Service Type" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,transmission:0 +msgid "Transmission Used by the vehicle" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:740 +#: view:fleet.vehicle.log.contract:0 +#: model:ir.actions.act_window,name:fleet.act_renew_contract +#, python-format +msgid "Renew Contract" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "show the odometer logs for this vehicle" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,odometer_unit:0 +msgid "Unit of the odometer " +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.services:0 +msgid "Services Costs Per Month" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Effective Costs" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_8 +msgid "Repair and maintenance" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,purchaser_id:0 +msgid "Person to which the contract is signed for" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_log_contract_act +msgid "" +"

\n" +" Click to create a new contract. \n" +"

\n" +" Manage all your contracts (leasing, insurances, etc.) with\n" +" their related services, costs. OpenERP will automatically " +"warn\n" +" you when some contracts have to be renewed.\n" +"

\n" +" Each contract (e.g.: leasing) may include several services\n" +" (reparation, insurances, periodic maintenance).\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_service_type +msgid "Type of services available on a vehicle" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_service_types_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_service_types_menu +msgid "Service Types" +msgstr "" + +#. module: fleet +#: view:board.board:0 +msgid "Contracts Costs" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_log_services_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_log_services_menu +msgid "Vehicles Services Logs" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_log_fuel_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_log_fuel_menu +msgid "Vehicles Fuel Logs" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.model.brand:0 +msgid "" +"$('.oe_picture').load(function() { if($(this).width() > $(this).height()) { " +"$(this).addClass('oe_employee_picture_wide') } });" +msgstr "" + +#. module: fleet +#: view:board.board:0 +msgid "Vehicles With Alerts" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_costs_act +msgid "" +"

\n" +" Click to create a new cost.\n" +"

\n" +" OpenERP helps you managing the costs for your different\n" +" vehicles. Costs are created automatically from services,\n" +" contracts (fixed or recurring) and fuel logs.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "show the fuel logs for this vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,purchaser_id:0 +msgid "Contractor" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,license_plate:0 +msgid "License Plate" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,state:0 +msgid "To Close" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Recurring Cost Frequency" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.fuel,inv_ref:0 +#: field:fleet.vehicle.log.services,inv_ref:0 +msgid "Invoice Reference" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,message_follower_ids:0 +msgid "Followers" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,location:0 +msgid "Location" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Costs Per Month" +msgstr "" + +#. module: fleet +#: field:fleet.contract.state,name:0 +msgid "Contract Status" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,contract_renewal_total:0 +msgid "Total of contracts due or overdue minus one" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,cost_subtype_id:0 +msgid "Type" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,contract_renewal_overdue:0 +msgid "Has Contracts Overdued" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,amount:0 +msgid "Total Price" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_27 +msgid "Heater Core Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_14 +msgid "Car Wash" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,driver_id:0 +msgid "Driver of the vehicle" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "other(s)" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_refueling +msgid "Refueling" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,message_summary:0 +msgid "" +"Holds the Chatter summary (number of messages, ...). This summary is " +"directly in html format in order to be inserted in kanban views." +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_5 +msgid "A/C Recharge" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_log_fuel +msgid "Fuel log for vehicles" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "Engine Options" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +msgid "Fuel Costs Per Month" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_sedan +msgid "Sedan" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,seats:0 +msgid "Seats Number" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_convertible +msgid "Convertible" +msgstr "" + +#. module: fleet +#: model:ir.ui.menu,name:fleet.fleet_configuration +msgid "Configuration" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +#: field:fleet.vehicle.log.contract,sum_cost:0 +msgid "Indicative Costs Total" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_junior +msgid "Junior" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,model_id:0 +msgid "Model of the vehicle" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_state_act +msgid "" +"

\n" +" Click to create a vehicule status.\n" +"

\n" +" You can customize available status to track the evolution " +"of\n" +" each vehicule. Example: Active, Being Repaired, Sold.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +#: field:fleet.vehicle,log_fuel:0 +#: view:fleet.vehicle.log.fuel:0 +msgid "Fuel Logs" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:409 +#: code:addons/fleet/fleet.py:413 +#: code:addons/fleet/fleet.py:417 +#: code:addons/fleet/fleet.py:420 +#, python-format +msgid "None" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_reporting_costs_non_effective +#: model:ir.ui.menu,name:fleet.menu_fleet_reporting_indicative_costs +msgid "Indicative Costs Analysis" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_12 +msgid "Brake Inspection" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,state_id:0 +msgid "Current state of the vehicle" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,transmission:0 +msgid "Manual" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_52 +msgid "Wheel Bearing Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,cost_subtype_id:0 +msgid "Cost type purchased with this cost" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,fuel_type:0 +msgid "Gasoline" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_model_brand_act +msgid "" +"

\n" +" Click to create a new brand.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,start_date:0 +msgid "Contract Start Date" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,odometer_unit:0 +msgid "Odometer Unit" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_30 +msgid "Intake Manifold Gasket Replacement" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Daily" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_6 +msgid "Snow tires" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,date:0 +msgid "Date when the cost has been executed" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +#: view:fleet.vehicle.model:0 +msgid "Vehicles costs" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_log_services +msgid "Services for vehicles" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Indicative Cost" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_26 +msgid "Heater Control Valve Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "" +"Create a new contract automatically with all the same informations except " +"for the date that will start at the end of current contract" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,state:0 +msgid "Terminated" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_cost +msgid "Cost related to a vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_33 +msgid "Other Maintenance" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +#: field:fleet.vehicle.cost,parent_id:0 +msgid "Parent" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,state_id:0 +#: view:fleet.vehicle.state:0 +msgid "State" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,cost_generated:0 +msgid "Recurring Cost Amount" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_49 +msgid "Transmission Replacement" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_log_fuel_act +msgid "" +"

\n" +" Click to create a new fuel log. \n" +"

\n" +" Here you can add refuelling entries for all vehicles. You " +"can\n" +" also filter logs of a particular vehicle using the search\n" +" field.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_11 +msgid "Brake Caliper Replacement" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,odometer:0 +msgid "Last Odometer" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_model_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_model_menu +msgid "Vehicle Model" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,doors:0 +msgid "Doors Number" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,acquisition_date:0 +msgid "Date when the vehicle has been bought" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.model:0 +msgid "Models" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "amount" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,fuel_type:0 +msgid "Fuel Used by the vehicle" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Set Contract In Progress" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,odometer_unit:0 +#: field:fleet.vehicle.odometer,unit:0 +msgid "Unit" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,message_is_follower:0 +msgid "Is a Follower" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,horsepower:0 +msgid "Horsepower" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,image:0 +#: field:fleet.vehicle,image_medium:0 +#: field:fleet.vehicle,image_small:0 +#: field:fleet.vehicle.model,image:0 +#: field:fleet.vehicle.model,image_medium:0 +#: field:fleet.vehicle.model,image_small:0 +#: field:fleet.vehicle.model.brand,image:0 +msgid "Logo" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,horsepower_tax:0 +msgid "Horsepower Taxation" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,log_services:0 +#: view:fleet.vehicle.log.services:0 +msgid "Services Logs" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.model:0 +msgid "Brand" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_43 +msgid "Thermostat Replacement" +msgstr "" + +#. module: fleet +#: field:fleet.service.type,category:0 +msgid "Category" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_log_fuel_graph +msgid "Fuel Costs by Month" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.model.brand,image:0 +msgid "" +"This field holds the image used as logo for the brand, limited to " +"1024x1024px." +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_11 +msgid "Management Fee" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "All vehicles" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +#: view:fleet.vehicle.log.services:0 +msgid "Additional Details" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_log_services_graph +msgid "Services Costs by Month" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_9 +msgid "Assistance" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.fuel,price_per_liter:0 +msgid "Price Per Liter" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_17 +msgid "Door Window Motor/Regulator Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_46 +msgid "Tire Service" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_8 +msgid "Ball Joint Replacement" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,fuel_type:0 +msgid "Fuel Type" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_22 +msgid "Fuel Injector Replacement" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_state_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_state_menu +msgid "Vehicle Status" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_50 +msgid "Water Pump Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,location:0 +msgid "Location of the vehicle (garage, ...)" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_28 +msgid "Heater Hose Replacement" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,state:0 +msgid "Status" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_40 +msgid "Rotor Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.model,brand_id:0 +msgid "Brand of the vehicle" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,start_date:0 +msgid "Date when the coverage of the contract begins" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,fuel_type:0 +msgid "Electric" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,tag_ids:0 +msgid "Tags" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +#: field:fleet.vehicle,log_contracts:0 +msgid "Contracts" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_13 +msgid "Brake Pad(s) Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +#: view:fleet.vehicle.log.services:0 +msgid "Odometer Details" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,driver_id:0 +msgid "Driver" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.model.brand,image_small:0 +msgid "" +"Small-sized photo of the brand. It is automatically resized as a 64x64px " +"image, with aspect ratio preserved. Use this field anywhere a small image is " +"required." +msgstr "" + +#. module: fleet +#: view:board.board:0 +msgid "Fleet Dashboard" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_break +msgid "Break" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_contract_omnium +msgid "Omnium" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.services:0 +msgid "Services Details" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_15 +msgid "Residual value (Excluding VAT)" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_7 +msgid "Alternator Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_3 +msgid "A/C Diagnosis" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_23 +msgid "Fuel Pump Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Activation Cost" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Cost Type" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_4 +msgid "A/C Evaporator Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "show all the costs for this vehicle" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.odometer:0 +msgid "Odometer Values Per Month" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_model_act +msgid "" +"

\n" +" Click to create a new model.\n" +"

\n" +" You can define several models (e.g. A3, A4) for each brand " +"(Audi).\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_act +msgid "" +"

\n" +" Click to create a new vehicle. \n" +"

\n" +" You will be able to manage your fleet by keeping track of " +"the\n" +" contracts, services, fixed and recurring costs, odometers " +"and\n" +" fuel logs associated to each vehicle.\n" +"

\n" +" OpenERP will warn you when services or contract have to be\n" +" renewed.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_13 +msgid "Entry into service tax" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,expiration_date:0 +msgid "Contract Expiration Date" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Cost Subtype" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.open_board_fleet +msgid "" +"
\n" +"

\n" +" Fleet dashboard is empty.\n" +"

\n" +" To add your first report into this dashboard, go to any\n" +" menu, switch to list or graph view, and click 'Add " +"to\n" +" Dashboard' in the extended search options.\n" +"

\n" +" You can filter and group data before inserting into the\n" +" dashboard using the search options.\n" +"

\n" +"
\n" +" " +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_12 +msgid "Rent (Excluding VAT)" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,odometer_unit:0 +msgid "Kilometers" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.fuel:0 +msgid "Vehicle Details" +msgstr "" + +#. module: fleet +#: selection:fleet.service.type,category:0 +#: field:fleet.vehicle.cost,contract_id:0 +#: selection:fleet.vehicle.cost,cost_type:0 +msgid "Contract" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_model_brand_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_model_brand_menu +msgid "Model brand of Vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_10 +msgid "Battery Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +#: field:fleet.vehicle.cost,date:0 +#: field:fleet.vehicle.odometer,date:0 +msgid "Date" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_menu +#: model:ir.ui.menu,name:fleet.fleet_vehicles +msgid "Vehicles" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle,odometer_unit:0 +msgid "Miles" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,cost_generated:0 +msgid "" +"Costs paid at regular intervals, depending on the cost frequency. If the " +"cost frequency is set to unique, the cost will be logged at the start date" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_17 +msgid "Emissions" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_model +msgid "Model of a vehicle" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.action_fleet_reporting_costs +#: model:ir.actions.act_window,help:fleet.action_fleet_reporting_costs_non_effective +msgid "" +"

\n" +" OpenERP helps you managing the costs for your different vehicles\n" +" Costs are generally created from services and contract and appears " +"here.\n" +"

\n" +"

\n" +" Thanks to the different filters, OpenERP can only print the " +"effective\n" +" costs, sort them by type and by vehicle.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,car_value:0 +msgid "Car Value" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.open_board_fleet +#: model:ir.module.category,name:fleet.module_fleet_category +#: model:ir.ui.menu,name:fleet.menu_fleet_dashboard +#: model:ir.ui.menu,name:fleet.menu_fleet_reporting +#: model:ir.ui.menu,name:fleet.menu_root +msgid "Fleet" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_14 +msgid "Total expenses (Excluding VAT)" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,odometer_id:0 +msgid "Odometer" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_45 +msgid "Tire Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.service.type:0 +msgid "Service types" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.fuel,purchaser_id:0 +#: field:fleet.vehicle.log.services,purchaser_id:0 +msgid "Purchaser" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_3 +msgid "Tax roll" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.model:0 +#: field:fleet.vehicle.model,vendors:0 +msgid "Vendors" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_contract_leasing +msgid "Leasing" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.model.brand,image_medium:0 +msgid "" +"Medium-sized logo of the brand. It is automatically resized as a 128x128px " +"image, with aspect ratio preserved. Use this field in form views or some " +"kanban views." +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Weekly" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +#: view:fleet.vehicle.odometer:0 +msgid "Odometer Logs" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,acquisition_date:0 +msgid "Acquisition Date" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_odometer +msgid "Odometer log for a vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,cost_type:0 +msgid "Category of the cost" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_5 +#: model:fleet.service.type,name:fleet.type_service_service_7 +msgid "Summer tires" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,contract_renewal_due_soon:0 +msgid "Has Contracts to renew" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_31 +msgid "Oil Change" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.model.brand,image_small:0 +msgid "Smal-sized photo" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_model_brand +msgid "Brand model of the vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_51 +msgid "Wheel Alignment" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_purchased +msgid "Purchased" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_odometer_act +msgid "" +"

\n" +" Here you can add various odometer entries for all vehicles.\n" +" You can also show odometer value for a particular vehicle " +"using\n" +" the search field.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.model,brand_id:0 +#: view:fleet.vehicle.model.brand:0 +msgid "Model Brand" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "General Properties" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_21 +msgid "Exhaust Manifold Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_47 +msgid "Transmission Filter Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_10 +msgid "Replacement Vehicle" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,state:0 +msgid "In Progress" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.log.contract,cost_frequency:0 +msgid "Yearly" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.model,modelname:0 +msgid "Model name" +msgstr "" + +#. module: fleet +#: view:board.board:0 +#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_costs_graph +msgid "Costs by Month" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_18 +msgid "Touring Assistance" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,power:0 +msgid "Power (kW)" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:418 +#, python-format +msgid "State: from '%s' to '%s'" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_2 +msgid "A/C Condenser Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_19 +msgid "Engine Coolant Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +msgid "Cost Details" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:410 +#, python-format +msgid "Model: from '%s' to '%s'" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.cost,cost_type:0 +msgid "Other" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Contract details" +msgstr "" + +#. module: fleet +#: model:fleet.vehicle.tag,name:fleet.vehicle_tag_leasing +msgid "Employee Car" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,auto_generated:0 +msgid "Automatically Generated" +msgstr "" + +#. module: fleet +#: selection:fleet.vehicle.cost,cost_type:0 +msgid "Fuel" +msgstr "" + +#. module: fleet +#: sql_constraint:fleet.vehicle.state:0 +msgid "State name already exists" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_37 +msgid "Radiator Repair" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_log_contract +msgid "Contract information on a vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,days_left:0 +msgid "Warning Date" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_19 +msgid "Residual value in %" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "Additional Properties" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle_state +msgid "fleet.vehicle.state" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Contract Costs Per Month" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_log_contract_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_log_contract_menu +msgid "Vehicles Contracts" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_48 +msgid "Transmission Fluid Replacement" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.model.brand,name:0 +msgid "Brand Name" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_36 +msgid "Power Steering Pump Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,contract_id:0 +msgid "Contract attached to this cost" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:397 +#, python-format +msgid "Vehicle %s has been added to the fleet!" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +#: view:fleet.vehicle.log.fuel:0 +#: view:fleet.vehicle.log.services:0 +msgid "Price" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,odometer:0 +#: field:fleet.vehicle.odometer,value:0 +msgid "Odometer Value" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +#: view:fleet.vehicle.cost:0 +#: field:fleet.vehicle.cost,vehicle_id:0 +#: field:fleet.vehicle.odometer,vehicle_id:0 +msgid "Vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.cost,cost_ids:0 +#: view:fleet.vehicle.log.contract:0 +#: view:fleet.vehicle.log.services:0 +msgid "Included Services" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.action_fleet_vehicle_kanban +msgid "" +"

\n" +" Here are displayed vehicles for which one or more contracts need " +"to be renewed. If you see this message, then there is no contracts to " +"renew.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_15 +msgid "Catalytic Converter Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_25 +msgid "Heater Blower Motor Replacement" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.fleet_vehicle_odometer_act +#: model:ir.ui.menu,name:fleet.fleet_vehicle_odometer_menu +msgid "Vehicles Odometer" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.log.contract,notes:0 +msgid "Write here all supplementary informations relative to this contract" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_29 +msgid "Ignition Coil Replacement" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_service_16 +msgid "Options" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_contract_repairing +msgid "Repairing" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_reporting_costs +#: model:ir.ui.menu,name:fleet.menu_fleet_reporting_costs +msgid "Costs Analysis" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.log.contract,ins_ref:0 +msgid "Contract Reference" +msgstr "" + +#. module: fleet +#: field:fleet.service.type,name:0 +#: field:fleet.vehicle,name:0 +#: field:fleet.vehicle.cost,name:0 +#: field:fleet.vehicle.log.contract,name:0 +#: field:fleet.vehicle.model,name:0 +#: field:fleet.vehicle.odometer,name:0 +#: field:fleet.vehicle.state,name:0 +#: field:fleet.vehicle.tag,name:0 +msgid "Name" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,doors:0 +msgid "Number of doors of the vehicle" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,transmission:0 +msgid "Transmission" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,vin_sn:0 +msgid "Chassis Number" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,color:0 +msgid "Color of the vehicle" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_log_services_act +msgid "" +"

\n" +" Click to create a new service entry. \n" +"

\n" +" OpenERP helps you keeping track of all the services done\n" +" on your vehicle. Services can be of many type: occasional\n" +" repair, fixed maintenance, etc.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,co2:0 +msgid "CO2 Emissions" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +msgid "Contract logs" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "Costs" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,message_summary:0 +msgid "Summary" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,name:fleet.action_fleet_vehicle_log_contract_graph +msgid "Contracts Costs by Month" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,model_id:0 +#: view:fleet.vehicle.model:0 +msgid "Model" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_41 +msgid "Spark Plug Replacement" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,message_ids:0 +msgid "Messages and communication history" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_vehicle +msgid "Information on a vehicle" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,co2:0 +msgid "CO2 emissions of the vehicle" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_53 +msgid "Windshield Wiper(s) Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.contract:0 +#: field:fleet.vehicle.log.contract,generated_cost_ids:0 +msgid "Generated Costs" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle.state,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: fleet +#: field:fleet.vehicle,color:0 +msgid "Color" +msgstr "" + +#. module: fleet +#: model:ir.actions.act_window,help:fleet.fleet_vehicle_service_types_act +msgid "" +"

\n" +" Click to create a new type of service.\n" +"

\n" +" Each service can used in contracts, as a standalone service " +"or both.\n" +"

\n" +" " +msgstr "" + +#. module: fleet +#: view:board.board:0 +msgid "Services Costs" +msgstr "" + +#. module: fleet +#: code:addons/fleet/fleet.py:47 +#, python-format +msgid "Emptying the odometer value of a vehicle is not allowed." +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,seats:0 +msgid "Number of seats of the vehicle" +msgstr "" + +#. module: fleet +#: model:res.groups,name:fleet.group_fleet_manager +msgid "Manager" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.services:0 +msgid "Cost" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_39 +msgid "Rotate Tires" +msgstr "" + +#. module: fleet +#: model:fleet.service.type,name:fleet.type_service_42 +msgid "Starter Replacement" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.cost:0 +#: field:fleet.vehicle.cost,year:0 +msgid "Year" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle,license_plate:0 +msgid "License plate number of the vehicle (ie: plate number for a car)" +msgstr "" + +#. module: fleet +#: model:ir.model,name:fleet.model_fleet_contract_state +msgid "Contains the different possible status of a leasing contract" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle:0 +msgid "show the contract for this vehicle" +msgstr "" + +#. module: fleet +#: view:fleet.vehicle.log.services:0 +msgid "Total" +msgstr "" + +#. module: fleet +#: help:fleet.service.type,category:0 +msgid "" +"Choose wheter the service refer to contracts, vehicle services or both" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.cost,cost_type:0 +msgid "For internal purpose only" +msgstr "" + +#. module: fleet +#: help:fleet.vehicle.state,sequence:0 +msgid "Used to order the note stages" +msgstr "" diff --git a/addons/gamification/__init__.py b/addons/gamification/__init__.py new file mode 100644 index 00000000000..21f9c9491ac --- /dev/null +++ b/addons/gamification/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import models +import wizard diff --git a/addons/gamification/__openerp__.py b/addons/gamification/__openerp__.py new file mode 100644 index 00000000000..c522e287725 --- /dev/null +++ b/addons/gamification/__openerp__.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + 'name': 'Gamification', + 'version': '1.0', + 'author': 'OpenERP SA', + 'category': 'Human Ressources', + 'depends': ['mail', 'email_template', 'web_kanban_gauge'], + 'description': """ +Gamification process +==================== +The Gamification module provides ways to evaluate and motivate the users of OpenERP. + +The users can be evaluated using goals and numerical objectives to reach. +**Goals** are assigned through **challenges** to evaluate and compare members of a team with each others and through time. + +For non-numerical achievements, **badges** can be granted to users. From a simple "thank you" to an exceptional achievement, a badge is an easy way to exprimate gratitude to a user for their good work. + +Both goals and badges are flexibles and can be adapted to a large range of modules and actions. When installed, this module creates easy goals to help new users to discover OpenERP and configure their user profile. +""", + + 'data': [ + 'wizard/update_goal.xml', + 'wizard/grant_badge.xml', + 'views/badge.xml', + 'views/challenge.xml', + 'views/goal.xml', + 'data/cron.xml', + 'security/gamification_security.xml', + 'security/ir.model.access.csv', + 'data/goal_base.xml', + 'data/badge.xml', + ], + 'installable': True, + 'application': True, + 'auto_install': False, + + 'css': ['static/src/css/gamification.css'], + 'js': ['static/src/js/gamification.js',], + 'qweb': ['static/src/xml/gamification.xml'], +} diff --git a/addons/gamification/data/badge.xml b/addons/gamification/data/badge.xml new file mode 100644 index 00000000000..dc9f1212ae1 --- /dev/null +++ b/addons/gamification/data/badge.xml @@ -0,0 +1,1142 @@ + + + + + Good Job + You did great at your job. + everyone + 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 + RU5ErkJggg== + + + + Problem Solver + No one can solve challenges like you do. + everyone + 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 + + + + Hidden + You have found the hidden badge + nobody + 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 + oZLwTwSrpfvBrHNcSUesOjyfJLWUiLcDPe1haF///Zh9t1HQUWnFS9BX3I8e/xzHFh2TVUtN+Lbz + vXeNyl1Q937yIlQiWMLFMViuueWucSU84WK7R7jWAjcAr06aDOj4AOv7+ugevpnD+mYMu9hyYaOF + iWGEGAnPEVn4LqcmxzAKk8wXqQAPA89QO5jsuqlinaPKOF+zHqGqeIQKESsRLOGFHZebfOq6rjZH + uNqd7xOOeN0NbAWG1rWjOgZuIJvcixUZohjqQ2sbrW2MJppvGgOtTNrVEpXiPIPlQ5w9f5r5hQmc + UO4c8BjwLMulgFyhynmEyhWpHLW1q7IIlQiWcHX9Y3iEy+u6XPFq8whX3PnzVzgCNggwkDToHryR + waGdHK7uaIqGSRglenKPUZl9hEPnl9zfrgCPAA+xXBzPrVdWdMTIFaqsR6TyLC+kuweUJfQTwRKu + oZ+8ritMLQnVdV5tjoC5n7jz6QTWABud8HFzbwzKoR6i8U529LcxG7uJaNsI58p9KKrYNg0/22hh + olTNPSllclPkAOfm57HSJ8hmZykUcxRLRco2aWr5UsdZruRpeZxUyRP25Txila9bm6rUrU+JUIlg + CddRuJTHdYXrnFf9x3VdEeeziVrJm80sp1BEN3VAJrqFdV0xThk30hk1wEximQnaI7Bg92FrN31V + o7DRujazjYsUzdROyHbBg6vadzbGc79uM/KE7DyZkqZLzZEqwTBjZLMLRAunmEnlmSsDy4vgM9TS + D445guO9zcgrUgWPULkCVagTKa+bkrBPBEtYBfEyLuK8vO6r/uP+ecT5++4a2Q5gOzBKrWLqBYRN + xZo2g5F2E6J9nGEn6zpM+tqTPFJ8yfMertPMcUv0ANmyJlvRpIo2qaJNoVTilsgTnM9ajGcsZvMX + TckoA2eAk44wTXuExVswseIJ5Yp1QlXwfLzhXn3IJyIlgiU0oA/rxStUJ2BRj2DFnE+9eLkCZnrW + yFyn5mbkez9uvtgLXchb9giKKyZZj2NKsZxW4Doib4hWL1DecK9UJ1Tur0uef7fq+X+JSIlgCT4W + L/cT8giYG0J6xapeuCKev296RMzwfFV1X72uj4uEWF6h8N7zqD3CVC9Q9SLlFar678uev29dZE1K + REoESwhI/xp1ImZ6RMwrZOG6UNHrukIe4fJ+6kXsYoKl60TKFZIXEimvWFU8604Vz59XX8BBiUiJ + YAlN4r4uJmKuEzPqhOlS319MtLybApdyU7pOYNzvq3XCVf/VrnNOlxInESkRLKEFRKw+nPSKWb2w + 1f/auIjDulg4eLFQ0Ou67Iv8nr7ER8RJBEsQnjcm1AsIm6pzbJdCv4CIvdD3iDgJIljC9R4vVzKO + 9FX+mSAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAI + giAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIghBg/j+I/UnoNLmiuQAAAABJRU5ErkJggg== + + + + + + Brilliant + With your brilliant ideas, you are an inspiration to others. + everyone + True + 2 + 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 + AABJRU5ErkJggg== + + + + + + + + Received Badge + Congratulation, you have received the badge ${object.badge_id.name} ! + % if object.sender_id + This badge was granted by ${object.sender_id.name}. + % endif +

+ + % if object.comment +

${object.comment}

+ % endif + ]]>
+
+
+
diff --git a/addons/gamification/data/cron.xml b/addons/gamification/data/cron.xml new file mode 100644 index 00000000000..8585771c97d --- /dev/null +++ b/addons/gamification/data/cron.xml @@ -0,0 +1,16 @@ + + + + + Run Goal Challenge Checker + 1 + days + -1 + + gamification.challenge + _cron_update + () + + + \ No newline at end of file diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml new file mode 100644 index 00000000000..66dd7be7431 --- /dev/null +++ b/addons/gamification/data/goal_base.xml @@ -0,0 +1,208 @@ + + + + + + + + Reminder for Goal Update + + Reminder ${object.name} + + +

You have not updated your progress for the goal ${object.definition_id.name} (currently reached at ${object.completeness}%) for at least ${object.remind_update_delay} days. Do not forget to do it.

+ +

If you have not changed your score yet, you can use the button "The current value is up to date" to indicate so.

+ ]]>
+
+ + + Simple Challenge Report Progress + + ${object.name} + +

The following message contains the current progress for the challenge ${object.name}

+ +% if object.visibility_mode == 'personal': + + + + + + + + % for line in ctx["challenge_lines"]: + = 100: + style="font-weight:bold;" + % endif + > + + + + + + % endfor +
GoalTargetCurrentCompleteness
${line['name']}${line['target']} + % if line['suffix']: + ${line['suffix']} + % endif + ${line['current']} + % if line['suffix']: + ${line['suffix']} + % endif + ${line['completeness']} %
+% else: + % for line in ctx["challenge_lines"]: + + + + + + + + + + + % for goal in line['goals']: + = 100: + style="font-weight:bold;" + % endif + > + + + + + + % endfor +
${line['name']}
#PersonCompletenessCurrent
${goal['rank']}${goal['name']}${goal['completeness']}%${goal['current']}/${line['target']} + % if line['suffix']: + ${line['suffix']} + % endif +
+ +

+ + % endfor +% endif + ]]>
+
+ +
+ + + + + + Set your Timezone + Configure your profile and specify your timezone + count + boolean + + [('id','=',user.id),('partner_id.tz', '!=', False)] + + user.id + + + + Set your Company Data + Write some information about your company (specify at least a name) + count + boolean + + [('user_ids', 'in', [user.id]), ('name', '=', 'Your Company')] + lower + + user.company_id.id + + + + + + Create User + ir.actions.act_window + res.users + form + current + + {'default_groups_ref': ['base.group_user']} + 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. + + + + Invite new Users + Create at least another user + boolean + count + + [('id', '!=', user.id)] + + + + + Mail Group Following + Follow mail groups to receive news + python + result = pool.get('mail.followers').search(cr, uid, [('res_model', '=', 'mail.group'), ('partner_id', '=', object.user_id.partner_id.id)], count=True, context=context) + + + + + + + Complete your Profile + once + personal + never + + inprogress + other + + + + Setup your Company + once + personal + never + + inprogress + other + + + + + + 1 + + + + + + 1 + + + + + 0 + + + + + 1 + + + + +
diff --git a/addons/gamification/html/index.html b/addons/gamification/html/index.html new file mode 100644 index 00000000000..890efa0d1ec --- /dev/null +++ b/addons/gamification/html/index.html @@ -0,0 +1,86 @@ +
+
+
+

Drive Engagement with Gamification

+

Leverage natural desire for competition

+

+ Reinforce good habits and improve win rates with real-time recognition and rewards inspired by game mechanics. Align teams around clear business objectives with challenges, personal objectives and team leader boards. +

+
+

Leaderboards

+
+ +
+

+ Promote leaders and competition amongst sales team with performance ratios. +

+
+
+

Personnal Objectives

+
+ +
+

+ Assign clear goals to users to align them with the company objectives. +

+
+
+

Visual Information

+
+ +
+

+ See in an glance the progress of each user. +

+
+
+
+ + +
+
+

Create custom Challenges

+
+

+Use predefined goals to generate easily your own challenges. Assign it to a team or individual users. Receive feedback as often as needed: daily, weekly... Repeat it automatically to compare progresses through time. +

+
+
+
+ +
+
+
+
+ +
+
+

Motivate with Badges

+
+
+ +
+
+
+

+Inspire achievement with recognition of coworker's good work by rewarding badges. These can be deserved manually or upon completion of challenges. Add fun to the competition with rare badges. +

+
+
+
+ +
+
+

Adapt to any module

+
+

+Create goals linked to any module. The evaluation system is very flexible and can be used for many different tasks : sales evaluation, creation of events, project completion or even helping new users to complete their profile. +

+
+
+
+ +
+
+
+
diff --git a/addons/gamification/models/__init__.py b/addons/gamification/models/__init__.py new file mode 100644 index 00000000000..812a08b1e19 --- /dev/null +++ b/addons/gamification/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import goal +import challenge +import res_users +import badge diff --git a/addons/gamification/models/badge.py b/addons/gamification/models/badge.py new file mode 100644 index 00000000000..1d879393ed2 --- /dev/null +++ b/addons/gamification/models/badge.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp import SUPERUSER_ID +from openerp.osv import fields, osv +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF +from openerp.tools.translate import _ + +from datetime import date +import logging + +_logger = logging.getLogger(__name__) + +class gamification_badge_user(osv.Model): + """User having received a badge""" + + _name = 'gamification.badge.user' + _description = 'Gamification user badge' + _order = "create_date desc" + + _columns = { + 'user_id': fields.many2one('res.users', string="User", required=True), + 'sender_id': fields.many2one('res.users', string="Sender", help="The user who has send the badge"), + 'badge_id': fields.many2one('gamification.badge', string='Badge', required=True), + 'comment': fields.text('Comment'), + 'badge_name': fields.related('badge_id', 'name', type="char", string="Badge Name"), + 'create_date': fields.datetime('Created', readonly=True), + 'create_uid': fields.many2one('res.users', string='Creator', readonly=True), + } + + + def _send_badge(self, cr, uid, ids, context=None): + """Send a notification to a user for receiving a badge + + Does not verify constrains on badge granting. + The users are added to the owner_ids (create badge_user if needed) + The stats counters are incremented + :param ids: list(int) of badge users that will receive the badge + """ + res = True + temp_obj = self.pool.get('email.template') + user_obj = self.pool.get('res.users') + template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_badge_received', context) + for badge_user in self.browse(cr, uid, ids, context=context): + body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.badge.user', badge_user.id, context=context) + res = user_obj.message_post(cr, uid, badge_user.user_id.id, body=body_html, context=context) + return res + + def create(self, cr, uid, vals, context=None): + self.pool.get('gamification.badge').check_granting(cr, uid, badge_id=vals.get('badge_id'), context=context) + return super(gamification_badge_user, self).create(cr, uid, vals, context=context) + + +class gamification_badge(osv.Model): + """Badge object that users can send and receive""" + + CAN_GRANT = 1 + NOBODY_CAN_GRANT = 2 + USER_NOT_VIP = 3 + BADGE_REQUIRED = 4 + TOO_MANY = 5 + + _name = 'gamification.badge' + _description = 'Gamification badge' + _inherit = ['mail.thread'] + + def _get_owners_info(self, cr, uid, ids, name, args, context=None): + """Return: + the list of unique res.users ids having received this badge + the total number of time this badge was granted + the total number of users this badge was granted to + """ + result = dict.fromkeys(ids, False) + for obj in self.browse(cr, uid, ids, context=context): + res = list(set(owner.user_id.id for owner in obj.owner_ids)) + result[obj.id] = { + 'unique_owner_ids': res, + 'stat_count': len(obj.owner_ids), + 'stat_count_distinct': len(res) + } + return result + + def _get_badge_user_stats(self, cr, uid, ids, name, args, context=None): + """Return stats related to badge users""" + result = dict.fromkeys(ids, False) + badge_user_obj = self.pool.get('gamification.badge.user') + first_month_day = date.today().replace(day=1).strftime(DF) + for bid in ids: + result[bid] = { + 'stat_my': badge_user_obj.search(cr, uid, [('badge_id', '=', bid), ('user_id', '=', uid)], context=context, count=True), + 'stat_this_month': badge_user_obj.search(cr, uid, [('badge_id', '=', bid), ('create_date', '>=', first_month_day)], context=context, count=True), + 'stat_my_this_month': badge_user_obj.search(cr, uid, [('badge_id', '=', bid), ('user_id', '=', uid), ('create_date', '>=', first_month_day)], context=context, count=True), + 'stat_my_monthly_sending': badge_user_obj.search(cr, uid, [('badge_id', '=', bid), ('create_uid', '=', uid), ('create_date', '>=', first_month_day)], context=context, count=True) + } + return result + + def _remaining_sending_calc(self, cr, uid, ids, name, args, context=None): + """Computes the number of badges remaining the user can send + + 0 if not allowed or no remaining + integer if limited sending + -1 if infinite (should not be displayed) + """ + result = dict.fromkeys(ids, False) + for badge in self.browse(cr, uid, ids, context=context): + if self._can_grant_badge(cr, uid, badge.id, context) != 1: + # if the user cannot grant this badge at all, result is 0 + result[badge.id] = 0 + elif not badge.rule_max: + # if there is no limitation, -1 is returned which means 'infinite' + result[badge.id] = -1 + else: + result[badge.id] = badge.rule_max_number - badge.stat_my_monthly_sending + return result + + _columns = { + 'name': fields.char('Badge', required=True, translate=True), + 'description': fields.text('Description'), + 'image': fields.binary("Image", help="This field holds the image used for the badge, limited to 256x256"), + 'rule_auth': fields.selection([ + ('everyone', 'Everyone'), + ('users', 'A selected list of users'), + ('having', 'People having some badges'), + ('nobody', 'No one, assigned through challenges'), + ], + string="Allowance to Grant", + help="Who can grant this badge", + required=True), + 'rule_auth_user_ids': fields.many2many('res.users', 'rel_badge_auth_users', + string='Authorized Users', + help="Only these people can give this badge"), + 'rule_auth_badge_ids': fields.many2many('gamification.badge', + 'rel_badge_badge', 'badge1_id', 'badge2_id', + string='Required Badges', + help="Only the people having these badges can give this badge"), + + 'rule_max': fields.boolean('Monthly Limited Sending', + help="Check to set a monthly limit per person of sending this badge"), + 'rule_max_number': fields.integer('Limitation Number', + help="The maximum number of time this badge can be sent per month per person."), + 'stat_my_monthly_sending': fields.function(_get_badge_user_stats, + type="integer", + string='My Monthly Sending Total', + multi='badge_users', + help="The number of time the current user has sent this badge this month."), + 'remaining_sending': fields.function(_remaining_sending_calc, type='integer', + string='Remaining Sending Allowed', help="If a maxium is set"), + + 'challenge_ids': fields.one2many('gamification.challenge', 'reward_id', + string="Reward of Challenges"), + + 'goal_definition_ids': fields.many2many('gamification.goal.definition', 'badge_unlocked_definition_rel', + string='Rewarded by', + help="The users that have succeeded theses goals will receive automatically the badge."), + + 'owner_ids': fields.one2many('gamification.badge.user', 'badge_id', + string='Owners', help='The list of instances of this badge granted to users'), + 'active': fields.boolean('Active'), + 'unique_owner_ids': fields.function(_get_owners_info, + string='Unique Owners', + help="The list of unique users having received this badge.", + multi='unique_users', + type="many2many", relation="res.users"), + + 'stat_count': fields.function(_get_owners_info, string='Total', + type="integer", + multi='unique_users', + help="The number of time this badge has been received."), + 'stat_count_distinct': fields.function(_get_owners_info, + type="integer", + string='Number of users', + multi='unique_users', + help="The number of time this badge has been received by unique users."), + 'stat_this_month': fields.function(_get_badge_user_stats, + type="integer", + string='Monthly total', + multi='badge_users', + help="The number of time this badge has been received this month."), + 'stat_my': fields.function(_get_badge_user_stats, string='My Total', + type="integer", + multi='badge_users', + help="The number of time the current user has received this badge."), + 'stat_my_this_month': fields.function(_get_badge_user_stats, + type="integer", + string='My Monthly Total', + multi='badge_users', + help="The number of time the current user has received this badge this month."), + } + + _defaults = { + 'rule_auth': 'everyone', + 'active': True, + } + + def check_granting(self, cr, uid, badge_id, context=None): + """Check the user 'uid' can grant the badge 'badge_id' and raise the appropriate exception + if not + + Do not check for SUPERUSER_ID + """ + status_code = self._can_grant_badge(cr, uid, badge_id, context=context) + if status_code == self.CAN_GRANT: + return True + elif status_code == self.NOBODY_CAN_GRANT: + raise osv.except_osv(_('Warning!'), _('This badge can not be sent by users.')) + elif status_code == self.USER_NOT_VIP: + raise osv.except_osv(_('Warning!'), _('You are not in the user allowed list.')) + elif status_code == self.BADGE_REQUIRED: + raise osv.except_osv(_('Warning!'), _('You do not have the required badges.')) + elif status_code == self.TOO_MANY: + raise osv.except_osv(_('Warning!'), _('You have already sent this badge too many time this month.')) + else: + _logger.exception("Unknown badge status code: %d" % int(status_code)) + return False + + def _can_grant_badge(self, cr, uid, badge_id, context=None): + """Check if a user can grant a badge to another user + + :param uid: the id of the res.users trying to send the badge + :param badge_id: the granted badge id + :return: integer representing the permission. + """ + if uid == SUPERUSER_ID: + return self.CAN_GRANT + + badge = self.browse(cr, uid, badge_id, context=context) + + if badge.rule_auth == 'nobody': + return self.NOBODY_CAN_GRANT + + elif badge.rule_auth == 'users' and uid not in [user.id for user in badge.rule_auth_user_ids]: + return self.USER_NOT_VIP + + elif badge.rule_auth == 'having': + all_user_badges = self.pool.get('gamification.badge.user').search(cr, uid, [('user_id', '=', uid)], context=context) + for required_badge in badge.rule_auth_badge_ids: + if required_badge.id not in all_user_badges: + return self.BADGE_REQUIRED + + if badge.rule_max and badge.stat_my_monthly_sending >= badge.rule_max_number: + return self.TOO_MANY + + # badge.rule_auth == 'everyone' -> no check + return self.CAN_GRANT + + def check_progress(self, cr, uid, context=None): + try: + model, res_id = template_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'gamification', 'badge_hidden') + except ValueError: + return True + badge_user_obj = self.pool.get('gamification.badge.user') + if not badge_user_obj.search(cr, uid, [('user_id', '=', uid), ('badge_id', '=', res_id)], context=context): + values = { + 'user_id': uid, + 'badge_id': res_id, + } + badge_user_obj.create(cr, SUPERUSER_ID, values, context=context) + return True \ No newline at end of file diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py new file mode 100644 index 00000000000..ae27aa96719 --- /dev/null +++ b/addons/gamification/models/challenge.py @@ -0,0 +1,821 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp import SUPERUSER_ID +from openerp.osv import fields, osv +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF +from openerp.tools.translate import _ + +from datetime import date, datetime, timedelta +import calendar +import logging +_logger = logging.getLogger(__name__) + +# display top 3 in ranking, could be db variable +MAX_VISIBILITY_RANKING = 3 + +def start_end_date_for_period(period, default_start_date=False, default_end_date=False): + """Return the start and end date for a goal period based on today + + :return: (start_date, end_date), datetime.date objects, False if the period is + not defined or unknown""" + today = date.today() + if period == 'daily': + start_date = today + end_date = start_date + elif period == 'weekly': + delta = timedelta(days=today.weekday()) + start_date = today - delta + end_date = start_date + timedelta(days=7) + elif period == 'monthly': + month_range = calendar.monthrange(today.year, today.month) + start_date = today.replace(day=1) + end_date = today.replace(day=month_range[1]) + elif period == 'yearly': + start_date = today.replace(month=1, day=1) + end_date = today.replace(month=12, day=31) + else: # period == 'once': + start_date = default_start_date # for manual goal, start each time + end_date = default_end_date + + if start_date and end_date: + return (start_date.strftime(DF), end_date.strftime(DF)) + else: + return (start_date, end_date) + + +class gamification_challenge(osv.Model): + """Gamification challenge + + Set of predifined objectives assigned to people with rules for recurrence and + rewards + + If 'user_ids' is defined and 'period' is different than 'one', the set will + be assigned to the users for each period (eg: every 1st of each month if + 'monthly' is selected) + """ + + _name = 'gamification.challenge' + _description = 'Gamification challenge' + _inherit = 'mail.thread' + + def _get_next_report_date(self, cr, uid, ids, field_name, arg, context=None): + """Return the next report date based on the last report date and report + period. + + :return: a string in DEFAULT_SERVER_DATE_FORMAT representing the date""" + res = {} + for challenge in self.browse(cr, uid, ids, context): + last = datetime.strptime(challenge.last_report_date, DF).date() + if challenge.report_message_frequency == 'daily': + next = last + timedelta(days=1) + res[challenge.id] = next.strftime(DF) + elif challenge.report_message_frequency == 'weekly': + next = last + timedelta(days=7) + res[challenge.id] = next.strftime(DF) + elif challenge.report_message_frequency == 'monthly': + month_range = calendar.monthrange(last.year, last.month) + next = last.replace(day=month_range[1]) + timedelta(days=1) + res[challenge.id] = next.strftime(DF) + elif challenge.report_message_frequency == 'yearly': + res[challenge.id] = last.replace(year=last.year + 1).strftime(DF) + # frequency == 'once', reported when closed only + else: + res[challenge.id] = False + + return res + + def _get_categories(self, cr, uid, context=None): + return [ + ('hr', 'Human Ressources / Engagement'), + ('other', 'Settings / Gamification Tools'), + ] + + def _get_report_template(self, cr, uid, context=None): + try: + return self.pool.get('ir.model.data').get_object_reference(cr, uid, 'gamification', 'simple_report_template')[1] + except ValueError: + return False + + _order = 'end_date, start_date, name, id' + _columns = { + 'name': fields.char('Challenge Name', required=True, translate=True), + 'description': fields.text('Description', translate=True), + 'state': fields.selection([ + ('draft', 'Draft'), + ('inprogress', 'In Progress'), + ('done', 'Done'), + ], + string='State', required=True, track_visibility='onchange'), + 'manager_id': fields.many2one('res.users', + string='Responsible', help="The user responsible for the challenge."), + + 'user_ids': fields.many2many('res.users', 'user_ids', + string='Users', + help="List of users participating to the challenge"), + 'autojoin_group_id': fields.many2one('res.groups', + string='Auto-subscription Group', + help='Group of users whose members will be automatically added to user_ids once the challenge is started'), + + 'period': fields.selection([ + ('once', 'Non recurring'), + ('daily', 'Daily'), + ('weekly', 'Weekly'), + ('monthly', 'Monthly'), + ('yearly', 'Yearly') + ], + string='Periodicity', + help='Period of automatic goal assigment. If none is selected, should be launched manually.', + required=True), + 'start_date': fields.date('Start Date', + help="The day a new challenge will be automatically started. If no periodicity is set, will use this date as the goal start date."), + 'end_date': fields.date('End Date', + help="The day a new challenge will be automatically closed. If no periodicity is set, will use this date as the goal end date."), + + 'invited_user_ids': fields.many2many('res.users', 'invited_user_ids', + string="Suggest to users"), + + 'line_ids': fields.one2many('gamification.challenge.line', 'challenge_id', + string='Lines', + help="List of goals that will be set", + required=True), + + 'reward_id': fields.many2one('gamification.badge', string="For Every Succeding User"), + 'reward_first_id': fields.many2one('gamification.badge', string="For 1st user"), + 'reward_second_id': fields.many2one('gamification.badge', string="For 2nd user"), + 'reward_third_id': fields.many2one('gamification.badge', string="For 3rd user"), + 'reward_failure': fields.boolean('Reward Bests if not Succeeded?'), + + 'visibility_mode': fields.selection([ + ('personal', 'Individual Goals'), + ('ranking', 'Leader Board (Group Ranking)'), + ], + string="Display Mode", required=True), + + 'report_message_frequency': fields.selection([ + ('never', 'Never'), + ('onchange', 'On change'), + ('daily', 'Daily'), + ('weekly', 'Weekly'), + ('monthly', 'Monthly'), + ('yearly', 'Yearly') + ], + string="Report Frequency", required=True), + 'report_message_group_id': fields.many2one('mail.group', + string='Send a copy to', + help='Group that will receive a copy of the report in addition to the user'), + 'report_template_id': fields.many2one('email.template', string="Report Template", required=True), + 'remind_update_delay': fields.integer('Non-updated manual goals will be reminded after', + help="Never reminded if no value or zero is specified."), + 'last_report_date': fields.date('Last Report Date'), + 'next_report_date': fields.function(_get_next_report_date, + type='date', string='Next Report Date', store=True), + + 'category': fields.selection(lambda s, *a, **k: s._get_categories(*a, **k), + string="Appears in", help="Define the visibility of the challenge through menus", required=True), + } + + _defaults = { + 'period': 'once', + 'state': 'draft', + 'visibility_mode': 'personal', + 'report_message_frequency': 'never', + 'last_report_date': fields.date.today, + 'start_date': fields.date.today, + 'manager_id': lambda s, cr, uid, c: uid, + 'category': 'hr', + 'reward_failure': False, + 'report_template_id': lambda s, *a, **k: s._get_report_template(*a, **k), + } + + + def create(self, cr, uid, vals, context=None): + """Overwrite the create method to add the user of groups""" + + # add users when change the group auto-subscription + if vals.get('autojoin_group_id'): + new_group = self.pool.get('res.groups').browse(cr, uid, vals['autojoin_group_id'], context=context) + + if not vals.get('user_ids'): + vals['user_ids'] = [] + vals['user_ids'] += [(4, user.id) for user in new_group.users] + + create_res = super(gamification_challenge, self).create(cr, uid, vals, context=context) + + # subscribe new users to the challenge + if vals.get('user_ids'): + # done with browse after super to be sure catch all after orm process + challenge = self.browse(cr, uid, create_res, context=context) + self.message_subscribe_users(cr, uid, [challenge.id], [user.id for user in challenge.user_ids], context=context) + + return create_res + + def write(self, cr, uid, ids, vals, context=None): + if isinstance(ids, (int,long)): + ids = [ids] + + # add users when change the group auto-subscription + if vals.get('autojoin_group_id'): + new_group = self.pool.get('res.groups').browse(cr, uid, vals['autojoin_group_id'], context=context) + + if not vals.get('user_ids'): + vals['user_ids'] = [] + vals['user_ids'] += [(4, user.id) for user in new_group.users] + + if vals.get('state') == 'inprogress': + # starting a challenge + if not vals.get('autojoin_group_id'): + # starting challenge, add users in autojoin group + if not vals.get('user_ids'): + vals['user_ids'] = [] + for challenge in self.browse(cr, uid, ids, context=context): + if challenge.autojoin_group_id: + vals['user_ids'] += [(4, user.id) for user in challenge.autojoin_group_id.users] + + self.generate_goals_from_challenge(cr, uid, ids, context=context) + + elif vals.get('state') == 'done': + self.check_challenge_reward(cr, uid, ids, force=True, context=context) + + elif vals.get('state') == 'draft': + # resetting progress + if self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', 'in', ids), ('state', 'in', ['inprogress', 'inprogress_update'])], context=context): + raise osv.except_osv("Error", "You can not reset a challenge with unfinished goals.") + + write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context) + + # subscribe new users to the challenge + if vals.get('user_ids'): + # done with browse after super if changes in groups + for challenge in self.browse(cr, uid, ids, context=context): + self.message_subscribe_users(cr, uid, [challenge.id], [user.id for user in challenge.user_ids], context=context) + + return write_res + + + ##### Update ##### + + def _cron_update(self, cr, uid, context=None, ids=False): + """Daily cron check. + + - Start planned challenges (in draft and with start_date = today) + - Create the missing goals (eg: modified the challenge to add lines) + - Update every running challenge + """ + # start planned challenges + planned_challenge_ids = self.search(cr, uid, [ + ('state', '=', 'draft'), + ('start_date', '<=', fields.date.today())]) + self.write(cr, uid, planned_challenge_ids, {'state': 'inprogress'}, context=context) + + # close planned challenges + planned_challenge_ids = self.search(cr, uid, [ + ('state', '=', 'inprogress'), + ('end_date', '>=', fields.date.today())]) + self.write(cr, uid, planned_challenge_ids, {'state': 'done'}, context=context) + + if not ids: + ids = self.search(cr, uid, [('state', '=', 'inprogress')], context=context) + + return self._update_all(cr, uid, ids, context=context) + + def _update_all(self, cr, uid, ids, context=None): + """Update the challenges and related goals + + :param list(int) ids: the ids of the challenges to update, if False will + update only challenges in progress.""" + if isinstance(ids, (int,long)): + ids = [ids] + + goal_obj = self.pool.get('gamification.goal') + + # we use yesterday to update the goals that just ended + yesterday = date.today() - timedelta(days=1) + goal_ids = goal_obj.search(cr, uid, [ + ('challenge_id', 'in', ids), + '|', + ('state', 'in', ('inprogress', 'inprogress_update')), + '&', + ('state', 'in', ('reached', 'failed')), + '|', + ('end_date', '>=', yesterday.strftime(DF)), + ('end_date', '=', False) + ], context=context) + # update every running goal already generated linked to selected challenges + goal_obj.update(cr, uid, goal_ids, context=context) + + for challenge in self.browse(cr, uid, ids, context=context): + if challenge.autojoin_group_id: + # check in case of new users in challenge, this happens if manager removed users in challenge manually + self.write(cr, uid, [challenge.id], {'user_ids': [(4, user.id) for user in challenge.autojoin_group_id.users]}, context=context) + self.generate_goals_from_challenge(cr, uid, [challenge.id], context=context) + + # goals closed but still opened at the last report date + closed_goals_to_report = goal_obj.search(cr, uid, [ + ('challenge_id', '=', challenge.id), + ('start_date', '>=', challenge.last_report_date), + ('end_date', '<=', challenge.last_report_date) + ]) + + if len(closed_goals_to_report) > 0: + # some goals need a final report + self.report_progress(cr, uid, challenge, subset_goal_ids=closed_goals_to_report, context=context) + + if fields.date.today() == challenge.next_report_date: + self.report_progress(cr, uid, challenge, context=context) + + self.check_challenge_reward(cr, uid, ids, context=context) + return True + + def quick_update(self, cr, uid, challenge_id, context=None): + """Update all the goals of a challenge, no generation of new goals""" + goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', '=', challenge_id)], context=context) + self.pool.get('gamification.goal').update(cr, uid, goal_ids, context=context) + return True + + + def action_check(self, cr, uid, ids, context=None): + """Check a challenge + + Create goals that haven't been created yet (eg: if added users) + Recompute the current value for each goal related""" + return self._update_all(cr, uid, ids=ids, context=context) + + def action_report_progress(self, cr, uid, ids, context=None): + """Manual report of a goal, does not influence automatic report frequency""" + if isinstance(ids, (int,long)): + ids = [ids] + for challenge in self.browse(cr, uid, ids, context): + self.report_progress(cr, uid, challenge, context=context) + return True + + + ##### Automatic actions ##### + + def generate_goals_from_challenge(self, cr, uid, ids, context=None): + """Generate the goals for each line and user. + + If goals already exist for this line and user, the line is skipped. This + can be called after each change in the list of users or lines. + :param list(int) ids: the list of challenge concerned""" + + for challenge in self.browse(cr, uid, ids, context): + (start_date, end_date) = start_end_date_for_period(challenge.period) + + # if no periodicity, use challenge dates + if not start_date and challenge.start_date: + start_date = challenge.start_date + if not end_date and challenge.end_date: + end_date = challenge.end_date + + for line in challenge.line_ids: + for user in challenge.user_ids: + + goal_obj = self.pool.get('gamification.goal') + domain = [('line_id', '=', line.id), ('user_id', '=', user.id)] + if start_date: + domain.append(('start_date', '=', start_date)) + + # goal already existing for this line ? + if len(goal_obj.search(cr, uid, domain, context=context)) > 0: + + # resume canceled goals + domain.append(('state', '=', 'canceled')) + canceled_goal_ids = goal_obj.search(cr, uid, domain, context=context) + goal_obj.write(cr, uid, canceled_goal_ids, {'state': 'inprogress'}, context=context) + goal_obj.update(cr, uid, canceled_goal_ids, context=context) + + # skip to next user + continue + + values = { + 'definition_id': line.definition_id.id, + 'line_id': line.id, + 'user_id': user.id, + 'target_goal': line.target_goal, + 'state': 'inprogress', + } + + if start_date: + values['start_date'] = start_date + if end_date: + values['end_date'] = end_date + + if challenge.remind_update_delay: + values['remind_update_delay'] = challenge.remind_update_delay + + new_goal_id = goal_obj.create(cr, uid, values, context) + + goal_obj.update(cr, uid, [new_goal_id], context=context) + + return True + + ##### JS utilities ##### + + def _get_serialized_challenge_lines(self, cr, uid, challenge, user_id=False, restrict_goal_ids=False, restrict_top=False, context=None): + """Return a serialised version of the goals information + + :challenge: browse record of challenge to compute + :user_id: res.users id of the user retrieving progress (False if no distinction, only for ranking challenges) + :restrict_goal_ids: compute only the results for this subset if gamification.goal ids, if False retrieve every goal of current running challenge + :restrict_top: for challenge lines where visibility_mode == 'ranking', retrieve only these bests results and itself, if False retrieve all + restrict_goal_ids has priority over restrict_top + + format list + # if visibility_mode == 'ranking' + { + 'name': , + 'description': , + 'condition': , + 'computation_mode': , + 'monetary': <{True,False}>, + 'suffix': , + 'action': <{True,False}>, + 'display_mode': <{progress,boolean}>, + 'target': , + 'own_goal_id': , + 'goals': [ + { + 'id': , + 'rank': , + 'user_id': , + 'name': , + 'state': , + 'completeness': , + 'current': , + } + ] + }, + # if visibility_mode == 'personal' + { + 'id': , + 'name': , + 'description': , + 'condition': , + 'computation_mode': , + 'monetary': <{True,False}>, + 'suffix': , + 'action': <{True,False}>, + 'display_mode': <{progress,boolean}>, + 'target': , + 'state': , + 'completeness': , + 'current': , + } + """ + goal_obj = self.pool.get('gamification.goal') + (start_date, end_date) = start_end_date_for_period(challenge.period) + + res_lines = [] + for line in challenge.line_ids: + line_data = { + 'name': line.definition_id.name, + 'description': line.definition_id.description, + 'condition': line.definition_id.condition, + 'computation_mode': line.definition_id.computation_mode, + 'monetary': line.definition_id.monetary, + 'suffix': line.definition_id.suffix, + 'action': True if line.definition_id.action_id else False, + 'display_mode': line.definition_id.display_mode, + 'target': line.target_goal, + } + domain = [ + ('line_id', '=', line.id), + ('state', '!=', 'draft'), + ] + if restrict_goal_ids: + domain.append(('ids', 'in', restrict_goal_ids)) + else: + # if no subset goals, use the dates for restriction + if start_date: + domain.append(('start_date', '=', start_date)) + if end_date: + domain.append(('end_date', '=', end_date)) + + if challenge.visibility_mode == 'personal': + if not user_id: + raise osv.except_osv(_('Error!'),_("Retrieving progress for personal challenge without user information")) + domain.append(('user_id', '=', user_id)) + sorting = goal_obj._order + limit = 1 + # initialise in case search returns no results + line_data.update({ + 'id': 0, + 'current': 0, + 'completeness': 0, + 'state': 'draft', + }) + else: + line_data.update({ + 'own_goal_id': False, + 'goals': [], + }) + sorting = "completeness desc, current desc" + limit = False + + goal_ids = goal_obj.search(cr, uid, domain, order=sorting, limit=limit, context=context) + ranking = 0 + for goal in goal_obj.browse(cr, uid, goal_ids, context=context): + if challenge.visibility_mode == 'personal': + # limit=1 so only one result + line_data.update({ + 'id': goal.id, + 'current': goal.current, + 'completeness': goal.completeness, + 'state': goal.state, + }) + else: + ranking += 1 + if user_id and goal.user_id.id == user_id: + line_data['own_goal_id'] = goal.id + elif restrict_top and ranking > restrict_top: + # not own goal, over top, skipping + continue + + line_data['goals'].append({ + 'id': goal.id, + 'user_id': goal.user_id.id, + 'name': goal.user_id.name, + 'rank': ranking, + 'current': goal.current, + 'completeness': goal.completeness, + 'state': goal.state, + }) + res_lines.append(line_data) + return res_lines + + ##### Reporting ##### + + def report_progress(self, cr, uid, challenge, context=None, users=False, subset_goal_ids=False): + """Post report about the progress of the goals + + :param challenge: the challenge object that need to be reported + :param users: the list(res.users) of users that are concerned by + the report. If False, will send the report to every user concerned + (goal users and group that receive a copy). Only used for challenge with + a visibility mode set to 'personal'. + :param goal_ids: the list(int) of goal ids linked to the challenge for + the report. If not specified, use the goals for the current challenge + period. This parameter can be used to produce report for previous challenge + periods. + :param subset_goal_ids: a list(int) of goal ids to restrict the report + """ + if context is None: + context = {} + + temp_obj = self.pool.get('email.template') + ctx = context.copy() + if challenge.visibility_mode == 'ranking': + lines_boards = self._get_serialized_challenge_lines(cr, uid, challenge, user_id=False, restrict_goal_ids=subset_goal_ids, restrict_top=False, context=context) + + ctx.update({'challenge_lines': lines_boards}) + body_html = temp_obj.render_template(cr, uid, challenge.report_template_id.body_html, 'gamification.challenge', challenge.id, context=ctx) + + # send to every follower of the challenge + self.message_post(cr, uid, challenge.id, + body=body_html, + context=context, + subtype='mail.mt_comment') + if challenge.report_message_group_id: + self.pool.get('mail.group').message_post(cr, uid, challenge.report_message_group_id.id, + body=body_html, + context=context, + subtype='mail.mt_comment') + + else: + # generate individual reports + for user in users or challenge.user_ids: + goals = self._get_serialized_challenge_lines(cr, uid, challenge, user.id, restrict_goal_ids=subset_goal_ids, context=context) + if not goals: + continue + + ctx.update({'challenge_lines': goals}) + body_html = temp_obj.render_template(cr, user.id, challenge.report_template_id.body_html, 'gamification.challenge', challenge.id, context=ctx) + + # send message only to users, not on the challenge + self.message_post(cr, uid, 0, + body=body_html, + partner_ids=[(4, user.partner_id.id)], + context=context, + subtype='mail.mt_comment') + if challenge.report_message_group_id: + self.pool.get('mail.group').message_post(cr, uid, challenge.report_message_group_id.id, + body=body_html, + context=context, + subtype='mail.mt_comment') + return self.write(cr, uid, challenge.id, {'last_report_date': fields.date.today()}, context=context) + + ##### Challenges ##### + def accept_challenge(self, cr, uid, challenge_ids, context=None, user_id=None): + """The user accept the suggested challenge""" + user_id = user_id or uid + user = self.pool.get('res.users').browse(cr, uid, user_id, context=context) + message = "%s has joined the challenge" % user.name + self.message_post(cr, uid, challenge_ids, body=message, context=context) + self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context) + return self.generate_goals_from_challenge(cr, uid, challenge_ids, context=context) + + def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None): + """The user discard the suggested challenge""" + user_id = user_id or uid + user = self.pool.get('res.users').browse(cr, uid, user_id, context=context) + message = "%s has refused the challenge" % user.name + self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context) + return self.write(cr, uid, challenge_ids, {'invited_user_ids': (3, user_id)}, context=context) + + def reply_challenge_wizard(self, cr, uid, challenge_id, context=None): + result = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'gamification', 'challenge_wizard') + id = result and result[1] or False + result = self.pool.get('ir.actions.act_window').read(cr, uid, [id], context=context)[0] + result['res_id'] = challenge_id + return result + + def check_challenge_reward(self, cr, uid, ids, force=False, context=None): + """Actions for the end of a challenge + + If a reward was selected, grant it to the correct users. + Rewards granted at: + - the end date for a challenge with no periodicity + - the end of a period for challenge with periodicity + - when a challenge is manually closed + (if no end date, a running challenge is never rewarded) + """ + if isinstance(ids, (int,long)): + ids = [ids] + context = context or {} + for challenge in self.browse(cr, uid, ids, context=context): + (start_date, end_date) = start_end_date_for_period(challenge.period, challenge.start_date, challenge.end_date) + yesterday = date.today() - timedelta(days=1) + if end_date == yesterday.strftime(DF) or force: + # open chatter message + message_body = _("The challenge %s is finished." % challenge.name) + + # reward for everybody succeeding + rewarded_users = [] + if challenge.reward_id: + for user in challenge.user_ids: + reached_goal_ids = self.pool.get('gamification.goal').search(cr, uid, [ + ('challenge_id', '=', challenge.id), + ('user_id', '=', user.id), + ('start_date', '=', start_date), + ('end_date', '=', end_date), + ('state', '=', 'reached') + ], context=context) + if len(reached_goal_ids) == len(challenge.line_ids): + self.reward_user(cr, uid, user.id, challenge.reward_id.id, context) + rewarded_users.append(user) + + if rewarded_users: + message_body += _("
Reward (badge %s) for every succeeding user was sent to %s." % (challenge.reward_id.name, ", ".join([user.name for user in rewarded_users]))) + else: + message_body += _("
Nobody has succeeded to reach every goal, no badge is rewared for this challenge.") + + # reward bests + if challenge.reward_first_id: + (first_user, second_user, third_user) = self.get_top3_users(cr, uid, challenge, context) + if first_user: + self.reward_user(cr, uid, first_user.id, challenge.reward_first_id.id, context) + message_body += _("
Special rewards were sent to the top competing users. The ranking for this challenge is :") + message_body += "
1. %s - %s" % (first_user.name, challenge.reward_first_id.name) + else: + message_body += _("Nobody reached the required conditions to receive special badges.") + + if second_user and challenge.reward_second_id: + self.reward_user(cr, uid, second_user.id, challenge.reward_second_id.id, context) + message_body += "
2. %s - %s" % (second_user.name, challenge.reward_second_id.name) + if third_user and challenge.reward_third_id: + self.reward_user(cr, uid, third_user.id, challenge.reward_second_id.id, context) + message_body += "
3. %s - %s" % (third_user.name, challenge.reward_third_id.name) + + self.message_post(cr, uid, challenge.id, body=message_body, context=context) + return True + + def get_top3_users(self, cr, uid, challenge, context=None): + """Get the top 3 users for a defined challenge + + Ranking criterias: + 1. succeed every goal of the challenge + 2. total completeness of each goal (can be over 100) + Top 3 is computed only for users succeeding every goal of the challenge, + except if reward_failure is True, in which case every user is + considered. + :return: ('first', 'second', 'third'), tuple containing the res.users + objects of the top 3 users. If no user meets the criterias for a rank, + it is set to False. Nobody can receive a rank is noone receives the + higher one (eg: if 'second' == False, 'third' will be False) + """ + goal_obj = self.pool.get('gamification.goal') + (start_date, end_date) = start_end_date_for_period(challenge.period, challenge.start_date, challenge.end_date) + challengers = [] + for user in challenge.user_ids: + all_reached = True + total_completness = 0 + # every goal of the user for the running period + goal_ids = goal_obj.search(cr, uid, [ + ('challenge_id', '=', challenge.id), + ('user_id', '=', user.id), + ('start_date', '=', start_date), + ('end_date', '=', end_date) + ], context=context) + for goal in goal_obj.browse(cr, uid, goal_ids, context=context): + if goal.state != 'reached': + all_reached = False + if goal.definition_condition == 'higher': + # can be over 100 + total_completness += 100.0 * goal.current / goal.target_goal + elif goal.state == 'reached': + # for lower goals, can not get percentage so 0 or 100 + total_completness += 100 + + challengers.append({'user': user, 'all_reached': all_reached, 'total_completness': total_completness}) + sorted_challengers = sorted(challengers, key=lambda k: (k['all_reached'], k['total_completness']), reverse=True) + + if len(sorted_challengers) == 0 or (not challenge.reward_failure and not sorted_challengers[0]['all_reached']): + # nobody succeeded + return (False, False, False) + if len(sorted_challengers) == 1 or (not challenge.reward_failure and not sorted_challengers[1]['all_reached']): + # only one user succeeded + return (sorted_challengers[0]['user'], False, False) + if len(sorted_challengers) == 2 or (not challenge.reward_failure and not sorted_challengers[2]['all_reached']): + # only one user succeeded + return (sorted_challengers[0]['user'], sorted_challengers[1]['user'], False) + return (sorted_challengers[0]['user'], sorted_challengers[1]['user'], sorted_challengers[2]['user']) + + def reward_user(self, cr, uid, user_id, badge_id, context=None): + """Create a badge user and send the badge to him + + :param user_id: the user to reward + :param badge_id: the concerned badge + """ + badge_user_obj = self.pool.get('gamification.badge.user') + user_badge_id = badge_user_obj.create(cr, uid, {'user_id': user_id, 'badge_id': badge_id}, context=context) + return badge_user_obj._send_badge(cr, uid, [user_badge_id], context=context) + + +class gamification_challenge_line(osv.Model): + """Gamification challenge line + + Predifined goal for 'gamification_challenge' + These are generic list of goals with only the target goal defined + Should only be created for the gamification_challenge object + """ + + _name = 'gamification.challenge.line' + _description = 'Gamification generic goal for challenge' + _order = "sequence, id" + + def on_change_definition_id(self, cr, uid, ids, definition_id=False, context=None): + goal_definition = self.pool.get('gamification.goal.definition') + if not definition_id: + return {'value': {'definition_id': False}} + goal_definition = goal_definition.browse(cr, uid, definition_id, context=context) + ret = { + 'value': { + 'condition': goal_definition.condition, + 'definition_full_suffix': goal_definition.full_suffix + } + } + return ret + + _columns = { + 'name': fields.related('definition_id', 'name', string="Name"), + 'challenge_id': fields.many2one('gamification.challenge', + string='Challenge', + required=True, + ondelete="cascade"), + 'definition_id': fields.many2one('gamification.goal.definition', + string='Goal Definition', + required=True, + ondelete="cascade"), + 'target_goal': fields.float('Target Value to Reach', + required=True), + 'sequence': fields.integer('Sequence', + help='Sequence number for ordering'), + 'condition': fields.related('definition_id', 'condition', type="selection", + readonly=True, string="Condition", selection=[('lower', '<='), ('higher', '>=')]), + 'definition_suffix': fields.related('definition_id', 'suffix', type="char", readonly=True, string="Unit"), + 'definition_monetary': fields.related('definition_id', 'monetary', type="boolean", readonly=True, string="Monetary"), + 'definition_full_suffix': fields.related('definition_id', 'full_suffix', type="char", readonly=True, string="Suffix"), + } + + _default = { + 'sequence': 1, + } diff --git a/addons/gamification/models/goal.py b/addons/gamification/models/goal.py new file mode 100644 index 00000000000..8792e219d71 --- /dev/null +++ b/addons/gamification/models/goal.py @@ -0,0 +1,394 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp import SUPERUSER_ID +from openerp.osv import fields, osv +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF +from openerp.tools.safe_eval import safe_eval +from openerp.tools.translate import _ + +import logging +import time +from datetime import date, datetime, timedelta + +_logger = logging.getLogger(__name__) + + +class gamification_goal_definition(osv.Model): + """Goal definition + + A goal definition contains the way to evaluate an objective + Each module wanting to be able to set goals to the users needs to create + a new gamification_goal_definition + """ + _name = 'gamification.goal.definition' + _description = 'Gamification goal definition' + + def _get_suffix(self, cr, uid, ids, field_name, arg, context=None): + res = dict.fromkeys(ids, '') + for goal in self.browse(cr, uid, ids, context=context): + if goal.suffix and not goal.monetary: + res[goal.id] = goal.suffix + elif goal.monetary: + # use the current user's company currency + user = self.pool.get('res.users').browse(cr, uid, uid, context) + if goal.suffix: + res[goal.id] = "%s %s" % (user.company_id.currency_id.symbol, goal.suffix) + else: + res[goal.id] = user.company_id.currency_id.symbol + else: + res[goal.id] = "" + return res + + _columns = { + 'name': fields.char('Goal Definition', required=True, translate=True), + 'description': fields.text('Goal Description'), + 'monetary': fields.boolean('Monetary Value', help="The target and current value are defined in the company currency."), + 'suffix': fields.char('Suffix', help="The unit of the target and current values", translate=True), + 'full_suffix': fields.function(_get_suffix, type="char", string="Full Suffix", help="The currency and suffix field"), + 'computation_mode': fields.selection([ + ('manually', 'Recorded manually'), + ('count', 'Automatic: number of records'), + ('sum', 'Automatic: sum on a field'), + ('python', 'Automatic: execute a specific Python code'), + ], + string="Computation Mode", + help="Defined how will be computed the goals. The result of the operation will be stored in the field 'Current'.", + required=True), + 'display_mode': fields.selection([ + ('progress', 'Progressive (using numerical values)'), + ('boolean', 'Exclusive (done or not-done)'), + ], + string="Displayed as", required=True), + 'model_id': fields.many2one('ir.model', + string='Model', + help='The model object for the field to evaluate'), + 'field_id': fields.many2one('ir.model.fields', + string='Field to Sum', + help='The field containing the value to evaluate'), + 'field_date_id': fields.many2one('ir.model.fields', + string='Date Field', + help='The date to use for the time period evaluated'), + 'domain': fields.char("Filter Domain", + help="Domain for filtering records. The rule can contain reference to 'user' that is a browse record of the current user, e.g. [('user_id', '=', user.id)].", + required=True), + 'compute_code': fields.text('Python Code', + help="Python code to be executed for each user. 'result' should contains the new current value. Evaluated user can be access through object.user_id."), + 'condition': fields.selection([ + ('higher', 'The higher the better'), + ('lower', 'The lower the better') + ], + string='Goal Performance', + help='A goal is considered as completed when the current value is compared to the value to reach', + required=True), + 'action_id': fields.many2one('ir.actions.act_window', string="Action", + help="The action that will be called to update the goal value."), + 'res_id_field': fields.char("ID Field of user", + help="The field name on the user profile (res.users) containing the value for res_id for action.") + } + + _defaults = { + 'condition': 'higher', + 'computation_mode': 'manually', + 'domain': "[]", + 'monetary': False, + 'display_mode': 'progress', + } + + def number_following(self, cr, uid, model_name="mail.thread", context=None): + """Return the number of 'model_name' objects the user is following + + The model specified in 'model_name' must inherit from mail.thread + """ + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + return self.pool.get('mail.followers').search(cr, uid, [('res_model', '=', model_name), ('partner_id', '=', user.partner_id.id)], count=True, context=context) + + + +class gamification_goal(osv.Model): + """Goal instance for a user + + An individual goal for a user on a specified time period""" + + _name = 'gamification.goal' + _description = 'Gamification goal instance' + _inherit = 'mail.thread' + + def _get_completion(self, cr, uid, ids, field_name, arg, context=None): + """Return the percentage of completeness of the goal, between 0 and 100""" + res = dict.fromkeys(ids, 0.0) + for goal in self.browse(cr, uid, ids, context=context): + if goal.definition_condition == 'higher': + if goal.current >= goal.target_goal: + res[goal.id] = 100.0 + else: + res[goal.id] = round(100.0 * goal.current / goal.target_goal, 2) + elif goal.current < goal.target_goal: + # a goal 'lower than' has only two values possible: 0 or 100% + res[goal.id] = 100.0 + else: + res[goal.id] = 0.0 + return res + + def on_change_definition_id(self, cr, uid, ids, definition_id=False, context=None): + goal_definition = self.pool.get('gamification.goal.definition') + if not definition_id: + return {'value': {'definition_id': False}} + goal_definition = goal_definition.browse(cr, uid, definition_id, context=context) + return {'value': {'computation_mode': goal_definition.computation_mode, 'definition_condition': goal_definition.condition}} + + _columns = { + 'definition_id': fields.many2one('gamification.goal.definition', string='Goal Definition', required=True, ondelete="cascade"), + 'user_id': fields.many2one('res.users', string='User', required=True), + 'line_id': fields.many2one('gamification.challenge.line', string='Goal Line', ondelete="cascade"), + 'challenge_id': fields.related('line_id', 'challenge_id', + string="Challenge", + type='many2one', + relation='gamification.challenge', + store=True), + 'start_date': fields.date('Start Date'), + 'end_date': fields.date('End Date'), # no start and end = always active + 'target_goal': fields.float('To Reach', + required=True, + track_visibility='always'), # no goal = global index + 'current': fields.float('Current Value', required=True, track_visibility='always'), + 'completeness': fields.function(_get_completion, type='float', string='Completeness'), + 'state': fields.selection([ + ('draft', 'Draft'), + ('inprogress', 'In progress'), + ('inprogress_update', 'In progress (to update)'), + ('reached', 'Reached'), + ('failed', 'Failed'), + ('canceled', 'Canceled'), + ], + string='State', + required=True, + track_visibility='always'), + + 'computation_mode': fields.related('definition_id', 'computation_mode', type='char', string="Computation mode"), + 'remind_update_delay': fields.integer('Remind delay', + help="The number of days after which the user assigned to a manual goal will be reminded. Never reminded if no value is specified."), + 'last_update': fields.date('Last Update', + help="In case of manual goal, reminders are sent if the goal as not been updated for a while (defined in challenge). Ignored in case of non-manual goal or goal not linked to a challenge."), + + 'definition_description': fields.related('definition_id', 'description', type='char', string='Definition Description', readonly=True), + 'definition_condition': fields.related('definition_id', 'condition', type='char', string='Definition Condition', readonly=True), + 'definition_suffix': fields.related('definition_id', 'full_suffix', type="char", string="Suffix", readonly=True), + 'definition_display': fields.related('definition_id', 'display_mode', type="char", string="Display Mode", readonly=True), + } + + _defaults = { + 'current': 0, + 'state': 'draft', + 'start_date': fields.date.today, + } + _order = 'create_date desc, end_date desc, definition_id, id' + + def _check_remind_delay(self, cr, uid, goal, context=None): + """Verify if a goal has not been updated for some time and send a + reminder message of needed. + + :return: data to write on the goal object + """ + if goal.remind_update_delay and goal.last_update: + delta_max = timedelta(days=goal.remind_update_delay) + last_update = datetime.strptime(goal.last_update, DF).date() + if date.today() - last_update > delta_max and goal.state == 'inprogress': + # generate a remind report + temp_obj = self.pool.get('email.template') + template_id = self.pool['ir.model.data'].get_object(cr, uid, 'gamification', 'email_template_goal_reminder', context) + body_html = temp_obj.render_template(cr, uid, template_id.body_html, 'gamification.goal', goal.id, context=context) + + self.message_post(cr, uid, goal.id, body=body_html, partner_ids=[goal.user_id.partner_id.id], context=context, subtype='mail.mt_comment') + return {'state': 'inprogress_update'} + return {} + + def update(self, cr, uid, ids, context=None): + """Update the goals to recomputes values and change of states + + If a manual goal is not updated for enough time, the user will be + reminded to do so (done only once, in 'inprogress' state). + If a goal reaches the target value, the status is set to reached + If the end date is passed (at least +1 day, time not considered) without + the target value being reached, the goal is set as failed.""" + if context is None: + context = {} + + for goal in self.browse(cr, uid, ids, context=context): + towrite = {} + if goal.state in ('draft', 'canceled'): + # skip if goal draft or canceled + continue + + if goal.definition_id.computation_mode == 'manually': + towrite.update(self._check_remind_delay(cr, uid, goal, context)) + + elif goal.definition_id.computation_mode == 'python': + # execute the chosen method + cxt = { + 'self': self.pool.get('gamification.goal'), + 'object': goal, + 'pool': self.pool, + 'cr': cr, + 'context': dict(context), # copy context to prevent side-effects of eval + 'uid': uid, + 'result': False, + 'date': date, 'datetime': datetime, 'timedelta': timedelta, 'time': time + } + code = goal.definition_id.compute_code.strip() + safe_eval(code, cxt, mode="exec", nocopy=True) + # the result of the evaluated codeis put in the 'result' local variable, propagated to the context + result = cxt.get('result', False) + if result and type(result) in (float, int, long): + if result != goal.current: + towrite['current'] = result + else: + _logger.exception(_('Invalid return content from the evaluation of %s' % code)) + + else: # count or sum + obj = self.pool.get(goal.definition_id.model_id.model) + field_date_name = goal.definition_id.field_date_id.name + + # eval the domain with user replaced by goal user object + domain = safe_eval(goal.definition_id.domain, {'user': goal.user_id}) + + # add temporal clause(s) to the domain if fields are filled on the goal + if goal.start_date and field_date_name: + domain.append((field_date_name, '>=', goal.start_date)) + if goal.end_date and field_date_name: + domain.append((field_date_name, '<=', goal.end_date)) + + if goal.definition_id.computation_mode == 'sum': + field_name = goal.definition_id.field_id.name + res = obj.read_group(cr, uid, domain, [field_name], [''], context=context) + new_value = res and res[0][field_name] or 0.0 + + else: # computation mode = count + new_value = obj.search(cr, uid, domain, context=context, count=True) + + # avoid useless write if the new value is the same as the old one + if new_value != goal.current: + towrite['current'] = new_value + + # check goal target reached + if (goal.definition_condition == 'higher' and towrite.get('current', goal.current) >= goal.target_goal) or (goal.definition_condition == 'lower' and towrite.get('current', goal.current) <= goal.target_goal): + towrite['state'] = 'reached' + + # check goal failure + elif goal.end_date and fields.date.today() > goal.end_date: + towrite['state'] = 'failed' + if towrite: + self.write(cr, uid, [goal.id], towrite, context=context) + return True + + def action_start(self, cr, uid, ids, context=None): + """Mark a goal as started. + + This should only be used when creating goals manually (in draft state)""" + self.write(cr, uid, ids, {'state': 'inprogress'}, context=context) + return self.update(cr, uid, ids, context=context) + + def action_reach(self, cr, uid, ids, context=None): + """Mark a goal as reached. + + If the target goal condition is not met, the state will be reset to In + Progress at the next goal update until the end date.""" + return self.write(cr, uid, ids, {'state': 'reached'}, context=context) + + def action_fail(self, cr, uid, ids, context=None): + """Set the state of the goal to failed. + + A failed goal will be ignored in future checks.""" + return self.write(cr, uid, ids, {'state': 'failed'}, context=context) + + def action_cancel(self, cr, uid, ids, context=None): + """Reset the completion after setting a goal as reached or failed. + + This is only the current state, if the date and/or target criterias + match the conditions for a change of state, this will be applied at the + next goal update.""" + return self.write(cr, uid, ids, {'state': 'inprogress'}, context=context) + + def create(self, cr, uid, vals, context=None): + """Overwrite the create method to add a 'no_remind_goal' field to True""" + if context is None: + context = {} + context['no_remind_goal'] = True + return super(gamification_goal, self).create(cr, uid, vals, context=context) + + def write(self, cr, uid, ids, vals, context=None): + """Overwrite the write method to update the last_update field to today + + If the current value is changed and the report frequency is set to On + change, a report is generated + """ + if context is None: + context = {} + vals['last_update'] = fields.date.today() + result = super(gamification_goal, self).write(cr, uid, ids, vals, context=context) + for goal in self.browse(cr, uid, ids, context=context): + if goal.state != "draft" and ('definition_id' in vals or 'user_id' in vals): + # avoid drag&drop in kanban view + raise osv.except_osv(_('Error!'), _('Can not modify the configuration of a started goal')) + + if vals.get('current'): + if 'no_remind_goal' in context: + # new goals should not be reported + continue + + if goal.challenge_id and goal.challenge_id.report_message_frequency == 'onchange': + self.pool.get('gamification.challenge').report_progress(cr, SUPERUSER_ID, goal.challenge_id, users=[goal.user_id], context=context) + return result + + def get_action(self, cr, uid, goal_id, context=None): + """Get the ir.action related to update the goal + + In case of a manual goal, should return a wizard to update the value + :return: action description in a dictionnary + """ + goal = self.browse(cr, uid, goal_id, context=context) + + if goal.definition_id.action_id: + # open a the action linked to the goal + action = goal.definition_id.action_id.read()[0] + + if goal.definition_id.res_id_field: + current_user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + action['res_id'] = safe_eval(goal.definition_id.res_id_field, {'user': current_user}) + + # if one element to display, should see it in form mode if possible + action['views'] = [(view_id, mode) for (view_id, mode) in action['views'] if mode == 'form'] or action['views'] + return action + + if goal.computation_mode == 'manually': + # open a wizard window to update the value manually + action = { + 'name': _("Update %s") % goal.definition_id.name, + 'id': goal_id, + 'type': 'ir.actions.act_window', + 'views': [[False, 'form']], + 'target': 'new', + 'context': {'default_goal_id': goal_id, 'default_current': goal.current}, + 'res_model': 'gamification.goal.wizard' + } + return action + + return False diff --git a/addons/gamification/models/res_users.py b/addons/gamification/models/res_users.py new file mode 100644 index 00000000000..408ddddf082 --- /dev/null +++ b/addons/gamification/models/res_users.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp.osv import osv +from challenge import MAX_VISIBILITY_RANKING + +class res_users_gamification_group(osv.Model): + """ Update of res.users class + - if adding groups to an user, check gamification.challenge linked to + this group, and the user. This is done by overriding the write method. + """ + _name = 'res.users' + _inherit = ['res.users'] + + def write(self, cr, uid, ids, vals, context=None): + """Overwrite to autosubscribe users if added to a group marked as autojoin, user will be added to challenge""" + write_res = super(res_users_gamification_group, self).write(cr, uid, ids, vals, context=context) + if vals.get('groups_id'): + # form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]} + user_group_ids = [command[1] for command in vals['groups_id'] if command[0] == 4] + user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]] + + challenge_obj = self.pool.get('gamification.challenge') + challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context) + if challenge_ids: + challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in ids]}, context=context) + return write_res + + def create(self, cr, uid, vals, context=None): + """Overwrite to autosubscribe users if added to a group marked as autojoin, user will be added to challenge""" + write_res = super(res_users_gamification_group, self).create(cr, uid, vals, context=context) + if vals.get('groups_id'): + # form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]} + user_group_ids = [command[1] for command in vals['groups_id'] if command[0] == 4] + user_group_ids += [id for command in vals['groups_id'] if command[0] == 6 for id in command[2]] + + challenge_obj = self.pool.get('gamification.challenge') + challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', user_group_ids)], context=context) + if challenge_ids: + challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, write_res)]}, context=context) + return write_res + + # def get_goals_todo_info(self, cr, uid, context=None): + + def get_serialised_gamification_summary(self, cr, uid, context=None): + return self._serialised_goals_summary(cr, uid, user_id=uid, context=context) + + def _serialised_goals_summary(self, cr, uid, user_id, context=None): + """Return a serialised list of goals assigned to the user, grouped by challenge + + [ + { + 'id': , + 'name': , + 'visibility_mode': , + 'currency': , + 'lines': [(see gamification_challenge._get_serialized_challenge_lines() format)] + }, + ] + """ + all_goals_info = [] + challenge_obj = self.pool.get('gamification.challenge') + + user = self.browse(cr, uid, uid, context=context) + challenge_ids = challenge_obj.search(cr, uid, [('user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context) + for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context): + # serialize goals info to be able to use it in javascript + all_goals_info.append({ + 'id': challenge.id, + 'name': challenge.name, + 'visibility_mode': challenge.visibility_mode, + 'currency': user.company_id.currency_id.id, + 'lines': challenge_obj._get_serialized_challenge_lines(cr, uid, challenge, user_id, restrict_top=MAX_VISIBILITY_RANKING, context=context), + }) + + return all_goals_info + + def get_challenge_suggestions(self, cr, uid, context=None): + """Return the list of challenges suggested to the user""" + challenge_info = [] + challenge_obj = self.pool.get('gamification.challenge') + challenge_ids = challenge_obj.search(cr, uid, [('invited_user_ids', 'in', uid), ('state', '=', 'inprogress')], context=context) + for challenge in challenge_obj.browse(cr, uid, challenge_ids, context=context): + values = { + 'id': challenge.id, + 'name': challenge.name, + 'description': challenge.description, + } + challenge_info.append(values) + return challenge_info + + +class res_groups_gamification_group(osv.Model): + """ Update of res.groups class + - if adding users from a group, check gamification.challenge linked to + this group, and the user. This is done by overriding the write method. + """ + _name = 'res.groups' + _inherit = 'res.groups' + + # No need to overwrite create as very unlikely to be the value in the autojoin_group_id field + def write(self, cr, uid, ids, vals, context=None): + """Overwrite to autosubscribe users if add users to a group marked as autojoin, these will be added to the challenge""" + write_res = super(res_groups_gamification_group, self).write(cr, uid, ids, vals, context=context) + if vals.get('users'): + # form: {'group_ids': [(3, 10), (3, 3), (4, 10), (4, 3)]} or {'group_ids': [(6, 0, [ids]} + user_ids = [command[1] for command in vals['users'] if command[0] == 4] + user_ids += [id for command in vals['users'] if command[0] == 6 for id in command[2]] + + challenge_obj = self.pool.get('gamification.challenge') + challenge_ids = challenge_obj.search(cr, uid, [('autojoin_group_id', 'in', ids)], context=context) + if challenge_ids: + challenge_obj.write(cr, uid, challenge_ids, {'user_ids': [(4, user_id) for user_id in user_ids]}, context=context) + return write_res diff --git a/addons/gamification/security/gamification_security.xml b/addons/gamification/security/gamification_security.xml new file mode 100644 index 00000000000..904ba50721e --- /dev/null +++ b/addons/gamification/security/gamification_security.xml @@ -0,0 +1,43 @@ + + + + + Gamification + + 17 + + + Manager + + + + + + User can only see his/her goals or goal from the same challenge in board visibility + + + + + + + [ + '|', + ('user_id','=',user.id), + '&', + ('challenge_id.user_ids','in',user.id), + ('challenge_id.visibility_mode','=','ranking')] + + + + Gamification Manager can see any goal + + + + + + + [(1, '=', 1)] + + + + diff --git a/addons/gamification/security/ir.model.access.csv b/addons/gamification/security/ir.model.access.csv new file mode 100644 index 00000000000..932c5d97c62 --- /dev/null +++ b/addons/gamification/security/ir.model.access.csv @@ -0,0 +1,19 @@ +id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink + +goal_employee,"Goal Employee",model_gamification_goal,base.group_user,1,1,0,0 +goal_manager,"Goal Manager",model_gamification_goal,group_goal_manager,1,1,1,1 + +goal_definition_employee,"Goal Definition Employee",model_gamification_goal_definition,base.group_user,1,0,0,0 +goal_definition_manager,"Goal Definition Manager",model_gamification_goal_definition,group_goal_manager,1,1,1,1 + +challenge_employee,"Goal Challenge Employee",model_gamification_challenge,base.group_user,1,0,0,0 +challenge_manager,"Goal Challenge Manager",model_gamification_challenge,group_goal_manager,1,1,1,1 + +challenge_line_employee,"Challenge Line Employee",model_gamification_challenge_line,base.group_user,1,0,0,0 +challenge_line_manager,"Challenge Line Manager",model_gamification_challenge_line,group_goal_manager,1,1,1,1 + +badge_employee,"Badge Employee",model_gamification_badge,base.group_user,1,0,0,0 +badge_manager,"Badge Manager",model_gamification_badge,group_goal_manager,1,1,1,1 + +badge_user_employee,"Badge-user Employee",model_gamification_badge_user,base.group_user,1,1,1,0 +badge_user_manager,"Badge-user Manager",model_gamification_badge_user,group_goal_manager,1,1,1,1 diff --git a/addons/gamification/static/description/icon.png b/addons/gamification/static/description/icon.png new file mode 100644 index 00000000000..52a75f726ba Binary files /dev/null and b/addons/gamification/static/description/icon.png differ diff --git a/addons/gamification/static/src/css/Makefile b/addons/gamification/static/src/css/Makefile new file mode 100644 index 00000000000..3a6a70cf59b --- /dev/null +++ b/addons/gamification/static/src/css/Makefile @@ -0,0 +1,3 @@ +gamification.css: gamification.sass + sass --trace -t expanded gamification.sass gamification.css + diff --git a/addons/gamification/static/src/css/gamification.css b/addons/gamification/static/src/css/gamification.css new file mode 100644 index 00000000000..4ac3a0340fa --- /dev/null +++ b/addons/gamification/static/src/css/gamification.css @@ -0,0 +1,190 @@ +@charset "UTF-8"; +.openerp .oe_kanban_view .oe_kanban_card.oe_kanban_goal { + width: 230px; + min-height: 200px; +} +.openerp .oe_kanban_view .oe_kanban_card.oe_kanban_badge { + width: 250px; + min-height: 150px; +} +.openerp .oe_kanban_badge_avatars { + margin-top: 8px; +} +.openerp .oe_kanban_badge_avatars img { + width: 30px; + height: 30px; + padding-left: 0; + margin-top: 3px; + border-radius: 2px; + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); +} +.openerp .oe_kanban_goal .oe_goal_state_block { + width: 200px; + height: 130px; + margin: auto; + margin-bottom: -20px; +} +.openerp .oe_kanban_goal .oe_goal_state_block .oe_goal_state { + font-size: 2.5em; + font-weight: bold; + padding-top: 30px; +} +.openerp .oe_kanban_goal .oe_goal_state_block .oe_goal_state.oe_e { + font-size: 7em; +} +.openerp .oe_kanban_goal .oe_goal_state_block, .openerp .oe_kanban_goal p { + text-align: center; +} +.openerp .oe_kanban_content .oe_goal_gauge:first-child { + margin: auto; +} +.openerp .oe_kanban_content .oe_goal_gauge svg { + margin-top: -20px; +} +.openerp .oe_no_overflow { + overflow: hidden; +} +.openerp .oe_red { + color: red; +} +.openerp .oe_green { + color: green; +} +.openerp .oe_orange { + color: orange; +} +.openerp .oe_form td .oe_no_padding { + margin-left: -6px; +} +.openerp .oe_mail_wall .oe_mail_wall_aside { + margin-top: 15px; + position: relative; + display: inline-block; + vertical-align: top; + width: 280px; + border-radius: 2px; +} +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_gamification_challenge_list { + background-color: #ededf6; +} +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_gamification_suggestion { + background-color: #d3def1; +} +.openerp .oe_mail_wall .oe_mail_wall_aside .oe_gamification_suggestion ul { + padding-left: 15px; +} +.openerp .oe_mail_wall .oe_mail_wall_aside h4, .openerp .oe_mail_wall .oe_mail_wall_aside .oe_goals_list .oe_thead { + text-align: center; + padding-bottom: 15px; +} +.openerp .oe_mail_wall .oe_mail_wall_aside > div { + border-bottom: solid 5px white; + border-radius: 2px; +} +.openerp .oe_mail_wall .oe_goal { + border-bottom: solid 3px white; + padding: 5px 10px; +} +.openerp .oe_mail_wall .oe_goal .oe_update_challenge.oe_e, .openerp .oe_mail_wall .oe_goal .oe_goal_action.oe_e { + visibility: hidden; + font-size: 25px; + float: right; + position: relative; +} +.openerp .oe_mail_wall .oe_goal div:hover > .oe_update_challenge, .openerp .oe_mail_wall .oe_goal div:hover > .oe_goal_action, .openerp .oe_mail_wall .oe_goal th:hover > .oe_goal_action { + visibility: visible; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list { + padding-left: 0; + margin-top: 5px; + margin-bottom: 10px; + width: 100%; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_no_progress div { + display: inline-block; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_no_progress::before { + content: "•"; + padding-right: 4px; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_no_progress.oe_goal_reached::before { + content: "✓"; + padding-right: 0; + margin-left: -2px; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_no_progress.oe_goal_reached .oe_cell { + text-decoration: line-through; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_cell.oe_goal_current { + font-size: 150%; + font-weight: bold; + min-width: 50px; + padding: 0 5px; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_goal_outer_box { + display: inline-block; + position: relative; + z-index: 0; + vertical-align: middle; + width: 100%; + border: solid 1px rgba(0, 0, 0, 0.03); + border-radius: 2px; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_goal_outer_box.oe_no_progress { + border: none; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_goal_progress_background { + background-color: white; + position: absolute; + height: 100%; + width: 100%; + z-index: -2; + top: 0; + left: 0; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_goal_progress { + background-color: #d4e9de; + position: absolute; + height: 100%; + width: 0; + z-index: -1; + top: 0; + left: 0; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_thead { + font-weight: normal; + padding: 5px; + text-align: center; +} +.openerp .oe_mail_wall .oe_goal .oe_goals_list .oe_cell { + padding: 3px 0; +} +.openerp .oe_mail_wall .oe_table.oe_goals_list .col0 { + font-size: 200%; + font-weight: bold; + width: 25px; + text-align: center; +} +.openerp .oe_mail_wall .oe_table.oe_goals_list .col1 { + padding: 0 5px; +} +.openerp .oe_mail_wall .oe_table.oe_goals_list .col2 { + width: auto; +} +.openerp .oe_mail_wall .oe_user_avatar { + width: 24px; + padding-right: 5px; +} +.openerp .oe_mail_wall .oe_mail { + display: inline-block; +} +.openerp .oe_mail_wall .oe_table { + display: table; +} +.openerp .oe_mail_wall .oe_row { + display: table-row; +} +.openerp .oe_mail_wall .oe_cell { + display: table-cell; + vertical-align: middle; +} diff --git a/addons/gamification/static/src/css/gamification.sass b/addons/gamification/static/src/css/gamification.sass new file mode 100644 index 00000000000..3bb6b570e66 --- /dev/null +++ b/addons/gamification/static/src/css/gamification.sass @@ -0,0 +1,181 @@ +@charset "utf-8" + +.openerp + // Kanban views + .oe_kanban_view + .oe_kanban_card.oe_kanban_goal + width: 230px + min-height: 200px + .oe_kanban_card.oe_kanban_badge + width: 250px + min-height: 150px + .oe_kanban_badge_avatars + margin-top: 8px + img + width: 30px + height: 30px + padding-left: 0 + margin-top: 3px + border-radius: 2px + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2) + + .oe_kanban_goal + .oe_goal_state_block + width: 200px + height: 130px + margin: auto + margin-bottom: -20px + .oe_goal_state + font-size: 2.5em + font-weight: bold + padding-top: 30px + .oe_goal_state.oe_e + font-size: 7em + .oe_goal_state_block,p + text-align: center + + .oe_kanban_content + .oe_goal_gauge:first-child + margin: auto /* avoid margin-right: 16px */ + .oe_goal_gauge + svg + margin-top: -20px + .oe_no_overflow + overflow: hidden + + + .oe_red + color: red + .oe_green + color: green + .oe_orange + color: orange + + + // compensate padding from .openerp .oe_form td.oe_form_group_cell + .oe_form_group_cell + .oe_form td .oe_no_padding + margin-left: -6px + + + .oe_mail_wall + .oe_mail_wall_aside + margin-top: 15px + position: relative + display: inline-block + vertical-align: top + width: 280px + border-radius: 2px + + .oe_gamification_challenge_list + background-color: #EDEDF6 + .oe_gamification_suggestion + background-color: rgb(211, 222, 241) + ul + padding-left: 15px + + h4, .oe_goals_list .oe_thead + text-align: center + padding-bottom: 15px + + .oe_mail_wall_aside > div + border-bottom: solid 5px white + border-radius: 2px + + .oe_goal + border-bottom: solid 3px white + padding: 5px 10px + .oe_update_challenge.oe_e, .oe_goal_action.oe_e + visibility: hidden + font-size: 25px + float: right + position: relative + div:hover > .oe_update_challenge, div:hover > .oe_goal_action, th:hover > .oe_goal_action + visibility: visible + + .oe_goals_list + padding-left: 0 + margin-top: 5px + margin-bottom: 10px + width: 100% + + .oe_no_progress + div + display: inline-block + .oe_no_progress::before + content: "•" + padding-right: 4px + .oe_no_progress.oe_goal_reached::before + content: "✓" + padding-right: 0 + margin-left: -2px + .oe_no_progress.oe_goal_reached + .oe_cell + text-decoration: line-through + + .oe_cell.oe_goal_current + font-size: 150% + font-weight: bold + min-width: 50px + padding: 0 5px + + .oe_goal_outer_box + display: inline-block + position: relative + z-index: 0 + vertical-align: middle + width: 100% + border: solid 1px rgba(0,0,0,0.03) + border-radius: 2px + .oe_goal_outer_box.oe_no_progress + border: none + + .oe_goal_progress_background + background-color: white + position: absolute + height: 100% + width: 100% + z-index: -2 + top: 0 + left: 0 + + .oe_goal_progress + background-color: rgb(212, 233, 222) + position: absolute + height: 100% + width: 0 + z-index: -1 + top: 0 + left: 0 + + .oe_thead + font-weight: normal + padding: 5px + text-align: center + .oe_cell + padding: 3px 0 + + .oe_table.oe_goals_list + .col0 + font-size: 200% + font-weight: bold + width: 25px + text-align: center + .col1 + padding: 0 5px + .col2 + width: auto + + .oe_user_avatar + width: 24px + padding-right: 5px + + .oe_mail + display: inline-block + + .oe_table + display: table + .oe_row + display: table-row + .oe_cell + display: table-cell + vertical-align: middle diff --git a/addons/gamification/static/src/js/gamification.js b/addons/gamification/static/src/js/gamification.js new file mode 100644 index 00000000000..2a8db5f369d --- /dev/null +++ b/addons/gamification/static/src/js/gamification.js @@ -0,0 +1,148 @@ +openerp.gamification = function(instance) { + var QWeb = instance.web.qweb; + + instance.gamification.Sidebar = instance.web.Widget.extend({ + template: 'gamification.UserWallSidebar', + init: function (parent, action) { + var self = this; + this._super(parent, action); + this.deferred = $.Deferred(); + this.goals_info = {}; + this.challenge_suggestions = {}; + $(document).off('keydown.klistener'); + }, + events: { + // update a challenge and related goals + 'click a.oe_update_challenge': function(event) { + var self = this; + var challenge_id = parseInt(event.currentTarget.id, 10); + var goals_updated = new instance.web.Model('gamification.challenge').call('quick_update', [challenge_id]); + $.when(goals_updated).done(function() { + self.get_goal_todo_info(); + }); + }, + // action to modify a goal + 'click a.oe_goal_action': function(event) { + var self = this; + var goal_id = parseInt(event.currentTarget.id, 10); + var goal_action = new instance.web.Model('gamification.goal').call('get_action', [goal_id]).then(function(res) { + goal_action['action'] = res; + }); + $.when(goal_action).done(function() { + var action = self.do_action(goal_action.action); + $.when(action).done(function () { + new instance.web.Model('gamification.goal').call('update', [[goal_id]]).then(function(res) { + self.get_goal_todo_info(); + }); + }); + }); + }, + // get more info about a challenge request + 'click a.oe_challenge_reply': function(event) { + var self = this; + var challenge_id = parseInt(event.currentTarget.id, 10); + var challenge_action = new instance.web.Model('gamification.challenge').call('reply_challenge_wizard', [challenge_id]).then(function(res) { + challenge_action['action'] = res; + }); + $.when(challenge_action).done(function() { + self.do_action(challenge_action.action).done(function () { + self.get_goal_todo_info(); + }); + }); + }, + 'click .oe_goal h4': function(event) { + var self = this; + this.kkeys = []; + $(document).on('keydown.klistener', function(event) { + if ("37,38,39,40,65,66".indexOf(event.keyCode) < 0) { + $(document).off('keydown.klistener'); + } else { + self.kkeys.push(event.keyCode); + if (self.kkeys.toString().indexOf("38,38,40,40,37,39,37,39,66,65") >= 0) { + new instance.web.Model('gamification.badge').call('check_progress', []); + $(document).off('keydown.klistener'); + } + } + }); + } + }, + start: function() { + var self = this; + this._super.apply(this, arguments); + self.get_goal_todo_info(); + self.get_challenge_suggestions(); + }, + get_goal_todo_info: function() { + var self = this; + var challenges = new instance.web.Model('res.users').call('get_serialised_gamification_summary', []).then(function(result) { + if (result.length === 0) { + self.$el.find(".oe_gamification_challenge_list").hide(); + } else { + self.$el.find(".oe_gamification_challenge_list").empty(); + _.each(result, function(item){ + var $item = $(QWeb.render("gamification.ChallengeSummary", {challenge: item})); + self.render_money_fields($item); + self.render_user_avatars($item); + self.$el.find('.oe_gamification_challenge_list').append($item); + }); + } + }); + }, + get_challenge_suggestions: function() { + var self = this; + var challenge_suggestions = new instance.web.Model('res.users').call('get_challenge_suggestions', []).then(function(result) { + if (result.length === 0) { + self.$el.find(".oe_gamification_suggestion").hide(); + } else { + var $item = $(QWeb.render("gamification.ChallengeSuggestion", {challenges: result})); + self.$el.find('.oe_gamification_suggestion').append($item); + } + }); + }, + render_money_fields: function(item) { + var self = this; + self.dfm = new instance.web.form.DefaultFieldManager(self); + // Generate a FieldMonetary for each .oe_goal_field_monetary + item.find(".oe_goal_field_monetary").each(function() { + var currency_id = parseInt( $(this).attr('data-id'), 10); + money_field = new instance.web.form.FieldMonetary(self.dfm, { + attrs: { + modifiers: '{"readonly": true}' + } + }); + money_field.set('currency', currency_id); + money_field.get_currency_info(); + money_field.set('value', parseInt($(this).text(), 10)); + money_field.replace($(this)); + }); + }, + render_user_avatars: function(item) { + var self = this; + item.find(".oe_user_avatar").each(function() { + var user_id = parseInt( $(this).attr('data-id'), 10); + var url = instance.session.url('/web/binary/image', {model: 'res.users', field: 'image_small', id: user_id}); + $(this).attr("src", url); + }); + } + }); + + instance.mail.Widget.include({ + start: function() { + this._super(); + var sidebar = new instance.gamification.Sidebar(this); + sidebar.appendTo($('.oe_mail_wall_aside')); + }, + }); + + instance.web_kanban.KanbanRecord.include({ + // open related goals when clicking on challenge kanban view + on_card_clicked: function() { + if (this.view.dataset.model === 'gamification.challenge') { + this.$('.oe_kanban_project_list a').first().click(); + } else { + this._super.apply(this, arguments); + } + }, + }); + +}; diff --git a/addons/gamification/static/src/xml/gamification.xml b/addons/gamification/static/src/xml/gamification.xml new file mode 100644 index 00000000000..6316ca886f0 --- /dev/null +++ b/addons/gamification/static/src/xml/gamification.xml @@ -0,0 +1,114 @@ + + +
+
+
+
+
+ +
+
+ e +

+
+ + +
+
+ +
+
+
+
+
+ + + + + + +
+
+ + Target: + + + Target: <= + + + +
+
+
+
+
+
+ + +
+
+
+ +
+
+ + Target: + + + Target: <= + + +
+
+
+
+
+ +
+
+
+ +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+ + +
+

Invited Challenges

+
    +
  • + +
  • +
+
+
+ +
diff --git a/addons/gamification/tests/__init__.py b/addons/gamification/tests/__init__.py new file mode 100644 index 00000000000..9cafd242b28 --- /dev/null +++ b/addons/gamification/tests/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2013 OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# 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 . +# +############################################################################## + +from . import test_challenge + +checks = [ + test_challenge, +] diff --git a/addons/gamification/tests/test_challenge.py b/addons/gamification/tests/test_challenge.py new file mode 100644 index 00000000000..6b93da727ac --- /dev/null +++ b/addons/gamification/tests/test_challenge.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2013 OpenERP S.A. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# 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 . +# +############################################################################## + +from openerp.tests import common + + +class test_challenge(common.TransactionCase): + + def setUp(self): + super(test_challenge, self).setUp() + cr, uid = self.cr, self.uid + self.data_obj = self.registry('ir.model.data') + self.user_obj = self.registry('res.users') + + self.challenge_obj = self.registry('gamification.challenge') + self.line_obj = self.registry('gamification.challenge.line') + self.goal_obj = self.registry('gamification.goal') + self.badge_obj = self.registry('gamification.badge') + self.badge_user_obj = self.registry('gamification.badge.user') + + self.demo_user_id = self.data_obj.get_object_reference(cr, uid, 'base', 'user_demo')[1] + self.group_user_id = self.data_obj.get_object_reference(cr, uid, 'base', 'group_user')[1] + self.challenge_base_id = self.data_obj.get_object_reference(cr, uid, 'gamification', 'challenge_base_discover')[1] + self.definition_timezone_id = self.data_obj.get_object_reference(cr, uid, 'gamification', 'definition_base_timezone')[1] + self.badge_id = self.data_obj.get_object_reference(cr, uid, 'gamification', 'badge_good_job')[1] + + def test_00_join_challenge(self): + cr, uid, context = self.cr, self.uid, {} + + user_ids = self.user_obj.search(cr, uid, [('groups_id', '=', self.group_user_id)]) + challenge = self.challenge_obj.browse(cr, uid, self.challenge_base_id, context=context) + + self.assertGreaterEqual(len(challenge.user_ids), len(user_ids), "Not enough users in base challenge") + + self.user_obj.create(cr, uid, { + 'name': 'R2D2', + 'login': 'r2d2@openerp.com', + 'email': 'r2d2@openerp.com', + 'groups_id': [(6, 0, [self.group_user_id])] + }, {'no_reset_password': True}) + + challenge = self.challenge_obj.browse(cr, uid, self.challenge_base_id, context=context) + self.assertGreaterEqual(len(challenge.user_ids), len(user_ids)+1, "These are not droids you are looking for") + + def test_10_reach_challenge(self): + cr, uid, context = self.cr, self.uid, {} + + self.challenge_obj.write(cr, uid, [self.challenge_base_id], {'state': 'inprogress'}, context=context) + challenge = self.challenge_obj.browse(cr, uid, self.challenge_base_id, context=context) + challenge_user_ids = [user.id for user in challenge.user_ids] + + self.assertEqual(challenge.state, 'inprogress', "Challenge failed the change of state") + + line_ids = self.line_obj.search(cr, uid, [('challenge_id', '=', self.challenge_base_id)], context=context) + goal_ids = self.goal_obj.search(cr, uid, [('challenge_id', '=', self.challenge_base_id), ('state', '!=', 'draft')], context=context) + self.assertEqual(len(goal_ids), len(line_ids)*len(challenge_user_ids), "Incorrect number of goals generated, should be 1 goal per user, per challenge line") + + # demo user will set a timezone + self.user_obj.write(cr, uid, self.demo_user_id, {'tz': "Europe/Brussels"}, context=context) + goal_ids = self.goal_obj.search(cr, uid, [('user_id', '=', self.demo_user_id), ('definition_id', '=', self.definition_timezone_id)], context=context) + + self.goal_obj.update(cr, uid, goal_ids, context=context) + reached_goal_ids = self.goal_obj.search(cr, uid, [('id', 'in', goal_ids), ('state', '=', 'reached')], context=context) + self.assertEqual(set(goal_ids), set(reached_goal_ids), "Not every goal was reached after changing timezone") + + # reward for two firsts as admin may have timezone + self.challenge_obj.write(cr, uid, self.challenge_base_id, {'reward_first_id': self.badge_id, 'reward_second_id': self.badge_id}, context=context) + self.challenge_obj.write(cr, uid, self.challenge_base_id, {'state': 'done'}, context=context) + + badge_ids = self.badge_user_obj.search(cr, uid, [('badge_id', '=', self.badge_id), ('user_id', '=', self.demo_user_id)]) + self.assertGreater(len(badge_ids), 0, "Demo user has not received the badge") \ No newline at end of file diff --git a/addons/gamification/views/badge.xml b/addons/gamification/views/badge.xml new file mode 100644 index 00000000000..0b37e62051d --- /dev/null +++ b/addons/gamification/views/badge.xml @@ -0,0 +1,194 @@ + + + + + + + Badges + gamification.badge + kanban,tree,form + +

+ Click to create a badge. +

+

+ A badge is a symbolic token granted to a user as a sign of reward. + It can be deserved automatically when some conditions are met or manually by users. + Some badges are harder than others to get with specific conditions. +

+
+
+ + + Badge List + gamification.badge + + + + + + + + + + + + + Badge Form + gamification.badge + +
+
+
+ +
+
+ +
+
+ + + + +
+ Security rules to define who is allowed to manually grant badges. Not enforced for administrator. +
+ + + + + +
+ + + + + + + + + + + + + + +
+
+
+
+ + + + Badge Kanban View + gamification.badge + + + + + + + + + + + + + + +
+
+
+ +
+
+

+ + + + + / + + + /∞ + + + + +
Can not grant
+
+

+ granted,
+ this month +

+
+
+ +

+
+ + + + + +
+
+
+
+
+
+
+
+ + + + + + Badge User Kanban View + gamification.badge.user + + + + + + + + + +
+
+
+ +
+

+ +

+ +

+
+

Granted by the

+
+
+
+
+
+
+
+
+
diff --git a/addons/gamification/views/challenge.xml b/addons/gamification/views/challenge.xml new file mode 100644 index 00000000000..075afcaccfa --- /dev/null +++ b/addons/gamification/views/challenge.xml @@ -0,0 +1,289 @@ + + + + + + Challenges List + gamification.challenge + + + + + + + + + + + + gamification.goal + Related Goals + kanban,tree + {'search_default_group_by_definition': True, 'search_default_inprogress': True, 'search_default_challenge_id': active_id, 'default_challenge_id': active_id} + +

+ There is no goals associated to this challenge matching your search. + Make sure that your challenge is active and assigned to at least one user. +

+
+
+ + + Challenge Form + gamification.challenge + +
+
+
+ + +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Badges are granted when a challenge is finished. This is either at the end of a running period (eg: end of the month for a monthly challenge), at the end date of a challenge (if no periodicity is set) or when the challenge is manually closed.

+
+
+ + + + + + +
+

Depending on the Display mode, reports will be individual or shared.

+
+ + + +
+ + + + + +
+
+ +
+
+ + +
+
+
+
+ + + Challenge Kanban + gamification.challenge + + + + + + +
+
+ í + +
+
+ +

+ +
+ + + +
+
+
+
+
+
+
+
+ + + Challenges + gamification.challenge + kanban,tree,form + {'search_default_inprogress':True, 'default_inprogress':True} + +

+ Click to create a challenge. +

+

+ Assign a list of goals to chosen users to evaluate them. + The challenge can use a period (weekly, monthly...) for automatic creation of goals. + The goals are created for the specified users or member of the group. +

+
+
+ + + + kanban + + + + + + form + + + + + + + Challenge line list + gamification.challenge.line + + + + + + + + + + + Challenge Search + gamification.challenge + + + + + + + + + + + + + + + + Challenge Wizard + gamification.challenge + +
+ +
+

+
+ + + + + + + + + + + + + + + + + + + +
+ There is no reward upon completion of this challenge. +
+ + + + + + +
+ Even if the challenge is failed, best challengers will be rewarded +
+
+
+
+
+
+ +
+
+ + + Challenge Description + gamification.challenge + form + + new + + +
+
\ No newline at end of file diff --git a/addons/gamification/views/goal.xml b/addons/gamification/views/goal.xml new file mode 100644 index 00000000000..a269f710c02 --- /dev/null +++ b/addons/gamification/views/goal.xml @@ -0,0 +1,289 @@ + + + + + + + Goals + gamification.goal + tree,form,kanban + {'search_default_group_by_user': True, 'search_default_group_by_definition': True} + +

+ Click to create a goal. +

+

+ A goal is defined by a user and a goal definition. + Goals can be created automatically by using challenges. +

+
+
+ + + Goal List + gamification.goal + + + + + + + + + + + + + + + + + Goal Form + gamification.goal + +
+
+
+ + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + Goal Search + gamification.goal + + + + + + + + + + + + + + + + + + + + + + + + Goal Kanban View + gamification.goal + + + + + + + + + + + + + + + + + + + +
+
+

+
+ +
+ +
+ +
+ W + N + X +
+
+ + + + + +
+ +
+ Target: less than +
+
+ +
+

+ + From + + + To + +

+
+
+
+
+
+
+
+ + + + + + Goal Definitions + gamification.goal.definition + tree,form + +

+ Click to create a goal definition. +

+

+ A goal definition is a technical model of goal defining a condition to reach. + The dates, values to reach or users are defined in goal instance. +

+
+
+ + + Goal Definitions List + gamification.goal.definition + + + + + + + + + + + Goal Definitions Form + gamification.goal.definition + +
+ + +
+
+
+ + + Goal Definition Search + gamification.goal.definition + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/addons/gamification/wizard/__init__.py b/addons/gamification/wizard/__init__.py new file mode 100644 index 00000000000..638fbef4373 --- /dev/null +++ b/addons/gamification/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import update_goal +import grant_badge diff --git a/addons/gamification/wizard/grant_badge.py b/addons/gamification/wizard/grant_badge.py new file mode 100644 index 00000000000..44f739fff4e --- /dev/null +++ b/addons/gamification/wizard/grant_badge.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp.osv import fields, osv +from openerp.tools.translate import _ + + +class grant_badge_wizard(osv.TransientModel): + """ Wizard allowing to grant a badge to a user""" + + _name = 'gamification.badge.user.wizard' + _columns = { + 'user_id': fields.many2one("res.users", string='User', required=True), + 'badge_id': fields.many2one("gamification.badge", string='Badge', required=True), + 'comment': fields.text('Comment'), + } + + def action_grant_badge(self, cr, uid, ids, context=None): + """Wizard action for sending a badge to a chosen user""" + + badge_obj = self.pool.get('gamification.badge') + badge_user_obj = self.pool.get('gamification.badge.user') + + for wiz in self.browse(cr, uid, ids, context=context): + if uid == wiz.user_id.id: + raise osv.except_osv(_('Warning!'), _('You can not grant a badge to yourself')) + + #create the badge + values = { + 'user_id': wiz.user_id.id, + 'sender_id': uid, + 'badge_id': wiz.badge_id.id, + 'comment': wiz.comment, + } + badge_user = badge_user_obj.create(cr, uid, values, context=context) + result = badge_obj._send_badge(cr, uid, badge_user, context=context) + + return result diff --git a/addons/gamification/wizard/grant_badge.xml b/addons/gamification/wizard/grant_badge.xml new file mode 100644 index 00000000000..e03dbac4096 --- /dev/null +++ b/addons/gamification/wizard/grant_badge.xml @@ -0,0 +1,33 @@ + + + + + + Grant Badge User Form + gamification.badge.user.wizard + +
+ Who would you like to reward? + + + + + +
+
+
+
+
+ + + +
+
diff --git a/addons/gamification/wizard/update_goal.py b/addons/gamification/wizard/update_goal.py new file mode 100644 index 00000000000..cbda3fefbce --- /dev/null +++ b/addons/gamification/wizard/update_goal.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA () +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see +# +############################################################################## + +from openerp.osv import fields, osv + +class goal_manual_wizard(osv.TransientModel): + """Wizard to update a manual goal""" + _name = 'gamification.goal.wizard' + _columns = { + 'goal_id': fields.many2one("gamification.goal", string='Goal', required=True), + 'current': fields.float('Current'), + } + + def action_update_current(self, cr, uid, ids, context=None): + """Wizard action for updating the current value""" + + goal_obj = self.pool.get('gamification.goal') + + for wiz in self.browse(cr, uid, ids, context=context): + towrite = { + 'current': wiz.current, + 'goal_id': wiz.goal_id.id, + } + goal_obj.write(cr, uid, [wiz.goal_id.id], towrite, context=context) + goal_obj.update(cr, uid, [wiz.goal_id.id], context=context) + return {} diff --git a/addons/gamification/wizard/update_goal.xml b/addons/gamification/wizard/update_goal.xml new file mode 100644 index 00000000000..793efab90ff --- /dev/null +++ b/addons/gamification/wizard/update_goal.xml @@ -0,0 +1,24 @@ + + + + + + Update the current value of the Goal + gamification.goal.wizard + +
+ Set the current value you have reached for this goal + + + + +
+
+
+
+
+ +
+
diff --git a/addons/gamification_sale_crm/__init__.py b/addons/gamification_sale_crm/__init__.py new file mode 100644 index 00000000000..e14c014a1ef --- /dev/null +++ b/addons/gamification_sale_crm/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## diff --git a/addons/gamification_sale_crm/__openerp__.py b/addons/gamification_sale_crm/__openerp__.py new file mode 100644 index 00000000000..b2ec9a10428 --- /dev/null +++ b/addons/gamification_sale_crm/__openerp__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013 OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + 'name': 'CRM Gamification', + 'version': '1.0', + 'author': 'OpenERP SA', + 'category': 'hidden', + 'depends': ['gamification','sale_crm'], + 'description': """Example of goal definitions and challenges that can be used related to the usage of the CRM Sale module.""", + + 'data': ['sale_crm_goals.xml'], + 'demo': ['sale_crm_goals_demo.xml'], + 'auto_install': True, +} diff --git a/addons/gamification_sale_crm/sale_crm_goals.xml b/addons/gamification_sale_crm/sale_crm_goals.xml new file mode 100644 index 00000000000..b48cc8a3117 --- /dev/null +++ b/addons/gamification_sale_crm/sale_crm_goals.xml @@ -0,0 +1,173 @@ + + + + + + + Total Invoiced + + sum + True + + + + [('state','!=','cancel'),('user_id','=',user.id),('type','=','out_invoice')] + + + + New Leads + Based on the creation date + count + leads + + + + [('user_id','=',user.id), '|', ('type', '=', 'lead'), ('type', '=', 'opportunity')] + + + + Time to Qualify a Lead + The average number of days to open the case (lower than) + sum + lower + days + + + + [('user_id','=',user.id),('type', '=', 'lead')] + + + + Days to Close a Deal + The average number of days to close the case (lower than) + sum + lower + days + + + + [('user_id','=',user.id)] + + + + + Logged Calls + Log a certain number of calls to reach this goal + count + calls + + + [('user_id','=',user.id),('state','=','done')] + + + + New Opportunities + Based on the opening date + count + opportunities + + + [('user_id','=',user.id),('type','=','opportunity')] + + + + New Sales Orders + Based on the creation date + count + orders + + + [('user_id','=',user.id),('state','not in',('draft', 'sent', 'cancel'))] + + + + Paid Sales Orders + Based on the invoice date + count + orders + + + [('state','=','paid'),('user_id','=',user.id),('type','=','out_invoice')] + + + Total Paid Sales Orders + Based on the invoice date + count + True + + + + [('state','=','paid'),('user_id','=',user.id),('type','=','out_invoice')] + + + + + Customer Refunds + Refund the least customers (lower than) + count + lower + invoices + + + [('state','!=','cancel'),('user_id','=',user.id),('type','=','out_refund')] + + + Total Customer Refunds + The total refunded value is a negative value. Validated when higher (min refunded). + sum + higher + True + + + + [('state','!=','cancel'),('user_id','=',user.id),('type','=','out_refund')] + + + + + + + Monthly Sales Targets + monthly + ranking + + weekly + + + + Lead Acquisition + monthly + ranking + + weekly + + + + + + 20000 + + + + + + + 7 + + 1 + + + + 15 + + 2 + + + + 5 + + 3 + + + + diff --git a/addons/gamification_sale_crm/sale_crm_goals_demo.xml b/addons/gamification_sale_crm/sale_crm_goals_demo.xml new file mode 100644 index 00000000000..fd69c36162f --- /dev/null +++ b/addons/gamification_sale_crm/sale_crm_goals_demo.xml @@ -0,0 +1,23 @@ + + + + + + + + inprogress + + + + + + + + + + 2000 + inprogress + + + + diff --git a/addons/hr/i18n/he.po b/addons/hr/i18n/he.po new file mode 100644 index 00000000000..b4f74a25a8d --- /dev/null +++ b/addons/hr/i18n/he.po @@ -0,0 +1,963 @@ +# Hebrew translation for openobject-addons +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the openobject-addons package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: openobject-addons\n" +"Report-Msgid-Bugs-To: FULL NAME \n" +"POT-Creation-Date: 2012-12-21 17:04+0000\n" +"PO-Revision-Date: 2013-12-30 19:04+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n" +"X-Generator: Launchpad (build 16877)\n" + +#. module: hr +#: model:process.node,name:hr.process_node_openerpuser0 +msgid "Openerp user" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_timesheet_sheet:0 +msgid "Allow timesheets validation by managers" +msgstr "" + +#. module: hr +#: field:hr.job,requirements:0 +msgid "Requirements" +msgstr "" + +#. module: hr +#: model:process.transition,name:hr.process_transition_contactofemployee0 +msgid "Link the employee to information" +msgstr "" + +#. module: hr +#: field:hr.employee,sinid:0 +msgid "SIN No" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_board_hr +#: model:ir.ui.menu,name:hr.menu_hr_dashboard +#: model:ir.ui.menu,name:hr.menu_hr_main +#: model:ir.ui.menu,name:hr.menu_hr_reporting +#: model:ir.ui.menu,name:hr.menu_hr_root +#: model:ir.ui.menu,name:hr.menu_human_resources_configuration +msgid "Human Resources" +msgstr "" + +#. module: hr +#: help:hr.employee,image_medium:0 +msgid "" +"Medium-sized photo of the employee. It is automatically resized as a " +"128x128px image, with aspect ratio preserved. Use this field in form views " +"or some kanban views." +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Time Tracking" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: view:hr.job:0 +msgid "Group By..." +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.view_department_form_installer +msgid "Create Your Departments" +msgstr "" + +#. module: hr +#: help:hr.job,no_of_employee:0 +msgid "Number of employees currently occupying this job position." +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_evaluation:0 +msgid "Organize employees periodic evaluation" +msgstr "" + +#. module: hr +#: view:hr.department:0 +#: view:hr.employee:0 +#: field:hr.employee,department_id:0 +#: view:hr.job:0 +#: field:hr.job,department_id:0 +#: model:ir.model,name:hr.model_hr_department +msgid "Department" +msgstr "" + +#. module: hr +#: field:hr.employee,work_email:0 +msgid "Work Email" +msgstr "" + +#. module: hr +#: help:hr.employee,image:0 +msgid "" +"This field holds the image used as photo for the employee, limited to " +"1024x1024px." +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_holidays:0 +msgid "This installs the module hr_holidays." +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "Jobs" +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "In Recruitment" +msgstr "" + +#. module: hr +#: field:hr.job,message_unread:0 +msgid "Unread Messages" +msgstr "" + +#. module: hr +#: field:hr.department,company_id:0 +#: view:hr.employee:0 +#: view:hr.job:0 +#: field:hr.job,company_id:0 +msgid "Company" +msgstr "" + +#. module: hr +#: field:hr.job,no_of_recruitment:0 +msgid "Expected in Recruitment" +msgstr "" + +#. module: hr +#: field:res.users,employee_ids:0 +msgid "Related employees" +msgstr "" + +#. module: hr +#: constraint:hr.employee.category:0 +msgid "Error! You cannot create recursive Categories." +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_recruitment:0 +msgid "This installs the module hr_recruitment." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Birth" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_view_categ_form +#: model:ir.ui.menu,name:hr.menu_view_employee_category_form +msgid "Employee Tags" +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "Launch Recruitement" +msgstr "" + +#. module: hr +#: model:process.transition,name:hr.process_transition_employeeuser0 +msgid "Link a user to an employee" +msgstr "" + +#. module: hr +#: field:hr.department,parent_id:0 +msgid "Parent Department" +msgstr "" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_config +msgid "Leaves" +msgstr "" + +#. module: hr +#: selection:hr.employee,marital:0 +msgid "Married" +msgstr "" + +#. module: hr +#: field:hr.job,message_ids:0 +msgid "Messages" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Talent Management" +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_timesheet_sheet:0 +msgid "This installs the module hr_timesheet_sheet." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Mobile:" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Position" +msgstr "" + +#. module: hr +#: help:hr.job,message_unread:0 +msgid "If checked new messages require your attention." +msgstr "" + +#. module: hr +#: field:hr.employee,color:0 +msgid "Color Index" +msgstr "" + +#. module: hr +#: model:process.transition,note:hr.process_transition_employeeuser0 +msgid "" +"The Related user field on the Employee form allows to link the OpenERP user " +"(and her rights) to the employee." +msgstr "" + +#. module: hr +#: field:hr.employee,image_medium:0 +msgid "Medium-sized photo" +msgstr "" + +#. module: hr +#: field:hr.employee,identification_id:0 +msgid "Identification No" +msgstr "" + +#. module: hr +#: selection:hr.employee,gender:0 +msgid "Female" +msgstr "" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config +msgid "Attendance" +msgstr "" + +#. module: hr +#: field:hr.employee,work_phone:0 +msgid "Work Phone" +msgstr "" + +#. module: hr +#: field:hr.employee.category,child_ids:0 +msgid "Child Categories" +msgstr "" + +#. module: hr +#: field:hr.job,description:0 +#: model:ir.model,name:hr.model_hr_job +msgid "Job Description" +msgstr "" + +#. module: hr +#: field:hr.employee,work_location:0 +msgid "Office Location" +msgstr "" + +#. module: hr +#: field:hr.job,message_follower_ids:0 +msgid "Followers" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: model:ir.model,name:hr.model_hr_employee +#: model:process.node,name:hr.process_node_employee0 +msgid "Employee" +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_employeecontact0 +msgid "Other information" +msgstr "" + +#. module: hr +#: help:hr.employee,image_small:0 +msgid "" +"Small-sized photo of the employee. It is automatically resized as a 64x64px " +"image, with aspect ratio preserved. Use this field anywhere a small image is " +"required." +msgstr "" + +#. module: hr +#: field:hr.employee,birthday:0 +msgid "Date of Birth" +msgstr "" + +#. module: hr +#: help:hr.job,no_of_recruitment:0 +msgid "Number of new employees you expect to recruit." +msgstr "" + +#. module: hr +#: model:ir.actions.client,name:hr.action_client_hr_menu +msgid "Open HR Menu" +msgstr "" + +#. module: hr +#: help:hr.job,message_summary:0 +msgid "" +"Holds the Chatter summary (number of messages, ...). This summary is " +"directly in html format in order to be inserted in kanban views." +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_account_analytic_analysis:0 +msgid "" +"This installs the module account_analytic_analysis, which will install sales " +"management too." +msgstr "" + +#. module: hr +#: view:board.board:0 +msgid "Human Resources Dashboard" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee,job_id:0 +#: view:hr.job:0 +msgid "Job" +msgstr "" + +#. module: hr +#: field:hr.job,no_of_employee:0 +msgid "Current Number of Employees" +msgstr "" + +#. module: hr +#: field:hr.department,member_ids:0 +msgid "Members" +msgstr "" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_hr_configuration +msgid "Configuration" +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_employee0 +msgid "Employee form and structure" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_expense:0 +msgid "Manage employees expenses" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Tel:" +msgstr "" + +#. module: hr +#: selection:hr.employee,marital:0 +msgid "Divorced" +msgstr "" + +#. module: hr +#: field:hr.employee.category,parent_id:0 +msgid "Parent Category" +msgstr "" + +#. module: hr +#: view:hr.department:0 +#: model:ir.actions.act_window,name:hr.open_module_tree_department +#: model:ir.ui.menu,name:hr.menu_hr_department_tree +msgid "Departments" +msgstr "" + +#. module: hr +#: model:process.node,name:hr.process_node_employeecontact0 +msgid "Employee Contact" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.action_hr_job +msgid "" +"

\n" +" Click to define a new job position.\n" +"

\n" +" Job Positions are used to define jobs and their " +"requirements.\n" +" You can keep track of the number of employees you have per " +"job\n" +" position and follow the evolution according to what you " +"planned\n" +" for the future.\n" +"

\n" +" You can attach a survey to a job position. It will be used " +"in\n" +" the recruitment process to evaluate the applicants for this " +"job\n" +" position.\n" +"

\n" +" " +msgstr "" + +#. module: hr +#: selection:hr.employee,gender:0 +msgid "Male" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "" +"$('.oe_employee_picture').load(function() { if($(this).width() > " +"$(this).height()) { $(this).addClass('oe_employee_picture_wide') } });" +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_evaluation:0 +msgid "This installs the module hr_evaluation." +msgstr "" + +#. module: hr +#: constraint:hr.employee:0 +msgid "Error! You cannot create recursive hierarchy of Employee(s)." +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_attendance:0 +msgid "This installs the module hr_attendance." +msgstr "" + +#. module: hr +#: field:hr.employee,image_small:0 +msgid "Smal-sized photo" +msgstr "" + +#. module: hr +#: view:hr.employee.category:0 +#: model:ir.model,name:hr.model_hr_employee_category +msgid "Employee Category" +msgstr "" + +#. module: hr +#: field:hr.employee,category_ids:0 +msgid "Tags" +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_contract:0 +msgid "This installs the module hr_contract." +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Related User" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "or" +msgstr "" + +#. module: hr +#: field:hr.employee.category,name:0 +msgid "Category" +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "Stop Recruitment" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_attendance:0 +msgid "Install attendances feature" +msgstr "" + +#. module: hr +#: help:hr.employee,bank_account_id:0 +msgid "Employee bank salary account" +msgstr "" + +#. module: hr +#: field:hr.department,note:0 +msgid "Note" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_view_employee_tree +msgid "Employees Structure" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Contact Information" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_holidays:0 +msgid "Manage holidays, leaves and allocation requests" +msgstr "" + +#. module: hr +#: field:hr.department,child_ids:0 +msgid "Child Departments" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: view:hr.job:0 +#: field:hr.job,state:0 +msgid "Status" +msgstr "" + +#. module: hr +#: field:hr.employee,otherid:0 +msgid "Other Id" +msgstr "" + +#. module: hr +#: model:process.process,name:hr.process_process_employeecontractprocess0 +msgid "Employee Contract" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Contracts" +msgstr "" + +#. module: hr +#: help:hr.job,message_ids:0 +msgid "Messages and communication history" +msgstr "" + +#. module: hr +#: field:hr.employee,ssnid:0 +msgid "SSN No" +msgstr "" + +#. module: hr +#: field:hr.job,message_is_follower:0 +msgid "Is a Follower" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_recruitment:0 +msgid "Manage the recruitment process" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Active" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Human Resources Management" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Install your country's payroll" +msgstr "" + +#. module: hr +#: field:hr.employee,bank_account_id:0 +msgid "Bank Account Number" +msgstr "" + +#. module: hr +#: view:hr.department:0 +msgid "Companies" +msgstr "" + +#. module: hr +#: field:hr.job,message_summary:0 +msgid "Summary" +msgstr "" + +#. module: hr +#: model:process.transition,note:hr.process_transition_contactofemployee0 +msgid "" +"In the Employee form, there are different kind of information like Contact " +"information." +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.open_view_employee_list_my +msgid "" +"

\n" +" Click to add a new employee.\n" +"

\n" +" With just a quick glance on the OpenERP employee screen, " +"you\n" +" can easily find all the information you need for each " +"person;\n" +" contact data, job position, availability, etc.\n" +"

\n" +" " +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "HR Settings" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Citizenship & Other Info" +msgstr "" + +#. module: hr +#: constraint:hr.department:0 +msgid "Error! You cannot create recursive departments." +msgstr "" + +#. module: hr +#: field:hr.employee,address_id:0 +msgid "Working Address" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Public Information" +msgstr "" + +#. module: hr +#: field:hr.employee,marital:0 +msgid "Marital Status" +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_ir_actions_act_window +msgid "ir.actions.act_window" +msgstr "" + +#. module: hr +#: field:hr.employee,last_login:0 +msgid "Latest Connection" +msgstr "" + +#. module: hr +#: field:hr.employee,image:0 +msgid "Photo" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Cancel" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.open_module_tree_department +msgid "" +"

\n" +" Click to create a department.\n" +"

\n" +" OpenERP's department structure is used to manage all " +"documents\n" +" related to employees by departments: expenses, timesheets,\n" +" leaves and holidays, recruitments, etc.\n" +"

\n" +" " +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_timesheet:0 +msgid "This installs the module hr_timesheet." +msgstr "" + +#. module: hr +#: help:hr.job,expected_employees:0 +msgid "" +"Expected number of employees for this job position after new recruitment." +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.view_department_form_installer +msgid "" +"

\n" +" Click to define a new department.\n" +"

\n" +" Your departments structure is used to manage all documents\n" +" related to employees by departments: expenses and " +"timesheets,\n" +" leaves and holidays, recruitments, etc.\n" +"

\n" +" " +msgstr "" + +#. module: hr +#: view:hr.employee:0 +msgid "Personal Information" +msgstr "" + +#. module: hr +#: field:hr.employee,city:0 +msgid "City" +msgstr "" + +#. module: hr +#: field:hr.employee,passport_id:0 +msgid "Passport No" +msgstr "" + +#. module: hr +#: field:hr.employee,mobile_phone:0 +msgid "Work Mobile" +msgstr "" + +#. module: hr +#: selection:hr.job,state:0 +msgid "Recruitement in Progress" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_account_analytic_analysis:0 +msgid "" +"Allow invoicing based on timesheets (the sale application will be installed)" +msgstr "" + +#. module: hr +#: view:hr.employee.category:0 +msgid "Employees Categories" +msgstr "" + +#. module: hr +#: field:hr.employee,address_home_id:0 +msgid "Home Address" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_timesheet:0 +msgid "Manage timesheets" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.open_payroll_modules +msgid "Payroll" +msgstr "" + +#. module: hr +#: selection:hr.employee,marital:0 +msgid "Single" +msgstr "" + +#. module: hr +#: field:hr.job,name:0 +msgid "Job Name" +msgstr "" + +#. module: hr +#: view:hr.job:0 +msgid "In Position" +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_payroll:0 +msgid "This installs the module hr_payroll." +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_contract:0 +msgid "Record contracts per employee" +msgstr "" + +#. module: hr +#: view:hr.department:0 +msgid "department" +msgstr "" + +#. module: hr +#: field:hr.employee,country_id:0 +msgid "Nationality" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Additional Features" +msgstr "" + +#. module: hr +#: field:hr.employee,notes:0 +msgid "Notes" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.action2 +msgid "Subordinate Hierarchy" +msgstr "" + +#. module: hr +#: field:hr.employee,resource_id:0 +msgid "Resource" +msgstr "" + +#. module: hr +#: field:hr.department,complete_name:0 +#: field:hr.employee,name_related:0 +#: field:hr.employee.category,complete_name:0 +msgid "Name" +msgstr "" + +#. module: hr +#: field:hr.employee,gender:0 +msgid "Gender" +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee.category,employee_ids:0 +#: field:hr.job,employee_ids:0 +#: model:ir.actions.act_window,name:hr.hr_employee_normal_action_tree +#: model:ir.actions.act_window,name:hr.open_view_employee_list +#: model:ir.actions.act_window,name:hr.open_view_employee_list_my +#: model:ir.ui.menu,name:hr.menu_open_view_employee_list_my +msgid "Employees" +msgstr "" + +#. module: hr +#: help:hr.employee,sinid:0 +msgid "Social Insurance Number" +msgstr "" + +#. module: hr +#: field:hr.department,name:0 +msgid "Department Name" +msgstr "" + +#. module: hr +#: model:ir.ui.menu,name:hr.menu_hr_reporting_timesheet +msgid "Reports" +msgstr "" + +#. module: hr +#: field:hr.config.settings,module_hr_payroll:0 +msgid "Manage payroll" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +#: model:ir.actions.act_window,name:hr.action_human_resources_configuration +msgid "Configure Human Resources" +msgstr "" + +#. module: hr +#: selection:hr.job,state:0 +msgid "No Recruitment" +msgstr "" + +#. module: hr +#: help:hr.employee,ssnid:0 +msgid "Social Security Number" +msgstr "" + +#. module: hr +#: model:process.node,note:hr.process_node_openerpuser0 +msgid "Creation of a OpenERP user" +msgstr "" + +#. module: hr +#: field:hr.employee,login:0 +msgid "Login" +msgstr "" + +#. module: hr +#: field:hr.job,expected_employees:0 +msgid "Total Forecasted Employees" +msgstr "" + +#. module: hr +#: help:hr.job,state:0 +msgid "" +"By default 'In position', set it to 'In Recruitment' if recruitment process " +"is going on for this job position." +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_res_users +msgid "Users" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,name:hr.action_hr_job +#: model:ir.ui.menu,name:hr.menu_hr_job +msgid "Job Positions" +msgstr "" + +#. module: hr +#: model:ir.actions.act_window,help:hr.open_board_hr +msgid "" +"
\n" +"

\n" +" Human Resources dashboard is empty.\n" +"

\n" +" To add your first report into this dashboard, go to any\n" +" menu, switch to list or graph view, and click 'Add " +"to\n" +" Dashboard' in the extended search options.\n" +"

\n" +" You can filter and group data before inserting into the\n" +" dashboard using the search options.\n" +"

\n" +"
\n" +" " +msgstr "" + +#. module: hr +#: view:hr.employee:0 +#: field:hr.employee,coach_id:0 +msgid "Coach" +msgstr "" + +#. module: hr +#: sql_constraint:hr.job:0 +msgid "The name of the job position must be unique per company!" +msgstr "" + +#. module: hr +#: help:hr.config.settings,module_hr_expense:0 +msgid "This installs the module hr_expense." +msgstr "" + +#. module: hr +#: model:ir.model,name:hr.model_hr_config_settings +msgid "hr.config.settings" +msgstr "" + +#. module: hr +#: field:hr.department,manager_id:0 +#: view:hr.employee:0 +#: field:hr.employee,parent_id:0 +msgid "Manager" +msgstr "" + +#. module: hr +#: selection:hr.employee,marital:0 +msgid "Widower" +msgstr "" + +#. module: hr +#: field:hr.employee,child_ids:0 +msgid "Subordinates" +msgstr "" + +#. module: hr +#: view:hr.config.settings:0 +msgid "Apply" +msgstr "" diff --git a/addons/hr/i18n/zh_TW.po b/addons/hr/i18n/zh_TW.po index e31a3c399fd..00daa2f9477 100644 --- a/addons/hr/i18n/zh_TW.po +++ b/addons/hr/i18n/zh_TW.po @@ -7,24 +7,24 @@ msgstr "" "Project-Id-Version: OpenERP Server 5.0.4\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-12-21 17:04+0000\n" -"PO-Revision-Date: 2012-05-10 17:48+0000\n" -"Last-Translator: Fabien (Open ERP) \n" +"PO-Revision-Date: 2013-12-27 05:02+0000\n" +"Last-Translator: Andy Cheng \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: 2013-09-12 05:56+0000\n" -"X-Generator: Launchpad (build 16761)\n" +"X-Launchpad-Export-Date: 2013-12-28 05:19+0000\n" +"X-Generator: Launchpad (build 16877)\n" #. module: hr #: model:process.node,name:hr.process_node_openerpuser0 msgid "Openerp user" -msgstr "" +msgstr "Openerp 使用者" #. module: hr #: field:hr.config.settings,module_hr_timesheet_sheet:0 msgid "Allow timesheets validation by managers" -msgstr "" +msgstr "允許主管批准工時表" #. module: hr #: field:hr.job,requirements:0 @@ -62,7 +62,7 @@ msgstr "" #. module: hr #: view:hr.config.settings:0 msgid "Time Tracking" -msgstr "" +msgstr "追蹤時間" #. module: hr #: view:hr.employee:0 @@ -73,17 +73,17 @@ msgstr "分組根據..." #. module: hr #: model:ir.actions.act_window,name:hr.view_department_form_installer msgid "Create Your Departments" -msgstr "" +msgstr "建立您的部門" #. module: hr #: help:hr.job,no_of_employee:0 msgid "Number of employees currently occupying this job position." -msgstr "" +msgstr "從事此職位的現有員工數量。" #. module: hr #: field:hr.config.settings,module_hr_evaluation:0 msgid "Organize employees periodic evaluation" -msgstr "" +msgstr "安排員工定期考評" #. module: hr #: view:hr.department:0 @@ -98,19 +98,19 @@ msgstr "部門" #. module: hr #: field:hr.employee,work_email:0 msgid "Work Email" -msgstr "" +msgstr "工作電子郵件" #. module: hr #: help:hr.employee,image:0 msgid "" "This field holds the image used as photo for the employee, limited to " "1024x1024px." -msgstr "" +msgstr "此欄位存放圖片作為員工照片,限制大小為 1024*1024 像素。" #. module: hr #: help:hr.config.settings,module_hr_holidays:0 msgid "This installs the module hr_holidays." -msgstr "" +msgstr "此功能將安裝 hr_holidays 模組。" #. module: hr #: view:hr.job:0 @@ -125,7 +125,7 @@ msgstr "正招聘" #. module: hr #: field:hr.job,message_unread:0 msgid "Unread Messages" -msgstr "" +msgstr "未讀訊息" #. module: hr #: field:hr.department,company_id:0 @@ -143,7 +143,7 @@ msgstr "" #. module: hr #: field:res.users,employee_ids:0 msgid "Related employees" -msgstr "" +msgstr "相關員工" #. module: hr #: constraint:hr.employee.category:0 @@ -153,28 +153,28 @@ msgstr "" #. module: hr #: help:hr.config.settings,module_hr_recruitment:0 msgid "This installs the module hr_recruitment." -msgstr "" +msgstr "此功能將安裝 hr_recruitment 模組。" #. module: hr #: view:hr.employee:0 msgid "Birth" -msgstr "" +msgstr "生日" #. module: hr #: model:ir.actions.act_window,name:hr.open_view_categ_form #: model:ir.ui.menu,name:hr.menu_view_employee_category_form msgid "Employee Tags" -msgstr "" +msgstr "員工標籤" #. module: hr #: view:hr.job:0 msgid "Launch Recruitement" -msgstr "" +msgstr "啟動招募" #. module: hr #: model:process.transition,name:hr.process_transition_employeeuser0 msgid "Link a user to an employee" -msgstr "" +msgstr "將一個使用者帳號連結到一位員工" #. module: hr #: field:hr.department,parent_id:0 @@ -184,7 +184,7 @@ msgstr "上級部門" #. module: hr #: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_config msgid "Leaves" -msgstr "" +msgstr "休假" #. module: hr #: selection:hr.employee,marital:0 @@ -194,37 +194,37 @@ msgstr "已婚" #. module: hr #: field:hr.job,message_ids:0 msgid "Messages" -msgstr "" +msgstr "訊息" #. module: hr #: view:hr.config.settings:0 msgid "Talent Management" -msgstr "" +msgstr "人才管理" #. module: hr #: help:hr.config.settings,module_hr_timesheet_sheet:0 msgid "This installs the module hr_timesheet_sheet." -msgstr "" +msgstr "此功能將安裝 hr_timesheet_sheet 模組。" #. module: hr #: view:hr.employee:0 msgid "Mobile:" -msgstr "" +msgstr "行動電話:" #. module: hr #: view:hr.employee:0 msgid "Position" -msgstr "" +msgstr "職位" #. module: hr #: help:hr.job,message_unread:0 msgid "If checked new messages require your attention." -msgstr "" +msgstr "當有新訊息時通知您。" #. module: hr #: field:hr.employee,color:0 msgid "Color Index" -msgstr "" +msgstr "顏色索引" #. module: hr #: model:process.transition,note:hr.process_transition_employeeuser0 @@ -236,7 +236,7 @@ msgstr "" #. module: hr #: field:hr.employee,image_medium:0 msgid "Medium-sized photo" -msgstr "" +msgstr "中等尺寸照片" #. module: hr #: field:hr.employee,identification_id:0 @@ -251,7 +251,7 @@ msgstr "女" #. module: hr #: model:ir.ui.menu,name:hr.menu_open_view_attendance_reason_new_config msgid "Attendance" -msgstr "" +msgstr "出勤" #. module: hr #: field:hr.employee,work_phone:0 @@ -277,7 +277,7 @@ msgstr "辦公室位置" #. module: hr #: field:hr.job,message_follower_ids:0 msgid "Followers" -msgstr "" +msgstr "關注者" #. module: hr #: view:hr.employee:0 @@ -307,12 +307,12 @@ msgstr "出生日期" #. module: hr #: help:hr.job,no_of_recruitment:0 msgid "Number of new employees you expect to recruit." -msgstr "" +msgstr "您期望聘雇的新員工數量。" #. module: hr #: model:ir.actions.client,name:hr.action_client_hr_menu msgid "Open HR Menu" -msgstr "" +msgstr "開啟人資選單" #. module: hr #: help:hr.job,message_summary:0 @@ -326,12 +326,12 @@ msgstr "" msgid "" "This installs the module account_analytic_analysis, which will install sales " "management too." -msgstr "" +msgstr "此功能將安裝 account_analytic_analysis 模組,同時也安裝業務銷售管理模組。" #. module: hr #: view:board.board:0 msgid "Human Resources Dashboard" -msgstr "" +msgstr "人力資源儀表板" #. module: hr #: view:hr.employee:0 @@ -343,7 +343,7 @@ msgstr "工作" #. module: hr #: field:hr.job,no_of_employee:0 msgid "Current Number of Employees" -msgstr "" +msgstr "現有員工數目" #. module: hr #: field:hr.department,member_ids:0 @@ -353,22 +353,22 @@ msgstr "成員" #. module: hr #: model:ir.ui.menu,name:hr.menu_hr_configuration msgid "Configuration" -msgstr "" +msgstr "組態設定" #. module: hr #: model:process.node,note:hr.process_node_employee0 msgid "Employee form and structure" -msgstr "" +msgstr "員工表單與架構" #. module: hr #: field:hr.config.settings,module_hr_expense:0 msgid "Manage employees expenses" -msgstr "" +msgstr "管理員工費用報支" #. module: hr #: view:hr.employee:0 msgid "Tel:" -msgstr "" +msgstr "電話:" #. module: hr #: selection:hr.employee,marital:0 @@ -430,7 +430,7 @@ msgstr "" #. module: hr #: help:hr.config.settings,module_hr_evaluation:0 msgid "This installs the module hr_evaluation." -msgstr "" +msgstr "此功能將安裝 hr_evaluation 模組。" #. module: hr #: constraint:hr.employee:0 @@ -440,12 +440,12 @@ msgstr "" #. module: hr #: help:hr.config.settings,module_hr_attendance:0 msgid "This installs the module hr_attendance." -msgstr "" +msgstr "此功能將安裝 hr_attendance 模組。" #. module: hr #: field:hr.employee,image_small:0 msgid "Smal-sized photo" -msgstr "" +msgstr "小尺吋照片" #. module: hr #: view:hr.employee.category:0 @@ -456,22 +456,22 @@ msgstr "員工分類" #. module: hr #: field:hr.employee,category_ids:0 msgid "Tags" -msgstr "" +msgstr "標籤" #. module: hr #: help:hr.config.settings,module_hr_contract:0 msgid "This installs the module hr_contract." -msgstr "" +msgstr "此功能將安裝 hr_contract 模組。" #. module: hr #: view:hr.employee:0 msgid "Related User" -msgstr "" +msgstr "相關使用者" #. module: hr #: view:hr.config.settings:0 msgid "or" -msgstr "" +msgstr "或" #. module: hr #: field:hr.employee.category,name:0 @@ -481,12 +481,12 @@ msgstr "分類" #. module: hr #: view:hr.job:0 msgid "Stop Recruitment" -msgstr "" +msgstr "停止招募" #. module: hr #: field:hr.config.settings,module_hr_attendance:0 msgid "Install attendances feature" -msgstr "" +msgstr "安裝出勤管理功能" #. module: hr #: help:hr.employee,bank_account_id:0 @@ -501,7 +501,7 @@ msgstr "備註" #. module: hr #: model:ir.actions.act_window,name:hr.open_view_employee_tree msgid "Employees Structure" -msgstr "" +msgstr "員工架構" #. module: hr #: view:hr.employee:0 @@ -511,7 +511,7 @@ msgstr "聯絡資料" #. module: hr #: field:hr.config.settings,module_hr_holidays:0 msgid "Manage holidays, leaves and allocation requests" -msgstr "" +msgstr "管理假日、請假及排假。" #. module: hr #: field:hr.department,child_ids:0 @@ -528,7 +528,7 @@ msgstr "狀況" #. module: hr #: field:hr.employee,otherid:0 msgid "Other Id" -msgstr "" +msgstr "其他ID" #. module: hr #: model:process.process,name:hr.process_process_employeecontractprocess0 @@ -538,12 +538,12 @@ msgstr "僱傭合約" #. module: hr #: view:hr.config.settings:0 msgid "Contracts" -msgstr "" +msgstr "合約" #. module: hr #: help:hr.job,message_ids:0 msgid "Messages and communication history" -msgstr "" +msgstr "訊息及聯絡紀錄" #. module: hr #: field:hr.employee,ssnid:0 @@ -553,12 +553,12 @@ msgstr "社會保障號碼(美國)" #. module: hr #: field:hr.job,message_is_follower:0 msgid "Is a Follower" -msgstr "" +msgstr "為關注者" #. module: hr #: field:hr.config.settings,module_hr_recruitment:0 msgid "Manage the recruitment process" -msgstr "" +msgstr "管理招募流程" #. module: hr #: view:hr.employee:0 @@ -568,12 +568,12 @@ msgstr "活躍" #. module: hr #: view:hr.config.settings:0 msgid "Human Resources Management" -msgstr "" +msgstr "人力資源管理" #. module: hr #: view:hr.config.settings:0 msgid "Install your country's payroll" -msgstr "" +msgstr "安裝您國家的薪資模組" #. module: hr #: field:hr.employee,bank_account_id:0 @@ -588,7 +588,7 @@ msgstr "公司" #. module: hr #: field:hr.job,message_summary:0 msgid "Summary" -msgstr "" +msgstr "摘要" #. module: hr #: model:process.transition,note:hr.process_transition_contactofemployee0 @@ -615,12 +615,12 @@ msgstr "" #. module: hr #: view:hr.employee:0 msgid "HR Settings" -msgstr "" +msgstr "人資設定" #. module: hr #: view:hr.employee:0 msgid "Citizenship & Other Info" -msgstr "" +msgstr "公民與其他資訊" #. module: hr #: constraint:hr.department:0 @@ -635,7 +635,7 @@ msgstr "辦公地址" #. module: hr #: view:hr.employee:0 msgid "Public Information" -msgstr "" +msgstr "公開資訊" #. module: hr #: field:hr.employee,marital:0 diff --git a/addons/hr/res_config.py b/addons/hr/res_config.py index 147c4e4d5b9..94c029262ff 100644 --- a/addons/hr/res_config.py +++ b/addons/hr/res_config.py @@ -42,6 +42,8 @@ class hr_config_settings(osv.osv_memory): help ="""This installs the module hr_contract."""), 'module_hr_evaluation': fields.boolean('Organize employees periodic evaluation', help ="""This installs the module hr_evaluation."""), + 'module_hr_gamification': fields.boolean('Drive engagement with challenges and badges', + help ="""This installs the module hr_gamification."""), 'module_account_analytic_analysis': fields.boolean('Allow invoicing based on timesheets (the sale application will be installed)', help ="""This installs the module account_analytic_analysis, which will install sales management too."""), 'module_hr_payroll': fields.boolean('Manage payroll', diff --git a/addons/hr/res_config_view.xml b/addons/hr/res_config_view.xml index 632ceb56918..3dc1795139c 100644 --- a/addons/hr/res_config_view.xml +++ b/addons/hr/res_config_view.xml @@ -56,6 +56,10 @@