[MERGE] Sync with trunk

bzr revid: tde@openerp.com-20140106135700-rt0g44w5xmpbtxiu
This commit is contained in:
Thibault Delavallée 2014-01-06 14:57:00 +01:00
commit 49c0b7a820
177 changed files with 31349 additions and 1278 deletions

View File

@ -135,7 +135,8 @@ for a particular financial year and for preparation of vouchers there is a modul
],
'css':[
'static/src/css/account_move_reconciliation.css',
'static/src/css/account_move_line_quickadd.css'
'static/src/css/account_move_line_quickadd.css',
'static/src/css/account_bank_and_cash.css',
],
'demo': [
'demo/account_demo.xml',

View File

@ -106,13 +106,13 @@ class account_bank_statement(osv.osv):
'balance_start': fields.float('Starting Balance', digits_compute=dp.get_precision('Account'),
states={'confirm':[('readonly',True)]}),
'balance_end_real': fields.float('Ending Balance', digits_compute=dp.get_precision('Account'),
states={'confirm': [('readonly', True)]}),
states={'confirm': [('readonly', True)]}, help="Computed using the cash control lines"),
'balance_end': fields.function(_end_balance,
store = {
'account.bank.statement': (lambda self, cr, uid, ids, c={}: ids, ['line_ids','move_line_ids','balance_start'], 10),
'account.bank.statement.line': (_get_statement, ['amount'], 10),
},
string="Computed Balance", help='Balance as calculated based on Starting Balance and transaction lines'),
string="Computed Balance", help='Balance as calculated based on Opening Balance and transaction lines'),
'company_id': fields.related('journal_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
'line_ids': fields.one2many('account.bank.statement.line',
'statement_id', 'Statement lines',
@ -128,6 +128,7 @@ class account_bank_statement(osv.osv):
'currency': fields.function(_currency, string='Currency',
type='many2one', relation='res.currency'),
'account_id': fields.related('journal_id', 'default_debit_account_id', type='many2one', relation='account.account', string='Account used in this journal', readonly=True, help='used in statement reconciliation domain, but shouldn\'t be used elswhere.'),
'cash_control': fields.related('journal_id', 'cash_control' , type='boolean', relation='account.journal',string='Cash control'),
}
_defaults = {
@ -450,22 +451,25 @@ class account_bank_statement(osv.osv):
def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
res = False
if journal_id:
cr.execute('SELECT balance_end_real \
FROM account_bank_statement \
WHERE journal_id = %s AND NOT state = %s \
ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
res = cr.fetchone()
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
if journal.with_last_closing_balance:
cr.execute('SELECT balance_end_real \
FROM account_bank_statement \
WHERE journal_id = %s AND NOT state = %s \
ORDER BY date DESC,id DESC LIMIT 1', (journal_id, 'draft'))
res = cr.fetchone()
return res and res[0] or 0.0
def onchange_journal_id(self, cr, uid, statement_id, journal_id, context=None):
if not journal_id:
return {}
balance_start = self._compute_balance_end_real(cr, uid, journal_id, context=context)
journal_data = self.pool.get('account.journal').read(cr, uid, journal_id, ['company_id', 'currency'], context=context)
company_id = journal_data['company_id']
currency_id = journal_data['currency'] or self.pool.get('res.company').browse(cr, uid, company_id[0], context=context).currency_id.id
return {'value': {'balance_start': balance_start, 'company_id': company_id, 'currency': currency_id}}
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
currency = journal.currency or journal.company_id.currency_id
res = {'balance_start': balance_start, 'company_id': journal.company_id.id, 'currency': currency.id}
if journal.type == 'cash':
res['cash_control'] = journal.cash_control
return {'value': res}
def unlink(self, cr, uid, ids, context=None):
stat = self.read(cr, uid, ids, ['state'], context=context)
@ -546,7 +550,7 @@ class account_bank_statement_line(osv.osv):
_name = "account.bank.statement.line"
_description = "Bank Statement Line"
_columns = {
'name': fields.char('OBI', required=True, help="Originator to Beneficiary Information"),
'name': fields.char('Description', required=True),
'date': fields.date('Date', required=True),
'amount': fields.float('Amount', digits_compute=dp.get_precision('Account')),
'type': fields.selection([

View File

@ -159,6 +159,10 @@ class account_cash_statement(osv.osv):
context=context
)
opening_details_ids = self._get_cash_open_box_lines(cr, uid, journal_id, context)
if opening_details_ids:
result['value']['opening_details_ids'] = opening_details_ids
if not statement_ids:
return result
@ -172,13 +176,14 @@ class account_cash_statement(osv.osv):
store = {
'account.bank.statement': (lambda self, cr, uid, ids, context=None: ids, ['line_ids','move_line_ids'], 10),
'account.bank.statement.line': (_get_statement_from_line, ['amount'], 10),
}),
},
help="Total of cash transaction lines."),
'closing_date': fields.datetime("Closed On"),
'details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='CashBox Lines'),
'opening_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Opening Cashbox Lines'),
'closing_details_ids' : fields.one2many('account.cashbox.line', 'bank_statement_id', string='Closing Cashbox Lines'),
'user_id': fields.many2one('res.users', 'Responsible', required=False),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float"),
'difference' : fields.function(_compute_difference, method=True, string="Difference", type="float", help="Difference between the theoretical closing balance and the real closing balance."),
'last_closing_balance' : fields.function(_compute_last_closing_balance, method=True, string='Last Closing Balance', type='float'),
}
_defaults = {
@ -187,13 +192,12 @@ class account_cash_statement(osv.osv):
'user_id': lambda self, cr, uid, context=None: uid,
}
def create(self, cr, uid, vals, context=None):
journal = False
if vals.get('journal_id'):
journal = self.pool.get('account.journal').browse(cr, uid, vals['journal_id'], context=context)
if journal and (journal.type == 'cash') and not vals.get('details_ids'):
vals['details_ids'] = []
def _get_cash_open_box_lines(self, cr, uid, journal_id, context):
details_ids = []
if not journal_id:
return details_ids
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context)
if journal and (journal.type == 'cash'):
last_pieces = None
if journal.with_last_closing_balance == True:
@ -206,16 +210,19 @@ class account_cash_statement(osv.osv):
last_pieces = dict(
(line.pieces, line.number_closing) for line in last_bank_statement.details_ids
)
for value in journal.cashbox_line_ids:
nested_values = {
'number_closing' : 0,
'number_opening' : last_pieces.get(value.pieces, 0) if isinstance(last_pieces, dict) else 0,
'pieces' : value.pieces
}
details_ids.append([0, False, nested_values])
return details_ids
vals['details_ids'].append([0, False, nested_values])
def create(self, cr, uid, vals, context=None):
journal_id = vals.get('journal_id')
if journal_id and not vals.get('opening_details_ids'):
vals['opening_details_ids'] = vals.get('opening_details_ids') or self._get_cash_open_box_lines(cr, uid, journal_id, context)
res_id = super(account_cash_statement, self).create(cr, uid, vals, context=context)
self._update_balances(cr, uid, [res_id], context)
return res_id
@ -233,7 +240,10 @@ class account_cash_statement(osv.osv):
@return: True on success, False otherwise
"""
if vals.get('journal_id', False):
cashbox_line_obj = self.pool.get('account.cashbox.line')
cashbox_ids = cashbox_line_obj.search(cr, uid, [('bank_statement_id', 'in', ids)], context=context)
cashbox_line_obj.unlink(cr, uid, cashbox_ids, context)
res = super(account_cash_statement, self).write(cr, uid, ids, vals, context=context)
self._update_balances(cr, uid, ids, context)
return res

View File

@ -2265,7 +2265,6 @@
<group>
<field name="journal_id" on_change="onchange_journal_id(journal_id)" widget="selection" domain="[('type', '=', 'cash')]" />
<field name="user_id" readonly="1" string="Responsible"/>
<field name="total_entry_encoding"/>
<field name='company_id' widget="selection" groups="base.group_multi_company" />
</group>
<group>
@ -2273,6 +2272,7 @@
<field name="closing_date" readonly="1"/>
<field name="period_id" class="oe_inline"/>
<field name="currency" invisible="1"/>
<field name="cash_control" invisible="1"/>
</group>
</group>
<notebook>
@ -2306,41 +2306,64 @@
</form>
</field>
</page>
<page string="Cash Control">
<page string="Cash Control" attrs="{'invisible' : [('cash_control', '=', False)]}">
<group col="2" expand="1">
<field name="opening_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '!=', 'draft')]}">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces"/>
<field name="number_opening" string="Opening Unit Numbers" on_change="on_change_sub_opening(pieces, number_opening, parent.balance_end)"/>
<field name="subtotal_opening" string="Opening Subtotal"/>
</tree>
</field>
<field name="closing_details_ids" nolabel="1" colspan="4" attrs="{'invisible' : [('state', '=', 'draft')]}">
<tree string="Closing Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_opening" string="Opening Unit Numbers" readonly="1" />
<field name="subtotal_opening" string="Opening Subtotal" readonly="1" />
<field name="number_closing" string="Closing Unit Numbers" on_change="on_change_sub_closing(pieces, number_closing, parent.balance_end)"/>
<field name="subtotal_closing" string="Closing Subtotal"/>
</tree>
</field>
<group string="Opening Cash Control" attrs="{'invisible' : [('state', '!=', 'draft')]}">
<field name="opening_details_ids" colspan="2" nolabel="1">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces"/>
<field name="number_opening" on_change="on_change_sub_opening(pieces, number_opening)" />
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
</group>
<group>
<group string="Opening Cash Control" attrs="{'invisible' : [('state', '=', 'draft')]}">
<field name="details_ids" colspan="2" nolabel="1" attrs="{'readonly' : [('state', '!=', 'draft')]}">
<tree string="Opening Cashbox Lines" editable="bottom">
<field name="pieces"/>
<field name="number_opening" on_change="on_change_sub_opening(pieces, number_opening)"/>
<field name="subtotal_opening" string="Opening Subtotal" sum="Total"/>
</tree>
</field>
</group>
<group string="Closing Cash Control" attrs="{'invisible' : [('state', '=', 'draft')]}">
<field name="closing_details_ids" colspan="2" nolabel="1" attrs="{'readonly' : [('state', '=', 'confirm')]}">
<tree string="Closing Cashbox Lines" editable="bottom">
<field name="pieces" readonly="1" />
<field name="number_closing" on_change="on_change_sub_closing(pieces, number_closing)"/>
<field name="subtotal_closing" string="Closing Subtotal" sum="Total"/>
</tree>
</field>
</group>
</group>
</group>
</page>
<page string="Journal Entries" attrs="{'invisible': [('state','!=','confirm')]}">
<field name="move_line_ids" string="Journal Entries"/>
</page>
</notebook>
<group col="6" colspan="4">
<group col="2" colspan="2">
<separator string="Opening Balance" colspan="4"/>
<field name="balance_start" readonly="1" string="Opening Cash Control" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="last_closing_balance" readonly="1" string="Last Closing Balance" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="total_entry_encoding" widget="monetary" options="{'currency_field': 'currency_id'}"/>
</group>
<group string="Closing Balance">
<field name="balance_end" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<group>
<group class="oe_subtotal_footer oe_right">
<label for="balance_start" class="oe_subtotal_footer_separator oe_open_balance" string="Opening Balance" style="padding-right: 23px !important; padding-top: 6px !important;"/>
<field name="balance_start" attrs="{'readonly' : ['|', ('cash_control', '=', True), ('state', '=', 'confirm')]}" nolabel="1" widget="monetary" class="oe_subtotal_footer_separator oe_open_balance" options="{'currency_field': 'currency'}" help="Total of opening cash control lines"/>
<label for="total_entry_encoding" string="+ Transactions" class="oe_force_bold oe_mini_subtotal_footer_separator" style="padding-right: 20px !important;"/>
<field name="total_entry_encoding" nolabel="1" class="oe_bold oe_account_total" widget="monetary" options="{'currency_field': 'currency'}"/>
<label for="balance_end" string="= Theoretical Closing Balance" class="oe_force_bold oe_mini_subtotal_footer_separator" style="padding-right: 20px !important;" help="Sum of opening balance and transactions."/>
<field name="balance_end" nolabel="1" class="oe_bold oe_account_total" widget="monetary" options="{'currency_field': 'currency'}"/>
</group>
<div>
<group class="oe_subtotal_footer oe_right" attrs="{'invisible': [('state', '=', 'draft')]}">
<label for="balance_end_real" class="oe_subtotal_footer_separator oe_real_closing_balance" string="Real Closing Balance" style="padding-right: 23px !important; padding-top: 6px !important;"/>
<field name="balance_end_real" attrs="{'readonly' : ['|', ('cash_control', '=', True), ('state', '=', 'confirm')]}" nolabel="1" class="oe_subtotal_footer_separator oe_real_closing_balance" widget="monetary" options="{'currency_field': 'currency'}" help="Total of closing cash control lines."/>
</group>
<group/>
<group/>
<group class="oe_subtotal_footer oe_right" attrs="{'invisible': [('state', '=', 'draft')]}">
<label for="difference" string="Difference" class="oe_subtotal_footer_separator oe_difference" style="padding-right: 20px !important;"/>
<field name="difference" nolabel="1" class="oe_subtotal_footer_separator oe_difference" widget="monetary" options="{'currency_field': 'currency'}"/>
</group>
</div>
</group>
</sheet>
</form>

View File

@ -3,9 +3,15 @@
<data noupdate="1">
<record id="analytic_journal_sale" model="account.analytic.journal">
<field name="code">SAL</field>
<field name="name">Sales</field>
<field name="type">sale</field>
</record>
<record id="exp" model="account.analytic.journal">
<field name="code">PUR</field>
<field name="name">Purchases</field>
<field name="type">purchase</field>
</record>
<!--
Payment term

File diff suppressed because it is too large Load Diff

View File

@ -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:04+0000\n"
"PO-Revision-Date: 2013-07-02 06:32+0000\n"
"PO-Revision-Date: 2013-12-19 08:06+0000\n"
"Last-Translator: Chertykov Denis <chertykov@gmail.com>\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:32+0000\n"
"X-Generator: Launchpad (build 16761)\n"
"X-Launchpad-Export-Date: 2013-12-20 05:11+0000\n"
"X-Generator: Launchpad (build 16872)\n"
#. module: account
#: model:process.transition,name:account.process_transition_supplierreconcilepaid0
@ -184,6 +184,13 @@ msgid ""
" </p>\n"
" "
msgstr ""
"<p class=\"oe_view_nocontent_create\">\n"
" Щелкните, чтобы добавить отчетный период.\n"
" </p><p>\n"
" Отчетный период как правило - месяц или квартал .\n"
" Обычно он соответствует периодам налоговой декларации.\n"
" </p>\n"
" "
#. module: account
#: model:ir.actions.act_window,name:account.action_view_created_invoice_dashboard

View File

@ -6,11 +6,6 @@
<field name="name">Sales</field>
<field name="type">sale</field>
</record>
<record id="exp" model="account.analytic.journal">
<field name="code">PUR</field>
<field name="name">Purchases</field>
<field name="type">purchase</field>
</record>
<record id="sit" model="account.analytic.journal">
<field name="code">START</field>
<field name="name">Miscellaneous Operation</field>

View File

@ -0,0 +1,27 @@
.openerp .oe_force_bold {
font-weight: bold !important;
}
.openerp label.oe_open_balance{
margin-right: -18px;
}
.openerp label.oe_subtotal_footer_separator{
float:right;
width: 184px !important;
}
.openerp label.oe_mini_subtotal_footer_separator{
margin-right: -14px;
}
.openerp .oe_account_total, .openerp .oe_pos_total {
margin-left: -2px;
}
.openerp label.oe_real_closing_balance{
min-width: 184px !important;
}
.openerp label.oe_difference, .openerp label.oe_pos_difference {
margin-right: -10px;
padding-left: 10px !important;
min-width: 195px !important;
}
.openerp .oe_opening_total{
margin-right: 4px;
}

View File

@ -450,6 +450,7 @@ class account_analytic_account(osv.osv):
'is_overdue_quantity' : fields.function(_is_overdue_quantity, method=True, type='boolean', string='Overdue Quantity',
store={
'account.analytic.line' : (_get_analytic_account, None, 20),
'account.analytic.account': (lambda self, cr, uid, ids, c=None: ids, ['quantity_max'], 10),
}),
'ca_invoiced': fields.function(_ca_invoiced_calc, type='float', string='Invoiced Amount',
help="Total customer invoiced amount for this account.",

View File

@ -0,0 +1,607 @@
# Slovak translation for openobject-addons
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
"PO-Revision-Date: 2014-01-04 11:30+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Slovak <sk@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-01-05 05:26+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "No order to invoice, create"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Group By..."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "To Invoice"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Remaining"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Contracts in progress"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,last_worked_invoiced_date:0
msgid ""
"If invoice from the costs, this is the date of the latest work or cost that "
"have been invoiced."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,last_worked_date:0
msgid "Date of Last Cost/Work"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_to_invoice:0
msgid "Uninvoiced Amount"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid ""
"When invoicing on timesheet, OpenERP uses the\n"
" pricelist of the contract which uses the price\n"
" defined on the product related to each employee "
"to\n"
" define the customer invoice price rate."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "⇒ Invoice"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_invoiced:0
msgid "Invoiced Amount"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,last_worked_invoiced_date:0
msgid "Date of Last Invoiced Cost"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,fix_price_to_invoice:0
msgid "Sum of quotations for this contract."
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_invoiced:0
msgid "Total customer invoiced amount for this account."
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,timesheet_ca_invoiced:0
msgid "Sum of timesheet lines invoiced for this contract."
msgstr ""
#. module: account_analytic_analysis
#: code:addons/account_analytic_analysis/account_analytic_analysis.py:464
#, python-format
msgid "Sales Order Lines of %s"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,revenue_per_hour:0
msgid "Computed using the formula: Invoiced Amount / Total Time"
msgstr ""
#. module: account_analytic_analysis
#: field:account_analytic_analysis.summary.month,account_id:0
#: field:account_analytic_analysis.summary.user,account_id:0
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_account
msgid "Analytic Account"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Partner"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Contracts that are not assigned to an account manager."
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,help:account_analytic_analysis.action_account_analytic_overdue
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to define a new contract.\n"
" </p><p>\n"
" You will find here the contracts to be renewed because the\n"
" end date is passed or the working effort is higher than the\n"
" maximum authorized one.\n"
" </p><p>\n"
" OpenERP automatically sets contracts to be renewed in a "
"pending\n"
" state. After the negociation, the salesman should close or "
"renew\n"
" pending contracts.\n"
" </p>\n"
" "
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "End Date"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Account Manager"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,remaining_hours_to_invoice:0
msgid "Computed using the formula: Maximum Time - Total Invoiced Time"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Expected"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Contracts not assigned"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,theorical_margin:0
msgid "Computed using the formula: Theoretical Revenue - Total Costs"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_qtt_invoiced:0
msgid "Invoiced Time"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,fix_price_to_invoice:0
#: field:account.analytic.account,remaining_hours:0
#: field:account.analytic.account,remaining_hours_to_invoice:0
#: field:account.analytic.account,timesheet_ca_invoiced:0
msgid "Remaining Time"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid ""
"{'required': [('type','=','contract')], 'invisible': [('type','in',['view', "
"'normal','template'])]}"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,real_margin_rate:0
msgid "Real Margin Rate (%)"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,remaining_hours:0
msgid "Computed using the formula: Maximum Time - Total Worked Time"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,hours_quantity:0
msgid ""
"Number of time you spent on the analytic account (from timesheet). It "
"computes quantities on all journal of type 'general'."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Nothing to invoice, create"
msgstr ""
#. module: account_analytic_analysis
#: model:res.groups,name:account_analytic_analysis.group_template_required
msgid "Mandatory use of templates in contracts"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_quantity:0
msgid "Total Worked Time"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,real_margin:0
msgid "Real Margin"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_analysis_summary_month
msgid "Hours summary by month"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,real_margin_rate:0
msgid "Computes using the formula: (Real Margin / Total Costs) * 100."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "or view"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Customer Contracts"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Parent"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,month_ids:0
#: field:account_analytic_analysis.summary.month,month:0
msgid "Month"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_hr_tree_invoiced_all
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_hr_tree_invoiced_all
msgid "Time & Materials to Invoice"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_overdue_all
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_overdue_all
msgid "Contracts"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Start Date"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Invoiced"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid ""
"The contracts to be renewed because the deadline is passed or the working "
"hours are higher than the allocated hours"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Pending contracts to renew with your customer"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Timesheets"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,hours_qtt_non_invoiced:0
msgid ""
"Number of time (hours/days) (from journal of type 'general') that can be "
"invoiced if you invoice based on analytic account."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Pending"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,is_overdue_quantity:0
msgid "Overdue Quantity"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Status"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,ca_theorical:0
msgid "Theoretical Revenue"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "To Renew"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid ""
"A contract in OpenERP is an analytic account having a partner set on it."
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
#: model:ir.actions.act_window,name:account_analytic_analysis.action_sales_order
msgid "Sales Orders"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,last_invoice_date:0
msgid "If invoice from the costs, this is the date of the latest invoiced."
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_theorical:0
msgid ""
"Based on the costs you had on the project, what would have been the revenue "
"if all these costs have been invoiced at the normal sale price provided by "
"the pricelist."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,user_ids:0
#: field:account_analytic_analysis.summary.user,user:0
msgid "User"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,help:account_analytic_analysis.template_of_contract_action
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click here to create a template of contract.\n"
" </p><p>\n"
" Templates are used to prefigure contract/project that \n"
" can be selected by the salespeople to quickly configure "
"the\n"
" terms and conditions of the contract.\n"
" </p>\n"
" "
msgstr ""
#. module: account_analytic_analysis
#: model:ir.model,name:account_analytic_analysis.model_account_analytic_analysis_summary_user
msgid "Hours Summary by User"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Contract"
msgstr ""
#. module: account_analytic_analysis
#: help:sale.config.settings,group_template_required:0
msgid ""
"Allows you to set the template field as required when creating an analytic "
"account or a contract."
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,hours_qtt_invoiced:0
msgid ""
"Number of time (hours/days) that can be invoiced plus those that already "
"have been invoiced."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,revenue_per_hour:0
msgid "Revenue per Time (real)"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,help:account_analytic_analysis.action_account_analytic_overdue_all
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to create a new contract.\n"
" </p><p>\n"
" Use contracts to follow tasks, issues, timesheets or "
"invoicing based on\n"
" work done, expenses and/or sales orders. OpenERP will "
"automatically manage\n"
" the alerts for the renewal of the contracts to the right "
"salesperson.\n"
" </p>\n"
" "
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,toinvoice_total:0
msgid "Total to Invoice"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Sale Orders"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Open"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,invoiced_total:0
msgid "Total Invoiced"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,remaining_ca:0
msgid "Computed using the formula: Max Invoice Price - Invoiced Amount."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,last_invoice_date:0
msgid "Last Invoice Date"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Units Remaining"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,help:account_analytic_analysis.action_hr_tree_invoiced_all
msgid ""
"<p>\n"
" You will find here timesheets and purchases you did for\n"
" contracts that can be reinvoiced to the customer. If you "
"want\n"
" to record new activities to invoice, you should use the "
"timesheet\n"
" menu instead.\n"
" </p>\n"
" "
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_qtt_non_invoiced:0
msgid "Uninvoiced Time"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Invoicing"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,total_cost:0
msgid "Total Costs"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,remaining_total:0
msgid ""
"Expectation of remaining income for this contract. Computed as the sum of "
"remaining subtotals which, in turn, are computed as the maximum between "
"'(Estimation - Invoiced)' and 'To Invoice' amounts"
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.action_account_analytic_overdue
#: model:ir.ui.menu,name:account_analytic_analysis.menu_action_account_analytic_overdue
msgid "Contracts to Renew"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,toinvoice_total:0
msgid " Sum of everything that could be invoiced for this contract."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,theorical_margin:0
msgid "Theoretical Margin"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,remaining_total:0
msgid "Total Remaining"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,real_margin:0
msgid "Computed using the formula: Invoiced Amount - Total Costs."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,hours_qtt_est:0
msgid "Estimation of Hours to Invoice"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,fix_price_invoices:0
msgid "Fixed Price"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,last_worked_date:0
msgid "Date of the latest work done on this account."
msgstr ""
#. module: account_analytic_analysis
#: model:ir.model,name:account_analytic_analysis.model_sale_config_settings
msgid "sale.config.settings"
msgstr ""
#. module: account_analytic_analysis
#: field:sale.config.settings,group_template_required:0
msgid "Mandatory use of templates."
msgstr ""
#. module: account_analytic_analysis
#: model:ir.actions.act_window,name:account_analytic_analysis.template_of_contract_action
#: model:ir.ui.menu,name:account_analytic_analysis.menu_template_of_contract_action
msgid "Contract Template"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Units Done"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,total_cost:0
msgid ""
"Total of costs for this account. It includes real costs (from invoices) and "
"indirect costs, like time spent on timesheets."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,est_total:0
msgid "Total Estimation"
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,remaining_ca:0
msgid "Remaining Revenue"
msgstr ""
#. module: account_analytic_analysis
#: help:account.analytic.account,ca_to_invoice:0
msgid ""
"If invoice from analytic account, the remaining amount you can invoice to "
"the customer based on the total costs."
msgstr ""
#. module: account_analytic_analysis
#: field:account_analytic_analysis.summary.month,unit_amount:0
#: field:account_analytic_analysis.summary.user,unit_amount:0
msgid "Total Time"
msgstr ""
#. module: account_analytic_analysis
#: model:res.groups,comment:account_analytic_analysis.group_template_required
msgid ""
"the field template of the analytic accounts and contracts will be required."
msgstr ""
#. module: account_analytic_analysis
#: field:account.analytic.account,invoice_on_timesheets:0
msgid "On Timesheets"
msgstr ""
#. module: account_analytic_analysis
#: view:account.analytic.account:0
msgid "Total"
msgstr ""

View File

@ -270,6 +270,20 @@
</xpath>
</field>
</record>
<record id="view_bank_statement_inherit_form2" model="ir.ui.view">
<field name="name">account.bank.statement.form.inherit</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form2"/>
<field name="arch" type="xml">
<xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/tree/field[@name='analytic_account_id']" position="replace">
<field name="analytics_id" groups="analytic.group_analytic_accounting"/>
</xpath>
<xpath expr="/form/sheet/notebook/page/field[@name='line_ids']/form/group/field[@name='analytic_account_id']" position="replace">
<field name="analytics_id" groups="analytic.group_analytic_accounting"/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -115,7 +115,7 @@
- product_id: product.product_product_3
product_qty: 1
price_unit: 10
date_planned: '2013-08-31'
date_planned: !eval "'%s' % (time.strftime('%Y-%m-%d'))"
-
I confirm the purchase order.
-
@ -235,7 +235,7 @@
As the Invoice state of the picking order is To be invoiced. I create invoice for my outgoing picking order.
-
!python {model: stock.invoice.onshipping}: |
wiz_id = self.create(cr, uid, {'invoice_date': '2013-03-04', 'journal_id': ref('account.sales_journal')},
wiz_id = self.create(cr, uid, {'journal_id': ref('account.sales_journal')},
{'active_ids': [ref("stock_picking_out001")], "active_model": "stock.picking"})
self.create_invoice(cr, uid, [wiz_id], {"lang": "en_US",
"search_default_available": 1, "tz": False, "active_model": "stock.picking",

View File

@ -122,7 +122,7 @@
- product_id: product_fifo_anglo_saxon
product_qty: 1
price_unit: 9
date_planned: '2013-08-31'
date_planned: !eval "'%s' % (time.strftime('%Y-%m-%d'))"
taxes_id: []
-
I confirm the purchase order.
@ -237,7 +237,7 @@
As the Invoice state of the picking order is To be invoiced. I create invoice for my outgoing picking order.
-
!python {model: stock.invoice.onshipping}: |
wiz_id = self.create(cr, uid, {'invoice_date': '2013-03-04', 'journal_id': ref('account.sales_journal')},
wiz_id = self.create(cr, uid, {'journal_id': ref('account.sales_journal')},
{'active_ids': [ref("stock_picking_out001_fifo")], "active_model": "stock.picking"})
self.create_invoice(cr, uid, [wiz_id], {"lang": "en_US",
"search_default_available": 1, "tz": False, "active_model": "stock.picking",

View File

@ -7,19 +7,19 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2011-01-11 11:14+0000\n"
"PO-Revision-Date: 2012-08-19 10:21+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"PO-Revision-Date: 2013-12-29 09:12+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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 06:05+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: account_chart
#: model:ir.module.module,description:account_chart.module_meta_information
msgid "Remove minimal account chart"
msgstr "移除小的會計科目表"
msgstr "移除小的會計科目表"
#. module: account_chart
#: model:ir.module.module,shortdesc:account_chart.module_meta_information

View File

@ -49,9 +49,21 @@ class account_voucher(osv.osv):
if 'value' in default:
amount = 'amount' in default['value'] and default['value']['amount'] or amount
# Currency complete name is not available in res.currency model
# Exceptions done here (EUR, USD, BRL) cover 75% of cases
# For other currencies, display the currency code
currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context)
if currency.name.upper() == 'EUR':
currency_name = 'Euro'
elif currency.name.upper() == 'USD':
currency_name = 'Dollars'
elif currency.name.upper() == 'BRL':
currency_name = 'reais'
else:
currency_name = currency.name
#TODO : generic amount_to_text is not ready yet, otherwise language (and country) and currency can be passed
#amount_in_word = amount_to_text(amount, context=context)
amount_in_word = amount_to_text(amount)
amount_in_word = amount_to_text(amount, currency=currency_name)
default['value'].update({'amount_in_word':amount_in_word})
if journal_id:
allow_check_writing = self.pool.get('account.journal').browse(cr, uid, journal_id, context=context).allow_check_writing

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2012-08-22 06:48+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"PO-Revision-Date: 2013-12-29 09:09+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\n"
"Language-Team: Cenoq\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 06:35+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: account_check_writing
#: selection:res.company,check_layout:0
@ -56,13 +56,13 @@ msgstr "支票位於底部"
#. module: account_check_writing
#: model:ir.actions.act_window,name:account_check_writing.action_account_check_write
msgid "Print Check in Batch"
msgstr ""
msgstr "整批列印支票"
#. module: account_check_writing
#: code:addons/account_check_writing/wizard/account_check_batch_printing.py:59
#, python-format
msgid "One of the printed check already got a number."
msgstr ""
msgstr "已列印的支票中有一張已有號碼。"
#. module: account_check_writing
#: help:account.journal,allow_check_writing:0
@ -109,7 +109,7 @@ msgstr "原始金額"
#. module: account_check_writing
#: field:res.company,check_layout:0
msgid "Check Layout"
msgstr ""
msgstr "支票格式"
#. module: account_check_writing
#: field:account.voucher,allow_check:0
@ -131,7 +131,7 @@ msgstr "使用套表列印的支票"
#. module: account_check_writing
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_bottom
msgid "Print Check (Bottom)"
msgstr ""
msgstr "列印支票(底端)"
#. module: account_check_writing
#: model:ir.actions.act_window,help:account_check_writing.action_write_check
@ -160,7 +160,7 @@ msgstr "到期日期"
#. module: account_check_writing
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_middle
msgid "Print Check (Middle)"
msgstr ""
msgstr "列印支票(中間)"
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_res_company
@ -171,12 +171,12 @@ msgstr "公司"
#: code:addons/account_check_writing/wizard/account_check_batch_printing.py:59
#, python-format
msgid "Error!"
msgstr ""
msgstr "錯誤!"
#. module: account_check_writing
#: help:account.check.write,check_number:0
msgid "The number of the next check number to be printed."
msgstr ""
msgstr "下一張列印的支票的號碼"
#. module: account_check_writing
#: report:account.print.check.bottom:0
@ -187,7 +187,7 @@ msgstr "截止餘額"
#. module: account_check_writing
#: model:ir.actions.report.xml,name:account_check_writing.account_print_check_top
msgid "Print Check (Top)"
msgstr ""
msgstr "列印支票(頂端)"
#. module: account_check_writing
#: report:account.print.check.bottom:0
@ -204,7 +204,7 @@ msgstr "手工憑證"
#. module: account_check_writing
#: view:account.check.write:0
msgid "or"
msgstr ""
msgstr ""
#. module: account_check_writing
#: field:account.voucher,amount_in_word:0
@ -214,22 +214,22 @@ msgstr "金額大寫"
#. module: account_check_writing
#: model:ir.model,name:account_check_writing.model_account_check_write
msgid "Prin Check in Batch"
msgstr ""
msgstr "整批列印支票"
#. module: account_check_writing
#: view:account.check.write:0
msgid "Cancel"
msgstr ""
msgstr "取消"
#. module: account_check_writing
#: field:account.check.write,check_number:0
msgid "Next Check Number"
msgstr ""
msgstr "下一個支票號碼"
#. module: account_check_writing
#: view:account.check.write:0
msgid "Check"
msgstr ""
msgstr "支票"
#~ msgid ""
#~ "The check payment form allows you to track the payment you do to your "

View File

@ -34,7 +34,6 @@ class report_print_check(report_sxw.rml_parse):
'fill_stars' : self.fill_stars,
})
def fill_stars(self, amount):
amount = amount.replace('Dollars','')
if len(amount) < 100:
stars = 100 - len(amount)
return ' '.join([amount,'*'*stars])

View File

@ -7,14 +7,14 @@ 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:05+0000\n"
"PO-Revision-Date: 2012-08-24 12:49+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"PO-Revision-Date: 2013-12-24 10:29+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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:21+0000\n"
"X-Generator: Launchpad (build 16761)\n"
"X-Launchpad-Export-Date: 2013-12-25 06:02+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: account_followup
#: model:email.template,subject:account_followup.email_template_account_followup_default
@ -22,12 +22,12 @@ msgstr ""
#: model:email.template,subject:account_followup.email_template_account_followup_level1
#: model:email.template,subject:account_followup.email_template_account_followup_level2
msgid "${user.company_id.name} Payment Reminder"
msgstr ""
msgstr "${user.company_id.name} 提醒付款"
#. module: account_followup
#: help:res.partner,latest_followup_level_id:0
msgid "The maximum follow-up level"
msgstr ""
msgstr "最大後續追蹤層級"
#. module: account_followup
#: view:account_followup.stat:0
@ -48,13 +48,13 @@ msgstr ""
#. module: account_followup
#: field:res.partner,payment_next_action_date:0
msgid "Next Action Date"
msgstr ""
msgstr "下個動作日期"
#. module: account_followup
#: view:account_followup.followup.line:0
#: field:account_followup.followup.line,manual_action:0
msgid "Manual Action"
msgstr ""
msgstr "手動動作"
#. module: account_followup
#: field:account_followup.sending.results,needprinting:0
@ -64,7 +64,7 @@ msgstr ""
#. module: account_followup
#: view:res.partner:0
msgid "⇾ Mark as Done"
msgstr ""
msgstr "⇾ 標為已完成"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_note:0
@ -104,17 +104,17 @@ msgstr ""
#. module: account_followup
#: view:account_followup.followup.line:0
msgid "Follow-up Steps"
msgstr ""
msgstr "後續追蹤步驟"
#. module: account_followup
#: field:account_followup.print,email_body:0
msgid "Email Body"
msgstr ""
msgstr "Email內文"
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_account_followup_print
msgid "Send Follow-Ups"
msgstr ""
msgstr "送出後續追蹤"
#. module: account_followup
#: report:account_followup.followup.print:0
@ -133,7 +133,7 @@ msgstr ""
#. module: account_followup
#: view:res.partner:0
msgid "No Responsible"
msgstr ""
msgstr "沒有負責人"
#. module: account_followup
#: model:account_followup.followup.line,description:account_followup.demo_followup_line2
@ -209,17 +209,17 @@ msgstr "借方合計"
#. module: account_followup
#: field:res.partner,payment_next_action:0
msgid "Next Action"
msgstr ""
msgstr "下個動作"
#. module: account_followup
#: view:account_followup.followup.line:0
msgid ": Partner Name"
msgstr ""
msgstr "業務夥伴名稱"
#. module: account_followup
#: field:account_followup.followup.line,manual_action_responsible_id:0
msgid "Assign a Responsible"
msgstr ""
msgstr "指定一負責人"
#. module: account_followup
#: view:account_followup.followup:0
@ -269,7 +269,7 @@ msgstr "合夥人"
#. module: account_followup
#: sql_constraint:account_followup.followup:0
msgid "Only one follow-up per company is allowed"
msgstr ""
msgstr "一間公司僅允許一項後續追蹤"
#. module: account_followup
#: code:addons/account_followup/wizard/account_followup_print.py:254
@ -300,7 +300,7 @@ msgstr ""
#. module: account_followup
#: model:ir.actions.act_window,name:account_followup.action_customer_followup
msgid "Manual Follow-Ups"
msgstr ""
msgstr "手動後續追蹤"
#. module: account_followup
#: view:account_followup.followup.line:0
@ -356,12 +356,12 @@ msgstr "借方"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_stat
msgid "Follow-up Statistics"
msgstr ""
msgstr "後續追蹤統計分析"
#. module: account_followup
#: view:res.partner:0
msgid "Send Overdue Email"
msgstr ""
msgstr "送出帳務逾期通知信"
#. module: account_followup
#: model:ir.model,name:account_followup.model_account_followup_followup_line

View File

@ -41,7 +41,7 @@
<field name="journal"/>
<field name="bank_id" domain="[('partner_id','=',partner_id)]" />
<field name="company_id" widget='selection' groups="base.group_multi_company" on_change="onchange_company_id(company_id)"/>
<field name="partner_id" widget='selection' invisible="1"/>
<field name="partner_id" invisible="1"/>
</group>
</form>
</field>

View File

@ -7,14 +7,14 @@ 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:05+0000\n"
"PO-Revision-Date: 2012-08-29 15:27+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"PO-Revision-Date: 2013-12-29 09:05+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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:48+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: account_payment
#: model:ir.actions.act_window,help:account_payment.action_payment_order_tree
@ -106,7 +106,7 @@ msgstr "到期日"
#. module: account_payment
#: view:payment.order.create:0
msgid "_Add to payment order"
msgstr ""
msgstr "新增至付款單"
#. module: account_payment
#: model:ir.actions.act_window,name:account_payment.action_account_payment_populate_statement
@ -127,7 +127,7 @@ msgstr ""
#: code:addons/account_payment/account_move_line.py:110
#, python-format
msgid "Error!"
msgstr ""
msgstr "錯誤!"
#. module: account_payment
#: report:payment.order:0
@ -148,7 +148,7 @@ msgstr "取消"
#. module: account_payment
#: model:ir.actions.act_window,name:account_payment.action_payment_order_tree_new
msgid "New Payment Order"
msgstr ""
msgstr "新增付款單"
#. module: account_payment
#: report:payment.order:0
@ -165,12 +165,12 @@ msgstr ""
#: model:ir.actions.act_window,name:account_payment.action_payment_order_tree
#: model:ir.ui.menu,name:account_payment.menu_action_payment_order_form
msgid "Payment Orders"
msgstr ""
msgstr "付款單"
#. module: account_payment
#: selection:payment.order,date_prefered:0
msgid "Directly"
msgstr ""
msgstr "直接"
#. module: account_payment
#: model:ir.actions.act_window,name:account_payment.action_payment_line_form
@ -217,7 +217,7 @@ msgstr ""
#. module: account_payment
#: view:account.bank.statement:0
msgid "Import Payment Lines"
msgstr ""
msgstr "匯入付款細項"
#. module: account_payment
#: view:payment.line:0
@ -256,17 +256,17 @@ msgstr ""
#. module: account_payment
#: field:payment.order,date_created:0
msgid "Creation Date"
msgstr ""
msgstr "建立日期"
#. module: account_payment
#: help:payment.mode,journal:0
msgid "Bank or Cash Journal for the Payment Mode"
msgstr ""
msgstr "付款模式的銀行或現金日記帳簿"
#. module: account_payment
#: selection:payment.order,date_prefered:0
msgid "Fixed date"
msgstr ""
msgstr "固定日期"
#. module: account_payment
#: field:payment.line,info_partner:0
@ -282,12 +282,12 @@ msgstr "目的帳號"
#. module: account_payment
#: view:payment.order:0
msgid "Search Payment Orders"
msgstr ""
msgstr "搜尋付款單"
#. module: account_payment
#: field:payment.line,create_date:0
msgid "Created"
msgstr ""
msgstr "已建立"
#. module: account_payment
#: view:payment.order:0
@ -394,7 +394,7 @@ msgstr "草稿"
#: view:payment.order:0
#: field:payment.order,state:0
msgid "Status"
msgstr ""
msgstr "狀態"
#. module: account_payment
#: help:payment.line,communication2:0
@ -424,7 +424,7 @@ msgstr "付款明細"
#. module: account_payment
#: model:ir.model,name:account_payment.model_account_move_line
msgid "Journal Items"
msgstr ""
msgstr "日記簿項目"
#. module: account_payment
#: help:payment.line,move_line_id:0
@ -441,7 +441,7 @@ msgstr "搜尋"
#. module: account_payment
#: field:payment.order,user_id:0
msgid "Responsible"
msgstr ""
msgstr "負責人"
#. module: account_payment
#: field:payment.line,date:0
@ -456,7 +456,7 @@ msgstr "總計:"
#. module: account_payment
#: field:payment.order,date_done:0
msgid "Execution Date"
msgstr ""
msgstr "執行日期"
#. module: account_payment
#: view:account.payment.populate.statement:0
@ -501,7 +501,7 @@ msgstr "您的參考"
#. module: account_payment
#: view:payment.order:0
msgid "Payment order"
msgstr ""
msgstr "付款單"
#. module: account_payment
#: view:payment.line:0
@ -535,7 +535,7 @@ msgstr "取消"
#. module: account_payment
#: field:payment.line,bank_id:0
msgid "Destination Bank Account"
msgstr ""
msgstr "目的銀行帳戶"
#. module: account_payment
#: view:payment.line:0
@ -548,7 +548,7 @@ msgstr "資訊"
#: model:ir.model,name:account_payment.model_payment_order
#: view:payment.order:0
msgid "Payment Order"
msgstr ""
msgstr "付款單"
#. module: account_payment
#: help:payment.line,amount:0
@ -573,7 +573,7 @@ msgstr "通訊 2"
#. module: account_payment
#: field:payment.order,date_scheduled:0
msgid "Scheduled Date"
msgstr ""
msgstr "預定日期"
#. module: account_payment
#: view:account.payment.make.payment:0
@ -584,7 +584,7 @@ msgstr "是否進行付款?"
#: view:payment.mode:0
#: field:payment.mode,journal:0
msgid "Journal"
msgstr ""
msgstr "帳簿"
#. module: account_payment
#: field:payment.mode,bank_id:0
@ -612,12 +612,12 @@ msgstr "付款"
#. module: account_payment
#: report:payment.order:0
msgid "Payment Order / Payment"
msgstr ""
msgstr "付款單 / 付款"
#. module: account_payment
#: field:payment.line,move_line_id:0
msgid "Entry line"
msgstr ""
msgstr "分錄細項"
#. module: account_payment
#: help:payment.line,communication:0
@ -640,7 +640,7 @@ msgstr "銀行帳戶"
#: view:payment.line:0
#: view:payment.order:0
msgid "Entry Information"
msgstr ""
msgstr "分錄資訊"
#. module: account_payment
#: model:ir.model,name:account_payment.model_payment_order_create
@ -673,7 +673,7 @@ msgstr ""
#: view:account.payment.populate.statement:0
#: view:payment.order.create:0
msgid "or"
msgstr ""
msgstr ""
#. module: account_payment
#: help:payment.mode,bank_id:0

View File

@ -746,7 +746,7 @@ class account_voucher(osv.osv):
ids = context['move_line_ids']
invoice_id = context.get('invoice_id', False)
company_currency = journal.company_id.currency_id.id
move_line_found = False
move_lines_found = []
#order the lines by most old first
ids.reverse()
@ -761,21 +761,20 @@ class account_voucher(osv.osv):
if line.invoice.id == invoice_id:
#if the invoice linked to the voucher line is equal to the invoice_id in context
#then we assign the amount on that line, whatever the other voucher lines
move_line_found = line.id
break
move_lines_found.append(line.id)
elif currency_id == company_currency:
#otherwise treatments is the same but with other field names
if line.amount_residual == price:
#if the amount residual is equal the amount voucher, we assign it to that voucher
#line, whatever the other voucher lines
move_line_found = line.id
move_lines_found.append(line.id)
break
#otherwise we will split the voucher amount on each line (by most old first)
total_credit += line.credit or 0.0
total_debit += line.debit or 0.0
elif currency_id == line.currency_id.id:
if line.amount_residual_currency == price:
move_line_found = line.id
move_lines_found.append(line.id)
break
total_credit += line.credit and line.amount_currency or 0.0
total_debit += line.debit and line.amount_currency or 0.0
@ -800,15 +799,16 @@ class account_voucher(osv.osv):
'move_line_id':line.id,
'account_id':line.account_id.id,
'amount_original': amount_original,
'amount': (move_line_found == line.id) and min(abs(price), amount_unreconciled) or 0.0,
'amount': (line.id in move_lines_found) and min(abs(price), amount_unreconciled) or 0.0,
'date_original':line.date,
'date_due':line.date_maturity,
'amount_unreconciled': amount_unreconciled,
'currency_id': line_currency_id,
}
price -= rs['amount']
#in case a corresponding move_line hasn't been found, we now try to assign the voucher amount
#on existing invoices: we split voucher amount by most old first, but only for lines in the same currency
if not move_line_found:
if not move_lines_found:
if currency_id == line_currency_id:
if line.credit:
amount = min(amount_unreconciled, abs(total_debit))

View File

@ -7,19 +7,19 @@ 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-08-28 02:30+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"PO-Revision-Date: 2013-12-29 08:26+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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:59+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: account_voucher
#: field:account.bank.statement.line,voucher_id:0
msgid "Reconciliation"
msgstr ""
msgstr "核銷"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_config_settings
@ -63,7 +63,7 @@ msgstr "計算公式 憑證上输入的金额 - 憑證行的金额合計."
#. module: account_voucher
#: view:account.voucher:0
msgid "(Update)"
msgstr ""
msgstr "(更新)"
#. module: account_voucher
#: view:account.voucher:0
@ -90,7 +90,7 @@ msgstr "三月"
#. module: account_voucher
#: field:account.voucher,message_unread:0
msgid "Unread Messages"
msgstr ""
msgstr "未讀訊息"
#. module: account_voucher
#: view:account.voucher:0
@ -100,7 +100,7 @@ msgstr "付賬"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure you want to cancel this receipt?"
msgstr ""
msgstr "你確定要取消這張收據嗎?"
#. module: account_voucher
#: view:account.voucher:0
@ -121,7 +121,7 @@ msgstr "依發票年份分組"
#: view:sale.receipt.report:0
#: field:sale.receipt.report,user_id:0
msgid "Salesperson"
msgstr ""
msgstr "業務人員"
#. module: account_voucher
#: view:account.voucher:0
@ -134,7 +134,7 @@ msgstr "換領券統計"
msgid ""
"You can not change the journal as you already reconciled some statement "
"lines!"
msgstr ""
msgstr "你已經核銷部分項目,所以無法變更日記帳簿!"
#. module: account_voucher
#: view:account.voucher:0
@ -145,7 +145,7 @@ msgstr "驗證"
#: model:ir.actions.act_window,name:account_voucher.action_vendor_payment
#: model:ir.ui.menu,name:account_voucher.menu_action_vendor_payment
msgid "Supplier Payments"
msgstr ""
msgstr "供應商付款"
#. module: account_voucher
#: model:ir.actions.act_window,help:account_voucher.action_purchase_receipt
@ -207,13 +207,13 @@ msgstr "備註"
#. module: account_voucher
#: field:account.voucher,message_ids:0
msgid "Messages"
msgstr ""
msgstr "訊息"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_purchase_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_purchase_receipt
msgid "Purchase Receipts"
msgstr ""
msgstr "採購單據"
#. module: account_voucher
#: field:account.voucher.line,move_line_id:0
@ -225,7 +225,7 @@ msgstr "會計憑證行"
#: code:addons/account_voucher/account_voucher.py:1073
#, python-format
msgid "Error!"
msgstr ""
msgstr "錯誤!"
#. module: account_voucher
#: field:account.voucher.line,amount:0
@ -271,7 +271,7 @@ msgstr ""
#. module: account_voucher
#: help:account.voucher,message_unread:0
msgid "If checked new messages require your attention."
msgstr ""
msgstr "當有新訊息時通知您。"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_bank_statement_line
@ -294,7 +294,7 @@ msgstr "稅"
#: code:addons/account_voucher/account_voucher.py:971
#, python-format
msgid "Invalid Action!"
msgstr ""
msgstr "無效的動作!"
#. module: account_voucher
#: field:account.voucher,comment:0
@ -326,7 +326,7 @@ msgstr "付款資料"
#. module: account_voucher
#: view:account.voucher:0
msgid "(update)"
msgstr ""
msgstr "(更新)"
#. module: account_voucher
#: view:account.voucher:0
@ -395,7 +395,7 @@ msgstr "供應商換領券"
#. module: account_voucher
#: field:account.voucher,message_follower_ids:0
msgid "Followers"
msgstr ""
msgstr "關注者"
#. module: account_voucher
#: selection:account.voucher.line,type:0
@ -406,7 +406,7 @@ msgstr "借方"
#: code:addons/account_voucher/account_voucher.py:1641
#, python-format
msgid "Unable to change journal !"
msgstr ""
msgstr "無法變更日記帳簿!"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -544,7 +544,7 @@ msgstr ""
#: field:account.config.settings,expense_currency_exchange_account_id:0
#: field:res.company,expense_currency_exchange_account_id:0
msgid "Loss Exchange Rate Account"
msgstr ""
msgstr "匯損科目"
#. module: account_voucher
#: view:account.voucher:0
@ -587,7 +587,7 @@ msgstr "支出明細"
#. module: account_voucher
#: view:account.voucher:0
msgid "Sale voucher"
msgstr ""
msgstr "銷售單據"
#. module: account_voucher
#: help:account.voucher,is_multi_currency:0
@ -599,7 +599,7 @@ msgstr "此字段由系統內部使用,區分該憑證是否涉及外幣"
#. module: account_voucher
#: view:account.invoice:0
msgid "Register Payment"
msgstr ""
msgstr "登記付款紀錄"
#. module: account_voucher
#: field:account.statement.from.invoice.lines,line_ids:0
@ -638,17 +638,17 @@ msgstr "應收應付"
#. module: account_voucher
#: view:account.voucher:0
msgid "Voucher Payment"
msgstr ""
msgstr "付款單據"
#. module: account_voucher
#: field:sale.receipt.report,state:0
msgid "Voucher Status"
msgstr ""
msgstr "單據狀態"
#. module: account_voucher
#: view:account.voucher:0
msgid "Are you sure to unreconcile this record?"
msgstr ""
msgstr "你是否要取消核銷此紀錄?"
#. module: account_voucher
#: field:account.voucher,company_id:0
@ -672,7 +672,7 @@ msgstr "核銷付款餘額"
#: code:addons/account_voucher/account_voucher.py:1067
#, python-format
msgid "Configuration Error !"
msgstr ""
msgstr "設置錯誤!"
#. module: account_voucher
#: view:account.voucher:0
@ -689,14 +689,14 @@ msgstr "連稅總額"
#. module: account_voucher
#: view:account.voucher:0
msgid "Purchase Voucher"
msgstr ""
msgstr "採購單據"
#. module: account_voucher
#: view:account.voucher:0
#: field:account.voucher,state:0
#: view:sale.receipt.report:0
msgid "Status"
msgstr ""
msgstr "狀態"
#. module: account_voucher
#: view:account.voucher:0
@ -707,7 +707,7 @@ msgstr "分配"
#: view:account.statement.from.invoice.lines:0
#: view:account.voucher:0
msgid "or"
msgstr ""
msgstr ""
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -717,7 +717,7 @@ msgstr "八月"
#. module: account_voucher
#: view:account.voucher:0
msgid "Validate Payment"
msgstr ""
msgstr "認可付款"
#. module: account_voucher
#: help:account.voucher,audit:0
@ -756,12 +756,12 @@ msgstr "已付款"
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_sale_receipt
msgid "Sales Receipts"
msgstr ""
msgstr "銷售收據"
#. module: account_voucher
#: field:account.voucher,message_is_follower:0
msgid "Is a Follower"
msgstr ""
msgstr "為關注者"
#. module: account_voucher
#: field:account.voucher,analytic_id:0
@ -815,7 +815,7 @@ msgstr "預付款?"
#: code:addons/account_voucher/account_voucher.py:1208
#, python-format
msgid "The invoice you are willing to pay is not valid anymore."
msgstr ""
msgstr "你要付款的發票已經不再有效。"
#. module: account_voucher
#: selection:sale.receipt.report,month:0
@ -836,12 +836,12 @@ msgstr "公司"
#. module: account_voucher
#: field:account.voucher,message_summary:0
msgid "Summary"
msgstr ""
msgstr "摘要"
#. module: account_voucher
#: field:account.voucher,active:0
msgid "Active"
msgstr ""
msgstr "啟用"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1074
@ -854,14 +854,14 @@ msgstr ""
#: model:ir.actions.act_window,name:account_voucher.action_vendor_receipt
#: model:ir.ui.menu,name:account_voucher.menu_action_vendor_receipt
msgid "Customer Payments"
msgstr ""
msgstr "客戶付款"
#. module: account_voucher
#: model:ir.actions.act_window,name:account_voucher.action_sale_receipt_report_all
#: model:ir.ui.menu,name:account_voucher.menu_action_sale_receipt_report_all
#: view:sale.receipt.report:0
msgid "Sales Receipts Analysis"
msgstr ""
msgstr "銷售收據分析"
#. module: account_voucher
#: view:sale.receipt.report:0
@ -956,7 +956,7 @@ msgstr "取消"
#. module: account_voucher
#: model:ir.actions.client,name:account_voucher.action_client_invoice_menu
msgid "Open Invoicing Menu"
msgstr ""
msgstr "開啟發票開立選單"
#. module: account_voucher
#: selection:account.voucher,state:0
@ -1044,7 +1044,7 @@ msgstr "五月"
#. module: account_voucher
#: view:account.voucher:0
msgid "Sale Receipt"
msgstr ""
msgstr "銷售收據"
#. module: account_voucher
#: view:account.voucher:0
@ -1129,7 +1129,7 @@ msgstr "年份"
#: field:account.config.settings,income_currency_exchange_account_id:0
#: field:res.company,income_currency_exchange_account_id:0
msgid "Gain Exchange Rate Account"
msgstr ""
msgstr "匯益科目"
#. module: account_voucher
#: selection:account.voucher,type:0
@ -1155,7 +1155,7 @@ msgstr "預設類型"
#. module: account_voucher
#: help:account.voucher,message_ids:0
msgid "Messages and communication history"
msgstr ""
msgstr "訊息及聯絡紀錄"
#. module: account_voucher
#: model:ir.model,name:account_voucher.model_account_statement_from_invoice_lines
@ -1194,7 +1194,7 @@ msgstr "會計分錄的生效日期"
#. module: account_voucher
#: model:mail.message.subtype,name:account_voucher.mt_voucher_state_change
msgid "Status Change"
msgstr ""
msgstr "狀態變更"
#. module: account_voucher
#: selection:account.voucher,payment_option:0
@ -1241,14 +1241,14 @@ msgstr "未結餘額"
#. module: account_voucher
#: model:mail.message.subtype,description:account_voucher.mt_voucher_state_change
msgid "Status <b>changed</b>"
msgstr ""
msgstr "狀態<b>已變更</b>"
#. module: account_voucher
#: code:addons/account_voucher/account_voucher.py:1106
#: code:addons/account_voucher/account_voucher.py:1110
#, python-format
msgid "Insufficient Configuration!"
msgstr ""
msgstr "設置不夠完整!"
#. module: account_voucher
#: help:account.voucher,active:0

View File

@ -1,43 +1,28 @@
# Chinese (Traditional) translation for openobject-addons
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-03 16:03+0000\n"
"PO-Revision-Date: 2012-08-19 10:28+0000\n"
"Last-Translator: Eric Huang <eh@cenoq.com>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-12-29 17:06+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2012-12-04 05:53+0000\n"
"X-Generator: Launchpad (build 16335)\n"
"X-Launchpad-Export-Date: 2013-12-30 04:39+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: base_crypt
#: model:ir.model,name:base_crypt.model_res_users
#. module: auth_crypt
#: field:res.users,password_crypt:0
msgid "Encrypted Password"
msgstr "已加密的密碼"
#. module: auth_crypt
#: model:ir.model,name:auth_crypt.model_res_users
msgid "Users"
msgstr ""
#~ msgid "Base - Password Encryption"
#~ msgstr "基礎 - 密碼加密"
#, python-format
#~ msgid "Please specify the password !"
#~ msgstr "請指定密碼 !"
#~ msgid "You can not have two users with the same login !"
#~ msgstr "您不能同時登入二個使用者!"
#, python-format
#~ msgid "Error"
#~ msgstr "錯誤"
#~ msgid "The chosen company is not in the allowed companies for this user"
#~ msgstr "所選的公司不是使用者被允許的公司。"
#~ msgid "res.users"
#~ msgstr "res.users"
msgstr "使用者"

View File

@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"PO-Revision-Date: 2013-12-29 09:17+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\n"
"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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

View File

@ -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):

View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to setup a new automated action rule. \n"
" </p><p>\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"
" </p>\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 ""

File diff suppressed because it is too large Load Diff

View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""

View File

@ -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 <wwycheuk@gmail.com>\n"
"PO-Revision-Date: 2013-12-29 15:39+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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

View File

@ -7,19 +7,19 @@ 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:05+0000\n"
"PO-Revision-Date: 2009-01-30 12:44+0000\n"
"Last-Translator: <>\n"
"PO-Revision-Date: 2013-12-27 04:38+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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:19+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: base_vat
#: view:res.partner:0
msgid "Check Validity"
msgstr ""
msgstr "檢查有效性"
#. module: base_vat
#: code:addons/base_vat/base_vat.py:152
@ -28,11 +28,13 @@ msgid ""
"This VAT number does not seem to be valid.\n"
"Note: the expected format is %s"
msgstr ""
"這個統編似乎是無效的。\n"
"提醒:格式應為 %s"
#. module: base_vat
#: field:res.company,vat_check_vies:0
msgid "VIES VAT Check"
msgstr ""
msgstr "VIES 統編VAT檢查"
#. module: base_vat
#: model:ir.model,name:base_vat.model_res_company
@ -43,7 +45,7 @@ msgstr "公司"
#: code:addons/base_vat/base_vat.py:113
#, python-format
msgid "Error!"
msgstr "錯誤!"
msgstr "錯誤"
#. module: base_vat
#: help:res.partner,vat_subjected:0
@ -51,20 +53,23 @@ msgid ""
"Check this box if the partner is subjected to the VAT. It will be used for "
"the VAT legal statement."
msgstr ""
"Check this box if the partner is subjected to the VAT. It will be used for "
"the VAT legal statement.\r\n"
"如果該業務夥伴需申報(加值型)營業稅,則勾選此框。這會用在營業稅相關的稅務報告。"
#. module: base_vat
#: model:ir.model,name:base_vat.model_res_partner
msgid "Partner"
msgstr "夥伴"
msgstr "業務夥伴"
#. module: base_vat
#: help:res.company,vat_check_vies:0
msgid ""
"If checked, Partners VAT numbers will be fully validated against EU's VIES "
"service rather than via a simple format validation (checksum)."
msgstr ""
msgstr "如果勾選此框,則業務夥伴的統編會以歐盟的 VIES 做完整檢查否則僅會作基本格式檢查checksum檢查"
#. module: base_vat
#: field:res.partner,vat_subjected:0
msgid "VAT Legal Statement"
msgstr ""
msgstr "營業稅報告"

167
addons/board/i18n/he.po Normal file
View File

@ -0,0 +1,167 @@
# 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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-12-30 18:41+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: board
#: model:ir.actions.act_window,name:board.action_board_create
#: model:ir.ui.menu,name:board.menu_board_create
msgid "Create Board"
msgstr ""
#. module: board
#: view:board.create:0
msgid "Create"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:4
#, python-format
msgid "Reset Layout.."
msgstr ""
#. module: board
#: view:board.create:0
msgid "Create New Dashboard"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:40
#, python-format
msgid "Choose dashboard layout"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:70
#, python-format
msgid "Add"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/js/dashboard.js:139
#, python-format
msgid "Are you sure you want to remove this item ?"
msgstr ""
#. module: board
#: model:ir.model,name:board.model_board_board
msgid "Board"
msgstr ""
#. module: board
#: view:board.board:0
#: model:ir.actions.act_window,name:board.open_board_my_dash_action
#: model:ir.ui.menu,name:board.menu_board_my_dash
msgid "My Dashboard"
msgstr ""
#. module: board
#: field:board.create,name:0
msgid "Board Name"
msgstr ""
#. module: board
#: model:ir.model,name:board.model_board_create
msgid "Board Creation"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:67
#, python-format
msgid "Add to Dashboard"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:28
#, python-format
msgid "&nbsp;"
msgstr ""
#. module: board
#: model:ir.actions.act_window,help:board.open_board_my_dash_action
msgid ""
"<div class=\"oe_empty_custom_dashboard\">\n"
" <p>\n"
" <b>Your personal dashboard is empty.</b>\n"
" </p><p>\n"
" To add your first report into this dashboard, go to any\n"
" menu, switch to list or graph view, and click <i>'Add "
"to\n"
" Dashboard'</i> in the extended search options.\n"
" </p><p>\n"
" You can filter and group data before inserting into the\n"
" dashboard using the search options.\n"
" </p>\n"
" </div>\n"
" "
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:6
#, python-format
msgid "Reset"
msgstr ""
#. module: board
#: field:board.create,menu_parent_id:0
msgid "Parent Menu"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:8
#, python-format
msgid "Change Layout.."
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/js/dashboard.js:93
#, python-format
msgid "Edit Layout"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:10
#, python-format
msgid "Change Layout"
msgstr ""
#. module: board
#: view:board.create:0
msgid "Cancel"
msgstr ""
#. module: board
#: view:board.create:0
msgid "or"
msgstr ""
#. module: board
#. openerp-web
#: code:addons/board/static/src/xml/board.xml:69
#, python-format
msgid "Title of new dashboard item"
msgstr ""

View File

@ -0,0 +1,37 @@
# 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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2013-12-30 18:41+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2013-12-31 04:47+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: contacts
#: model:ir.actions.act_window,help:contacts.action_contacts
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to add a contact in your address book.\n"
" </p><p>\n"
" OpenERP helps you easily track all activities related to\n"
" a customer; discussions, history of business opportunities,\n"
" documents, etc.\n"
" </p>\n"
" "
msgstr ""
#. module: contacts
#: model:ir.actions.act_window,name:contacts.action_contacts
#: model:ir.ui.menu,name:contacts.menu_contacts
msgid "Contacts"
msgstr ""

View File

@ -0,0 +1,37 @@
# Slovak translation for openobject-addons
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2014-01-04 10:36+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Slovak <sk@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-01-05 05:26+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: contacts
#: model:ir.actions.act_window,help:contacts.action_contacts
msgid ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to add a contact in your address book.\n"
" </p><p>\n"
" OpenERP helps you easily track all activities related to\n"
" a customer; discussions, history of business opportunities,\n"
" documents, etc.\n"
" </p>\n"
" "
msgstr ""
#. module: contacts
#: model:ir.actions.act_window,name:contacts.action_contacts
#: model:ir.ui.menu,name:contacts.menu_contacts
msgid "Contacts"
msgstr "Kontakty"

View File

@ -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}"/>
<field name="email_from" string="Email"/>
<field name="email_from" string="Email" widget="email"/>
<field name="phone"/>
</group>

3014
addons/crm/i18n/he.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to create a new request. \n"
" </p><p>\n"
" Helpdesk and Support allow you to track your interventions.\n"
" </p><p>\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"
" </p>\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 ""

View File

@ -0,0 +1,85 @@
# Hebrew translation for openobject-addons
# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
# This file is distributed under the same license as the openobject-addons package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
"PO-Revision-Date: 2014-01-03 03:46+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2014-01-04 05:42+0000\n"
"X-Generator: Launchpad (build 16877)\n"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_project_task
msgid "Task"
msgstr "משימה"
#. module: crm_todo
#: view:crm.lead:0
msgid "Timebox"
msgstr ""
#. module: crm_todo
#: view:crm.lead:0
msgid "Lead"
msgstr "ליד (Lead)"
#. module: crm_todo
#: view:crm.lead:0
msgid "For cancelling the task"
msgstr "לביטול המשימה"
#. module: crm_todo
#: view:crm.lead:0
msgid "Next"
msgstr "הבא"
#. module: crm_todo
#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
msgid "My Tasks"
msgstr "המשימות שלי"
#. module: crm_todo
#: view:crm.lead:0
#: field:crm.lead,task_ids:0
msgid "Tasks"
msgstr "משימות"
#. module: crm_todo
#: view:crm.lead:0
msgid "Done"
msgstr "בוצע"
#. module: crm_todo
#: view:crm.lead:0
msgid "Cancel"
msgstr "בטל"
#. module: crm_todo
#: model:ir.model,name:crm_todo.model_crm_lead
msgid "Lead/Opportunity"
msgstr "ליד/הזדמנות"
#. module: crm_todo
#: field:project.task,lead_id:0
msgid "Lead / Opportunity"
msgstr "ליד/הזדמנות"
#. module: crm_todo
#: view:crm.lead:0
msgid "For changing to done state"
msgstr "לשינוי לסטטוס בוצע"
#. module: crm_todo
#: view:crm.lead:0
msgid "Previous"
msgstr "הקודם"

View File

@ -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

758
addons/document/i18n/he.po Normal file
View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to create a new document. \n"
" </p><p>\n"
" The Documents repository gives you access to all attachments, "
"such\n"
" as mails, project documents, invoices etc.\n"
" </p>\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 ""

View File

@ -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),

View File

@ -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
-

87
addons/edi/i18n/he.po Normal file
View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""

View File

@ -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))

View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""

View File

@ -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': '<p>Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}</p>',

View File

@ -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 <raoul@example.com>',
'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" <admin@example.com>'],
['"Followers of Pigs" <raoul@raoul.fr>'], ['"Followers of Pigs" <bert@bert.fr>']]
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')

View File

@ -19,7 +19,7 @@
#
##############################################################################
from openerp import tools
from openerp import tools, SUPERUSER_ID
from openerp.osv import osv, fields
@ -157,9 +157,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):

1912
addons/fleet/i18n/lo.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import models
import wizard

View File

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'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'],
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record forcecreate="True" id="ir_cron_check_challenge"
model="ir.cron">
<field name="name">Run Goal Challenge Checker</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="model">gamification.challenge</field>
<field name="function">_cron_update</field>
<field name="args">()</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,208 @@
<?xml version="1.0"?>
<openerp>
<!-- Mail template is done in a NOUPDATE block
so users can freely customize/delete them -->
<data noupdate="0">
<!--Email template -->
<record id="email_template_goal_reminder" model="email.template">
<field name="name">Reminder for Goal Update</field>
<field name="body_html"><![CDATA[
<header>
<strong>Reminder ${object.name}</strong>
</header>
<p>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.</p>
<p>If you have not changed your score yet, you can use the button "The current value is up to date" to indicate so.</p>
]]></field>
</record>
<record id="simple_report_template" model="email.template">
<field name="name">Simple Challenge Report Progress</field>
<field name="body_html"><![CDATA[
<header>
<strong>${object.name}</strong>
</header>
<p class="oe_grey">The following message contains the current progress for the challenge ${object.name}</p>
% if object.visibility_mode == 'personal':
<table width="100%" border="1">
<tr>
<th>Goal</th>
<th>Target</th>
<th>Current</th>
<th>Completeness</th>
</tr>
% for line in ctx["challenge_lines"]:
<tr
% if line['completeness'] >= 100:
style="font-weight:bold;"
% endif
>
<td>${line['name']}</td>
<td>${line['target']}
% if line['suffix']:
${line['suffix']}
% endif
</td>
<td>${line['current']}
% if line['suffix']:
${line['suffix']}
% endif
</td>
<td>${line['completeness']} %</td>
</tr>
% endfor
</table>
% else:
% for line in ctx["challenge_lines"]:
<table width="100%" border="1">
<tr>
<th colspan="4">${line['name']}</th>
</tr>
<tr>
<th>#</th>
<th>Person</th>
<th>Completeness</th>
<th>Current</th>
</tr>
% for goal in line['goals']:
<tr
% if goal.completeness >= 100:
style="font-weight:bold;"
% endif
>
<td>${goal['rank']}</td>
<td>${goal['name']}</td>
<td>${goal['completeness']}%</td>
<td>${goal['current']}/${line['target']}
% if line['suffix']:
${line['suffix']}
% endif
</td>
</tr>
% endfor
</table>
<br/><br/>
% endfor
% endif
]]></field>
</record>
</data>
<data>
<!-- goal definitions -->
<record model="gamification.goal.definition" id="definition_base_timezone">
<field name="name">Set your Timezone</field>
<field name="description">Configure your profile and specify your timezone</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('base.model_res_users')" />
<field name="domain">[('id','=',user.id),('partner_id.tz', '!=', False)]</field>
<field name="action_id" eval="ref('base.action_res_users_my')" />
<field name="res_id_field">user.id</field>
</record>
<record model="gamification.goal.definition" id="definition_base_company_data">
<field name="name">Set your Company Data</field>
<field name="description">Write some information about your company (specify at least a name)</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('base.model_res_company')" />
<field name="domain">[('user_ids', 'in', [user.id]), ('name', '=', 'Your Company')]</field>
<field name="condition">lower</field>
<field name="action_id" eval="ref('base.action_res_company_form')" />
<field name="res_id_field">user.company_id.id</field>
</record>
<record model="gamification.goal.definition" id="definition_base_company_logo">
<field name="name">Set your Company Logo</field>
<field name="computation_mode">count</field>
<field name="display_mode">boolean</field>
<field name="model_id" eval="ref('base.model_res_company')" />
<field name="domain">[('user_ids', 'in', user.id),('logo', '!=', False)]</field>
<field name="action_id" eval="ref('base.action_res_company_form')" />
<field name="res_id_field">user.company_id.id</field>
</record>
<record id="action_new_simplified_res_users" model="ir.actions.act_window">
<field name="name">Create User</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.users</field>
<field name="view_type">form</field>
<field name="target">current</field>
<field name="view_id" ref="base.view_users_simple_form"/>
<field name="context">{'default_groups_ref': ['base.group_user']}</field>
<field name="help">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.</field>
</record>
<record model="gamification.goal.definition" id="definition_base_invite">
<field name="name">Invite new Users</field>
<field name="description">Create at least another user</field>
<field name="display_mode">boolean</field>
<field name="computation_mode">count</field>
<field name="model_id" eval="ref('base.model_res_users')" />
<field name="domain">[('id', '!=', user.id)]</field>
<field name="action_id" eval="ref('action_new_simplified_res_users')" />
</record>
<record model="gamification.goal.definition" id="definition_nbr_following">
<field name="name">Mail Group Following</field>
<field name="description">Follow mail groups to receive news</field>
<field name="computation_mode">python</field>
<field name="compute_code">result = pool.get('mail.followers').search(cr, uid, [('res_model', '=', 'mail.group'), ('partner_id', '=', object.user_id.partner_id.id)], count=True, context=context)</field>
<field name="action_id" eval="ref('mail.action_view_groups')" />
</record>
<!-- challenges -->
<record model="gamification.challenge" id="challenge_base_discover">
<field name="name">Complete your Profile</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="autojoin_group_id" eval="ref('base.group_user')" />
<field name="state">inprogress</field>
<field name="category">other</field>
</record>
<record model="gamification.challenge" id="challenge_base_configure">
<field name="name">Setup your Company</field>
<field name="period">once</field>
<field name="visibility_mode">personal</field>
<field name="report_message_frequency">never</field>
<field name="user_ids" eval="[(4, ref('base.user_root'))]" />
<field name="state">inprogress</field>
<field name="category">other</field>
</record>
<!-- lines -->
<record model="gamification.challenge.line" id="line_base_discover1">
<field name="definition_id" eval="ref('definition_base_timezone')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_base_discover')" />
</record>
<record model="gamification.challenge.line" id="line_base_admin2">
<field name="definition_id" eval="ref('definition_base_company_logo')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_base_configure')" />
</record>
<record model="gamification.challenge.line" id="line_base_admin1">
<field name="definition_id" eval="ref('definition_base_company_data')" />
<field name="target_goal">0</field>
<field name="challenge_id" eval="ref('challenge_base_configure')" />
</record>
<record model="gamification.challenge.line" id="line_base_admin3">
<field name="definition_id" eval="ref('definition_base_invite')" />
<field name="target_goal">1</field>
<field name="challenge_id" eval="ref('challenge_base_configure')" />
</record>
</data>
</openerp>

View File

@ -0,0 +1,86 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Drive Engagement with Gamification</h2>
<h3 class="oe_slogan">Leverage natural desire for competition</h3>
<p class="oe_mt32">
Reinforce good habits and improve win rates with real-time recognition and rewards inspired by <a href="http://en.wikipedia.org/wiki/Gamification">game mechanics</a>. Align teams around clear business objectives with challenges, personal objectives and team leader boards.
</p>
<div class="oe_span4 oe_centered">
<h3>Leaderboards</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="crm_game_01.png">
</div>
<p>
Promote leaders and competition amongst sales team with performance ratios.
</p>
</div>
<div class="oe_span4 oe_centered">
<h3>Personnal Objectives</h3>
<div class="oe_row_img">
<img class="oe_picture" src="crm_game_02.png">
</div>
<p>
Assign clear goals to users to align them with the company objectives.
</p>
</div>
<div class="oe_span4 oe_centered">
<h3>Visual Information</h3>
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="crm_game_03.png">
</div>
<p>
See in an glance the progress of each user.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Create custom Challenges</h2>
<div class="oe_span6">
<p class="oe_mt32">
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.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="crm_sc_05.png">
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Motivate with Badges</h2>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture" src="crm_linkedin.png">
</div>
</div>
<div class="oe_span6">
<p class="oe_mt32">
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.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan">Adapt to any module</h2>
<div class="oe_span6">
<p class="oe_mt32">
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.
</p>
</div>
<div class="oe_span6">
<div class="oe_row_img oe_centered">
<img class="oe_picture oe_screenshot" src="crm_sc_02.png">
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import goal
import challenge
import res_users
import badge

View File

@ -0,0 +1,276 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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

View File

@ -0,0 +1,821 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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: <list(int)> compute only the results for this subset if gamification.goal ids, if False retrieve every goal of current running challenge
:restrict_top: <int> 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': <gamification.goal.description name>,
'description': <gamification.goal.description description>,
'condition': <reach condition {lower,higher}>,
'computation_mode': <target computation {manually,count,sum,python}>,
'monetary': <{True,False}>,
'suffix': <value suffix>,
'action': <{True,False}>,
'display_mode': <{progress,boolean}>,
'target': <challenge line target>,
'own_goal_id': <gamification.goal id where user_id == uid>,
'goals': [
{
'id': <gamification.goal id>,
'rank': <user ranking>,
'user_id': <res.users id>,
'name': <res.users name>,
'state': <gamification.goal state {draft,inprogress,inprogress_update,reached,failed,canceled}>,
'completeness': <percentage>,
'current': <current value>,
}
]
},
# if visibility_mode == 'personal'
{
'id': <gamification.goal id>,
'name': <gamification.goal.description name>,
'description': <gamification.goal.description description>,
'condition': <reach condition {lower,higher}>,
'computation_mode': <target computation {manually,count,sum,python}>,
'monetary': <{True,False}>,
'suffix': <value suffix>,
'action': <{True,False}>,
'display_mode': <{progress,boolean}>,
'target': <challenge line target>,
'state': <gamification.goal state {draft,inprogress,inprogress_update,reached,failed,canceled}>,
'completeness': <percentage>,
'current': <current value>,
}
"""
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 += _("<br/>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 += _("<br/>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 += _("<br/>Special rewards were sent to the top competing users. The ranking for this challenge is :")
message_body += "<br/> 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 += "<br/> 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 += "<br/> 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,
}

View File

@ -0,0 +1,394 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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

View File

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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': <gamification.challenge id>,
'name': <gamification.challenge name>,
'visibility_mode': <visibility {ranking,personal}>,
'currency': <res.currency id>,
'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

View File

@ -0,0 +1,43 @@
<?xml version="1.0" ?>
<openerp>
<data noupdate="1">
<record model="ir.module.category" id="module_goal_category">
<field name="name">Gamification</field>
<field name="description"></field>
<field name="sequence">17</field>
</record>
<record id="group_goal_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="module_goal_category"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
<record id="goal_user_visibility" model="ir.rule">
<field name="name">User can only see his/her goals or goal from the same challenge in board visibility</field>
<field name="model_id" ref="model_gamification_goal"/>
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="domain_force">[
'|',
('user_id','=',user.id),
'&amp;',
('challenge_id.user_ids','in',user.id),
('challenge_id.visibility_mode','=','ranking')]</field>
</record>
<record id="goal_gamification_manager_visibility" model="ir.rule">
<field name="name">Gamification Manager can see any goal</field>
<field name="model_id" ref="model_gamification_goal"/>
<field name="groups" eval="[(4, ref('group_goal_manager'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
<field name="domain_force">[(1, '=', 1)]</field>
</record>
</data>
</openerp>

View File

@ -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
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 goal_employee Goal Employee model_gamification_goal base.group_user 1 1 0 0
3 goal_manager Goal Manager model_gamification_goal group_goal_manager 1 1 1 1
4 goal_definition_employee Goal Definition Employee model_gamification_goal_definition base.group_user 1 0 0 0
5 goal_definition_manager Goal Definition Manager model_gamification_goal_definition group_goal_manager 1 1 1 1
6 challenge_employee Goal Challenge Employee model_gamification_challenge base.group_user 1 0 0 0
7 challenge_manager Goal Challenge Manager model_gamification_challenge group_goal_manager 1 1 1 1
8 challenge_line_employee Challenge Line Employee model_gamification_challenge_line base.group_user 1 0 0 0
9 challenge_line_manager Challenge Line Manager model_gamification_challenge_line group_goal_manager 1 1 1 1
10 badge_employee Badge Employee model_gamification_badge base.group_user 1 0 0 0
11 badge_manager Badge Manager model_gamification_badge group_goal_manager 1 1 1 1
12 badge_user_employee Badge-user Employee model_gamification_badge_user base.group_user 1 1 1 0
13 badge_user_manager Badge-user Manager model_gamification_badge_user group_goal_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,3 @@
gamification.css: gamification.sass
sass --trace -t expanded gamification.sass gamification.css

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
},
});
};

View File

@ -0,0 +1,114 @@
<templates>
<t t-name="gamification.UserWallSidebar" class="oe_gamification_user_wall_sidebar">
<div>
<div class="oe_gamification_suggestion"></div>
<div class="oe_gamification_challenge_list"></div>
</div>
</t>
<t t-name="gamification.ChallengeSummary">
<div class="oe_goal">
<div>
<a class="oe_update_challenge oe_e" rol="button" t-attf-id="{challenge.id}">e</a>
<h4><t t-esc="challenge.name" /></h4>
</div>
<t t-if="challenge.visibility_mode == 'personal'">
<div class="oe_table oe_goals_list">
<div t-foreach="challenge.lines" t-as="line" t-attf-class="oe_row oe_goal_outer_box #{line.state == 'reached' ? 'oe_goal_reached' : ''} #{line.display_mode != 'progress' ? 'oe_no_progress' : ''}">
<t t-if="line.display_mode == 'progress'">
<div class="oe_goal_progress_background"></div>
<div class="oe_goal_progress" t-attf-style="#{line.display_mode == 'progress' ? 'width: '+line.completeness+'%;' : 'width:0;'}"></div>
<div class="oe_cell oe_goal_current"><t t-esc="line.current" /></div>
</t>
<div class="oe_cell">
<t t-if="line.computation_mode != 'manually' and !line.action">
<span t-att-title="line.description"><t t-esc="line.name" /></span>
</t>
<t t-if="line.action or line.computation_mode == 'manually'">
<span t-att-title="line.description"><a class="oe_goal_action" t-att-id="line.id"><t t-esc="line.name" /></a></span>
</t>
<t t-if="line.display_mode == 'progress'"><br/>
<div class="oe_grey">
<t t-if="line.definition_condition == 'higher'">
Target:
</t>
<t t-if="line.definition_condition == 'lower'">
Target: &lt;=
</t>
<span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="line.target"/></span>
<t t-if="line.suffix"><t t-esc="line.suffix"/></t>
</div>
</t>
</div>
</div>
</div>
</t>
<t t-if="challenge.visibility_mode == 'ranking'">
<div t-foreach="challenge.lines" t-as="line" class="oe_goals_list oe_table">
<div class="oe_row">
<div class="oe_cell oe_thead" colspan="3" t-attf-title="#{line.description ? line.description : ''}">
<strong><t t-esc="line.name"/></strong>
<br/>
<div class="oe_grey">
<t t-if="line.definition_condition == 'higher'">
Target:
</t>
<t t-if="line.definition_condition == 'lower'">
Target: &lt;=
</t>
<span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="line.target" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t>
</div>
</div>
</div>
<div t-foreach="line.goals" t-as="goal" t-attf-class="#{goal.id == line.own_goal_id ? 'oe_bold' : ''}">
<div t-attf-class="oe_row oe_goal_outer_box #{goal.state == 'reached' ? 'oe_goal_reached' : ''} #{line.display_mode != 'progress' ? 'oe_no_progress' : ''}">
<t t-if="line.display_mode == 'progress'">
<div class="oe_goal_progress_background"></div>
<div class="oe_goal_progress" t-attf-style="#{line.display_mode == 'progress' ? 'width: '+goal.completeness+'%;' : 'width:0;'}"></div>
</t>
<div class="oe_cell col0"><t t-esc="goal.rank" /></div>
<div class="oe_cell col1"><img class="oe_user_avatar" t-attf-alt="#{goal.name}" t-attf-data-id="#{goal.user_id}"/></div>
<div class="oe_cell col2">
<t t-if="line.display_mode == 'progress'">
<!-- progress, action on current value -->
<t t-esc="goal.name"/><br/>
<t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.action)">
<span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="goal.current" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t>
</t>
<t t-if="goal.id == line.own_goal_id and (line.action or line.computation_mode == 'manually')">
<a class="oe_goal_action" t-att-id="line.own_goal_id">
<span t-attf-class="#{line.monetary ? 'oe_goal_field_monetary' : ''}" t-attf-data-id="#{line.monetary ? challenge.currency : ''}"><t t-esc="goal.current" /></span><t t-if="line.suffix"> <t t-esc="line.suffix"/></t>
</a>
</t>
</t>
<t t-if="line.display_mode != 'progress'">
<!-- not progress, action on user name -->
<t t-if="goal.id != line.own_goal_id or (line.computation_mode != 'manually' and !line.action)">
<t t-esc="goal.name"/>
</t>
<t t-if="goal.id == line.own_goal_id and (line.action or line.computation_mode == 'manually')">
<a class="oe_goal_action" t-att-id="line.own_goal_id"><t t-esc="goal.name"/></a>
</t>
</t>
</div>
</div>
</div>
</div>
</t>
</div>
</t>
<t t-name="gamification.ChallengeSuggestion">
<div class="oe_goal">
<h4>Invited Challenges</h4>
<ul t-foreach="challenges" t-as="challenge" class="oe_goals_list">
<li>
<strong><a class="oe_challenge_reply" t-attf-title="#{challenge.description.value ? challenge.description.value : ''}" t-attf-id="{challenge.id}" title="more details..."><t t-esc="challenge.name"/></a></strong>
</li>
</ul>
</div>
</t>
</templates>

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013 OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_challenge
checks = [
test_challenge,
]

View File

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Business Applications
# Copyright (c) 2013 OpenERP S.A. <http://openerp.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from 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")

View File

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- Badge views -->
<record id="badge_list_action" model="ir.actions.act_window">
<field name="name">Badges</field>
<field name="res_model">gamification.badge</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a badge.
</p>
<p>
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.
</p>
</field>
</record>
<record id="badge_list_view" model="ir.ui.view">
<field name="name">Badge List</field>
<field name="model">gamification.badge</field>
<field name="arch" type="xml">
<tree string="Badge List">
<field name="name"/>
<field name="stat_count"/>
<field name="stat_this_month"/>
<field name="stat_my"/>
<field name="rule_auth"/>
</tree>
</field>
</record>
<record id="badge_form_view" model="ir.ui.view">
<field name="name">Badge Form</field>
<field name="model">gamification.badge</field>
<field name="arch" type="xml">
<form string="Badge" version="7.0">
<header>
<button string="Grant this Badge" type="action" name="%(action_grant_wizard)d" class="oe_highlight" attrs="{'invisible': [('remaining_sending','=',0)]}" />
<button string="Check Badge" type="object" name="check_automatic" groups="base.group_no_one" />
</header>
<sheet>
<div class="oe_right oe_button_box">
</div>
<field name="image" widget='image' class="oe_left oe_avatar"/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name"/>
</h1>
</div>
<group>
<field name="description" nolabel="1" placeholder="Badge Description" />
</group>
<group string="Granting">
<div class="oe_grey" colspan="4">
Security rules to define who is allowed to manually grant badges. Not enforced for administrator.
</div>
<field name="rule_auth" widget="radio" />
<field name="rule_auth_user_ids" attrs="{'invisible': [('rule_auth','!=','users')]}" widget="many2many_tags" />
<field name="rule_auth_badge_ids" attrs="{'invisible': [('rule_auth','!=','having')]}" widget="many2many_tags" />
<field name="rule_max" attrs="{'invisible': [('rule_auth','=','nobody')]}" />
<field name="rule_max_number" attrs="{'invisible': ['|',('rule_max','=',False),('rule_auth','=','nobody')]}"/>
<label for="stat_my_monthly_sending"/>
<div>
<field name="stat_my_monthly_sending" attrs="{'invisible': [('rule_auth','=','nobody')]}" />
<div attrs="{'invisible': [('remaining_sending','=',-1)]}" class="oe_grey">
You can still grant <field name="remaining_sending" class="oe_inline"/> badges this month
</div>
<div attrs="{'invisible': [('remaining_sending','!=',-1)]}" class="oe_grey">
No monthly sending limit
</div>
</div>
</group>
<group string="Rewards for challenges">
<field name="challenge_ids" widget="many2many_kanban" nolabel="1" />
</group>
<group string="Statistics">
<group>
<field name="stat_count"/>
<field name="stat_this_month"/>
<field name="stat_count_distinct"/>
</group>
<group>
<field name="stat_my"/>
<field name="stat_my_this_month"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="badge_kanban_view" model="ir.ui.view" >
<field name="name">Badge Kanban View</field>
<field name="model">gamification.badge</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="name"/>
<field name="description"/>
<field name="image"/>
<field name="stat_my"/>
<field name="stat_count"/>
<field name="stat_this_month"/>
<field name="unique_owner_ids"/>
<field name="stat_my_monthly_sending"/>
<field name="remaining_sending" />
<field name="rule_max_number" />
<templates>
<t t-name="kanban-box">
<div t-attf-class="#{record.stat_my.raw_value ? 'oe_kanban_color_5' : 'oe_kanban_color_white'} oe_kanban_card oe_kanban_global_click oe_kanban_badge">
<div class="oe_kanban_content">
<div class="oe_kanban_left">
<a type="open"><img t-att-src="kanban_image('gamification.badge', 'image', record.image.raw_value)" t-att-title="record.name.value" width="90" height="90" /></a>
</div>
<div class="oe_no_overflow">
<h4><field name="name"/></h4>
<t t-if="record.remaining_sending.value != 0">
<button type="action" name="%(action_grant_wizard)d" class="oe_highlight">Grant</button>
<span class="oe_grey">
<t t-if="record.remaining_sending.value != -1">
<t t-esc="record.stat_my_monthly_sending.value"/>/<t t-esc="record.rule_max_number.value"/>
</t>
<t t-if="record.remaining_sending.value == -1">
<t t-esc="record.stat_my_monthly_sending.value"/>/∞
</t>
</span>
</t>
<t t-if="record.remaining_sending.value == 0">
<div class="oe_grey">Can not grant</div>
</t>
<p>
<strong><t t-esc="record.stat_count.raw_value"/></strong> granted,<br/>
<strong><t t-esc="record.stat_this_month.raw_value"/></strong> this month
</p>
</div>
<div class="oe_kanban_badge_avatars">
<t t-if="record.description.value">
<p><em><field name="description"/></em></p>
</t>
<a type="object" name="get_granted_employees">
<t t-foreach="record.unique_owner_ids.raw_value.slice(0,11)" t-as="owner">
<img t-att-src="kanban_image('res.users', 'image_small', owner)" t-att-data-member_id="owner"/>
</t>
</a>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<!-- Badge user viewss -->
<record id="badge_user_kanban_view" model="ir.ui.view" >
<field name="name">Badge User Kanban View</field>
<field name="model">gamification.badge.user</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="badge_name"/>
<field name="badge_id"/>
<field name="user_id"/>
<field name="comment"/>
<field name="create_date"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card oe_kanban_global_click oe_kanban_badge oe_kanban_color_white">
<div class="oe_kanban_content">
<div class="oe_kanban_left">
<a type="open"><img t-att-src="kanban_image('gamification.badge', 'image', record.badge_id.raw_value)" t-att-title="record.badge_name.value" width="24" height="24" /></a>
</div>
<h4>
<a type="open"><t t-esc="record.badge_name.raw_value" /></a>
</h4>
<t t-if="record.comment.raw_value">
<p><em><field name="comment"/></em></p>
</t>
<p>Granted by <a type="open"><field name="create_uid" /></a> the <t t-esc="record.create_date.raw_value.toString(Date.CultureInfo.formatPatterns.shortDate)" /></p>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,289 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="challenge_list_view" model="ir.ui.view">
<field name="name">Challenges List</field>
<field name="model">gamification.challenge</field>
<field name="arch" type="xml">
<tree string="Goal definitions" colors="blue:state == 'draft';grey:state == 'done'">
<field name="name"/>
<field name="period"/>
<field name="manager_id"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="goals_from_challenge_act" model="ir.actions.act_window">
<field name="res_model">gamification.goal</field>
<field name="name">Related Goals</field>
<field name="view_mode">kanban,tree</field>
<field name="context">{'search_default_group_by_definition': True, 'search_default_inprogress': True, 'search_default_challenge_id': active_id, 'default_challenge_id': active_id}</field>
<field name="help" type="html">
<p>
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.
</p>
</field>
</record>
<record id="challenge_form_view" model="ir.ui.view">
<field name="name">Challenge Form</field>
<field name="model">gamification.challenge</field>
<field name="arch" type="xml">
<form string="Goal definitions" version="7.0">
<header>
<button string="Refresh Challenge" type="object" name="action_check" states="inprogress"/>
<button string="Send Report" type="object" name="action_report_progress" states="inprogress,done" groups="base.group_no_one"/>
<field name="state" widget="statusbar" clickable="True"/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" placeholder="e.g. Monthly Sales Objectives"/>
</h1>
<label for="user_ids" class="oe_edit_only" string="Assign Challenge To"/>
<div>
<field name="user_ids" widget="many2many_tags" />
</div>
</div>
<!-- action buttons -->
<div class="oe_right oe_button_box">
<button type="action" name="%(goals_from_challenge_act)d" string="Related Goals" attrs="{'invisible': [('state','=','draft')]}" />
</div>
<group>
<group>
<field name="period" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="visibility_mode" widget="radio" colspan="1" />
</group>
<group>
<field name="manager_id"/>
<field name="start_date" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="end_date" attrs="{'readonly':[('state','!=','draft')]}"/>
</group>
</group>
<notebook>
<page string="Goals">
<field name="line_ids" nolabel="1" colspan="4">
<tree string="Line List" version="7.0" editable="bottom" >
<field name="sequence" widget="handle"/>
<field name="definition_id" on_change="on_change_definition_id(definition_id)" />
<field name="condition"/>
<field name="target_goal"/>
<field name="definition_full_suffix"/>
</tree>
</field>
<field name="description" placeholder="Describe the challenge: what is does, who it targets, why it matters..."/>
</page>
<page string="Reward">
<group>
<field name="reward_id"/>
<field name="reward_first_id" />
<field name="reward_second_id" attrs="{'invisible': [('reward_first_id','=', False)]}" />
<field name="reward_third_id" attrs="{'invisible': ['|',('reward_first_id','=', False),('reward_second_id','=', False)]}" />
<field name="reward_failure" attrs="{'invisible': [('reward_first_id','=', False)]}" />
</group>
<div class="oe_grey">
<p>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.</p>
</div>
</page>
<page string="Advanced Options">
<group string="Subscriptions">
<field name="autojoin_group_id" />
<field name="invited_user_ids" widget="many2many_tags" />
</group>
<group string="Notification Messages">
<div class="oe_grey" colspan="4">
<p>Depending on the Display mode, reports will be individual or shared.</p>
</div>
<field name="report_message_frequency" />
<field name="report_template_id" attrs="{'invisible': [('report_message_frequency','=','never')]}" />
<field name="report_message_group_id" attrs="{'invisible': [('report_message_frequency','=','never')]}" />
</group>
<group string="Reminders for Manual Goals">
<label for="remind_update_delay" />
<div>
<field name="remind_update_delay" class="oe_inline"/> days
</div>
</group>
<group string="Category" groups="base.group_no_one">
<field name="category" widget="radio" />
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_challenge_kanban">
<field name="name">Challenge Kanban</field>
<field name="model">gamification.challenge</field>
<field name="arch" type="xml">
<kanban string="Challenges" class="oe_background_grey" version="7.0">
<field name="line_ids"/>
<field name="user_ids"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_goal oe_kanban_global_click">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">í</span>
<ul class="oe_dropdown_menu">
<li><a type="edit">Configure Challenge</a></li>
</ul>
</div>
<div class="oe_kanban_content">
<h4><field name="name"/></h4>
<div class="oe_kanban_project_list">
<a type="action" name="%(goals_from_challenge_act)d" style="margin-right: 10px">
<span t-if="record.line_ids.raw_value.length gt 1"><t t-esc="record.line_ids.raw_value.length"/> Goals</span>
<span t-if="record.line_ids.raw_value.length lt 2"><t t-esc="record.line_ids.raw_value.length"/> Goal</span>
</a>
</div>
<div class="oe_kanban_badge_avatars">
<t t-foreach="record.user_ids.raw_value.slice(0,11)" t-as="member">
<img t-att-src="kanban_image('res.users', 'image_small', member)" t-att-data-member_id="member"/>
</t>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="challenge_list_action" model="ir.actions.act_window">
<field name="name">Challenges</field>
<field name="res_model">gamification.challenge</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_inprogress':True, 'default_inprogress':True}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a challenge.
</p>
<p>
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.
</p>
</field>
</record>
<!-- Specify form view ID to avoid selecting view_challenge_wizard -->
<record id="challenge_list_action_view1" model="ir.actions.act_window.view">
<field eval="1" name="sequence"/>
<field name="view_mode">kanban</field>
<field name="act_window_id" ref="challenge_list_action"/>
<field name="view_id" ref="view_challenge_kanban"/>
</record>
<record id="challenge_list_action_view2" model="ir.actions.act_window.view">
<field eval="10" name="sequence"/>
<field name="view_mode">form</field>
<field name="act_window_id" ref="challenge_list_action"/>
<field name="view_id" ref="challenge_form_view"/>
</record>
<!-- Line -->
<record id="challenge_line_list_view" model="ir.ui.view">
<field name="name">Challenge line list</field>
<field name="model">gamification.challenge.line</field>
<field name="arch" type="xml">
<tree string="Challenge Lines" >
<field name="definition_id"/>
<field name="target_goal"/>
</tree>
</field>
</record>
<record id="challenge_search_view" model="ir.ui.view">
<field name="name">Challenge Search</field>
<field name="model">gamification.challenge</field>
<field name="arch" type="xml">
<search string="Search Challenges">
<filter name="inprogress" string="Running Challenges"
domain="[('state', '=', 'inprogress')]"/>
<filter name="hr_challenges" string="HR Challenges"
domain="[('category', '=', 'hr')]"/>
<field name="name"/>
<group expand="0" string="Group By...">
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
<filter string="Period" domain="[]" context="{'group_by':'period'}"/>
</group>
</search>
</field>
</record>
<record id="view_challenge_wizard" model="ir.ui.view">
<field name="name">Challenge Wizard</field>
<field name="model">gamification.challenge</field>
<field name="arch" type="xml">
<form string="Challenge" version="7.0">
<field name="reward_failure" invisible="1"/>
<div class="oe_title">
<h1><field name="name" nolabel="1" readonly="1"/></h1>
</div>
<field name="description" nolabel="1" readonly="1" />
<group>
<field name="start_date" readonly="1" />
<field name="end_date" readonly="1" />
<field name="user_ids" string="Participating" readonly="1" widget="many2many_tags" />
<field name="invited_user_ids" string="Invited" readonly="1" widget="many2many_tags" />
</group>
<group string="Goals">
<field name="line_ids" nolabel="1" readonly="1" colspan="4">
<tree string="Challenge Lines" version="7.0" editable="bottom" >
<field name="sequence" widget="handle"/>
<field name="definition_id"/>
<field name="condition"/>
<field name="target_goal"/>
<field name="definition_full_suffix"/>
</tree>
</field>
</group>
<group string="Reward">
<div class="oe_grey" attrs="{'invisible': ['|',('reward_id','!=',False),('reward_first_id','!=',False)]}">
There is no reward upon completion of this challenge.
</div>
<group attrs="{'invisible': [('reward_id','=',False),('reward_first_id','=',False)]}">
<field name="reward_id" readonly="1" attrs="{'invisible': [('reward_first_id','=', False)]}" />
<field name="reward_first_id" readonly="1" attrs="{'invisible': [('reward_first_id','=', False)]}" />
<field name="reward_second_id" readonly="1" attrs="{'invisible': [('reward_second_id','=', False)]}" />
<field name="reward_third_id" readonly="1" attrs="{'invisible': [('reward_third_id','=', False)]}" />
</group>
<div class="oe_grey" attrs="{'invisible': [('reward_failure','=',False)]}">
Even if the challenge is failed, best challengers will be rewarded
</div>
</group>
<footer>
<center>
<button string="Accept" type="object" name="accept_challenge" class="oe_highlight" />
<button string="Reject" type="object" name="discard_challenge"/> or
<button string="reply later" special="cancel" class="oe_link"/>
</center>
</footer>
</form>
</field>
</record>
<record id="challenge_wizard" model="ir.actions.act_window">
<field name="name">Challenge Description</field>
<field name="res_model">gamification.challenge</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_challenge_wizard"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,289 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<!-- Goal views -->
<record id="goal_list_action" model="ir.actions.act_window">
<field name="name">Goals</field>
<field name="res_model">gamification.goal</field>
<field name="view_mode">tree,form,kanban</field>
<field name="context">{'search_default_group_by_user': True, 'search_default_group_by_definition': True}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a goal.
</p>
<p>
A goal is defined by a user and a goal definition.
Goals can be created automatically by using challenges.
</p>
</field>
</record>
<record id="goal_list_view" model="ir.ui.view">
<field name="name">Goal List</field>
<field name="model">gamification.goal</field>
<field name="arch" type="xml">
<tree string="Goal List" colors="red:state == 'failed';green:state == 'reached';grey:state == 'canceled'">
<field name="definition_id" invisible="1" />
<field name="user_id" invisible="1" />
<field name="start_date"/>
<field name="end_date"/>
<field name="current"/>
<field name="target_goal"/>
<field name="completeness" widget="progressbar"/>
<field name="state" invisible="1"/>
<field name="line_id" invisible="1"/>
</tree>
</field>
</record>
<record id="goal_form_view" model="ir.ui.view">
<field name="name">Goal Form</field>
<field name="model">gamification.goal</field>
<field name="arch" type="xml">
<form string="Goal" version="7.0">
<header>
<button string="Start goal" type="object" name="action_start" states="draft" class="oe_highlight"/>
<button string="Goal Reached" type="object" name="action_reach" states="inprogress,inprogress_update" />
<button string="Goal Failed" type="object" name="action_fail" states="inprogress,inprogress_update"/>
<button string="Reset Completion" type="object" name="action_cancel" states="failed,reached" groups="base.group_no_one" />
<field name="state" widget="statusbar" statusbar_visible="draft,inprogress,reached" />
</header>
<sheet>
<group>
<group string="Reference">
<field name="definition_id" on_change="on_change_definition_id(definition_id)" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="user_id" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="challenge_id" attrs="{'readonly':[('state','!=','draft')]}"/>
</group>
<group string="Schedule">
<field name="start_date" attrs="{'readonly':[('state','!=','draft')]}"/>
<field name="end_date" />
<field name="computation_mode" invisible="1"/>
<label for="remind_update_delay" attrs="{'invisible':[('computation_mode','!=', 'manually')]}"/>
<div attrs="{'invisible':[('computation_mode','!=', 'manually')]}">
<field name="remind_update_delay" class="oe_inline"/>
days
</div>
<field name="last_update" groups="base.group_no_one"/>
</group>
<group string="Data" colspan="4">
<label for="target_goal" />
<div>
<field name="target_goal" attrs="{'readonly':[('state','!=','draft')]}" class="oe_inline"/>
<field name="definition_suffix" class="oe_inline"/>
</div>
<label for="current" />
<div>
<field name="current" class="oe_inline"/>
<button string="refresh" type="object" name="update" class="oe_link" attrs="{'invisible':['|',('computation_mode', '=', 'manually'),('state', '=', 'draft')]}" />
<div class="oe_grey" attrs="{'invisible':[('definition_id', '=', False)]}">
Reached when current value is <strong><field name="definition_condition" class="oe_inline"/></strong> than the target.
</div>
</div>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="goal_search_view" model="ir.ui.view">
<field name="name">Goal Search</field>
<field name="model">gamification.goal</field>
<field name="arch" type="xml">
<search string="Search Goals">
<filter name="my" string="My Goals" domain="[('user_id', '=', uid)]"/>
<separator/>
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
<filter name="inprogress" string="Current"
domain="[
'|',
('state', 'in', ('inprogress', 'inprogress_update')),
('end_date', '>=', context_today().strftime('%%Y-%%m-%%d'))
]"/>
<filter name="closed" string="Passed" domain="[('state', 'in', ('reached', 'failed'))]"/>
<separator/>
<field name="user_id"/>
<field name="definition_id"/>
<field name="challenge_id"/>
<group expand="0" string="Group By...">
<filter name="group_by_user" string="User" domain="[]" context="{'group_by':'user_id'}"/>
<filter name="group_by_definition" string="Goal Definition" domain="[]" context="{'group_by':'definition_id'}"/>
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
<filter string="End Date" domain="[]" context="{'group_by':'end_date'}"/>
</group>
</search>
</field>
</record>
<record id="goal_kanban_view" model="ir.ui.view" >
<field name="name">Goal Kanban View</field>
<field name="model">gamification.goal</field>
<field name="arch" type="xml">
<kanban version="7.0" class="oe_background_grey">
<field name="definition_id"/>
<field name="user_id"/>
<field name="current"/>
<field name="completeness"/>
<field name="state"/>
<field name="target_goal"/>
<field name="definition_condition"/>
<field name="definition_suffix"/>
<field name="definition_display"/>
<field name="start_date"/>
<field name="end_date"/>
<field name="last_update"/>
<templates>
<t t-name="kanban-tooltip">
<field name="definition_description"/>
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_gamification_goal oe_kanban_goal #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'failed' ? 'oe_kanban_color_2' : ''} #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'reached' ? 'oe_kanban_color_5' : ''}">
<div class="oe_kanban_content">
<p><h4 class="oe_goal_name" tooltip="kanban-tooltip"><field name="definition_id" /></h4></p>
<div class="oe_kanban_left">
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" />
</div>
<field name="user_id" />
<div class="oe_goal_state_block">
<t t-if="record.definition_display.raw_value == 'boolean'">
<div class="oe_goal_state oe_e">
<t t-if="record.state.raw_value=='reached'"><span class="oe_green" title="Goal Reached">W</span></t>
<t t-if="record.state.raw_value=='inprogress' || record.state.raw_value=='inprogress_update'"><span title="Goal in Progress">N</span></t>
<t t-if="record.state.raw_value=='failed'"><span class="oe_red" title="Goal Failed">X</span></t>
</div>
</t>
<t t-if="record.definition_display.raw_value == 'progress'">
<t t-if="record.definition_condition.raw_value =='higher'">
<field name="current" widget="gauge" style="width:160px; height: 120px;" options="{'max_field': 'target_goal', 'label_field': 'definition_suffix'}" />
</t>
<t t-if="record.definition_condition.raw_value != 'higher'">
<div t-attf-class="oe_goal_state #{record.current.raw_value == record.target_goal.raw_value+1 ? 'oe_orange' : record.current.raw_value &gt; record.target_goal.raw_value ? 'oe_red' : 'oe_green'}">
<t t-esc="record.current.raw_value" />
</div>
<em>Target: less than <t t-esc="record.target_goal.raw_value" /></em>
</t>
</t>
</div>
<p>
<t t-if="record.start_date.value">
From <t t-esc="record.start_date.value" />
</t>
<t t-if="record.end_date.value">
To <t t-esc="record.end_date.value" />
</t>
</p>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<!-- Goal definitions view -->
<record id="goal_definition_list_action" model="ir.actions.act_window">
<field name="name">Goal Definitions</field>
<field name="res_model">gamification.goal.definition</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a goal definition.
</p>
<p>
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.
</p>
</field>
</record>
<record id="goal_definition_list_view" model="ir.ui.view">
<field name="name">Goal Definitions List</field>
<field name="model">gamification.goal.definition</field>
<field name="arch" type="xml">
<tree string="Goal Definitions">
<field name="name"/>
<field name="computation_mode"/>
</tree>
</field>
</record>
<record id="goal_definition_form_view" model="ir.ui.view">
<field name="name">Goal Definitions Form</field>
<field name="model">gamification.goal.definition</field>
<field name="arch" type="xml">
<form string="Goal definitions" version="7.0">
<sheet>
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" class="oe_inline"/>
</h1>
<label for="description" class="oe_edit_only"/>
<div>
<field name="description" class="oe_inline"/>
</div>
<group string="How to compute the goal?">
<field widget="radio" name="computation_mode"/>
<!-- Hide the fields below if manually -->
<field name="model_id" attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))], 'required':[('computation_mode','in',('sum', 'count'))]}" class="oe_inline"/>
<field name="field_id" attrs="{'invisible':[('computation_mode','!=','sum')], 'required':[('computation_mode','=','sum')]}" domain="[('model_id','=',model_id)]" class="oe_inline"/>
<field name="field_date_id" attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))]}" domain="[('ttype', 'in', ('date', 'datetime')), ('model_id','=',model_id)]" class="oe_inline"/>
<field name="domain" attrs="{'invisible':[('computation_mode','not in',('sum', 'count'))], 'required':[('computation_mode','in',('sum', 'count'))]}" class="oe_inline"/>
<field name="compute_code" attrs="{'invisible':[('computation_mode','!=','python')], 'required':[('computation_mode','=','python')]}" placeholder="e.g. result = pool.get('mail.followers').search(cr, uid, [('res_model', '=', 'mail.group'), ('partner_id', '=', object.user_id.partner_id.id)], count=True, context=context)"/>
<field name="condition" widget="radio"/>
</group>
<group string="Formating Options">
<field name="display_mode" widget="radio" />
<field name="suffix" placeholder="e.g. days"/>
<field name="monetary"/>
</group>
<group string="Clickable Goals" attrs="{'invisible': [('computation_mode', '=', 'manually')]}">
<field name="action_id" class="oe_inline"/>
<field name="res_id_field" attrs="{'invisible': [('action_id', '=', False)]}" class="oe_inline"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="goal_definition_search_view" model="ir.ui.view">
<field name="name">Goal Definition Search</field>
<field name="model">gamification.goal.definition</field>
<field name="arch" type="xml">
<search string="Search Goal Definitions">
<field name="name"/>
<field name="model_id"/>
<field name="field_id"/>
<group expand="0" string="Group By...">
<filter string="Model" domain="[]" context="{'group_by':'model_id'}"/>
<filter string="Computation Mode" domain="[]" context="{'group_by':'computation_mode'}"/>
</group>
</search>
</field>
</record>
<!-- menus in settings - technical feature required -->
<menuitem id="gamification_menu" name="Gamification Tools" parent="base.menu_administration" groups="base.group_no_one" />
<menuitem id="gamification_goal_menu" parent="gamification_menu" action="goal_list_action" sequence="0"/>
<menuitem id="gamification_challenge_menu" parent="gamification_menu" action="challenge_list_action" sequence="10"/>
<menuitem id="gamification_definition_menu" parent="gamification_menu" action="goal_definition_list_action" sequence="20"/>
<menuitem id="gamification_badge_menu" parent="gamification_menu" action="badge_list_action" sequence="30"/>
</data>
</openerp>

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import update_goal
import grant_badge

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_badge_wizard_grant" model="ir.ui.view">
<field name="name">Grant Badge User Form</field>
<field name="model">gamification.badge.user.wizard</field>
<field name="arch" type="xml">
<form string="Grant Badge To" version="7.0">
Who would you like to reward?
<group>
<field name="user_id" nolabel="1" />
<field name="badge_id" invisible="1"/>
<field name="comment" nolabel="1" placeholder="Describe what they did and why it matters (will be public)" class="oe_no_padding" />
</group>
<footer>
<button string="Grant Badge" type="object" name="action_grant_badge" class="oe_highlight" /> or
<button string="Cancel" special="cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<act_window domain="[]" id="action_grant_wizard"
name="Grant Badge"
target="new"
res_model="gamification.badge.user.wizard"
context="{'default_badge_id': active_id, 'badge_id': active_id}"
view_type="form" view_mode="form"
view_id="gamification.view_badge_wizard_grant" />
</data>
</openerp>

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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 <http://www.gnu.org/licenses/>
#
##############################################################################
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 {}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="view_goal_wizard_update_current" model="ir.ui.view">
<field name="name">Update the current value of the Goal</field>
<field name="model">gamification.goal.wizard</field>
<field name="arch" type="xml">
<form string="Grant Badge To" version="7.0">
Set the current value you have reached for this goal
<group>
<field name="goal_id" invisible="1"/>
<field name="current" />
</group>
<footer>
<button string="Update" type="object" name="action_update_current" class="oe_highlight" /> or
<button string="Cancel" special="cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'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,
}

View File

@ -0,0 +1,173 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- goal definitions -->
<record model="gamification.goal.definition" id="definition_crm_tot_invoices">
<field name="name">Total Invoiced</field>
<field name="description"></field>
<field name="computation_mode">sum</field>
<field name="monetary">True</field>
<field name="model_id" eval="ref('account.model_account_invoice_report')" />
<field name="field_id" eval="ref('account.field_account_invoice_report_price_total')" />
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
<field name="domain">[('state','!=','cancel'),('user_id','=',user.id),('type','=','out_invoice')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_new_leads">
<field name="name">New Leads</field>
<field name="description">Based on the creation date</field>
<field name="computation_mode">count</field>
<field name="suffix">leads</field>
<field name="model_id" eval="ref('crm.model_crm_lead')" />
<field name="field_date_id" eval="ref('crm.field_crm_lead_create_date')" />
<!-- lead AND opportunity as don't want to be penalised for lead converted to opportunity -->
<field name="domain">[('user_id','=',user.id), '|', ('type', '=', 'lead'), ('type', '=', 'opportunity')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_lead_delay_open">
<field name="name">Time to Qualify a Lead</field>
<field name="description">The average number of days to open the case (lower than)</field>
<field name="computation_mode">sum</field>
<field name="condition">lower</field>
<field name="suffix">days</field>
<field name="model_id" eval="ref('crm.model_crm_lead_report')" />
<field name="field_id" eval="ref('crm.field_crm_lead_report_delay_close')" />
<field name="field_date_id" eval="ref('crm.field_crm_lead_report_date_closed')" />
<field name="domain">[('user_id','=',user.id),('type', '=', 'lead')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_lead_delay_close">
<field name="name">Days to Close a Deal</field>
<field name="description">The average number of days to close the case (lower than)</field>
<field name="computation_mode">sum</field>
<field name="condition">lower</field>
<field name="suffix">days</field>
<field name="model_id" eval="ref('crm.model_crm_lead_report')" />
<field name="field_id" eval="ref('crm.field_crm_lead_report_delay_open')" />
<field name="field_date_id" eval="ref('crm.field_crm_lead_report_opening_date')" />
<field name="domain">[('user_id','=',user.id)]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_call">
<field name="name">Logged Calls</field>
<field name="description">Log a certain number of calls to reach this goal</field>
<field name="computation_mode">count</field>
<field name="suffix">calls</field>
<field name="model_id" eval="ref('crm.model_crm_phonecall')" />
<field name="field_date_id" eval="ref('crm.field_crm_phonecall_date_closed')" />
<field name="domain">[('user_id','=',user.id),('state','=','done')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_new_opportunities">
<field name="name">New Opportunities</field>
<field name="description">Based on the opening date</field>
<field name="computation_mode">count</field>
<field name="suffix">opportunities</field>
<field name="model_id" eval="ref('crm.model_crm_lead')" />
<field name="field_date_id" eval="ref('crm.field_crm_lead_date_open')" />
<field name="domain">[('user_id','=',user.id),('type','=','opportunity')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_sale_order_created">
<field name="name">New Sales Orders</field>
<field name="description">Based on the creation date</field>
<field name="computation_mode">count</field>
<field name="suffix">orders</field>
<field name="model_id" eval="ref('sale.model_sale_order')" />
<field name="field_date_id" eval="ref('sale.field_sale_order_date_order')" />
<field name="domain">[('user_id','=',user.id),('state','not in',('draft', 'sent', 'cancel'))]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_paid_sale_order">
<field name="name">Paid Sales Orders</field>
<field name="description">Based on the invoice date</field>
<field name="computation_mode">count</field>
<field name="suffix">orders</field>
<field name="model_id" eval="ref('account.model_account_invoice_report')" />
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
<field name="domain">[('state','=','paid'),('user_id','=',user.id),('type','=','out_invoice')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_tot_paid_sale_order">
<field name="name">Total Paid Sales Orders</field>
<field name="description">Based on the invoice date</field>
<field name="computation_mode">count</field>
<field name="monetary">True</field>
<field name="model_id" eval="ref('account.model_account_invoice_report')" />
<field name="field_id" eval="ref('account.field_account_invoice_report_price_total')" />
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
<field name="domain">[('state','=','paid'),('user_id','=',user.id),('type','=','out_invoice')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_nbr_customer_refunds">
<field name="name">Customer Refunds</field>
<field name="description">Refund the least customers (lower than)</field>
<field name="computation_mode">count</field>
<field name="condition">lower</field>
<field name="suffix">invoices</field>
<field name="model_id" eval="ref('account.model_account_invoice_report')" />
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
<field name="domain">[('state','!=','cancel'),('user_id','=',user.id),('type','=','out_refund')]</field>
</record>
<record model="gamification.goal.definition" id="definition_crm_tot_customer_refunds">
<field name="name">Total Customer Refunds</field>
<field name="description">The total refunded value is a negative value. Validated when higher (min refunded).</field>
<field name="computation_mode">sum</field>
<field name="condition">higher</field>
<field name="monetary">True</field>
<field name="model_id" eval="ref('account.model_account_invoice_report')" />
<field name="field_id" eval="ref('account.field_account_invoice_report_price_total')" />
<field name="field_date_id" eval="ref('account.field_account_invoice_report_day')" />
<field name="domain">[('state','!=','cancel'),('user_id','=',user.id),('type','=','out_refund')]</field>
</record>
<!-- challenges -->
<record model="gamification.challenge" id="challenge_crm_sale">
<field name="name">Monthly Sales Targets</field>
<field name="period">monthly</field>
<field name="visibility_mode">ranking</field>
<field name="autojoin_group_id" eval="ref('base.group_sale_salesman')" />
<field name="report_message_frequency">weekly</field>
</record>
<record model="gamification.challenge" id="challenge_crm_marketing">
<field name="name">Lead Acquisition</field>
<field name="period">monthly</field>
<field name="visibility_mode">ranking</field>
<field name="autojoin_group_id" eval="ref('base.group_sale_salesman')" />
<field name="report_message_frequency">weekly</field>
</record>
<!-- lines -->
<record model="gamification.challenge.line" id="line_crm_sale1">
<field name="definition_id" eval="ref('definition_crm_tot_invoices')" />
<field name="target_goal">20000</field>
<field name="challenge_id" eval="ref('challenge_crm_sale')" />
</record>
<record model="gamification.challenge.line" id="line_crm_marketing1">
<field name="definition_id" eval="ref('definition_crm_nbr_new_leads')" />
<field name="target_goal">7</field>
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
<field name="sequence">1</field>
</record>
<record model="gamification.challenge.line" id="line_crm_marketing2">
<field name="definition_id" eval="ref('definition_crm_lead_delay_open')" />
<field name="target_goal">15</field>
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
<field name="sequence">2</field>
</record>
<record model="gamification.challenge.line" id="line_crm_marketing3">
<field name="definition_id" eval="ref('definition_crm_nbr_new_opportunities')" />
<field name="target_goal">5</field>
<field name="challenge_id" eval="ref('challenge_crm_marketing')" />
<field name="sequence">3</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- challenges -->
<record model="gamification.challenge" id="challenge_crm_sale">
<field name="user_ids" eval="[(4,ref('base.user_demo'))]" />
<field name="state">inprogress</field>
</record>
<!-- goals -->
<record model="gamification.goal" id="goal_crm_sale1">
<field name="definition_id" eval="ref('definition_crm_tot_invoices')" />
<field name="user_id" eval="ref('base.user_demo')" />
<field name="line_id" eval="ref('line_crm_sale1')" />
<field name="start_date" eval="time.strftime('%Y-%m-01')" />
<field name="end_date" eval="time.strftime('%Y-%m-31')" />
<field name="target_goal">2000</field>
<field name="state">inprogress</field>
</record>
</data>
</openerp>

File diff suppressed because one or more lines are too long

963
addons/hr/i18n/he.po Normal file
View File

@ -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 <EMAIL@ADDRESS>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\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 <EMAIL@ADDRESS>\n"
"Language-Team: Hebrew <he@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to define a new job position.\n"
" </p><p>\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"
" </p><p>\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"
" </p>\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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to add a new employee.\n"
" </p><p>\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"
" </p>\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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to create a department.\n"
" </p><p>\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"
" </p>\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 ""
"<p class=\"oe_view_nocontent_create\">\n"
" Click to define a new department.\n"
" </p><p>\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"
" </p>\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 ""
"<div class=\"oe_empty_custom_dashboard\">\n"
" <p>\n"
" <b>Human Resources dashboard is empty.</b>\n"
" </p><p>\n"
" To add your first report into this dashboard, go to any\n"
" menu, switch to list or graph view, and click <i>'Add "
"to\n"
" Dashboard'</i> in the extended search options.\n"
" </p><p>\n"
" You can filter and group data before inserting into the\n"
" dashboard using the search options.\n"
" </p>\n"
" </div>\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 ""

View File

@ -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) <fp@tinyerp.com>\n"
"PO-Revision-Date: 2013-12-27 05:02+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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

View File

@ -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',

View File

@ -56,6 +56,10 @@
<field name="module_hr_expense" class="oe_inline"/>
<label for="module_hr_expense"/>
</div>
<div>
<field name="module_hr_gamification" class="oe_inline"/>
<label for="module_hr_gamification"/>
</div>
</div>
</group>
<group name="timesheet_grp">

View File

@ -57,9 +57,10 @@ class res_users(osv.Model):
various mailboxes, we do not have access to the current partner_id. """
if kwargs.get('type') == 'email':
return super(res_users, self).message_post(cr, uid, thread_id, context=context, **kwargs)
res = None
employee_ids = self._message_post_get_eid(cr, uid, thread_id, context=context)
if not employee_ids:
pass # dpo something
if not employee_ids: # no employee: fall back on previous behavior
return super(res_users, self).message_post(cr, uid, thread_id, context=context, **kwargs)
for employee_id in employee_ids:
res = self.pool.get('hr.employee').message_post(cr, uid, employee_id, context=context, **kwargs)
return res

View File

@ -72,4 +72,4 @@
.openerp .oe_employee_vignette .oe_followers {
width: auto;
float: none;
}
}

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2010-today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
##############################################################################
import models

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
{
'name': 'Applicant Resumes and Letters',
'version': '1.0',
'category': 'Human Resources',
'sequence': 25,
'summary': 'Search job applications by Index content.',
'description': """This module allows you to search job applications by content
of resumes and letters.""",
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': [
'hr_recruitment',
'document'
],
'data': [
'views/hr_applicant.xml'
],
'demo': [
'demo/hr_applicant.xml'
],
'installable': True,
'auto_install': True,
'application': True,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,257 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="applicant_attach1" model="ir.attachment">
<field name="datas">JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURl
Y29kZT4+CnN0cmVhbQp4nJ1UTWvDMAy951f4PKhnKbEdQyk0TXrYrRDYYey2D9hhsF7292fZtdJk
djpG4REqS37vSbKSIL6rL6GE8l/aaYmibUC24vxaPd6Jzxjzv/N71Y2VNj5krRHji7g/ggAlxren
rYIdbhUS1AQNgSYwBHb3PD5Uw1idsuU0Srss2FKeI9jHCh663cYSYglK4UP8KpAA7bz2LIueEgfW
FhQdPYCKpNKFACx9SHQB11U3sLgNKB+aBPHKS6UAWXk3NPswEG0wHMGcgDo1Cyz7HQ620w09ezAw
q5ZPTwFXEu5Q1sKik83S6BtiimGg6YBuNixwmNsFk+CrP3vOwXnbiuxj28AuxoTqjR/ZwUI6+zvj
aUUfBAcDHFPbUEVe/mvaM5dYI/5hxZSRy3HDmm1xvKl6tr3IN8U+66sp34AtjBs5i00cqjVSpkWP
uY3bM6nLG1La3GBwtk5xG27udHGbvSodM6jMwE7RQTRsVx3C+8ukrRrgHx69fAT6VBLslQGzZf3P
I4BULQK1El0arvg6kAFItmMX5495n8QPLYlXWAplbmRzdHJlYW0KZW5kb2JqCgozIDAgb2JqCjQx
MwplbmRvYmoKCjUgMCBvYmoKPDwvTGVuZ3RoIDYgMCBSL0ZpbHRlci9GbGF0ZURlY29kZS9MZW5n
dGgxIDE4MjEyPj4Kc3RyZWFtCnic3XsJXFTXvf8599w7GwPMDDsIXAZxiQgI4hYThlVRtgBuSY2O
zCBEYAgzuD4jxocbGJKagKiN1qbG2DRaaw3GFI1iE7PU2GjaxqapjWljQkyedUkNnLzfOfcOW0zS
z+v//3mfz2PkzrnnnvNbvr/1XBJPXb0TGVEDIshWVm2vvf0+vYYQehMhbClb6pF9ta0/gfFfEBKS
ymsXV3e7UD5CognWPL+4akX5uuXzcuH+ZYTCxAqn3dE4bkMCQpEn4PmECpiIpjVauP8S7odXVHuW
/8b/EQmhqGFwf3+Vq8zesfb8Krhfzu6r7ctrP8LPsOfn4V6usVc7L60/dy/cX4fb67Uut+d+tPZr
hNI+Zs9r65y1jZ2vdiFk0yGkjYA5DB/2Y4Shht0LRJQ0Wp3e4GP09fM3mS0BgUHBIaFh4RHDIqOi
5Rhr7PC4ESNHjb5rDPq/+dOB3uC/+/ET8F3OZzYIa5DQ9+lAp+C5wNd14DfwJvwSjPeiHriuQ9ew
gbyKJ8KoE/bOFWNgtgXt5DtbyN9RPXkZvYPOoIsw+jueTGAvfgfF4A+A2qZ+LqQT7k7BdRXpJHNx
NK5Gz+AXgOIq4OlCawT4FoqB8lviOZh9C22Az1b0DHLBmEm2DuR/Hx1GTeg62iZcQffD+CV0GuSh
yE/hgS+gm0Bpv3CPUA7rTgO17Wg7XocuILeIsAFWXpIuCGOA6mHQAKFFaKd0QdrG8IDvC9IX8ASc
VdOhCdTGghYMt734ZTxOKEDvwP5VqJT8gDxMLuJGMVZcRq6gFgGRheghdFa6oAlELdpY1KIpxyvE
hfyziuknLBMX4v3oCtBcRL6E+xiQbCfXGKHDQrFUIBWAzuUwt5NfW5SrxoTeIrcB9ycEiqeLOSQN
nqwS89A2tAd2jgRkEHKRVODuQqukLcoH7YfPWGkLaQX6HA2cItyDdgrluAmkvQloukgWmgg8IqWr
qBEfBrmRdjVySxcQCkQvajWSSASM4mXTQSEu13HQdt9c+bV5MWPjh9zKJq18EBUd9F0hd3z9ddFc
MUKad1AadpDE6Q6KcbGXvu3hpbHxM4vmyh04JDtLJZu9MAsmS+bCkN3BNMxnZ/FnjOtBKQ7+5S48
KJdVyJtNm2OnbDY5p4wFm1fQVrFCegaylxZFv4xEDMogDQ48gnXSOkFEiV3nu8ch0/nu891JAeYY
c1yMOaZCRD1uEtHzEW3V+n15rU4zmsWJAFZBYj2goEMBaIwtFLeZUJt+o8Vk0AEhKdl3khlF6VMC
TT3dyT3d5pDJ41DidUYXm1OSJ6SOHxEbF5MsBgWKY7A5Frd80vyjnVtoHj58Gwv0668+eV1K7D37
ZGPj1r0fXnz/r737GE+MHwKe68BPzKjQFqDR+hBkJm1+nfqTWoNGg3QW0/mu7mRgdBk4vWmebJ6c
ZIszIRM2mWUkY9mchJJwiinJbEM2nGmymYtQES4yFZkt83ECjrVqgsyx5pSge3FKcnCIuO7ulbnP
Hzl6NOH4uqylE8iKhLv+8GbvO+LCi8vWWIcrGGz6+kNxOsjjg0JQLEjUbEHNxk5Le6je4p9FLEH3
hpqud/cwSEEi09UkDCwCgxX9RyZbzCYh1iqYTRahovnxx5u3PP74liu3bn5y5eZN8sF77164ePHC
u+/tpL+jf6WX6Dt4LKSBKJzAsvYpwGEkeGIAGm8Ll0zYqDuiwc1oh5/mpEEI0CK9pPH19wk0nZ/a
1TO1K3kyA/8ymMF0NdkyeXISDgJdI3FMUAzoG5Makzp+Qoo48lxZPl5L13TQC3jMc7/UBLbft7is
pSeRnGsp6HhB0fcQ8M0CvnrkixJsYbojyNhl2IFOaoQjIsnzwRopD800aP2A8eXunqmgeGJ38uUe
rjq4UhDwMsfglKBYKDy/x9U9NbiaXsLRHR3iwp7ElhaSIWReYfrtBj4GTTRwGWEL0CNiOGI8TY5I
RCMijU+eHuh397zJtQJ0zUyjwOC7mVYjUpk+wpoH5v3+yk9/Rf+IP8Ct//HIzvMnyT8fB/lXgb3m
gr2C0DCUbRuBggk2NOm3aIKPYE2zL34lrDmg07c9kgjDTPpgDcodZjFNj+Qm7DJbGD9mx8umq/C5
ftXC/AsHxSgWnRjkh2NlZDahlGSLlnuTVpzb8+HxF+aeqK489QD9ir6H5S/evdUhPrGx8XmT8OD9
mhdfmzT5xTFj8GQcgI3YRv98es9zB3eC/k2gfw7Elh5V24ZpsYAFjVaToRUIOqyTNFgrmMVxWjNK
MkB0cQAAiandYOckSAtak3iG/c6zHgrBGM+3jQgRQrWjhRHaSdo5gkN4SFsvrNQaQjUj8GhNDs7V
zMGLcYVGNx/ND4iB6AQLmWObwEJfnvoaUd0p6cJXKeJbt8eIb32VAhg2Aoax3OdHoxrbXQYtCpeN
of5adCRU22yJaZKPRzYPZzHgi0PFMD+Dxpgli5qge+8CHLsgGSQr4nZdvt7DYsJ0lcUpYGmBYI1M
ik6Sk2KSrLvRbrxb2G3Y7bMneHfI7tDdYbvD/ebzEFXQTp1ojk0FxMHi4yfcjVMVwFOV0I3CQuc9
P/7JyqptL+CjR+/+ZcPP3vzqH7fw+q0Pnnig/NjcptP3jJCFlIdrnbXvvDQ6r3ftXseCV/YcOxm5
fsWE8R0jRxYXJ2/l+QZVgx1coKsV/cQ2MtTirxe1KDJCow0yNsukM+JkmEmLzP66fE2BOd+/YFho
fnh2rOn6zIPG0pkHzaUPzD2Kwr8+MWlez1RuJgs309TL18FUTOnJkBWTbNOSxCQpSZOkTdIl6ZMM
ST5pwWkhaaFpYWnhaRFpw9Ii06IaSIPYIDVoGrQNugZ9g6HBpyW4JaQltCWsJbwlomVYS2RLVCye
j7n2YTjWDNlVSWZ9AzWrCc9YK2dscO1LzSm6e9/kGbmTn302piwtz0muTs8+Rz/oXSas/cy96qPe
NcLaL2rZt7hw4dS0HIh9DIEpfCSO5LUjwuYr7EHPi3s0Eo4UkQ7inefd7uuQ31MYO8jpV3rgRxxJ
z9HJ9KyCJ6sZBeDX4Du2YE2bKLShjbo28RcGLOnHaUkUSjHyetHVxYh185wZwNKU+nuaLO0tFR7r
rROO9yyTLuynOft7P9yv0GY5MQJsFYDibaF6P4IIxLS503jSANGDZvjqNT45geCDySwfJ4IVWFGC
AL4DSmLE0YceXtvU0TFun/tnzwlHemcIR9oee/FnvRvEhfsWll1Scj8tFqPFZaDLMJRiGxZq1JNm
f31zUKd/e8SpsJORoUaNJnwasljuVTJIcjJLH5d5IVBTlloIrRrMPJkVAua9qQy8vA2NjZs2NTZu
EMLHtjvPXPn4dUd7wtGjwph337t44cLF93o3l8zDE7EZB+Mpc0pa/nlTwQBiM0J8cAgG7QZ80sj0
nwFAcAx6lCqZrGIQAPZSpGGGU8LqVMeS2kc3Hz067rmHn9+H9zEQGATCiq/27LM7Lqnx8fWH5GWw
pxn4hRi1OowOiW3+ujbDRv92i14b5YNSLaae8z1d3gp487dM9YmpUZhzY/XApAFu1Q+crGh5mK4T
pr1za2HnPd333ffUGyRrf4+F/u2TeIXXBdBNA/YdieptNl+j4OcTEh2l0wtaQ0hUdFRGZFSowScq
WgxCTfiEGNgUdCK02Sw2x3Wa20dFGnyiI7SoMELjl6vVBFqzR5mudwEIl1lS96Z1E71x1XTjqiWE
pyKeR/0+A3i0/DrPioMS1PzDynBQIBN7pKrI+EQhAbMqmhxM3ircXbJ61Q9enLFpS/fvSo48tPjl
0pXrb+iyd/3wvdfv3ytOPpyQcF/JzBmxfuE7V+89FhvbmZpaNq9hnOAXvXXNjw/EcN+KA19+HnAV
kAFts6WjOIxESRTiJFELv5o4SRL1ccSgg18cZyAGFAeNNTFkIKJtwwfJRr2k12k1vDHVS4kGH9Of
unkDNhVqsVc53Wdak/SZVvk3YKT7DAqHlrDCEW5A/tBFtyCRYB9BJEZRr9Xo1uNNAisWmEApx7Ek
hsQKFRfwfvqLG/jMuZreG1XnpNhekbxwewxupKuQWnct0DeYIFaSoGNBgeHNfoHNuna/TryDhEBV
F6aZLT7T+yMlsbs/UPqcUo2QgZFD7u/oSGh3vHHlk9ed26n/xsbGpqbGxo3knJD5z+4tJXMwtAUQ
JRPnUJ933/vTeYgc5ks31fpqgP4ikLA8JG3UQvuqi9VEERSLfaDB6OpR2hfetEIjLKXGpbAcBLE6
hb6Ai17HE3pe2y/W53XMuH1BzUHbgG4snIuGoftso9GwOEkjwdmZhETEaTRShsn8rG9bYKuI2gRk
MgjYEBViNZHhkaYe4HXihFIfGMPrbyomkrj/wVdI8jxrHGufJqCJ92JFc6XYQQet0fphXC+80FN/
DIemOnK2NjzwWu3iV+0Xsc88x6QL+/fvP40T7l3ZVrj6sYzMN8clX/n1whOe9L8xu7zC+iGwi49i
l74c1u7fGbEjDHLXNJ7FcphdkpXEOcAuStrkxuClR+lnR4wMgkRKWjc2rt+8eX3jxt4P43eUv/7x
lTcggXV0CIksgZ3/03vC8uK59Az9nH5KT88p2cKOVRhOb0jUSU9D/hpnC/WTdP7kCDLjk7ojBp2P
Ho4VGpPFb3BX2319aherpsxNWJEY1Aea4Ri3hz74YP3ZS2f3s7ZWepqebOnd/R+Ltu59Q1jYgu+F
M8VWekm4hhORhEJtPuQnaI+GiDgSWMEp6E1IDT2spAWR2AB8s+f09jKceJauxWsUezcBfuPA3mHQ
DYeH/RIdCm4jvr80HjK16VtJe3hAshGN0ySFs5qmHgJ4EryaFOdtFmMg4fPEovj2hIniuPw9D0C/
fwqn4cgH9uTP2D/7dFfX6bnP5aaOHo1bcS2uwe2jR5+9x0bfpm/R39K3bff01z9+Jhhc/3bcuf51
37H+mb+n/mkCe5/hBVBAnXS2WAr52KTUv76Y7vRrx6fIyUiI52k8sgd4z8D6F9dXb1W/GeRPy+Dc
BWH9949fL2/HX2xQfGnDlt4zGkNLyRz6G/oJuM6ZOfiG6k6KPWYDBisgro2o0RavE4igJUQA/bFe
EHCGgTXQOuihfSA9Qm6U4NAoJho0KMlX6aND1D66izVmSgSe8XbTbAyJ0d+A0XzbcEln0IfgUBKi
C9VDG01G6EbrJ+DJZIJukt7PXwsfA5mPoZ/WY3bGwrEA82zIHAIWsf8xerOd3nhJutCrE768PUYa
2fMZCbj9R7Xvnwjya1CqLUyKAwVIHCT+DAn6JCIR2GxF0VoTO45MVg7U3kTBfudZoVcCVjFN5Pne
T94RdL2p0oXZt9dKY5i9ylkvy2uKL8qwRWNf4gs1wxdqho+2TcJQNLDRgKJ0osbfONzP1NNznrep
rE9gI8uAswVDAhQjKWDAWH6EFD6go/HvYz559dUzvRukyJ5PyVs9Kc/QndhxHEHHyM4MeRAn/JyM
DbZw8lO9pS3K2BbaGtU+PCgqQhODIqz+UTHRw0E5SLimq96O4fzVJNu7iSgRJwqJJFFMlBI1idpE
XaI+0ZDok4bScJqQRtLENClNk6ZN06Xp0wxpPoWoEBcKhYZCnwVoAV4gLDAs8NmFduFdwi6yS9wl
7dLs0u7S7dLvMuzyOYAO4APCAXJAPCAd0BzQHtAd0B8wHPA5jo7j48Jxclw8Lh3XHNce1x3XHzcc
98n5NmFUVmSBuEBaoFmgXaBboGeMv43QcHAQzHsGpZkIUHMAC4eBLwfwh/kTJhUVTp40s3FLU9OW
x5qaHvv8xo3PP79+Xbg6saho4qSCPGEnJIMz9HX6Nk7CE6AvTNpNl9O19FG6HG/Ej+A1eCOPD+jh
xbn8XDncFqD23+IvdBLmzfd4g9J8K438wNY79gpx9f5AcPbueIN13dP3907s6zfjIAeEoURbuLHJ
94QJNYWdCG4mpmZ9J0uAFiPS5IRDt+XNfyZ6nXVZd0iA3pOdGDfjR8W0h17EcVi8b3tB7tb5P3/p
2PMLt6VPhqPyJBwIn0l3xb+SPuUvb5+9dPe9zLfr6TXxB+BfZhSJ7rHJKMpk9o9oI0E8DZujzKEm
oz8KtSQbJ4Qma1KjvKdmdggDsbq4o8EZFHxcsmpiB9hBG6IN8NoBZoQWbbju9q1bPb23NjW91mba
sL19w4b27RsiBNyA1+MNuIE20BX0Pdo+vdNBbuFcHE7/Rl+kHfRvOAziYC/g/zB/Z2ZGMkgaG4ba
DPo2y0bcZvhFtNknLDpAJ0jILypYSh42To+iLEkxygu08zxbT+47Fk3uf49GBrxQY66kZd2pOBrj
hz8/2Pr0vs8//eG6tU/SGfilj75ct27rs/Qm/SfNEc70vr9qyw83CeX03trVDzv2/uZXm54ODD67
+42zgGcEfUXcLrkhXsejWtu4UWOGh4cQP6M+Yjw5EKI/YDSPHH5gTEjUgXFjUkf6akaBkccEonDf
BGNgzBjj2IRU6Dd7ukx0aheken60ZyifZ1NdF7rgyD95sjLND/2+6tE2oCGwIUjDYqK/DgT0H/L5
0Yg9UrxmwsSQfheyBIl+DUuWrF27ZElD8+Nx64p//M47Py5aP/zgEzfp+3gGtkyompyUtmoK3UHn
4+V46rnbQszaHTvWPrpjB/3YlZZ17eWXr+Xck7azE2LmKNhrZWDQhrBQ/DvcDFb9Lb35F+gT+PkX
jwMrmo6gPQK0CKLpPO+I+JGXHXfxOH7QFdAaiIscnu+Go7tt1gANagv+mcm3yfiYqc2qaRvWam2P
C9AQHG3VRxlHhEXHmXoug0v2vSi8yWKEvV3ytrmABuFnDYuZN8Kp4y0psoXpbh0hlK7dunXt+o0b
LqU9ln/idOL+mj989o8/Y/EafZ9+mvuk0PrSM8+89Iufv3Cwd9NLcSNxDA5zLMGG6/+F9XQzddEN
1B2N1Pc6LEeHgszgmdrosDZDdJvJ8DMRN6HHxLbgVlN7nDUKjfC1ajXDcAATursb5O5rbD5S3uYk
YbWh4bU9KFCIlQUl0Ae+/iQfMGl/k8Skvf4+7bkGhStwxpP0/bVPPgnKbJQOg7D0A/p3xxJ66x/X
6E1cj5/AK/GW6N4qr0I8B7F3sBNB7lFoGvTcAW1Bhib9Xt82TXSTvHdYW2yrpj3oudHBAYgEhkWN
MEURa3SgPno09NxdalSB/N19nRmPLB5AA493I8bg1L4jR3/jTXRbd9JPbyx+d3H5bxbtPXRo2/bt
TTufWD+vs2LFr3Pfw9ImEj3y1ad+++mI4WdSx7duebR978pq96pRo16S5Yu/WvWM0rO0gPxjISew
zGUVtZHhbVpzk+mxwDZflp1927X7oyA3h0RhgxWZoqPYYaFLrY9eX6FdEEc8WTPJUFAgGiQ8k/ms
cL23a8yc+I+xiX54a9npgh+8ZH/2V8eevW97DsvoT5j86dVPuukXsvxW8riDe3YfiosDT18HshVw
P45FiSjTFhdqRG0jNW1RY9ssULlHPpcUahx+V1TQ8Ch/fVRQhJVE+cdEJ4GI3VxG3uip8Jp42A96
Ax7nPTP3Ja1Y63CYCRhwvhMqNmx9qnHj1qfo62ufuPb2uWtPrG3dRenly/TrXfkNK1Y2rFm1okE4
3bZ5c3tb86ZtpTGH1xw6d+7QmsMxMa/tev3yh2d2n8GLlj/yyPKVDWsVvMHXS1ee+3PxuAX+U2+g
aB3/s98bzz25o/+PgLRYfF4DQYF0fVOwT1tNIwf8pRAP+cshFs+hCnQaP8T+cocOod1oFfRzjewd
IuSO0zDH5qvRBTjds781bUOvoHV4K6w5hTqhc22CDq0RKvQpVA91IgL2rIH7TXD6Xsfpj0AL0T50
Gcu4FIrNecEqbCPgGcRGashe8oU4SnxQPC9Nlf5TOqjRaYo0mzX7NFe1I7S12re1VDdVj/Sj9FX6
E4ZAw9OGwz5+Pg/5vG4MNT6qahKPUsHeylt+E2pnmktzsBlORSLMBWO/Pn0X9OmOYeUCdSzAOpc6
hgyJ3OpYhPE6dSxBX75VHWuQH9qljlk1/Lk69oE46FTHvvqt6KI69oPupAYoY1EPd52GPeoYI9ln
oToWkM6nQR0TmN+ojkUY71PHcMrzeU0da9Awn7+oYx2y+vSoYx80xRiljn0DRhjnqmM/VBH9SKar
dkVd5eIKjzyqbLScnJSUIi9aIWdUetyeOqe9Ol7OrSlLkNOrquRitsotFzvdzrqlTkeCIcv5kH12
vVxWYa9Z7HTL9jqnXFkj19Yvqqoskx2uantljXdNib3GLee7alwZLteSoXND72c769yVrho5OSEl
RXnGHg1YWe6qAUE8IF6Fx1M7JTHRAfNL6xPcrvq6Mme5q26xM6HG6cnhy5hYTLU+leRRbqdTXuSs
ci0bnSD/C0okGAz9m0E4u6xQ7oPOMPY7fwyG/znI8hDOlSCi7KmzO5zV9rolsqt8KBWDochZV13p
5gjC6gpnnRN4La6z13icjni5vA6Uh22gMMAUL3tcsr1mhVwLmMMG1yIPKFxZsxi4lIHQbKWnwqki
bi8rc1XXwnK2wFMB1AEkZ40bALZySKyjgZhDtrvdrrJKO/ADBMvqq501HruHyVNeWQUYj2IU+Qa5
xFXuWQaYW0dzSeqctXUuR32Zk5NxVIJilYvqPU4uw6AN8WClsqp6B5NkWaWnwlXvAWGqK1VGbH2d
AiWQrXfDeqZOvFzt5Fpz+7or4gfwiGc8E111stsJdoDVlSCqqv4Q1kw4IFvLgPao0HFGyypc1d/c
wMxQXl9XAwydfKPDJbtd8bK7ftFDzjIPm1EwrgKXZAqVuWoclUwP9xSDoRQe2Re5ljq5BooXcQH6
nKDG5QEzuJVZZpXafg9QnsnuCjsotcipogZigJPbB+npqgG/qJOrXXXOO6ote1bUOsvtwChBEWrw
02r7Cka/2uWoLK9kjmav8oDrwQCI2h0OrrkCHYsvex3IVV9lr+OMHE535eIaLsbiqhW1FW62iXmo
vQyIuNkOrzzuoZwUj3MogNmrBhAYQkTd55WlnyKIWFO1Qq4c5OqgUp2T/SdIfC0buBmYzDbeEHGC
3zkVBZa56hxu2doXi1bG2/tAtrLQtXLYwDp5aswsckI0Mar1YAemxFJXZZ9gzuUeiBrZXlsLIWZf
VOVkDxT9gfIQw1TYPXKF3Q0UnTWDcQF2/R7ukOtrHKrA1sF5xapo+F2WdbuqWGRz0zFD2eUqlkEg
XrwLa+1lS+yLQTGIxRpXX/741x1rECtIWiCis6qcCTU9W84pLCiVSwpzSuekF2fLuSVyUXHh7Nys
7CzZml4C99Z4eU5u6fTCWaUyrChOLyidJxfmyOkF8+SZuQVZ8XL23KLi7JISubBYzs0vysvNhrnc
gsy8WVm5BdPkDNhXUFgq5+Xm55YC0dJCvlUllZtdwojlZxdnTofb9IzcvNzSefFyTm5pAaOZA0TT
5aL04tLczFl56cVy0aziosKSbKCRBWQLcgtyioFLdn42KAGEMguL5hXnTpteGg+bSmEyXi4tTs/K
zk8vnhnPJCwElYtlviQBpAQacvZstrlkenpenpyRW1pSWpydns/WMnSmFRTmM4xmFWSll+YWFsgZ
2aBKekZetiIbqJKZl56bHy9npeenT8su6WfClqnq9MPBNkzLLsguTs+Ll0uKsjNz2QBwzC3Ozizl
KwF7QCKPi5tZWFCSfd8smIB1XhZgkOnZnAUokA7/MrlkXP0CUJfRKS0sLu0TZU5uSXa8nF6cW8JE
yCkuBHGZPWEH03EW4MmMV6DKy2zE5r7pHbCK7VYVzMpOzwOCJUyMb6wF78peXuas9TDfVoNbSY88
lSr5M557rZIEwIWn1UDgKnN8CP4MkcUrj5Lh+oOLleR4Nf2y9AHeDdVISb+OpU7Igm6WSiA+XCyZ
LKt080iHMljtUuue214FzGBX3yrIl/Yq2ObuE3NwQHkLYm1dJWxZVlfpgWQi2+thtq5ypVqK69RS
NVQDxmWo/HVOdy1UqsqlzqoVCbC2jtUzLkllDbRb1arqHL4yzxRvDvXIizlxBygOTVmCbPjOfi1x
WeWSysRKyFHLE2orahPVRIkyoROvRStQHapEi+FM4kEynI7L0Gj4TkZJ8EmB0SJYIaMMWOOBbt0D
q53IDueTeJjNRTWwPgFG6agKPjIq7qPl5ndO+HbCnqVwdcBKA8qC0UNAYTacX2TYXQHjGtjj5Dvs
nL4MVGrgWgtrFgHdSlgnw34X8LXzZ0PplHAqjEI+rKqB3wz4daEl37vu+57P5vK7gauLy5QMWqTA
Z+A+76470yznswoiHhU9hpAH9JsC5+VE0ExZvxTWJ8A6F3zXgc5OvreOo5MANJywJ2cANS9aXqt9
00rsGbOAk1vSCVi60DJYy2z2/8YSzKaGO3JWkLPDaKDM3/Q6Axr7b3wY9/8NT74z2v06V6ooyvy5
ndu4mqO6BOZcYNnvk4VpVsTpVXNq/T6o0K7gz5yqXos5lxruYQ5Op5w/dfZxUyyseFM8l8vFJazh
+2tVP1c4uICqR7VwJfcKRZcyFWkvTQ+XYrCP22FVGfeQWpW6lwJbrciueJKTR43iwdYBXmLllmN7
HfzbzeUqgz12VT/FB8vAK6s5FQ9/4sWnHEZVqh+P6pOxnwOLcya/B2JB8XPGsR8TNlMLVxdwqedy
9kvj4Bp4uK8tgqce/tTL49s5xKuxVAaS1XMqCibLuA9U8Jj3qMhU87mBGnnp1w3ySkXaeo5h/ADr
sHE1t6fX1v3x64bd8d+iR3yfnok878icshIPCu1KFdXB1v9urb3IKdLW9nm0Z4jX9Wu0jONR/S9x
8EZDOc+ZNaqGzgEcHfzKeMTzb4bEQ7CijNNT1gz04yo1S3otVMZ5O7jElaqkU3h0lqq77EDRxTND
vw0G5qJ+BL6ZCVi98KjR4B601hsr/YgNzAED98lcZ7tqqUV9edvrawoaSia3f4c9XbzGyKrtq/l3
f/74V2zhAc1red2yqxolDELqu/YyTFb0yV/No6+Sx7I3ozHZPWrWU2YUSRmmjgE2H+h13vrFuCh4
1QMVO9/n1cjBJWX2qhmAxmJYx7SpUOfqBuRQO/cexXe9PIbi4/5enQbmOMcgD7NzG91Jgu+WZDC/
objcScZ41e5VfF/ld2T1OjUDObl81YPoemfcfZ7pjZuhVcSp5jvnIAss41o5+H7rHeqitU/voTvY
em/VtQ7wNiV28obUmUU87l0DZK1X48FriaXwtPIOiDnRco5zjRrRtfBRqpidZ1Zn346B9ldk/u6I
qeCZXubfblVGJ/eob/cXRbs75XD2tJ6vGozwnVCVByA30Ib/05h18+zprdn9UeeNKNZBVPX1IHXq
jsEUa7lHL4HrYtViSl2s4dgO7T/+f2Ssb9dqkRojHrUulvchNR1lcz6FqADuGJ9CuCtFc6CfLObP
cmFOhn6uGJ7MhrssmM3idknnT9hzK4/GOTBmFAvRLE5LoVEMV0Z7Hsww2jK/Z3czYX0B0GJ7s9Fc
ziMbqJXwlcWcdj7M5sF3trqO7ciEmVlwz8bTEOtGFX4FsKuUxw7bx2RRJC2F+X6ug6XK5Ry9kuXD
XTHQn64+TQfauZwekz+eI8XGBX1y5qiSpnOMGGVGMxMkyuN3bHYWfBfBuhKOZzrXWZG2gOuQA88V
XbK5BIolFIky4bsIeLMV00CuUi4F41SqroznGjJ9svh+xnUmn1UkK1StzMb9VBJULBU5GP6z+ziX
cP3z4CNz/UthppTbJh3oe+l6fWcap5Df50ezuH7pHIdCziGDP2MoMjzz+lYWD7BKJseL2Y1JnsU5
pXNESu6oiZfaYOvcyTu8HKZx/bI5Unl8dQngmA3rc/tmFH/M5bpmqtgqNBW/V3wibwC6mVxHZtn7
gGu26lPpHLvBWigRwuTv10KxQLp6zRyAWb/1C1TrZvbZupB72TdRmcNjMZuvSue2LulDIYfHb74q
+awBHua14yzVPwv7JBuMrzeOvOv+ldyh0PLyHmzBLO5PeaqEJX1ofD9dJXdlQ10r4+cdT1/eHly5
B3aP/V3pwP4zfkCuHdgJKFl4Gl9bPWRd/6ySn5Wa1X/mGdjD3alyeU/JSk/f3/16uw8ldytno4Hd
r4P36Uov6O7rSpT64errTJbxp/01XTkNVvMVA897bs5X0axe3TGUltJf2nm3wLi574Dmd1WooSfE
Wl7vFS7L+NijdiZMv3p1LZtfOeRUXDfkVPV9NvDq8n3413F716pnqkqOMOsnE1S6dch7PuvHhCGg
vN2qHmL1fu9j1KagoX0ow2DxAMkdqsWVN2WMp+HfeL+WyPFeAr+JXEYH7/wSeBdeC3ODO0rlv4VA
Xz+C7kd3+DkqNOCgQ0/Ol9KH4SDUighcG/j/T0thHMCvFmSBq5mPTfzqj7bD1Y+PfQ99Ok1Kj8O+
aDXcGVEcXH1QMlwNnJ6er9IhP7hq+VjD10h8LPJ5wmcEPoNt8yihlPSuJj2UfEXJ7WTyz2Pky9Xk
1s1m6RYlt06IN2/Mk242k5sN4o3rI6Qb88gNm3h9BPnHtUTpH7fJtUTyX5R8QcnnyeRqIPmslXSD
iN2UdHd8fc72tfjpNPLJFYf0SSu54iAfU/L3v0VIf6fkbxHkI0ouLyEfUvLXY+TSX8KkS7fJX8LI
B63kz5S8T8mfLgZJf6LkYhB5r5X88Q9B0h8p+cMWH+kPQeT3q8m7U8gFuLkwhZyn5J3fGaR3KPmd
gZyj5G1Kzm42S2eHkd8Gk7coebOVvNEUJ71ByeuUnFlNXqPkVUp+Q8np7b5SFyWnKDlJySuUnAB6
JwLJcSPp/PUxqZOSX788X/r1MfLrBvHlY3HSy/PJyzbxWBx5iZKjraSjJV16kZIj8HXkNvkV0DpM
yS8d5JCD/MKPHLSQA5S8QG295OeUPE/JzyxkPyXP7fOTnksm+/zIs3vN0rOjyF4z+ekzY6WfribP
jCU/oWQPJT+mZPeuMGm3g+x62iTtCiNPm8iPDGQnJTuAyQ5KtvuS9m0JUjsl2xJIG/BvayWtTx2T
Wil5CnzrqWPkqQbxycfjpCfnkydt4lZKfkjJE3D/xDHyeBxpATBa0sljoO1jgWSLD2mGiWYHaQLQ
muLIZjPZRMlGSjZQsr7RLK2npNFM/pOSdZQ8as6QHi0haylpWE7WPLJaWkPJI6vJ6ijyH5Ss8iMr
KVlGyVJK6j1Gqd6f1HdgZHtP9BiJ54TothC3Tayj5GFKailx1ZRIrlZSUz1Kqikh1aNIFSVLkslD
lFQmk4rbZPExUk6JkxIHJWWLoqQyShYhk7QoitgpWUjJAkoevN9HetCPzHeQH7xGHoCbBwLJ/T4E
PHpuIJlDyWxKZkWESbOSSSklJZQUU3LfalJESWEgKaAkH4+V8inJO0ZmjiIzckOlGRNJbqZFyg0l
07NDpemUTIO7aQ6SA3c5x0h2KMmCiayJJDPDLGVaSGaHYLPpxYx0fynDTDI6BAR36TY/Kd2fpHfg
E3BnSzNKNj9i68ANcJdm1EtpRpLWgW02h3gvJfeACPfcJlMpuXsUmULJZAB4soNMGhcuTZpJJlIy
YWygNIGS1JlkfFK4NH4mSYGvFEqSYWEyJePg8bhwkhROEmGUGEoS9MFSwjEyNj5AGhtIxnYIjG28
ySzFB5B4Jm6rOOauOGkMJXfByrviyGhhijSaklGUjKRkhD+JC86Q4rLJcH8SS4nV31+yUhIjj5Vi
VhN5LImeSaKAcxQlkZQMA2yHURIBVokII+GUhFESSkkIUAjJIcFBY6XgDBIUaJKCxpJAEwmAdQGB
xAL7LZSYQXNzBjEBB5OZmBTs/P2Mkr8/8Vew8/M1SH5G4qdg5wvY+RqIL2B3WDTqiZH51kTRhxID
aGKgRB9MdCaipUQDpDWUSIGEgHLkNhFgQphCMAiAxxJkIrgDOxq34DH/d37Q/7YA/+ZPJPpvgO3r
dQplbmRzdHJlYW0KZW5kb2JqCgo2IDAgb2JqCjEwNDEzCmVuZG9iagoKNyAwIG9iago8PC9UeXBl
L0ZvbnREZXNjcmlwdG9yL0ZvbnROYW1lL0JBQUFBQStEZWphVnVTYW5zTW9ubwovRmxhZ3MgNQov
Rm9udEJCb3hbLTU1NyAtMzc0IDcxNiAxMDQxXS9JdGFsaWNBbmdsZSAwCi9Bc2NlbnQgOTI4Ci9E
ZXNjZW50IC0yMzUKL0NhcEhlaWdodCAxMDQxCi9TdGVtViA4MAovRm9udEZpbGUyIDUgMCBSCj4+
CmVuZG9iagoKOCAwIG9iago8PC9MZW5ndGggNDE2L0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVh
bQp4nF2TzW7iMBSF93kKLzuLKvEPCZVQJAaKxKIz1dA+QEgME2lwIhMWvH197klbaRagz/G9l8/m
JN/st/vQT/lrHNqDn9SpD1301+EWW6+O/tyHTBvV9e00r+S7vTRjlqfew/06+cs+nIbVKsv/pL3r
FO/qYd0NR/8jy3/Hzsc+nNXD++aQ1ofbOP7zFx8mVWR1rTp/SnNemvFXc/G5dD3uu7TdT/fH1PJd
8HYfvTKy1lRph85fx6b1sQlnn62Kolar3a7OfOj+23OWLcdT+7eJqVSn0qJYFHViI1wZsBUud2BH
LsEL8hO4JG/AFXkBXgq7Z/ATn2vwmrwF/xQ28rsbYbsGb9krc55ZL3N2dMMcXZBRo+nv0Ktnfwum
v5P62d+B6W/lOf0tzqtnf2H6V1JPf4Mzavo7mU//cgmmf4Wz6NkfZ9T0txWY/hYzDf0t6s3sj7s1
9C8x39B/AU9Dfwc3Q38nvfQ3uB9Df4v/xdDfykz6W5lJf4t7M/S3SwnJnAbEBXn+jKFqbzGmCEro
JXtIXR/813sxDiO65PMBZrbPkAplbmRzdHJlYW0KZW5kb2JqCgo5IDAgb2JqCjw8L1R5cGUvRm9u
dC9TdWJ0eXBlL1RydWVUeXBlL0Jhc2VGb250L0JBQUFBQStEZWphVnVTYW5zTW9ubwovRmlyc3RD
aGFyIDAKL0xhc3RDaGFyIDQzCi9XaWR0aHNbNjAyIDYwMiA2MDIgNjAyIDYwMiA2MDIgNjAyIDYw
MiA2MDIgNjAyIDYwMiA2MDIgNjAyIDYwMiA2MDIgNjAyCjYwMiA2MDIgNjAyIDYwMiA2MDIgNjAy
IDYwMiA2MDIgNjAyIDYwMiA2MDIgNjAyIDYwMiA2MDIgNjAyIDYwMgo2MDIgNjAyIDYwMiA2MDIg
NjAyIDYwMiA2MDIgNjAyIDYwMiA2MDIgNjAyIDYwMiBdCi9Gb250RGVzY3JpcHRvciA3IDAgUgov
VG9Vbmljb2RlIDggMCBSCj4+CmVuZG9iagoKMTAgMCBvYmoKPDwvRjEgOSAwIFIKPj4KZW5kb2Jq
CgoxMSAwIG9iago8PC9Gb250IDEwIDAgUgovUHJvY1NldFsvUERGL1RleHRdCj4+CmVuZG9iagoK
MSAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDQgMCBSL1Jlc291cmNlcyAxMSAwIFIvTWVkaWFC
b3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwvUy9UcmFuc3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0kgdHJ1
ZT4+L0NvbnRlbnRzIDIgMCBSPj4KZW5kb2JqCgo0IDAgb2JqCjw8L1R5cGUvUGFnZXMKL1Jlc291
cmNlcyAxMSAwIFIKL01lZGlhQm94WyAwIDAgNTk1IDg0MiBdCi9LaWRzWyAxIDAgUiBdCi9Db3Vu
dCAxPj4KZW5kb2JqCgoxMiAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgNCAwIFIKL09wZW5B
Y3Rpb25bMSAwIFIgL1hZWiBudWxsIG51bGwgMF0KL0xhbmcoZW4tSU4pCj4+CmVuZG9iagoKMTMg
MCBvYmoKPDwvQ3JlYXRvcjxGRUZGMDA1NzAwNzIwMDY5MDA3NDAwNjUwMDcyPgovUHJvZHVjZXI8
RkVGRjAwNEMwMDY5MDA2MjAwNzIwMDY1MDA0RjAwNjYwMDY2MDA2OTAwNjMwMDY1MDAyMDAwMzMw
MDJFMDAzNj4KL0NyZWF0aW9uRGF0ZShEOjIwMTMwOTE3MTA1MjE5KzA1JzMwJyk+PgplbmRvYmoK
CnhyZWYKMCAxNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMTIxNDEgMDAwMDAgbiAKMDAwMDAw
MDAxOSAwMDAwMCBuIAowMDAwMDAwNTAzIDAwMDAwIG4gCjAwMDAwMTIyODQgMDAwMDAgbiAKMDAw
MDAwMDUyMyAwMDAwMCBuIAowMDAwMDExMDIxIDAwMDAwIG4gCjAwMDAwMTEwNDMgMDAwMDAgbiAK
MDAwMDAxMTIzOCAwMDAwMCBuIAowMDAwMDExNzIzIDAwMDAwIG4gCjAwMDAwMTIwNTQgMDAwMDAg
biAKMDAwMDAxMjA4NiAwMDAwMCBuIAowMDAwMDEyMzgzIDAwMDAwIG4gCjAwMDAwMTI0ODAgMDAw
MDAgbiAKdHJhaWxlcgo8PC9TaXplIDE0L1Jvb3QgMTIgMCBSCi9JbmZvIDEzIDAgUgovSUQgWyA8
MUQ3RURGOENDMTExODZGOUQwNERCQTNCNTIxRUIwRUQ+CjwxRDdFREY4Q0MxMTE4NkY5RDA0REJB
M0I1MjFFQjBFRD4gXQovRG9jQ2hlY2tzdW0gL0FGQTcyQ0IwMzY4QzE1RjAyN0YxODgxNDAxQkM3
QkQ0Cj4+CnN0YXJ0eHJlZgoxMjY1NQolJUVPRgo=</field>
<field name="datas_fname">Jones_CV.pdf</field>
<field name="name">Jones_CV.pdf</field>
<field name="res_id" ref="hr_recruitment.hr_case_salesman0"/>
<field name="res_model">hr.applicant</field>
</record>
<record id="applicant_attach2" model="ir.attachment">
<field name="datas">UFJPRklMRSANCg0KTmFtZSAgICAgICAgICAgIDogU2hhbmUgV2lsbGlhbXMgIA0KQWRkcmVzcyAgICAgICAgIDogODEgQWNhZGVteSBBdmVudWUsIA0KICAgICAgICAgICAgICAgICAgICAgOkJpcm1pbmdoYW1CNDYgM0FHLCANCiAgICAgICAgICAgICAgICAgICAgIDpVbml0ZWQgS2luZ2RvbSwgDQpRdWFsaWZpY2F0aW9uICAgOiBNQ0EgDQpFbWFpbCAgICAgICAgICAgICA6IFNoYW5lV2lsbGlhbXNAaW5mby5jb20gDQpNb2JpbGUgICAgICAgICAgIDogOTk2MzIxNDU4NyA=</field>
<field name="datas_fname">Williams_CV.doc</field>
<field name="name">Williams_CV.doc</field>
<field name="res_id" ref="hr_recruitment.hr_case_programmer"/>
<field name="res_model">hr.applicant</field>
</record>
<record id="applicant_attach3" model="ir.attachment">
<field name="datas">UHJvZmlsZQ0KDQpOYW1lICAgICAgICAgIDpKb3NlDQpBZGRyZXNzICAgICAgIDo5MywgUHJlc3MgQXZlbnVlDQogICAgICAgICAgICAgICAgICAgOkxlIEJvdXJnZXQgZHUgTGFjLCA3MzM3NywNCiAgICAgICAgICAgICAgICAgICA6IEZyYW5jZSANClF1YWxpZmljYXRpb24gOk1DQQ0KRW1haWwgICAgICAgICAgIDpKb3NlQGdtYWlsLmNvbQ0KTW9iaWxlICAgICAgICAgIDo5OTY4NTEzNTg3</field>
<field name="datas_fname">Jose_CV.txt</field>
<field name="name">Jose_CV.txt</field>
<field name="res_id" ref="hr_recruitment.hr_case_fresher0"/>
<field name="res_model">hr.applicant</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
import hr_applicant

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
class hr_applicant(osv.Model):
_inherit = 'hr.applicant'
def _get_index_content(self, cr, uid, ids, fields, args, context=None):
res = dict.fromkeys(ids, '')
Attachment = self.pool.get('ir.attachment')
attachment_ids = Attachment.search(cr, uid, [('res_model', '=', 'hr.applicant'), ('res_id', 'in', ids)], context=context)
for attachment in Attachment.browse(cr, uid, attachment_ids, context=context):
res[attachment.res_id] += attachment.index_content or ''
return res
def _content_search(self, cr, user, obj, name, args, context=None):
record_ids = set()
Attachment = self.pool.get('ir.attachment')
args = ['&'] + args + [('res_model', '=', 'hr.applicant')]
att_ids = Attachment.search(cr, user, args, context=context)
record_ids = set(att.res_id for att in Attachment.browse(cr, user, att_ids, context=context))
return [('id', 'in', list(record_ids))]
_columns = {
'index_content': fields.function(
_get_index_content, fnct_search=_content_search,
string='Index Content', type="text"),
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="view_crm_case_jobs_filter_inherit" model="ir.ui.view">
<field name="name">Jobs - Recruitment Search</field>
<field name="model">hr.applicant</field>
<field name="inherit_id" ref="hr_recruitment.view_crm_case_jobs_filter" />
<field name="arch" type="xml">
<field name="job_id" position="before">
<field name="index_content" string="Resume Content"/>
</field>
</field>
</record>
<record model="ir.actions.act_window" id="hr_applicant_resumes">
<field name="name">Resumes and Letters</field>
<field name="res_model">ir.attachment</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="document.view_document_file_tree"/>
<field name="domain">[('res_model','=','hr.applicant')]</field>
<field name="help" type="html">
<p>
Search through resumes and motivation letters.
</p>
</field>
</record>
<menuitem
name="Resumes and Letters"
parent="base.menu_crm_case_job_req_main"
id="menu_crm_case_categ0_act_job02" action="hr_applicant_resumes" sequence="3"/>
</data>
</openerp>

View File

@ -101,6 +101,8 @@ Thanks,
class hr_employee(osv.osv):
_name = "hr.employee"
_inherit="hr.employee"
_columns = {
'evaluation_plan_id': fields.many2one('hr_evaluation.plan', 'Appraisal Plan'),
'evaluation_date': fields.date('Next Appraisal Date', help="The date of the next appraisal is computed by the appraisal plan's dates (first appraisal + periodicity)."),
@ -123,6 +125,8 @@ class hr_employee(osv.osv):
obj_evaluation.button_plan_in_progress(cr, uid, [plan_id], context=context)
return True
class hr_evaluation(osv.osv):
_name = "hr_evaluation.evaluation"
_inherit = "mail.thread"

View File

@ -39,4 +39,4 @@ access_survey_response_hr_employee,survey.response.employee,survey.model_survey_
access_survey_question_column_heading_hr_employee,survey.question.column.heading.employee,survey.model_survey_question_column_heading,base.group_user,1,0,0,0
access_survey_response_line_hr_employee,survey.response.line.employee,survey.model_survey_response_line,base.group_user,1,1,1,0
access_survey_response_answer_hr_employee,survey.response.answer.hr.employee,survey.model_survey_response_answer,base.group_user,1,1,1,0
access_survey_tbl_column_heading_hr_employee,survey.tbl.column.heading,survey.model_survey_tbl_column_heading,base.group_user,1,1,1,0
access_survey_tbl_column_heading_hr_employee,survey.tbl.column.heading,survey.model_survey_tbl_column_heading,base.group_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
39 access_survey_question_column_heading_hr_employee survey.question.column.heading.employee survey.model_survey_question_column_heading base.group_user 1 0 0 0
40 access_survey_response_line_hr_employee survey.response.line.employee survey.model_survey_response_line base.group_user 1 1 1 0
41 access_survey_response_answer_hr_employee survey.response.answer.hr.employee survey.model_survey_response_answer base.group_user 1 1 1 0
42 access_survey_tbl_column_heading_hr_employee survey.tbl.column.heading survey.model_survey_tbl_column_heading base.group_user 1 1 1 0

View File

@ -7,57 +7,57 @@ 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: 2009-01-30 13:19+0000\n"
"Last-Translator: <>\n"
"PO-Revision-Date: 2013-12-27 04:48+0000\n"
"Last-Translator: Andy Cheng <andy@dobtor.com>\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:53+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_expense
#: view:hr.expense.expense:0
#: model:process.node,name:hr_expense.process_node_confirmedexpenses0
msgid "Confirmed Expenses"
msgstr ""
msgstr "已確認費用報支"
#. module: hr_expense
#: model:ir.model,name:hr_expense.model_hr_expense_line
msgid "Expense Line"
msgstr ""
msgstr "費用報支項目"
#. module: hr_expense
#: model:process.node,note:hr_expense.process_node_reimbursement0
msgid "The accoutant reimburse the expenses"
msgstr ""
msgstr "會計師報支費用"
#. module: hr_expense
#: model:mail.message.subtype,description:hr_expense.mt_expense_approved
msgid "Expense approved"
msgstr ""
msgstr "費用報支已核准"
#. module: hr_expense
#: field:hr.expense.expense,date_confirm:0
#: field:hr.expense.report,date_confirm:0
msgid "Confirmation Date"
msgstr ""
msgstr "確認日期"
#. module: hr_expense
#: view:hr.expense.expense:0
#: view:hr.expense.report:0
msgid "Group By..."
msgstr ""
msgstr "分組..."
#. module: hr_expense
#: model:product.template,name:hr_expense.air_ticket_product_template
msgid "Air Ticket"
msgstr ""
msgstr "機票"
#. module: hr_expense
#: report:hr.expense:0
msgid "Validated By"
msgstr ""
msgstr "已完成審核"
#. module: hr_expense
#: view:hr.expense.expense:0
@ -65,45 +65,45 @@ msgstr ""
#: view:hr.expense.report:0
#: field:hr.expense.report,department_id:0
msgid "Department"
msgstr ""
msgstr "部門"
#. module: hr_expense
#: view:hr.expense.expense:0
msgid "New Expense"
msgstr ""
msgstr "新增費用報支"
#. module: hr_expense
#: field:hr.expense.line,uom_id:0
#: view:product.product:0
msgid "Unit of Measure"
msgstr ""
msgstr "度量單位"
#. module: hr_expense
#: selection:hr.expense.report,month:0
msgid "March"
msgstr ""
msgstr "三月"
#. module: hr_expense
#: field:hr.expense.expense,message_unread:0
msgid "Unread Messages"
msgstr ""
msgstr "未讀訊息"
#. module: hr_expense
#: field:hr.expense.expense,company_id:0
#: view:hr.expense.report:0
#: field:hr.expense.report,company_id:0
msgid "Company"
msgstr ""
msgstr "公司"
#. module: hr_expense
#: view:hr.expense.expense:0
msgid "Set to Draft"
msgstr ""
msgstr "設為草稿"
#. module: hr_expense
#: view:hr.expense.expense:0
msgid "To Pay"
msgstr ""
msgstr "應付款"
#. module: hr_expense
#: code:addons/hr_expense/hr_expense.py:172
@ -111,12 +111,12 @@ msgstr ""
msgid ""
"No expense journal found. Please make sure you have a journal with type "
"'purchase' configured."
msgstr ""
msgstr "未找到費用日記帳。請確認您是否有設置型態為「採購」的日記帳。"
#. module: hr_expense
#: model:ir.model,name:hr_expense.model_hr_expense_report
msgid "Expenses Statistics"
msgstr ""
msgstr "費用報支統計"
#. module: hr_expense
#: view:hr.expense.expense:0
@ -127,7 +127,7 @@ msgstr ""
#: view:hr.expense.report:0
#: field:hr.expense.report,day:0
msgid "Day"
msgstr ""
msgstr ""
#. module: hr_expense
#: help:hr.expense.expense,date_valid:0
@ -139,12 +139,12 @@ msgstr ""
#. module: hr_expense
#: view:hr.expense.expense:0
msgid "Notes"
msgstr ""
msgstr "備註"
#. module: hr_expense
#: field:hr.expense.expense,message_ids:0
msgid "Messages"
msgstr ""
msgstr "訊息"
#. module: hr_expense
#: code:addons/hr_expense/hr_expense.py:172
@ -154,28 +154,28 @@ msgstr ""
#: code:addons/hr_expense/hr_expense.py:353
#, python-format
msgid "Error!"
msgstr ""
msgstr "錯誤!"
#. module: hr_expense
#: model:mail.message.subtype,description:hr_expense.mt_expense_refused
msgid "Expense refused"
msgstr ""
msgstr "費用報支被拒"
#. module: hr_expense
#: model:ir.actions.act_window,name:hr_expense.hr_expense_product
#: view:product.product:0
msgid "Products"
msgstr ""
msgstr "產品"
#. module: hr_expense
#: view:hr.expense.report:0
msgid "Confirm Expenses"
msgstr ""
msgstr "確認費用報支"
#. module: hr_expense
#: selection:hr.expense.report,state:0
msgid "Cancelled"
msgstr ""
msgstr "已取消"
#. module: hr_expense
#: model:process.node,note:hr_expense.process_node_refused0
@ -190,17 +190,17 @@ msgstr ""
#. module: hr_expense
#: selection:hr.expense.report,state:0
msgid "Waiting confirmation"
msgstr ""
msgstr "等待確認中"
#. module: hr_expense
#: selection:hr.expense.report,state:0
msgid "Accepted"
msgstr ""
msgstr "已接受"
#. module: hr_expense
#: field:hr.expense.line,ref:0
msgid "Reference"
msgstr ""
msgstr "參考"
#. module: hr_expense
#: report:hr.expense:0
@ -228,7 +228,7 @@ msgstr ""
#: view:hr.expense.report:0
#: field:hr.expense.report,nbr:0
msgid "# of Lines"
msgstr ""
msgstr "項目數量"
#. module: hr_expense
#: help:hr.expense.expense,message_summary:0
@ -241,33 +241,33 @@ msgstr ""
#: code:addons/hr_expense/hr_expense.py:453
#, python-format
msgid "Warning"
msgstr ""
msgstr "警告"
#. module: hr_expense
#: report:hr.expense:0
msgid "(Date and signature)"
msgstr ""
msgstr "(日期與簽名)"
#. module: hr_expense
#: report:hr.expense:0
msgid "Total:"
msgstr ""
msgstr "合計:"
#. module: hr_expense
#: model:process.transition,name:hr_expense.process_transition_refuseexpense0
msgid "Refuse expense"
msgstr ""
msgstr "拒絕費用報支"
#. module: hr_expense
#: field:hr.expense.report,price_average:0
msgid "Average Price"
msgstr ""
msgstr "平均價格"
#. module: hr_expense
#: view:hr.expense.expense:0
#: model:process.transition.action,name:hr_expense.process_transition_action_confirm0
msgid "Confirm"
msgstr ""
msgstr "確認"
#. module: hr_expense
#: model:process.node,note:hr_expense.process_node_supplierinvoice0

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import models
import wizard

View File

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013 OpenERP SA (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'HR Gamification',
'version': '1.0',
'author': 'OpenERP SA',
'category': 'hidden',
'depends': ['gamification', 'hr'],
'description': """Use the HR ressources for the gamification process.
The HR officer can now manage challenges and badges.
This allow the user to send badges to employees instead of simple users.
Badge received are displayed on the user profile.
""",
'data': [
'security/ir.model.access.csv',
'security/gamification_security.xml',
'wizard/grant_badge.xml',
'views/gamification.xml',
],
'js': ['static/src/js/gamification.js'],
}

Some files were not shown because too many files have changed in this diff Show More